): void {
// Do nothing.
}
diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js
index b35910c818ac4e..adf7b4d488aaa1 100644
--- a/Libraries/react-native/react-native-implementation.js
+++ b/Libraries/react-native/react-native-implementation.js
@@ -71,14 +71,6 @@ module.exports = {
get KeyboardAvoidingView() {
return require('KeyboardAvoidingView');
},
- get ListView() {
- warnOnce(
- 'listview-deprecation',
- 'ListView is deprecated and will be removed in a future release. ' +
- 'See https://fb.me/nolistview for more information',
- );
- return require('ListView');
- },
get MaskedViewIOS() {
warnOnce(
'maskedviewios-moved',
@@ -136,14 +128,6 @@ module.exports = {
get SwipeableFlatList() {
return require('SwipeableFlatList');
},
- get SwipeableListView() {
- warnOnce(
- 'swipablelistview-deprecation',
- 'ListView and SwipeableListView are deprecated and will be removed in a future release. ' +
- 'See https://fb.me/nolistview for more information',
- );
- return require('SwipeableListView');
- },
get Text() {
return require('Text');
},
@@ -229,6 +213,12 @@ module.exports = {
return require('BackHandler');
},
get CameraRoll() {
+ warnOnce(
+ 'cameraroll-moved',
+ 'CameraRoll 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/cameraroll' instead of 'react-native'. " +
+ 'See https://github.com/react-native-community/react-native-cameraroll',
+ );
return require('CameraRoll');
},
get Clipboard() {
@@ -374,3 +364,31 @@ module.exports = {
return require('DeprecatedViewPropTypes');
},
};
+
+if (__DEV__) {
+ // $FlowFixMe This is intentional: Flow will error when attempting to access ListView.
+ Object.defineProperty(module.exports, 'ListView', {
+ configurable: true,
+ get() {
+ invariant(
+ false,
+ 'ListView has been removed from React Native. ' +
+ 'See https://fb.me/nolistview for more information or use ' +
+ '`deprecated-react-native-listview`.',
+ );
+ },
+ });
+
+ // $FlowFixMe This is intentional: Flow will error when attempting to access SwipeableListView.
+ Object.defineProperty(module.exports, 'SwipeableListView', {
+ configurable: true,
+ get() {
+ invariant(
+ false,
+ 'SwipeableListView has been removed from React Native. ' +
+ 'See https://fb.me/nolistview for more information or use ' +
+ '`deprecated-react-native-swipeable-listview`.',
+ );
+ },
+ });
+}
diff --git a/README.md b/README.md
index 0a3250a9a3ccea..1bd961a60aec2d 100644
--- a/README.md
+++ b/README.md
@@ -1,58 +1,147 @@
-# [React Native](https://facebook.github.io/react-native/) · [![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.
-
-See the official [React Native website](https://facebook.github.io/react-native/) for an introduction to React Native.
+
+
+
+ Learn once, write anywhere:
+ Build mobile apps with React.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+React Native brings [**React**'s][r] declarative UI framework to iOS and Android. With React Native, you use native UI controls and have full access to the native platform.
+
+- **Declarative.** React makes it painless to create interactive UIs. Declarative views make your code more predictable and easier to debug.
+- **Component-Based.** Build encapsulated components that manage their own state, then compose them to make complex UIs.
+- **Developer Velocity.** See local changes in seconds. Changes to JavaScript code can be live reloaded without rebuilding the native app.
+- **Portability.** Reuse code across iOS, Android, and [other platforms][p].
+
+[r]: https://reactjs.org/
+[p]: https://facebook.github.io/react-native/docs/out-of-tree-platforms
+
+## Contents
- [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)
+- [Building your first React Native app](#building-your-first-react-native-app)
+- [Documentation](#documentation)
+- [Upgrading](#upgrading)
+- [How to Contribute](#how-to-contribute)
+- [Code of Conduct](#code-of-conduct)
- [License](#license)
----
-## Requirements
+## π 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).
+React Native apps may target iOS 9.0 and Android 4.1 (API 16) or newer. You may use Windows, macOS, or Linux as your development operating system, though building and running iOS apps is limited to macOS. Tools like [Expo](https://expo.io) can be used to work around this.
-## Building your first React Native app
+## π 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:
-- [Trying out React Native](https://snack.expo.io/BJ-uC-nrb)
-- [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)
+- [Trying out React Native][hello-world]
+- [Creating a New Application][new-app]
+- [Adding React Native to an Existing Application][existing]
+
+[hello-world]: https://snack.expo.io/@hramos/hello,-world!
+[new-app]: https://facebook.github.io/react-native/docs/getting-started.html
+[existing]: https://facebook.github.io/react-native/docs/integration-with-existing-apps.html
+
+## π Documentation
+
+The full documentation for React Native can be found on our [website][docs].
+
+The React Native documentation discusses components, APIs, and topics that are specific to React Native. For further documentation on the React API that is shared between React Native and React DOM, refer to the [React documentation][r-docs].
+
+The source for the React Native documentation and website is hosted on a separate repo, [**@facebook/react-native-website**][repo-website].
+
+[docs]: https://facebook.github.io/react-native/docs/getting-started.html
+[r-docs]: https://reactjs.org/docs/getting-started.html
+[repo-website]: (https://github.com/facebook/react-native-website)
+
+## π Upgrading
+
+Upgrading to new versions of React Native may give you access to more APIs, views, developer tools and other goodies. See the [Upgrading Guide][u] for instructions.
+
+React Native releases are discussed in the React Native Community, [**@react-native-community/react-native-releases**][repo-releases].
+
+[u]: https://facebook.github.io/react-native/docs/upgrading
+[repo-releases]: https://github.com/react-native-community/react-native-releases
+
+## π How to Contribute
+
+The main purpose of this repository is to continue evolving React Native core. We want to make contributing to this project as easy and transparent as possible, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React Native.
+
+### [Code of Conduct][code]
+
+Facebook has adopted a Code of Conduct that we expect project participants to adhere to.
+Please read the [full text][code] so that you can understand what actions will and will not be tolerated.
+
+[code]: https://code.fb.com/codeofconduct/
+
+### [Contributing Guide][contribute]
+
+Read our [**Contributing Guide**][contribute] to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to React Native.
-## How React Native works
+[contribute]: https://facebook.github.io/react-native/docs/contributing
-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.
+### [Open Source Roadmap][roadmap]
-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.
+You can learn more about our vision for React Native in the [**Roadmap**][roadmap].
-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.
+[roadmap]: https://github.com/facebook/react-native/wiki/Roadmap
-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.
+### Good First Issues
-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).
+We have a list of [good first issues][gfi] that contain bugs which have a relatively limited scope. This is a great place to get started, gain experience, and get familiar with our contribution process.
-## Full documentation
+[gfi]: https://github.com/facebook/react-native/labels/good%20first%20issue
-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, . Releases are discussed in the React Native Community, , and larger discussions and proposals are in .
+### Discussions
-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/).
+Larger discussions and proposals are discussed in [**@react-native-community/discussions-and-proposals**][repo-meta].
-## 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
+[repo-meta]: https://github.com/react-native-community/discussions-and-proposals
-See the [CONTRIBUTING](./CONTRIBUTING.md) file for how to help out.
+## π License
-## License
+React Native is MIT licensed, as found in the [LICENSE][l] file.
-React Native is MIT licensed, as found in the LICENSE file.
+React Native documentation is Creative Commons licensed, as found in the [LICENSE-docs][ld] file.
-React Native documentation is Creative Commons licensed, as found in the LICENSE-docs file.
+[l]: https://github.com/facebook/react-native/blob/master/LICENSE
+[ld]: https://github.com/facebook/react-native/blob/master/LICENSE-docs
diff --git a/RNTester/README.md b/RNTester/README.md
index 0ad4267787ce2f..cb4b7162a2258a 100644
--- a/RNTester/README.md
+++ b/RNTester/README.md
@@ -12,7 +12,7 @@ Before running the app, make sure you ran:
### Running on iOS
-Mac OS and Xcode are required.
+Both macOS and Xcode are required.
- Open `RNTester/RNTester.xcodeproj` in Xcode
- Hit the Run button
diff --git a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testScrollViewExample_1-iOS12@2x.png b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testScrollViewExample_1-iOS12@2x.png
index 06297ec33c570a..1232aed8ba7ef3 100644
Binary files a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testScrollViewExample_1-iOS12@2x.png and b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testScrollViewExample_1-iOS12@2x.png differ
diff --git a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testSliderExample_1-iOS12@2x.png b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testSliderExample_1-iOS12@2x.png
index 3476ceda8b6ca2..6f22306ea6f211 100644
Binary files a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testSliderExample_1-iOS12@2x.png and b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testSliderExample_1-iOS12@2x.png differ
diff --git a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testSwitchExample_1-iOS12@2x.png b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testSwitchExample_1-iOS12@2x.png
index aa1292f087c250..d844d1148234c0 100644
Binary files a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testSwitchExample_1-iOS12@2x.png and b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testSwitchExample_1-iOS12@2x.png differ
diff --git a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTextExample_1-iOS12@2x.png b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTextExample_1-iOS12@2x.png
index 9854157e297f9e..600673dc5588c9 100644
Binary files a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTextExample_1-iOS12@2x.png and b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testTextExample_1-iOS12@2x.png differ
diff --git a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testViewExample_1-iOS12@2x.png b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testViewExample_1-iOS12@2x.png
index a79c579819b947..c0f4ac370ed7ae 100644
Binary files a/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testViewExample_1-iOS12@2x.png and b/RNTester/RNTesterIntegrationTests/ReferenceImages/RNTester-js-RNTesterApp.ios/testViewExample_1-iOS12@2x.png differ
diff --git a/RNTester/RNTesterUnitTests/RCTEventDispatcherTests.m b/RNTester/RNTesterUnitTests/RCTEventDispatcherTests.m
index bffde88f8977ce..6ad636fcfc6b6e 100644
--- a/RNTester/RNTesterUnitTests/RCTEventDispatcherTests.m
+++ b/RNTester/RNTesterUnitTests/RCTEventDispatcherTests.m
@@ -64,8 +64,8 @@ - (void)dispatchBlock:(dispatch_block_t)block
@end
@implementation RCTDummyBridge
-- (void)dispatchBlock:(dispatch_block_t)block
- queue:(dispatch_queue_t)queue
+- (void)dispatchBlock:(dispatch_block_t __unused)block
+ queue:(dispatch_queue_t __unused)queue
{}
@end
diff --git a/RNTester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m b/RNTester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m
index eee726bf6bf32c..38d64d864e60ba 100644
--- a/RNTester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m
+++ b/RNTester/RNTesterUnitTests/RCTNativeAnimatedNodesManagerTests.m
@@ -127,8 +127,10 @@ - (void)setUp
{
[super setUp];
+ RCTBridge *bridge = [OCMockObject niceMockForClass:[RCTBridge class]];
_uiManager = [OCMockObject niceMockForClass:[RCTUIManager class]];
- _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithUIManager:_uiManager];
+ OCMStub([bridge uiManager]).andReturn(_uiManager);
+ _nodesManager = [[RCTNativeAnimatedNodesManager alloc] initWithBridge:bridge];
_displayLink = [RCTFakeDisplayLink new];
}
diff --git a/RNTester/e2e/__tests__/Switch-test.js b/RNTester/e2e/__tests__/Switch-test.js
deleted file mode 100644
index 783685d724a783..00000000000000
--- a/RNTester/e2e/__tests__/Switch-test.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @emails oncall+react_native
- * @format
- */
-
-/* global device, element, by, expect */
-
-const jestExpect = require('expect');
-const {
- openComponentWithLabel,
- openExampleWithTitle,
-} = require('../e2e-helpers');
-
-describe('Switch', () => {
- beforeAll(async () => {
- await device.reloadReactNative();
- await openComponentWithLabel('', ' Native boolean input');
- });
-
- describe('Switches can be set to true or false', () => {
- beforeAll(async () => {
- await openExampleWithTitle('Switches can be set to true or false');
- });
-
- it('Switch that starts off should switch', async () => {
- const testID = 'on-off-initial-off';
- const indicatorID = 'on-off-initial-off-indicator';
-
- await expect(element(by.id(testID))).toHaveValue('0');
- await expect(element(by.id(indicatorID))).toHaveText('Off');
- await element(by.id(testID)).tap();
- await expect(element(by.id(testID))).toHaveValue('1');
- await expect(element(by.id(indicatorID))).toHaveText('On');
- });
- });
-
- describe('Switches can be disabled', () => {
- beforeAll(async () => {
- await openExampleWithTitle('Switches can be disabled');
- });
-
- it('disabled switch should not toggle', async () => {
- const onTestID = 'disabled-initial-on';
- const offTestID = 'disabled-initial-off';
- const onIndicatorID = 'disabled-initial-on-indicator';
- const offIndicatorID = 'disabled-initial-off-indicator';
-
- await expect(element(by.id(onTestID))).toHaveValue('1');
- await expect(element(by.id(onIndicatorID))).toHaveText('On');
-
- try {
- await element(by.id(onTestID)).tap();
- throw new Error('Does not match');
- } catch (err) {
- jestExpect(err.message.message).toEqual(
- jestExpect.stringContaining(
- 'Cannot perform action due to constraint(s) failure',
- ),
- );
- }
- await expect(element(by.id(onTestID))).toHaveValue('1');
- await expect(element(by.id(onIndicatorID))).toHaveText('On');
-
- await expect(element(by.id(offTestID))).toHaveValue('0');
- await expect(element(by.id(offIndicatorID))).toHaveText('Off');
- try {
- await element(by.id(offTestID)).tap();
- throw new Error('Does not match');
- } catch (err) {
- jestExpect(err.message.message).toEqual(
- jestExpect.stringContaining(
- 'Cannot perform action due to constraint(s) failure',
- ),
- );
- }
- await expect(element(by.id(offTestID))).toHaveValue('0');
- await expect(element(by.id(offIndicatorID))).toHaveText('Off');
- });
- });
-});
diff --git a/RNTester/js/AccessibilityAndroidExample.android.js b/RNTester/js/AccessibilityAndroidExample.android.js
index ac4b6c00108667..b6e4c89bda0877 100644
--- a/RNTester/js/AccessibilityAndroidExample.android.js
+++ b/RNTester/js/AccessibilityAndroidExample.android.js
@@ -35,32 +35,6 @@ class AccessibilityAndroidExample extends React.Component {
count: 0,
backgroundImportantForAcc: 0,
forgroundImportantForAcc: 0,
- screenReaderEnabled: false,
- };
-
- componentDidMount() {
- AccessibilityInfo.addEventListener(
- 'change',
- this._handleScreenReaderToggled,
- );
- AccessibilityInfo.fetch().done(isEnabled => {
- this.setState({
- screenReaderEnabled: isEnabled,
- });
- });
- }
-
- componentWillUnmount() {
- AccessibilityInfo.removeEventListener(
- 'change',
- this._handleScreenReaderToggled,
- );
- }
-
- _handleScreenReaderToggled = isEnabled => {
- this.setState({
- screenReaderEnabled: isEnabled,
- });
};
_addOne = () => {
@@ -83,109 +57,7 @@ class AccessibilityAndroidExample extends React.Component {
render() {
return (
-
-
-
- This is
- nontouchable normal view.
-
-
-
-
-
- This is
-
- nontouchable accessible view without label.
-
-
-
-
-
-
- This is
-
- nontouchable accessible view with label.
-
-
-
-
-
-
- ToastAndroid.show('Toasts work by default', ToastAndroid.SHORT)
- }
- accessibilityRole="button">
-
- Click me
- Or not
-
-
-
-
-
-
- ToastAndroid.show('Toasts work by default', ToastAndroid.SHORT)
- }
- accessibilityRole="button"
- accessibilityStates={['disabled']}
- disabled={true}>
-
- I am disabled
- Clicking me will not trigger any action.
-
-
-
-
-
-
- ToastAndroid.show('Toasts work by default', ToastAndroid.SHORT)
- }
- accessibilityRole="button"
- accessibilityHint="Triggers
- Toasts">
-
- Click Me!
-
-
-
-
-
-
- Accessible view with hint, role, and state
-
- Talkback will say: accessibility hint button, selected{' '}
-
-
-
-
-
-
- Accessible view with label, hint, role, and state
-
- Talkback will say: accessibility label, hint button, selected{' '}
-
-
-
-
-
-
- This accessible view has no label, so the text is read.
-
-
-
+
@@ -197,13 +69,6 @@ class AccessibilityAndroidExample extends React.Component {
-
-
- The screen reader is{' '}
- {this.state.screenReaderEnabled ? 'enabled' : 'disabled'}.
-
-
-
+
+
+ Text's accessibilityLabel is the raw text itself unless it is set
+ explicitly.
+
+
+
+
+
+ This text component's accessibilityLabel is set explicitly.
+
+
+
+
+
+ This is text one.
+ This is text two.
+
+
+
+
+
+ This is text one.
+ This is text two.
+
+
+
+
+
+ This is text one.
+ This is text two.
+
+
+
+ {/* Android screen readers will say the accessibility hint instead of the text
+ since the view doesn't have a label. */}
+
+
+ This is text one.
+ This is text two.
+
+
+
+
+
+ This is text one.
+ This is text two.
+
+
+
+
+ This is a title.
+
+
+
+ Alert.alert('Link has been clicked!')}
+ accessibilityRole="link">
+
+ Click me
+
+
+
+
+
+ Alert.alert('Button has been pressed!')}
+ accessibilityRole="button">
+ Click me
+
+
+
+
+ Alert.alert('Button has been pressed!')}
+ accessibilityRole="button"
+ accessibilityStates={['disabled']}
+ disabled={true}>
+
+
+ I am disabled. Clicking me will not trigger any action.
+
+
+
+
+
+
+
+ This view is selected and disabled.
+
+
+
+
+
+ Accessible view with label, hint, role, and state
+
+
+
+ );
+ }
+}
+
+class ScreenReaderStatusExample extends React.Component<{}> {
+ state = {
+ screenReaderEnabled: false,
+ };
+
+ componentDidMount() {
+ AccessibilityInfo.addEventListener(
+ 'change',
+ this._handleScreenReaderToggled,
+ );
+ AccessibilityInfo.fetch().done(isEnabled => {
+ this.setState({
+ screenReaderEnabled: isEnabled,
+ });
+ });
+ }
+
+ componentWillUnmount() {
+ AccessibilityInfo.removeEventListener(
+ 'change',
+ this._handleScreenReaderToggled,
+ );
+ }
+
+ _handleScreenReaderToggled = isEnabled => {
+ this.setState({
+ screenReaderEnabled: isEnabled,
+ });
+ };
+
+ render() {
+ return (
+
+
+ The screen reader is{' '}
+ {this.state.screenReaderEnabled ? 'enabled' : 'disabled'}.
+
+
+ );
+ }
+}
+
+exports.title = 'Accessibility';
+exports.description = 'Examples of using Accessibility APIs.';
+exports.examples = [
+ {
+ title: 'Accessibility elements',
+ render(): React.Element {
+ return ;
+ },
+ },
+ {
+ title: 'Check if the screen reader is enabled',
+ render(): React.Element {
+ return ;
+ },
+ },
+];
diff --git a/RNTester/js/AccessibilityIOSExample.js b/RNTester/js/AccessibilityIOSExample.js
index f9feffc05c76ad..bcd6bccd670f77 100644
--- a/RNTester/js/AccessibilityIOSExample.js
+++ b/RNTester/js/AccessibilityIOSExample.js
@@ -14,11 +14,13 @@ const React = require('react');
const ReactNative = require('react-native');
const {AccessibilityInfo, Text, View, TouchableOpacity, Alert} = ReactNative;
+const RNTesterBlock = require('./RNTesterBlock');
+
type Props = $ReadOnly<{||}>;
class AccessibilityIOSExample extends React.Component {
render() {
return (
-
+
Alert.alert('Alert', 'onAccessibilityTap success')
@@ -36,112 +38,23 @@ class AccessibilityIOSExample extends React.Component {
accessible={true}>
Accessibility escape example
-
- Accessibility label example
-
-
- Accessibility traits example
-
-
- Text's accessibilityLabel is the raw text itself unless it is set
- explicitly.
-
-
- This text component's accessibilityLabel is set explicitly.
-
-
-
- This view component has both an accessibilityLabel and an
- accessibilityHint explicitly set.
-
-
-
- This text component has both an accessibilityLabel and an
- accessibilityHint explicitly set.
-
-
-
-
- This button has both an accessibilityLabel and an
- accessibilityHint explicitly set.
-
-
-
This view's children are hidden from the accessibility tree
-
- );
- }
-}
-
-class ScreenReaderStatusExample extends React.Component<{}, $FlowFixMeState> {
- state = {
- screenReaderEnabled: false,
- };
-
- componentDidMount() {
- AccessibilityInfo.addEventListener(
- 'change',
- this._handleScreenReaderToggled,
- );
- AccessibilityInfo.fetch().done(isEnabled => {
- this.setState({
- screenReaderEnabled: isEnabled,
- });
- });
- }
-
- componentWillUnmount() {
- AccessibilityInfo.removeEventListener(
- 'change',
- this._handleScreenReaderToggled,
- );
- }
-
- _handleScreenReaderToggled = isEnabled => {
- this.setState({
- screenReaderEnabled: isEnabled,
- });
- };
-
- render() {
- return (
-
-
- The screen reader is{' '}
- {this.state.screenReaderEnabled ? 'enabled' : 'disabled'}.
-
-
+
);
}
}
exports.title = 'AccessibilityIOS';
-exports.description = "Interface to show iOS' accessibility samples";
+exports.description = 'iOS specific Accessibility APIs';
exports.examples = [
{
- title: 'Accessibility elements',
+ title: 'iOS Accessibility elements',
render(): React.Element {
return ;
},
},
- {
- title: 'Check if the screen reader is enabled',
- render(): React.Element {
- return ;
- },
- },
];
diff --git a/RNTester/js/ImageExample.js b/RNTester/js/ImageExample.js
index 7b55b1c4f2569f..6f32a108426b47 100644
--- a/RNTester/js/ImageExample.js
+++ b/RNTester/js/ImageExample.js
@@ -93,7 +93,7 @@ class NetworkImageCallbackExample extends React.Component<
`β Prefetch OK (+${new Date() - mountTime}ms)`,
);
Image.queryCache([IMAGE_PREFETCH_URL]).then(map => {
- const result = map.get(IMAGE_PREFETCH_URL);
+ const result = map[IMAGE_PREFETCH_URL];
if (result) {
this._loadEventFired(
`β queryCache "${result}" (+${new Date() -
@@ -836,10 +836,7 @@ exports.examples = [
return (
);
},
diff --git a/RNTester/js/ListViewExample.js b/RNTester/js/ListViewExample.js
deleted file mode 100644
index a8663da20bd5b7..00000000000000
--- a/RNTester/js/ListViewExample.js
+++ /dev/null
@@ -1,175 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict-local
- */
-
-'use strict';
-
-const React = require('react');
-const ReactNative = require('react-native');
-const {
- Image,
- ListView,
- TouchableHighlight,
- StyleSheet,
- Text,
- View,
-} = ReactNative;
-const ListViewDataSource = require('ListViewDataSource');
-const RNTesterPage = require('./RNTesterPage');
-
-import type {RNTesterProps} from 'RNTesterTypes';
-
-type State = {|
- dataSource: ListViewDataSource,
-|};
-
-class ListViewExample extends React.Component {
- state = {
- dataSource: this.getInitialDataSource(),
- };
-
- _pressData: {[key: number]: boolean} = {};
-
- getInitialDataSource() {
- const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
- return ds.cloneWithRows(this._genRows({}));
- }
-
- UNSAFE_componentWillMount() {
- this._pressData = {};
- }
-
- render() {
- return (
- '}
- noSpacer={true}
- noScroll={true}>
-
-
- );
- }
-
- _renderRow = (
- rowData: string,
- sectionID: number,
- rowID: number,
- highlightRow: (sectionID: number, rowID: number) => void,
- ) => {
- const rowHash = Math.abs(hashCode(rowData));
- const imgSource = THUMB_URLS[rowHash % THUMB_URLS.length];
- return (
- {
- this._pressRow(rowID);
- highlightRow(sectionID, rowID);
- }}>
-
-
-
-
- {rowData + ' - ' + LOREM_IPSUM.substr(0, (rowHash % 301) + 10)}
-
-
-
-
- );
- };
-
- _genRows(pressData: {[key: number]: boolean}): Array {
- const dataBlob = [];
- for (let ii = 0; ii < 100; ii++) {
- const pressedText = pressData[ii] ? ' (pressed)' : '';
- dataBlob.push('Row ' + ii + pressedText);
- }
- return dataBlob;
- }
-
- _pressRow = (rowID: number) => {
- this._pressData[rowID] = !this._pressData[rowID];
- this.setState({
- dataSource: this.state.dataSource.cloneWithRows(
- this._genRows(this._pressData),
- ),
- });
- };
-
- _renderSeparator(
- sectionID: number,
- rowID: number,
- adjacentRowHighlighted: boolean,
- ) {
- return (
-
- );
- }
-}
-
-const THUMB_URLS = [
- require('./Thumbnails/like.png'),
- require('./Thumbnails/dislike.png'),
- require('./Thumbnails/call.png'),
- require('./Thumbnails/fist.png'),
- require('./Thumbnails/bandaged.png'),
- require('./Thumbnails/flowers.png'),
- require('./Thumbnails/heart.png'),
- require('./Thumbnails/liking.png'),
- require('./Thumbnails/party.png'),
- require('./Thumbnails/poke.png'),
- require('./Thumbnails/superlike.png'),
- require('./Thumbnails/victory.png'),
-];
-const LOREM_IPSUM =
- 'Lorem ipsum dolor sit amet, ius ad pertinax oportere accommodare, an vix civibus corrumpit referrentur. Te nam case ludus inciderint, te mea facilisi adipiscing. Sea id integre luptatum. In tota sale consequuntur nec. Erat ocurreret mei ei. Eu paulo sapientem vulputate est, vel an accusam intellegam interesset. Nam eu stet pericula reprimique, ea vim illud modus, putant invidunt reprehendunt ne qui.';
-
-/* eslint no-bitwise: 0 */
-const hashCode = function(str) {
- let hash = 15;
- for (let ii = str.length - 1; ii >= 0; ii--) {
- hash = (hash << 5) - hash + str.charCodeAt(ii);
- }
- return hash;
-};
-
-const styles = StyleSheet.create({
- row: {
- flexDirection: 'row',
- justifyContent: 'center',
- padding: 10,
- backgroundColor: '#F6F6F6',
- },
- thumb: {
- width: 64,
- height: 64,
- },
- text: {
- flex: 1,
- },
-});
-
-exports.title = '';
-exports.description = 'Performant, scrollable list of data.';
-exports.examples = [
- {
- title: 'Simple list of items',
- render: function(): React.Element {
- return ;
- },
- },
-];
diff --git a/RNTester/js/ListViewGridLayoutExample.js b/RNTester/js/ListViewGridLayoutExample.js
deleted file mode 100644
index e3d6cb5b63c973..00000000000000
--- a/RNTester/js/ListViewGridLayoutExample.js
+++ /dev/null
@@ -1,161 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow strict-local
- */
-
-'use strict';
-
-const React = require('react');
-const ReactNative = require('react-native');
-const {
- Image,
- ListView,
- TouchableHighlight,
- StyleSheet,
- Text,
- View,
-} = ReactNative;
-const ListViewDataSource = require('ListViewDataSource');
-
-import type {RNTesterProps} from 'RNTesterTypes';
-
-const THUMB_URLS = [
- require('./Thumbnails/like.png'),
- require('./Thumbnails/dislike.png'),
- require('./Thumbnails/call.png'),
- require('./Thumbnails/fist.png'),
- require('./Thumbnails/bandaged.png'),
- require('./Thumbnails/flowers.png'),
- require('./Thumbnails/heart.png'),
- require('./Thumbnails/liking.png'),
- require('./Thumbnails/party.png'),
- require('./Thumbnails/poke.png'),
- require('./Thumbnails/superlike.png'),
- require('./Thumbnails/victory.png'),
-];
-
-type State = {|
- dataSource: ListViewDataSource,
-|};
-
-class ListViewGridLayoutExample extends React.Component {
- state = {
- dataSource: this.getInitialDataSource(),
- };
-
- getInitialDataSource() {
- const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
- return ds.cloneWithRows(this._genRows({}));
- }
-
- _pressData: {[key: number]: boolean} = {};
-
- UNSAFE_componentWillMount() {
- this._pressData = {};
- }
-
- render() {
- return (
- // ListView wraps ScrollView and so takes on its properties.
- // With that in mind you can use the ScrollView's contentContainerStyle prop to style the items.
-
- );
- }
-
- _renderRow = (rowData: string, sectionID: number, rowID: number) => {
- const rowHash = Math.abs(hashCode(rowData));
- const imgSource = THUMB_URLS[rowHash % THUMB_URLS.length];
- return (
- this._pressRow(rowID)}
- underlayColor="transparent">
-
-
-
- {rowData}
-
-
-
- );
- };
-
- _genRows(pressData: {[key: number]: boolean}): Array {
- const dataBlob = [];
- for (let ii = 0; ii < 100; ii++) {
- const pressedText = pressData[ii] ? ' (X)' : '';
- dataBlob.push('Cell ' + ii + pressedText);
- }
- return dataBlob;
- }
-
- _pressRow = (rowID: number) => {
- this._pressData[rowID] = !this._pressData[rowID];
- this.setState({
- dataSource: this.state.dataSource.cloneWithRows(
- this._genRows(this._pressData),
- ),
- });
- };
-}
-
-/* eslint no-bitwise: 0 */
-const hashCode = function(str) {
- let hash = 15;
- for (let ii = str.length - 1; ii >= 0; ii--) {
- hash = (hash << 5) - hash + str.charCodeAt(ii);
- }
- return hash;
-};
-
-const styles = StyleSheet.create({
- list: {
- justifyContent: 'space-around',
- flexDirection: 'row',
- flexWrap: 'wrap',
- alignItems: 'flex-start',
- },
- row: {
- justifyContent: 'center',
- padding: 5,
- margin: 3,
- width: 100,
- height: 100,
- backgroundColor: '#F6F6F6',
- alignItems: 'center',
- borderWidth: 1,
- borderRadius: 5,
- borderColor: '#CCC',
- },
- thumb: {
- width: 64,
- height: 64,
- },
- text: {
- flex: 1,
- marginTop: 5,
- fontWeight: 'bold',
- },
-});
-
-exports.title = ' - Grid Layout';
-exports.description = 'Flexbox grid layout.';
-exports.examples = [
- {
- title: 'Simple list view with grid layout',
- render: function(): React.Element {
- return ;
- },
- },
-];
diff --git a/RNTester/js/ListViewPagingExample.js b/RNTester/js/ListViewPagingExample.js
deleted file mode 100644
index aa41c9d4e5da74..00000000000000
--- a/RNTester/js/ListViewPagingExample.js
+++ /dev/null
@@ -1,290 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
-
-'use strict';
-
-const React = require('react');
-const ReactNative = require('react-native');
-const {
- Image,
- LayoutAnimation,
- ListView,
- StyleSheet,
- Text,
- TouchableOpacity,
- View,
-} = ReactNative;
-
-const NativeModules = require('NativeModules');
-const {UIManager} = NativeModules;
-
-const THUMB_URLS = [
- require('./Thumbnails/like.png'),
- require('./Thumbnails/dislike.png'),
- require('./Thumbnails/call.png'),
- require('./Thumbnails/fist.png'),
- require('./Thumbnails/bandaged.png'),
- require('./Thumbnails/flowers.png'),
- require('./Thumbnails/heart.png'),
- require('./Thumbnails/liking.png'),
- require('./Thumbnails/party.png'),
- require('./Thumbnails/poke.png'),
- require('./Thumbnails/superlike.png'),
- require('./Thumbnails/victory.png'),
-];
-const NUM_SECTIONS = 100;
-const NUM_ROWS_PER_SECTION = 10;
-
-class Thumb extends React.Component<{}, $FlowFixMeState> {
- UNSAFE_componentWillMount() {
- UIManager.setLayoutAnimationEnabledExperimental &&
- UIManager.setLayoutAnimationEnabledExperimental(true);
- }
-
- _getThumbIdx = () => {
- return Math.floor(Math.random() * THUMB_URLS.length);
- };
-
- _onPressThumb = () => {
- const config =
- layoutAnimationConfigs[
- this.state.thumbIndex % layoutAnimationConfigs.length
- ];
- LayoutAnimation.configureNext(config);
- this.setState({
- thumbIndex: this._getThumbIdx(),
- dir: this.state.dir === 'row' ? 'column' : 'row',
- });
- };
-
- state = {thumbIndex: this._getThumbIdx(), dir: 'row'};
-
- render() {
- return (
-
-
-
-
- {this.state.dir === 'column' ? (
-
- Oooo, look at this new text! So awesome it may just be crazy. Let me
- keep typing here so it wraps at least one line.
-
- ) : (
-
- )}
-
- );
- }
-}
-
-class ListViewPagingExample extends React.Component<$FlowFixMeProps, *> {
- constructor(props) {
- super(props);
- const getSectionData = (dataBlob, sectionID) => {
- return dataBlob[sectionID];
- };
- const getRowData = (dataBlob, sectionID, rowID) => {
- return dataBlob[rowID];
- };
-
- const dataSource = new ListView.DataSource({
- getRowData: getRowData,
- getSectionHeaderData: getSectionData,
- rowHasChanged: (row1, row2) => row1 !== row2,
- sectionHeaderHasChanged: (s1, s2) => s1 !== s2,
- });
-
- const dataBlob = {};
- const sectionIDs = [];
- const rowIDs = [];
- for (let ii = 0; ii < NUM_SECTIONS; ii++) {
- const sectionName = 'Section ' + ii;
- sectionIDs.push(sectionName);
- dataBlob[sectionName] = sectionName;
- rowIDs[ii] = [];
-
- for (let jj = 0; jj < NUM_ROWS_PER_SECTION; jj++) {
- const rowName = 'S' + ii + ', R' + jj;
- rowIDs[ii].push(rowName);
- dataBlob[rowName] = rowName;
- }
- }
-
- this.state = {
- dataSource: dataSource.cloneWithRowsAndSections(
- dataBlob,
- sectionIDs,
- rowIDs,
- ),
- headerPressCount: 0,
- };
- }
-
- renderRow = (
- rowData: string,
- sectionID: string,
- rowID: string,
- ): React.Element => {
- return ;
- };
-
- renderSectionHeader = (sectionData: string, sectionID: string) => {
- return (
-
- {sectionData}
-
- );
- };
-
- renderHeader = () => {
- const headerLikeText =
- this.state.headerPressCount % 2 ? (
-
- 1 Like
-
- ) : null;
- return (
-
- {headerLikeText}
-
- Table Header (click me)
-
-
- );
- };
-
- renderFooter = () => {
- return (
-
- console.log('Footer!')} style={styles.text}>
- Table Footer
-
-
- );
- };
-
- render() {
- return (
-
- console.log({visibleRows, changedRows})
- }
- renderHeader={this.renderHeader}
- renderFooter={this.renderFooter}
- renderSectionHeader={this.renderSectionHeader}
- renderRow={this.renderRow}
- initialListSize={10}
- pageSize={4}
- scrollRenderAheadDistance={500}
- stickySectionHeadersEnabled
- />
- );
- }
-
- _onPressHeader = () => {
- const config =
- layoutAnimationConfigs[
- Math.floor(this.state.headerPressCount / 2) %
- layoutAnimationConfigs.length
- ];
- LayoutAnimation.configureNext(config);
- this.setState({headerPressCount: this.state.headerPressCount + 1});
- };
-}
-
-const styles = StyleSheet.create({
- listview: {
- backgroundColor: '#B0C4DE',
- },
- header: {
- height: 40,
- justifyContent: 'center',
- alignItems: 'center',
- backgroundColor: '#3B5998',
- flexDirection: 'row',
- },
- text: {
- color: 'white',
- paddingHorizontal: 8,
- },
- buttonContents: {
- flexDirection: 'row',
- justifyContent: 'center',
- alignItems: 'center',
- marginHorizontal: 5,
- marginVertical: 3,
- padding: 5,
- backgroundColor: '#EAEAEA',
- borderRadius: 3,
- paddingVertical: 10,
- },
- img: {
- width: 64,
- height: 64,
- marginHorizontal: 10,
- backgroundColor: 'transparent',
- },
- section: {
- flexDirection: 'column',
- justifyContent: 'center',
- alignItems: 'flex-start',
- padding: 6,
- backgroundColor: '#5890ff',
- },
-});
-
-const animations = {
- layout: {
- spring: {
- duration: 750,
- create: {
- duration: 300,
- type: LayoutAnimation.Types.easeInEaseOut,
- property: LayoutAnimation.Properties.opacity,
- },
- update: {
- type: LayoutAnimation.Types.spring,
- springDamping: 0.4,
- },
- },
- easeInEaseOut: {
- duration: 300,
- create: {
- type: LayoutAnimation.Types.easeInEaseOut,
- property: LayoutAnimation.Properties.scaleXY,
- },
- update: {
- delay: 100,
- type: LayoutAnimation.Types.easeInEaseOut,
- },
- },
- },
-};
-
-const layoutAnimationConfigs = [
- animations.layout.spring,
- animations.layout.easeInEaseOut,
-];
-
-exports.title = ' - Paging';
-exports.description = 'Floating headers & layout animations.';
-exports.examples = [
- {
- title: 'Simple list view with pagination',
- render: function(): React.Element {
- return ;
- },
- },
-];
diff --git a/RNTester/js/RNTesterApp.ios.js b/RNTester/js/RNTesterApp.ios.js
index 0ba8d62eb7f062..c0c467261a82a5 100644
--- a/RNTester/js/RNTesterApp.ios.js
+++ b/RNTester/js/RNTesterApp.ios.js
@@ -43,8 +43,6 @@ type Props = {
};
YellowBox.ignoreWarnings([
- 'ListView and SwipeableListView are deprecated',
- 'ListView is deprecated',
'Module RCTImagePickerManager requires main queue setup',
]);
diff --git a/RNTester/js/RNTesterList.android.js b/RNTester/js/RNTesterList.android.js
index 9f1b648c7a5b41..61684752699a73 100644
--- a/RNTester/js/RNTesterList.android.js
+++ b/RNTester/js/RNTesterList.android.js
@@ -33,18 +33,6 @@ const ComponentExamples: Array = [
key: 'ImageExample',
module: require('./ImageExample'),
},
- {
- key: 'ListViewExample',
- module: require('./ListViewExample'),
- },
- {
- key: 'ListViewGridLayoutExample',
- module: require('./ListViewGridLayoutExample'),
- },
- {
- key: 'ListViewPagingExample',
- module: require('./ListViewPagingExample'),
- },
{
key: 'ModalExample',
module: require('./ModalExample'),
@@ -87,10 +75,6 @@ const ComponentExamples: Array = [
key: 'SwipeableFlatListExample',
module: require('./SwipeableFlatListExample'),
},
- {
- key: 'SwipeableListViewExample',
- module: require('./SwipeableListViewExample'),
- },
{
key: 'SwitchExample',
module: require('./SwitchExample'),
@@ -134,6 +118,10 @@ const ComponentExamples: Array = [
];
const APIExamples: Array = [
+ {
+ key: 'AccessibilityExample',
+ module: require('./AccessibilityExample'),
+ },
{
key: 'AccessibilityAndroidExample',
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
diff --git a/RNTester/js/RNTesterList.ios.js b/RNTester/js/RNTesterList.ios.js
index b2302c238c4ded..b2e9b49ab5db3e 100644
--- a/RNTester/js/RNTesterList.ios.js
+++ b/RNTester/js/RNTesterList.ios.js
@@ -58,21 +58,6 @@ const ComponentExamples: Array = [
module: require('./LayoutEventsExample'),
supportsTVOS: true,
},
- {
- key: 'ListViewExample',
- module: require('./ListViewExample'),
- supportsTVOS: true,
- },
- {
- key: 'ListViewGridLayoutExample',
- module: require('./ListViewGridLayoutExample'),
- supportsTVOS: true,
- },
- {
- key: 'ListViewPagingExample',
- module: require('./ListViewPagingExample'),
- supportsTVOS: true,
- },
{
key: 'MaskedViewExample',
module: require('./MaskedViewExample'),
@@ -148,11 +133,6 @@ const ComponentExamples: Array = [
module: require('./SwipeableFlatListExample'),
supportsTVOS: false,
},
- {
- key: 'SwipeableListViewExample',
- module: require('./SwipeableListViewExample'),
- supportsTVOS: false,
- },
{
key: 'SwitchExample',
module: require('./SwitchExample'),
@@ -191,6 +171,11 @@ const ComponentExamples: Array = [
];
const APIExamples: Array = [
+ {
+ key: 'AccessibilityExample',
+ module: require('./AccessibilityExample'),
+ supportsTVOS: false,
+ },
{
key: 'AccessibilityIOSExample',
module: require('./AccessibilityIOSExample'),
diff --git a/RNTester/js/SwipeableFlatListExample.js b/RNTester/js/SwipeableFlatListExample.js
index feef9fff12a9f6..d79336cc30aedb 100644
--- a/RNTester/js/SwipeableFlatListExample.js
+++ b/RNTester/js/SwipeableFlatListExample.js
@@ -47,7 +47,7 @@ class SwipeableFlatListExample extends React.Component {
render() {
return (
'}
+ title={this.props.navigator ? null : ''}
noSpacer={true}
noScroll={true}>
{
- state = {
- dataSource: SwipeableListView.getNewDataSource().cloneWithRowsAndSections(
- ...this._genDataSource({}),
- ),
- };
-
- _pressData: {[key: number]: boolean} = {};
-
- render(): React.Node {
- return (
- '}
- noSpacer={true}
- noScroll={true}>
- {
- return (
-
- {
- Alert.alert(
- 'Tips',
- 'You could do something with this row: ' + rowData.text,
- );
- }}>
- Remove
-
-
- );
- }}
- renderRow={this._renderRow}
- renderSeparator={this._renderSeperator}
- />
-
- );
- }
-
- _renderRow(rowData: Object, sectionID: string, rowID: string) {
- const rowHash = Math.abs(hashCode(rowData.id));
- const imgSource = THUMB_URLS[rowHash % THUMB_URLS.length];
- return (
- {}}>
-
-
-
-
- {rowData.id + ' - ' + LOREM_IPSUM.substr(0, (rowHash % 301) + 10)}
-
-
-
-
- );
- }
-
- _genDataSource(pressData: {[key: number]: boolean}) {
- const dataBlob = {};
- const sectionIDs = ['Section 0'];
- const rowIDs = [[]];
- /**
- * dataBlob example below:
- * {
- * 'Section 0': {
- * 'Row 0': {
- * id: '0',
- * text: 'row 0 text'
- * },
- * 'Row 1': {
- * id: '1',
- * text: 'row 1 text'
- * }
- * }
- * }
- */
-
- // Only one section in this example
- dataBlob['Section 0'] = {};
- for (let ii = 0; ii < 100; ii++) {
- const pressedText = pressData[ii] ? ' (pressed)' : '';
- dataBlob[sectionIDs[0]]['Row ' + ii] = {
- id: 'Row ' + ii,
- text: 'Row ' + ii + pressedText,
- };
- rowIDs[0].push('Row ' + ii);
- }
- return [dataBlob, sectionIDs, rowIDs];
- }
-
- _renderSeperator(
- sectionID: string,
- rowID: string,
- adjacentRowHighlighted: boolean,
- ) {
- return (
-
- );
- }
-}
-
-const THUMB_URLS = [
- require('./Thumbnails/like.png'),
- require('./Thumbnails/dislike.png'),
- require('./Thumbnails/call.png'),
- require('./Thumbnails/fist.png'),
- require('./Thumbnails/bandaged.png'),
- require('./Thumbnails/flowers.png'),
- require('./Thumbnails/heart.png'),
- require('./Thumbnails/liking.png'),
- require('./Thumbnails/party.png'),
- require('./Thumbnails/poke.png'),
- require('./Thumbnails/superlike.png'),
- require('./Thumbnails/victory.png'),
-];
-
-const LOREM_IPSUM = [
- 'Lorem ipsum dolor sit amet, ius ad pertinax oportere accommodare, an vix ',
- 'civibus corrumpit referrentur. Te nam case ludus inciderint, te mea facilisi ',
- 'adipiscing. Sea id integre luptatum. In tota sale consequuntur nec. Erat ',
- 'ocurreret mei ei. Eu paulo sapientem vulputate est, vel an accusam ',
- 'intellegam interesset. Nam eu stet pericula reprimique, ea vim illud modus, ',
- 'putant invidunt reprehendunt ne qui.',
-].join('');
-
-/* eslint-disable no-bitwise */
-const hashCode = str => {
- let hash = 15;
- for (let ii = str.length - 1; ii >= 0; ii--) {
- hash = (hash << 5) - hash + str.charCodeAt(ii);
- }
- return hash;
-};
-/* eslint-enable no-bitwise */
-
-const styles = StyleSheet.create({
- row: {
- flexDirection: 'row',
- justifyContent: 'center',
- padding: 10,
- backgroundColor: '#F6F6F6',
- },
- thumb: {
- width: 64,
- height: 64,
- },
- text: {
- flex: 1,
- },
- actionsContainer: {
- flex: 1,
- flexDirection: 'row',
- justifyContent: 'flex-end',
- alignItems: 'center',
- },
-});
-
-exports.title = '';
-exports.description = 'Performant, scrollable, swipeable list of data.';
-exports.examples = [
- {
- title: 'Simple swipable list',
- render: function(): React.Element {
- return ;
- },
- },
-];
diff --git a/RNTester/js/TextExample.android.js b/RNTester/js/TextExample.android.js
index 6726943b261f52..1eeeda49cc6bcd 100644
--- a/RNTester/js/TextExample.android.js
+++ b/RNTester/js/TextExample.android.js
@@ -325,6 +325,12 @@ class TextExample extends React.Component<{}> {
right right right right right right right right right right right
right right
+
+ justify (works when api level >= 26 otherwise fallbacks to "left"):
+ this text component{"'"}s contents are laid out with "textAlign:
+ justify" and as you can see all of the lines except the last one
+ span the available width of the parent container.
+
@@ -615,11 +621,13 @@ class TextExample extends React.Component<{}> {
Works with other text styles
+
+ {'testπ'.substring(0, 5)}
+
);
}
}
-
const styles = StyleSheet.create({
backgroundColorText: {
left: 5,
diff --git a/RNTester/js/TextExample.ios.js b/RNTester/js/TextExample.ios.js
index d52f9a8c6025c8..320854f88ae017 100644
--- a/RNTester/js/TextExample.ios.js
+++ b/RNTester/js/TextExample.ios.js
@@ -428,6 +428,12 @@ exports.examples = [
);
},
},
+ {
+ title: "Substring Emoji (should only see 'test')",
+ render: function() {
+ return {'testπ'.substring(0, 5)};
+ },
+ },
{
title: 'Text metrics',
render: function() {
diff --git a/RNTester/js/tumblr_mfqekpMktw1rn90umo1_500.gif b/RNTester/js/tumblr_mfqekpMktw1rn90umo1_500.gif
new file mode 100644
index 00000000000000..3e945c8c207d18
Binary files /dev/null and b/RNTester/js/tumblr_mfqekpMktw1rn90umo1_500.gif differ
diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m
index 4e05e2b43eb2c3..9530b5a225f0e2 100644
--- a/React/Base/RCTEventDispatcher.m
+++ b/React/Base/RCTEventDispatcher.m
@@ -85,11 +85,15 @@ - (void)sendInputEventWithName:(NSString *)name body:(NSDictionary *)body
RCTAssert([body[@"target"] isKindOfClass:[NSNumber class]],
@"Event body dictionary must include a 'target' property containing a React tag");
}
+
+ if (!body[@"target"]) {
+ return;
+ }
name = RCTNormalizeInputEventName(name);
[_bridge enqueueJSCall:@"RCTEventEmitter"
method:@"receiveEvent"
- args:body ? @[body[@"target"], name, body] : @[body[@"target"], name]
+ args:@[body[@"target"], name, body]
completion:NULL];
}
diff --git a/React/Base/RCTKeyCommands.m b/React/Base/RCTKeyCommands.m
index 4bde8957cb7cf9..8f8f19b8354527 100644
--- a/React/Base/RCTKeyCommands.m
+++ b/React/Base/RCTKeyCommands.m
@@ -14,11 +14,6 @@
#if RCT_DEV
-static BOOL RCTIsIOS8OrEarlier()
-{
- return [UIDevice currentDevice].systemVersion.floatValue < 9;
-}
-
@interface RCTKeyCommand : NSObject
@property (nonatomic, strong) UIKeyCommand *keyCommand;
@@ -119,7 +114,7 @@ - (void)RCT_handleKeyCommand:(UIKeyCommand *)key
// NOTE: throttle the key handler because on iOS 9 the handleKeyCommand:
// method gets called repeatedly if the command key is held down.
static NSTimeInterval lastCommand = 0;
- if (RCTIsIOS8OrEarlier() || CACurrentMediaTime() - lastCommand > 0.5) {
+ if (CACurrentMediaTime() - lastCommand > 0.5) {
for (RCTKeyCommand *command in [RCTKeyCommands sharedInstance].commands) {
if ([command.keyCommand.input isEqualToString:key.input] &&
command.keyCommand.modifierFlags == key.modifierFlags) {
@@ -171,7 +166,7 @@ - (void)RCT_handleDoublePressKeyCommand:(UIKeyCommand *)key
// NOTE: throttle the key handler because on iOS 9 the handleKeyCommand:
// method gets called repeatedly if the command key is held down.
- if (RCTIsIOS8OrEarlier() || CACurrentMediaTime() - lastDoubleCommand > 0.5) {
+ if (CACurrentMediaTime() - lastDoubleCommand > 0.5) {
command.block(key);
lastDoubleCommand = CACurrentMediaTime();
}
@@ -189,44 +184,14 @@ - (void)RCT_handleDoublePressKeyCommand:(UIKeyCommand *)key
@end
-@implementation UIApplication (RCTKeyCommands)
-
-// Required for iOS 8.x
-- (BOOL)RCT_sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event
-{
- if (action == @selector(RCT_handleKeyCommand:)) {
- [self RCT_handleKeyCommand:sender];
- return YES;
- } else if (action == @selector(RCT_handleDoublePressKeyCommand:)) {
- [self RCT_handleDoublePressKeyCommand:sender];
- return YES;
- }
- return [self RCT_sendAction:action to:target from:sender forEvent:event];
-}
-
-@end
-
@implementation RCTKeyCommands
+ (void)initialize
{
- if (RCTIsIOS8OrEarlier()) {
-
- // swizzle UIApplication
- RCTSwapInstanceMethods([UIApplication class],
- @selector(keyCommands),
- @selector(RCT_keyCommands));
-
- RCTSwapInstanceMethods([UIApplication class],
- @selector(sendAction:to:from:forEvent:),
- @selector(RCT_sendAction:to:from:forEvent:));
- } else {
-
- // swizzle UIResponder
- RCTSwapInstanceMethods([UIResponder class],
- @selector(keyCommands),
- @selector(RCT_keyCommands));
- }
+ // swizzle UIResponder
+ RCTSwapInstanceMethods([UIResponder class],
+ @selector(keyCommands),
+ @selector(RCT_keyCommands));
}
+ (instancetype)sharedInstance
@@ -254,17 +219,6 @@ - (void)registerKeyCommandWithInput:(NSString *)input
{
RCTAssertMainQueue();
- if (input.length && flags && RCTIsIOS8OrEarlier()) {
-
- // Workaround around the first cmd not working: http://openradar.appspot.com/19613391
- // You can register just the cmd key and do nothing. This ensures that
- // command-key modified commands will work first time. Fixed in iOS 9.
-
- [self registerKeyCommandWithInput:@""
- modifierFlags:flags
- action:nil];
- }
-
UIKeyCommand *command = [UIKeyCommand keyCommandWithInput:input
modifierFlags:flags
action:@selector(RCT_handleKeyCommand:)];
@@ -306,17 +260,6 @@ - (void)registerDoublePressKeyCommandWithInput:(NSString *)input
{
RCTAssertMainQueue();
- if (input.length && flags && RCTIsIOS8OrEarlier()) {
-
- // Workaround around the first cmd not working: http://openradar.appspot.com/19613391
- // You can register just the cmd key and do nothing. This ensures that
- // command-key modified commands will work first time. Fixed in iOS 9.
-
- [self registerDoublePressKeyCommandWithInput:@""
- modifierFlags:flags
- action:nil];
- }
-
UIKeyCommand *command = [UIKeyCommand keyCommandWithInput:input
modifierFlags:flags
action:@selector(RCT_handleDoublePressKeyCommand:)];
diff --git a/React/Base/RCTModuleData.mm b/React/Base/RCTModuleData.mm
index ba2dbd5196f9d4..c02c8810f6e171 100644
--- a/React/Base/RCTModuleData.mm
+++ b/React/Base/RCTModuleData.mm
@@ -330,9 +330,11 @@ - (void)gatherConstants
- (dispatch_queue_t)methodQueue
{
- (void)[self instance];
- RCTAssert(_methodQueue != nullptr, @"Module %@ has no methodQueue (instance: %@, bridge.valid: %d)",
- self, _instance, _bridge.valid);
+ if (_bridge.valid) {
+ id instance = self.instance;
+ RCTAssert(_methodQueue != nullptr, @"Module %@ has no methodQueue (instance: %@)",
+ self, instance);
+ }
return _methodQueue;
}
diff --git a/React/Base/RCTModuleMethod.mm b/React/Base/RCTModuleMethod.mm
index 767e11abd4116a..3d93a785b3147f 100644
--- a/React/Base/RCTModuleMethod.mm
+++ b/React/Base/RCTModuleMethod.mm
@@ -90,8 +90,8 @@ static BOOL RCTParseSelectorPart(const char **input, NSMutableString *selector)
static BOOL RCTParseUnused(const char **input)
{
- return RCTReadString(input, "__unused") ||
- RCTReadString(input, "__attribute__((unused))");
+ return RCTReadString(input, "__attribute__((unused))") ||
+ RCTReadString(input, "__unused");
}
static RCTNullability RCTParseNullability(const char **input)
@@ -106,9 +106,11 @@ static RCTNullability RCTParseNullability(const char **input)
static RCTNullability RCTParseNullabilityPostfix(const char **input)
{
- if (RCTReadString(input, "_Nullable")) {
+ if (RCTReadString(input, "_Nullable") ||
+ RCTReadString(input, "__nullable")) {
return RCTNullable;
- } else if (RCTReadString(input, "_Nonnull")) {
+ } else if (RCTReadString(input, "_Nonnull") ||
+ RCTReadString(input, "__nonnull")) {
return RCTNonnullable;
}
return RCTNullabilityUnspecified;
@@ -142,17 +144,34 @@ static BOOL checkCallbackMultipleInvocations(BOOL *didInvoke) {
// Parse type
if (RCTReadChar(&input, '(')) {
RCTSkipWhitespace(&input);
-
- BOOL unused = RCTParseUnused(&input);
- RCTSkipWhitespace(&input);
-
+
+ // 5 cases that both nullable and __unused exist
+ // 1: foo:(nullable __unused id)foo 2: foo:(nullable id __unused)foo
+ // 3: foo:(__unused id _Nullable)foo 4: foo:(id __unused _Nullable)foo
+ // 5: foo:(id _Nullable __unused)foo
RCTNullability nullability = RCTParseNullability(&input);
RCTSkipWhitespace(&input);
+
+ BOOL unused = RCTParseUnused(&input);
+ RCTSkipWhitespace(&input);
NSString *type = RCTParseType(&input);
RCTSkipWhitespace(&input);
+
if (nullability == RCTNullabilityUnspecified) {
nullability = RCTParseNullabilityPostfix(&input);
+ RCTSkipWhitespace(&input);
+ if (!unused) {
+ unused = RCTParseUnused(&input);
+ RCTSkipWhitespace(&input);
+ if (unused && nullability == RCTNullabilityUnspecified) {
+ nullability = RCTParseNullabilityPostfix(&input);
+ RCTSkipWhitespace(&input);
+ }
+ }
+ } else if (!unused) {
+ unused = RCTParseUnused(&input);
+ RCTSkipWhitespace(&input);
}
[args addObject:[[RCTMethodArgument alloc] initWithType:type
nullability:nullability
diff --git a/React/Base/RCTMultipartDataTask.m b/React/Base/RCTMultipartDataTask.m
index 3708a7d3575c34..285eaa9aa6c243 100644
--- a/React/Base/RCTMultipartDataTask.m
+++ b/React/Base/RCTMultipartDataTask.m
@@ -11,20 +11,6 @@ @interface RCTMultipartDataTask ()
+
#include
#include
@@ -28,7 +30,7 @@ class DispatchMessageQueueThread : public MessageQueueThread {
dispatch_async(queue, block);
}
}
- void runOnQueueSync(std::function&& func) override {
+ void runOnQueueSync(std::function&& __unused func) override {
LOG(FATAL) << "Unsupported operation";
}
void quitSynchronous() override {
diff --git a/React/CxxModule/RCTNativeModule.mm b/React/CxxModule/RCTNativeModule.mm
index ec88558b873da8..b59a68312a80d5 100644
--- a/React/CxxModule/RCTNativeModule.mm
+++ b/React/CxxModule/RCTNativeModule.mm
@@ -71,17 +71,19 @@
invokeInner(weakBridge, weakModuleData, methodId, std::move(params));
};
- if (m_bridge.valid) {
- dispatch_queue_t queue = m_moduleData.methodQueue;
- if (queue == RCTJSThread) {
- block();
- } else if (queue) {
- dispatch_async(queue, block);
- }
- } else {
- RCTLog(@"Attempted to invoke `%u` (method ID) on `%@` (NativeModule name) with an invalid bridge.",
- methodId, m_moduleData.name);
+ dispatch_queue_t queue = m_moduleData.methodQueue;
+ if (queue == RCTJSThread) {
+ block();
+ } else if (queue) {
+ dispatch_async(queue, block);
+ }
+
+ #ifdef RCT_DEV
+ if (!queue) {
+ RCTLog(@"Attempted to invoke `%u` (method ID) on `%@` (NativeModule name) without a method queue.",
+ methodId, m_moduleData.name);
}
+ #endif
}
MethodCallResult RCTNativeModule::callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic &¶ms) {
diff --git a/React/DevSupport/RCTDevMenu.m b/React/DevSupport/RCTDevMenu.m
index eff6040f8d1eb0..d631fa5dc7525c 100644
--- a/React/DevSupport/RCTDevMenu.m
+++ b/React/DevSupport/RCTDevMenu.m
@@ -219,9 +219,12 @@ - (void)setDefaultJSBundle {
if (!devSettings.isRemoteDebuggingAvailable) {
[items addObject:[RCTDevMenuItem buttonItemWithTitle:@"Remote JS Debugger Unavailable" handler:^{
+ NSString *message = RCTTurboModuleEnabled() ?
+ @"You cannot use remote JS debugging when TurboModule system is enabled" :
+ @"You need to include the RCTWebSocket library to enable remote JS debugging";
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:@"Remote JS Debugger Unavailable"
- message:@"You need to include the RCTWebSocket library to enable remote JS debugging"
+ message:message
preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(alertController) weakAlertController = alertController;
[alertController addAction:
diff --git a/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm
index d6270063ba1ca2..95f21877cc1164 100644
--- a/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm
+++ b/React/Fabric/Mounting/ComponentViews/ActivityIndicator/RCTActivityIndicatorViewComponentView.mm
@@ -7,8 +7,9 @@
#import "RCTActivityIndicatorViewComponentView.h"
-#import
-#import
+#import
+#import
+#import
using namespace facebook::react;
diff --git a/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm b/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm
index 2fc56881ee8cfd..2f6f670d883bb7 100644
--- a/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm
+++ b/React/Fabric/Mounting/ComponentViews/Slider/RCTSliderComponentView.mm
@@ -8,9 +8,9 @@
#import "RCTSliderComponentView.h"
#import
-#import
+#import
+#import
#import
-#import
#import
#import "MainQueueExecutor.h"
@@ -301,10 +301,12 @@ - (void)onChange:(UISlider *)sender withContinuous:(BOOL)continuous
}
if (continuous && _previousValue != value) {
- std::dynamic_pointer_cast(_eventEmitter)->onValueChange(value);
+ std::dynamic_pointer_cast(_eventEmitter)
+ ->onValueChange(SliderOnValueChangeStruct{.value = static_cast(value)});
}
if (!continuous) {
- std::dynamic_pointer_cast(_eventEmitter)->onSlidingComplete(value);
+ std::dynamic_pointer_cast(_eventEmitter)
+ ->onSlidingComplete(SliderOnSlidingCompleteStruct{.value = static_cast(value)});
}
_previousValue = value;
diff --git a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h
index 3e85e52aac64c3..a289ed2e82fa1e 100644
--- a/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h
+++ b/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.h
@@ -12,9 +12,9 @@
#import
#import
#import
+#import
#import
#import
-#import
NS_ASSUME_NONNULL_BEGIN
diff --git a/React/Fabric/Mounting/MountItems/RCTUpdateEventEmitterMountItem.h b/React/Fabric/Mounting/MountItems/RCTUpdateEventEmitterMountItem.h
index 7d16a9dc27edd3..5c0595f7fc4230 100644
--- a/React/Fabric/Mounting/MountItems/RCTUpdateEventEmitterMountItem.h
+++ b/React/Fabric/Mounting/MountItems/RCTUpdateEventEmitterMountItem.h
@@ -9,7 +9,7 @@
#import
#import
-#import
+#import
NS_ASSUME_NONNULL_BEGIN
diff --git a/React/Fabric/Mounting/MountItems/RCTUpdateStateMountItem.h b/React/Fabric/Mounting/MountItems/RCTUpdateStateMountItem.h
new file mode 100644
index 00000000000000..f92eb00be2422c
--- /dev/null
+++ b/React/Fabric/Mounting/MountItems/RCTUpdateStateMountItem.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.
+ */
+
+#import
+
+#import
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * Updates state of a component view.
+ */
+@interface RCTUpdateStateMountItem : NSObject
+
+- (instancetype)initWithTag:(ReactTag)tag
+ oldState:(facebook::react::State::Shared)oldState
+ newState:(facebook::react::State::Shared)newState;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/React/Fabric/Mounting/MountItems/RCTUpdateStateMountItem.mm b/React/Fabric/Mounting/MountItems/RCTUpdateStateMountItem.mm
new file mode 100644
index 00000000000000..ec6949f204a750
--- /dev/null
+++ b/React/Fabric/Mounting/MountItems/RCTUpdateStateMountItem.mm
@@ -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.
+ */
+
+#import "RCTUpdateStateMountItem.h"
+
+#import "RCTComponentViewRegistry.h"
+
+using namespace facebook::react;
+
+@implementation RCTUpdateStateMountItem {
+ ReactTag _tag;
+ State::Shared _oldState;
+ State::Shared _newState;
+}
+
+- (instancetype)initWithTag:(ReactTag)tag
+ oldState:(facebook::react::State::Shared)oldState
+ newState:(facebook::react::State::Shared)newState
+{
+ if (self = [super init]) {
+ _tag = tag;
+ _oldState = oldState;
+ _newState = newState;
+ }
+
+ return self;
+}
+
+- (void)executeWithRegistry:(RCTComponentViewRegistry *)registry
+{
+ UIView *componentView = [registry componentViewByTag:_tag];
+ [componentView updateState:_newState oldState:_oldState];
+}
+
+@end
diff --git a/React/Fabric/Mounting/RCTComponentViewProtocol.h b/React/Fabric/Mounting/RCTComponentViewProtocol.h
index 116f6ef4295ba2..f049b8f33a66c6 100644
--- a/React/Fabric/Mounting/RCTComponentViewProtocol.h
+++ b/React/Fabric/Mounting/RCTComponentViewProtocol.h
@@ -8,10 +8,11 @@
#import
#import
+#import
#import
#import
#import
-#import
+#import
NS_ASSUME_NONNULL_BEGIN
@@ -56,6 +57,12 @@ NS_ASSUME_NONNULL_BEGIN
- (void)updateLocalData:(facebook::react::SharedLocalData)localData
oldLocalData:(facebook::react::SharedLocalData)oldLocalData;
+/*
+ * Called for updating component's state.
+ * Receiver must update native view according to changed state.
+ */
+- (void)updateState:(facebook::react::State::Shared)state oldState:(facebook::react::State::Shared)oldState;
+
/*
* Called for updating component's event handlers set.
* Receiver must cache `eventEmitter` object inside and use it for emitting
diff --git a/React/Fabric/Mounting/RCTMountingManager.h b/React/Fabric/Mounting/RCTMountingManager.h
index d4a64da800e6bd..0f65e39812a45f 100644
--- a/React/Fabric/Mounting/RCTMountingManager.h
+++ b/React/Fabric/Mounting/RCTMountingManager.h
@@ -39,6 +39,9 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)optimisticallyCreateComponentViewWithComponentHandle:(facebook::react::ComponentHandle)componentHandle;
+- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
+ oldProps:(facebook::react::SharedProps)oldProps
+ newProps:(facebook::react::SharedProps)newProps;
@end
NS_ASSUME_NONNULL_END
diff --git a/React/Fabric/Mounting/RCTMountingManager.mm b/React/Fabric/Mounting/RCTMountingManager.mm
index 105f39919ecc1d..8bcc71cc454d8d 100644
--- a/React/Fabric/Mounting/RCTMountingManager.mm
+++ b/React/Fabric/Mounting/RCTMountingManager.mm
@@ -25,6 +25,7 @@
#import "RCTUpdateLayoutMetricsMountItem.h"
#import "RCTUpdateLocalDataMountItem.h"
#import "RCTUpdatePropsMountItem.h"
+#import "RCTUpdateStateMountItem.h"
using namespace facebook::react;
@@ -87,6 +88,13 @@ - (void)performTransactionWithMutations:(facebook::react::ShadowViewMutationList
newLocalData:mutation.newChildShadowView.localData]];
}
+ // State
+ if (mutation.newChildShadowView.state) {
+ [mountItems addObject:[[RCTUpdateStateMountItem alloc] initWithTag:mutation.newChildShadowView.tag
+ oldState:nullptr
+ newState:mutation.newChildShadowView.state]];
+ }
+
// Layout
if (mutation.newChildShadowView.layoutMetrics != EmptyLayoutMetrics) {
[mountItems addObject:[[RCTUpdateLayoutMetricsMountItem alloc]
@@ -142,6 +150,14 @@ - (void)performTransactionWithMutations:(facebook::react::ShadowViewMutationList
[mountItems addObject:mountItem];
}
+ // State
+ if (oldChildShadowView.state != newChildShadowView.state) {
+ RCTUpdateStateMountItem *mountItem = [[RCTUpdateStateMountItem alloc] initWithTag:newChildShadowView.tag
+ oldState:oldChildShadowView.state
+ newState:newChildShadowView.state];
+ [mountItems addObject:mountItem];
+ }
+
// Layout
if (oldChildShadowView.layoutMetrics != newChildShadowView.layoutMetrics) {
RCTUpdateLayoutMetricsMountItem *mountItem =
@@ -176,6 +192,17 @@ - (void)_performMountItems:(NSArray *)mountItems rootTag:(
[self.delegate mountingManager:self didMountComponentsWithRootTag:rootTag];
}
+- (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag
+ oldProps:(SharedProps)oldProps
+ newProps:(SharedProps)newProps
+{
+ RCTUpdatePropsMountItem *mountItem = [[RCTUpdatePropsMountItem alloc] initWithTag:reactTag
+ oldProps:oldProps
+ newProps:newProps];
+ RCTAssertMainQueue();
+ [mountItem executeWithRegistry:self->_componentViewRegistry];
+}
+
- (void)optimisticallyCreateComponentViewWithComponentHandle:(ComponentHandle)componentHandle
{
if (RCTIsMainQueue()) {
diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h
index b30cff79fb6bf0..7ea8dc5d7d7f5e 100644
--- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.h
+++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.h
@@ -27,6 +27,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)updateLocalData:(facebook::react::SharedLocalData)localData
oldLocalData:(facebook::react::SharedLocalData)oldLocalData;
+- (void)updateState:(facebook::react::State::Shared)state oldState:(facebook::react::State::Shared)oldState;
+
- (void)updateLayoutMetrics:(facebook::react::LayoutMetrics)layoutMetrics
oldLayoutMetrics:(facebook::react::LayoutMetrics)oldLayoutMetrics;
diff --git a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm
index 423945d261f5b4..428a7844cd8c19 100644
--- a/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm
+++ b/React/Fabric/Mounting/UIView+ComponentViewProtocol.mm
@@ -43,6 +43,11 @@ - (void)updateLocalData:(SharedLocalData)localData oldLocalData:(SharedLocalData
// Default implementation does nothing.
}
+- (void)updateState:(facebook::react::State::Shared)state oldState:(facebook::react::State::Shared)oldState
+{
+ // Default implementation does nothing.
+}
+
- (void)updateLayoutMetrics:(LayoutMetrics)layoutMetrics oldLayoutMetrics:(LayoutMetrics)oldLayoutMetrics
{
if (layoutMetrics.frame != oldLayoutMetrics.frame) {
diff --git a/React/Fabric/RCTScheduler.h b/React/Fabric/RCTScheduler.h
index a57c2cbf981989..709250d39bfad8 100644
--- a/React/Fabric/RCTScheduler.h
+++ b/React/Fabric/RCTScheduler.h
@@ -9,6 +9,7 @@
#import
#import
+#import
#import
#import
#import
@@ -54,6 +55,8 @@ NS_ASSUME_NONNULL_BEGIN
layoutContext:(facebook::react::LayoutContext)layoutContext
surfaceId:(facebook::react::SurfaceId)surfaceId;
+- (const facebook::react::ComponentDescriptor &)getComponentDescriptor:(facebook::react::ComponentHandle)handle;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm
index 60752913c55ed3..d749e5b5ddd621 100644
--- a/React/Fabric/RCTScheduler.mm
+++ b/React/Fabric/RCTScheduler.mm
@@ -19,26 +19,32 @@
using namespace facebook::react;
-class SchedulerDelegateProxy: public SchedulerDelegate {
-public:
- SchedulerDelegateProxy(void *scheduler):
- scheduler_(scheduler) {}
-
- void schedulerDidFinishTransaction(Tag rootTag, const ShadowViewMutationList &mutations, const long commitStartTime, const long layoutTime) override {
+class SchedulerDelegateProxy : public SchedulerDelegate {
+ public:
+ SchedulerDelegateProxy(void *scheduler) : scheduler_(scheduler) {}
+
+ void schedulerDidFinishTransaction(
+ Tag rootTag,
+ const ShadowViewMutationList &mutations,
+ const long commitStartTime,
+ const long layoutTime) override
+ {
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
[scheduler.delegate schedulerDidFinishTransaction:mutations rootTag:rootTag];
}
- void schedulerDidRequestPreliminaryViewAllocation(SurfaceId surfaceId, ComponentName componentName, bool isLayoutable, ComponentHandle componentHandle) override {
- if (!isLayoutable) {
+ void schedulerDidRequestPreliminaryViewAllocation(SurfaceId surfaceId, const ShadowView &shadowView) override
+ {
+ bool isLayoutableShadowNode = shadowView.layoutMetrics != EmptyLayoutMetrics;
+ if (!isLayoutableShadowNode) {
return;
}
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
- [scheduler.delegate schedulerOptimisticallyCreateComponentViewWithComponentHandle:componentHandle];
+ [scheduler.delegate schedulerOptimisticallyCreateComponentViewWithComponentHandle:shadowView.componentHandle];
}
-private:
+ private:
void *scheduler_;
};
@@ -51,7 +57,8 @@ - (instancetype)initWithContextContainer:(std::shared_ptr)contextContainer
{
if (self = [super init]) {
_delegateProxy = std::make_shared((__bridge void *)self);
- _scheduler = std::make_shared(std::static_pointer_cast(contextContainer), getDefaultComponentRegistryFactory());
+ _scheduler = std::make_shared(
+ std::static_pointer_cast(contextContainer), getDefaultComponentRegistryFactory());
_scheduler->setDelegate(_delegateProxy.get());
}
@@ -72,17 +79,9 @@ - (void)startSurfaceWithSurfaceId:(SurfaceId)surfaceId
SystraceSection s("-[RCTScheduler startSurfaceWithSurfaceId:...]");
auto props = convertIdToFollyDynamic(initialProps);
- _scheduler->startSurface(
- surfaceId,
- RCTStringFromNSString(moduleName),
- props,
- layoutConstraints,
- layoutContext);
+ _scheduler->startSurface(surfaceId, RCTStringFromNSString(moduleName), props, layoutConstraints, layoutContext);
_scheduler->renderTemplateToSurface(
- surfaceId,
- props.getDefault("navigationConfig")
- .getDefault("initialUITemplate", "")
- .getString());
+ surfaceId, props.getDefault("navigationConfig").getDefault("initialUITemplate", "").getString());
}
- (void)stopSurfaceWithSurfaceId:(SurfaceId)surfaceId
@@ -107,4 +106,9 @@ - (void)constraintSurfaceLayoutWithLayoutConstraints:(LayoutConstraints)layoutCo
_scheduler->constraintSurfaceLayout(surfaceId, layoutConstraints, layoutContext);
}
+- (const ComponentDescriptor &)getComponentDescriptor:(ComponentHandle)handle
+{
+ return _scheduler->getComponentDescriptor(handle);
+}
+
@end
diff --git a/React/Fabric/RCTSurfacePresenter.h b/React/Fabric/RCTSurfacePresenter.h
index c4f1f98fbfa939..1e684dd5a4f0de 100644
--- a/React/Fabric/RCTSurfacePresenter.h
+++ b/React/Fabric/RCTSurfacePresenter.h
@@ -10,9 +10,9 @@
#import
#import
-#import
#import
#import
+#import
NS_ASSUME_NONNULL_BEGIN
@@ -66,6 +66,8 @@ NS_ASSUME_NONNULL_BEGIN
maximumSize:(CGSize)maximumSize
surface:(RCTFabricSurface *)surface;
+- (BOOL)synchronouslyUpdateViewOnUIThread:(NSNumber *)reactTag props:(NSDictionary *)props;
+
@end
@interface RCTSurfacePresenter (Deprecated)
diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm
index 3a18def1d25918..c2036387166ed3 100644
--- a/React/Fabric/RCTSurfacePresenter.mm
+++ b/React/Fabric/RCTSurfacePresenter.mm
@@ -16,17 +16,18 @@
#import
#import
#import
+#import
#import
#import
#import
#import
#import
-#import
#import
+#import
#import
-#import
-#import
#import