Compare commits

...
Author SHA1 Message Date
Nicola Corti 502172e2ce Reformat MutationObserver test to comply with yarn lint --fix 2025-01-15 11:56:18 +00:00
Riccardo Cipolleschi 559d070e8e Use RNTester App downloaded from CI instead of building (#48637)
Summary:
This change improves the E2E testing by downloading the iOS RNTesterApp that is built in CI instead of building it locally. This should let us save 10 to 20 minutes when we test a new release.

## Changelog:
[Internal] - Use the RNTester app built in CI for release testing on iOS

Pull Request resolved: https://github.com/facebook/react-native/pull/48637

Test Plan:
- build the app in ci
- run `yarn test-e2e-local -c <my-token>` and `yarn test-e2e-local -h false -c <my-token>` and verify that the iOS app is not built, but run in the simulator

Reviewed By: cortinico

Differential Revision: D68161477

Pulled By: cipolleschi

fbshipit-source-id: 577d110f9ff0197a2d3348a08a60e60a4d0a752b
2025-01-15 01:04:29 -08:00
Joe Vilches 3420eb87b0 Allow text inputs to handle native requestFocus calls (#48547)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48547

For some unknown reason, we have been swallowing [`requestFocus`](https://developer.android.com/reference/android/view/View#requestFocus(int) calls since `TextInput` is a controlled component - meaning you can control this components value and focus state from JS. This decision was originally made pre 2015 and I cannot find the reason why

I do not think this makes sense. We can still request focus from JS, while allowing the OS to request focus as well in certain cases and we would still be controlling this text input.

This is breaking keyboard navigation. Pressing tab or arrow keys will no-op if the next destination is a `TextInput`. This is because Android will call `requestFocus` from [here](https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/view/ViewRootImpl.java;l=7868?q=performFocusNavigation) when handling key events. Notably, Explore By Touch (TalkBack) swiping gestures WOULD focus `TextInputs` since they go through `ExploreByTouchHelper` methods which we override to call the proper `requestFocusInternal()` method.

**In this diff**: I move the logic in `requestFocusInternal()` into `requestFocus`.

Changelog: [Android] [Fixed] - TextInputs can now receive focus via external keyboard

Reviewed By: NickGerleman

Differential Revision: D67953398

fbshipit-source-id: 506006769a7c8a63f0a9b7ce27cfbe8578777790
2025-01-14 16:31:52 -08:00
Rayner Kristanto 0f1d4704df Revert D68017325: Migrate StyleSheet/*.js to use export statements
Differential Revision:
D68017325

Original commit changeset: 3c5b94742f10

Original Phabricator Diff: D68017325

fbshipit-source-id: d7ea1edfe9cca151560e9c0e5554a07153cdb8da
2025-01-14 15:22:26 -08:00
Riccardo Cipolleschi b3648be84f Bump maestro to see if it improves stability (#48677)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48677

E2E tests are flaky again.
Let's bump maestro to see if stability improves.

This will also remove some noise from the logs, make them easier to read.

## Changelog
[Internal] - Bump maestro version

Reviewed By: cortinico

Differential Revision: D68160005

fbshipit-source-id: 40a25f974dfda75785bf08d8d236e771b44d13cf
2025-01-14 13:32:51 -08:00
Fabrizio Cucci 9d1e24cb2f Migrate rn-tester/IntegrationTests/IntegrationTestHarnessTest.js to function components (#48671)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48671

As per title.

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D68151272

fbshipit-source-id: 5d42da93ab4fe8aaf34b8916a6d0a234f51c235a
2025-01-14 12:18:41 -08:00
Samuel Susla 2204ec94d4 fix Pressable when transform style is animated (#48672)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48672

## Changelog:

[General] [Fixed] - Buttons becoming unresponsive when transform is animated

# The problem

D67872307 changes when `ensureUpdateSubscriptionExists`  is called to in `__attach`. This breaks the functionality because `__attach` is called before flag `__isNative` is set and subscriptions are never setup.

# Fix

The diff sets up subscriptions in `__makeNative` method.

Reviewed By: yungsters

Differential Revision: D68154908

fbshipit-source-id: e2ac108b064a66dda08902653d6bd20286f92458
2025-01-14 11:05:07 -08:00
Luna Wei e3c63cfd34 Remove native optionality (#48653)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48653

Changelog:
[General][Changed] - Mark intersectionRect required in NativeIntersectionObserverEntry

Reviewed By: rubennorte

Differential Revision: D68120751

fbshipit-source-id: 196b3d48cf33721031a0c2a9fa0a55d250926cbe
2025-01-14 09:58:50 -08:00
Dawid Małecki 48cafc0b69 Replace $FlowFixMe in StatusBar (#48662)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48662

Changelog:
[General][Changed] - Improved types in StatusBar by adding StackProps

Reviewed By: javache

Differential Revision: D68152452

fbshipit-source-id: a1ec30526e78eb7205e786ae1d0209037e4a0aba
2025-01-14 09:51:04 -08:00
Nicola Corti 6368555ab0 RN-Tester: Reorder buttons in the New Architecture sample (#48666)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48666

The New Architecture sample is getting too big and the two views are not visible anymore.
I'm fixing this but having buttons side by side.

Changelog:
[Internal] [Changed] -

Reviewed By: cipolleschi

Differential Revision: D68153245

fbshipit-source-id: 5557fd40f81078fe3994d8efe0e73784e043ed78
2025-01-14 09:15:36 -08:00
Nicola Corti ef7f714f57 Remove unnecessary LICENSE-docs (#48670)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48670

The `LICENSE-docs` was needed when this repo was also containing the reactnative.dev docs.
As this is not the case anymore, this file is unncessary.

Changelog:
[Internal] [Changed] - Remove unnecessary LICENSE-docs

Reviewed By: cipolleschi

Differential Revision: D68156336

fbshipit-source-id: 489bf2cb95916c20eb61bfb00e34b8e271bc08e3
2025-01-14 08:53:58 -08:00
Fabrizio Cucci 51fb5ab87a Migrate rn-tester/IntegrationTests/AccessibilityManagerTest.js to function components (#48663)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48663

As per title.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D68151132

fbshipit-source-id: 6fd9c4999a95a6888795c5200aafb15ff623479f
2025-01-14 08:45:21 -08:00
Thomas Nardone a511c1bdee Fix null safety in views/text/frescosupport (#48612)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48612

Manual fixes to resolve nullsafe issues.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D67992722

fbshipit-source-id: a26cde9788bc3456ec756326208b4907ad989d4e
2025-01-14 08:28:03 -08:00
Thomas Nardone 8b8b0ba5dc Mark nullsafe fixmes in views/text/frescosupport (#48613)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48613

First step for nullsafe - annotate and mark fixmes

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D67992721

fbshipit-source-id: 0c0a3ac7d4442d35bba1f48d6aabf13a3a1d47c2
2025-01-14 08:28:03 -08:00
Samuel Susla c799aa07e2 Back out "RN: Enable useInsertionEffectsForAnimations" (#48669)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48669

Original commit changeset: d09b2f1b7607

Original Phabricator Diff: D65906157

## Changelog:

[General] [Fixed] - Buttons becoming unresponsive when transform is animated

Reviewed By: yungsters

Differential Revision: D68152746

fbshipit-source-id: aa0c0aa3243c67c95128a75b40dd6aa1251abbca
2025-01-14 08:20:05 -08:00
Riccardo Cipolleschi f44ff97c47 Properly test JSC for template_app e2e tests (#48656)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48656

While working on 0.78, I realize we were not testing the template app with JSC.

This change should fix this.

## Changelog:
[Internal] - Disable Hermes for the JSC E2E tests with Maestro

Reviewed By: cortinico, fabriziocucci

Differential Revision: D68147849

fbshipit-source-id: 4fbe005b5d04d6163a37041d1bd57fd48a9dfda8
2025-01-14 08:11:25 -08:00
Dawid Małecki 9f7bacaa6b Add explicit types for methods from AnimatedImplementation in AnimatedMock (#48610)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48610

Changelog:
[Internal] - Improved typings for AnimatedImplementation methods exported from AnimatedMock

Reviewed By: huntie

Differential Revision: D68019816

fbshipit-source-id: ee73213c0b519be9b72b8dfb2e91a125021de63e
2025-01-14 07:31:54 -08:00
Wojciech Lewicki 07769d4d7e feat: Make DefaultReactNativeHost.clear() also invalidate DefaultReactHost (#48338)
Summary:
On bridgeless mode, `reactHost` is kept in memory even after destroying the `DefaultReactNativeHost` in brownfield scenario. Since it keeps references to the modules, they are not deallocated, and their `initialize` methods are not fired again when creating new instance of `react-native` later. It breaks the behavior of e.g. `react-native-screens`, which wants to listen for mutations and should get new `FabricUIManager`: https://github.com/software-mansion/react-native-screens/blob/20b7e83782cd5f79ddd0d61dadc13eeb4db4b258/android/src/main/java/com/swmansion/rnscreens/ScreensModule.kt#L45.

In this commit we change the `DefaultReactNativeHost.clear()` method to also invalidate the instance retained inside `DefaultReactHost`

## Changelog:

[ANDROID] [FIXED] - Make DefaultReactNativeHost.clear() also invalidate DefaultReactHost

Pull Request resolved: https://github.com/facebook/react-native/pull/48338

Test Plan: In brownfield scenario, destroy the instance of RN and see that modules are also destroyed.

Reviewed By: cipolleschi

Differential Revision: D67977140

Pulled By: cortinico

fbshipit-source-id: 1804f093ab1a905bef499078ddec32a13c50cc85
2025-01-14 07:31:35 -08:00
Dawid Małecki 8b5e2ea683 Replace ExactReactElement_DEPRECATED in ScrollViewStickyHeader (#48659)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48659

Changelog:
[Internal] - Replaced ExactReactElement_DEPRECATED with React.Node as a children type in ScrollViewStickyHeader

Reviewed By: fabriziocucci

Differential Revision: D68151420

fbshipit-source-id: d4406de67176ae1fea95b8b2ea85f41dc7f5045e
2025-01-14 07:16:41 -08:00
Nicola Corti b7eccf23de Back out "Do not reset rn-artifacts-version on release branch" (#48651)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48651

Original commit changeset: dace7c931ec3

Original Phabricator Diff: D67975049

Reviewed By: cipolleschi

Differential Revision: D68114130

fbshipit-source-id: 9fb1707191037127b9ae985d2e3298a64e911590
2025-01-14 07:09:27 -08:00
Nicola Corti 85f9939031 Fix crash for Hermes Release due to HermesExecutor migration (#48660)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48660

RN-Tester is currently instacrashing on release due to a migration to Kotlin for HermesExecutor
This fixes it.

Changelog:
[Internal] [Changed] - Fix crash for Hermes Release due to HermesExecutor migration

Reviewed By: javache

Differential Revision: D68151666

fbshipit-source-id: 31f404ec518831cf2151dc670cdf8553427ae8ab
2025-01-14 06:12:00 -08:00
Iwo Plaza e4d969a4ab Migrate StyleSheet/*.js to use export statements (#48609)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48609

# Motivation
This is an attempt at modernizing the export syntax in some of the files in `Libraries/StyleSheet/`. It will allow these files to get properly ingested by modern Flow tooling.

# This diff
- Migrates the use of `module.exports` into `export default` for files located in `Libraries/StyleSheet/*.js`. Some files were omitted due to ballooning complexity, but will be addressed in other Diffs.
- Updating internal *require*s to use ".default", no product code seems to be affected.
- Migrating `require`s into `import`s where applicable, taking into account the performance implications (context: https://fb.workplace.com/groups/react.technologies.discussions/permalink/3638114866420225/)
- Updates the current iteration of API snapshots (intended).
- Updates `react-native-codegen`'s require of processColorArray, analogous to D42346452.

Changelog:
[General][Breaking] - Deep imports from some files in `StyleSheet/` can break when using the `require()` syntax, but can be easily fixed by appending `.default`

Reviewed By: javache

Differential Revision: D68017325

fbshipit-source-id: 3c5b94742f101db0b2914c91efab6003dba2b61a
2025-01-14 05:34:18 -08:00
Fabrizio Cucci d95909ea15 Migrate rn-tester/js/components/RNTesterTitle.js to function components (#48649)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48649

As per title.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D68099051

fbshipit-source-id: 867010b692e6d71e4683cc12b4455be730413268
2025-01-14 03:20:05 -08:00
Fabrizio Cucci 817cb17f78 Migrate rn-tester/js/examples/Layout/LayoutExample.js to function components (#48646)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48646

As per title.

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D68098856

fbshipit-source-id: ad878569f5b88afa57895b4b08de32c880ee8242
2025-01-14 03:20:05 -08:00
Dawid Małecki 2056794d24 Refactor import syntax that caused $FlowFixMe generation in snap (#48639)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48639

Changelog:
[Internal] - refactored import syntax in File, ElementProperties, Inspector, InspectorOverlay, InspectorPanel, PerformanceOverlay, Modal, YellowBoxDeprecated

Reviewed By: andrewdacenko

Differential Revision: D68099152

fbshipit-source-id: a0d840a6000fd3974a3ce4673455180a8be66288
2025-01-14 03:08:44 -08:00
Dawid Małecki 647ca90a30 Replace $FlowFixMe in AnimatedWeb (#48633)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48633

Changelog:
[General][Changed] - Improved types in AnimatedWeb

Reviewed By: huntie

Differential Revision: D68092072

fbshipit-source-id: 396efffc64030b0b2d4085f969b92c422b227c0d
2025-01-14 02:59:52 -08:00
David Vacca 2d320fbd76 Cache ViewManagerDelegate on ViewManagers (#48550)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48550

Cache ViewManagerDelegate on ViewManagers

changelog: [internal] internal

Reviewed By: javache

Differential Revision: D67957883

fbshipit-source-id: 8ec2f34fca04833e391b0bd5b9329cdc9ee12f08
2025-01-13 23:39:45 -08:00
Fabrizio Cucci 980458c061 Migrate rn-tester/js/components/RNTesterButton.js to function components (#48645)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48645

As per title.

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D68098118

fbshipit-source-id: 09f9c318afc210ca2ce6967dac7109544ef6717c
2025-01-13 13:07:44 -08:00
Pieter De Baets 5a290c4cab Fix nullability of ViewManagerDelegate method args (#48602)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48602

See context in D64532446 / https://github.com/facebook/react-native/pull/47086

These argument types were already consumed as nullable in various OSS libraries, which prevents correct Kotlin migration of this code.

Changelog: [Android][Changed] Deprecated ViewManagerDelegate#setProperty and ViewManagerDelegate#receiveCommand

Reviewed By: mdvacca

Differential Revision: D67277871

fbshipit-source-id: a0743584891c7b2b4b50fff11de15da0078d5a1a
2025-01-13 10:54:37 -08:00
Fabrizio Cucci 90d2f65301 Migrate rn-tester/js/examples/AppState/AppStateExample.js to function components (#48644)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48644

As per title.

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D68095480

fbshipit-source-id: 2487fa5e66d672883cbfde0c68348a90db09d484
2025-01-13 10:47:13 -08:00
Fabrizio Cucci 05e8007e12 Migrate rn-tester/js/examples/OrientationChange/OrientationChangeExample.js to function components (#48643)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48643

As per title.

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D68095232

fbshipit-source-id: fdf45a3bb64c590ea21222a02ae94d975579db49
2025-01-13 10:47:13 -08:00
Fabrizio Cucci 1e0009407d Migrate rn-tester/js/components/TextInlineView.js to function components (#48640)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48640

As per title.

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D68095013

fbshipit-source-id: a593af63029352844e544245d88e7b4c9d7eb75c
2025-01-13 08:59:43 -08:00
Parsa Nasirimehr 12e321daf0 chore(Android): Migrate Hermes Executor to Kotlin (#48617)
Summary:
Migrating HermesExecutor and it's factory to Kotlin. Not sure if the TAG in HermesExecutorFactory is needed anymore or not, but the rest of the changes are pretty bog standard

## Changelog:

[INTERNAL] [FIXED] - Migrate HermesExecutor and HermesExecutorFactory to Kotlin

Pull Request resolved: https://github.com/facebook/react-native/pull/48617

Test Plan:
`./gradlew test`:
<img width="1266" alt="Screenshot 2025-01-11 at 04 01 12" src="https://github.com/user-attachments/assets/c0f1402c-796b-45fa-9ee3-41c5a5ffc356" />

Reviewed By: tdn120

Differential Revision: D68094681

Pulled By: cortinico

fbshipit-source-id: 16eae5c7c24886421cbd2cbf213295134a9c01cf
2025-01-13 08:44:05 -08:00
Thomas Nardone c7785e7ead Convert ReactTextInlineImageShadowNode (#48576)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48576

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D67981753

fbshipit-source-id: 5d8a2408af9af350c0d3b369677ff8ee00335554
2025-01-13 08:39:18 -08:00
Rubén Norte fe8d102663 Create placeholder for User Timing API tests (#48634)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48634

Changelog: [internal]

Just a placeholder to add new tests in the future.

Reviewed By: sammy-SC

Differential Revision: D68093342

fbshipit-source-id: 1e1d7fd71865763ef66b3bb1c76ff8b8ebca9fd9
2025-01-13 07:01:03 -08:00
Riccardo Cipolleschi 671520943f Remove build codegen from Cocoapods (#48631)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/48631

This step is already carried out by [generate-artifact-executor](https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/codegen/generate-artifacts-executor.js#L385) if needed.

We can remove it from cocoapods and this will make it easier to migrate away from them.

For 3rd party apps that uses a specific version of React Native, codegen is shipped in NPM as already built in the react-native/codegen package.

This change really affects only the React Native monorepo.

## Changelog
[Internal] - Remove build codegen step from cocoapods

Reviewed By: cortinico

Differential Revision: D68019743

fbshipit-source-id: 7aaf9275886ba8b86d38d943d2b26bd8eed11aa8
2025-01-13 07:00:12 -08:00
73 changed files with 1189 additions and 1342 deletions
-2
View File
@@ -20,8 +20,6 @@ runs:
- name: Set React Native Version
shell: bash
run: node ./scripts/releases/set-rn-artifacts-version.js --build-type ${{ inputs.release-type }}
# We don't want to re-set the artifacts version if we're on the release branch.
if: ${{ !contains(github.ref, '-stable') }}
- name: Setup gradle
uses: ./.github/actions/setup-gradle
with:
+1 -1
View File
@@ -35,7 +35,7 @@ runs:
steps:
- name: Installing Maestro
shell: bash
run: export MAESTRO_VERSION=1.39.5; curl -Ls "https://get.maestro.mobile.dev" | bash
run: export MAESTRO_VERSION=1.39.7; curl -Ls "https://get.maestro.mobile.dev" | bash
- name: Set up JDK 17
if: ${{ inputs.install-java == 'true' }}
uses: actions/setup-java@v4
+1 -1
View File
@@ -31,7 +31,7 @@ runs:
steps:
- name: Installing Maestro
shell: bash
run: export MAESTRO_VERSION=1.39.5; curl -Ls "https://get.maestro.mobile.dev" | bash
run: export MAESTRO_VERSION=1.39.7; curl -Ls "https://get.maestro.mobile.dev" | bash
- name: Installing Maestro dependencies
shell: bash
run: |
+6 -1
View File
@@ -157,7 +157,7 @@ jobs:
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
test_ios_rntester:
runs-on: macos-13
runs-on: macos-13-large
needs:
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos]
env:
@@ -369,6 +369,11 @@ jobs:
sed -i 's/newArchEnabled=true/newArchEnabled=false/' android/gradle.properties
fi
if [[ ${{matrix.jsengine}} == "JSC" ]]; then
echo "Using JSC instead of Hermes"
sed -i 's/hermesEnabled=true/hermesEnabled=false/' android/gradle.properties
fi
# Build
cd android
CAPITALIZED_FLAVOR=$(echo "${{ matrix.flavor }}" | awk '{print toupper(substr($0, 1, 1)) substr($0, 2)}')
-393
View File
@@ -1,393 +0,0 @@
Attribution 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More_considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution 4.0 International Public License ("Public License"). To the
extent this Public License may be interpreted as a contract, You are
granted the Licensed Rights in consideration of Your acceptance of
these terms and conditions, and the Licensor grants You such rights in
consideration of benefits the Licensor receives from making the
Licensed Material available under these terms and conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
d. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
e. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
f. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
g. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
h. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
i. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
j. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
k. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
4. If You Share Adapted Material You produce, the Adapter's
License You apply must not prevent recipients of the Adapted
Material from complying with this Public License.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material; and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public licenses.
Notwithstanding, Creative Commons may elect to apply one of its public
licenses to material it publishes and in those instances will be
considered the "Licensor." Except for the limited purpose of indicating
that material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the public
licenses.
Creative Commons may be contacted at creativecommons.org.
+1 -1
View File
@@ -192,4 +192,4 @@ export default {
forkEvent: AnimatedImplementation.forkEvent,
unforkEvent: AnimatedImplementation.unforkEvent,
Event: AnimatedEvent,
};
} as typeof AnimatedImplementation;
+27 -9
View File
@@ -10,17 +10,35 @@
'use strict';
import type {AnimatedComponentType} from './createAnimatedComponent';
import AnimatedImplementation from './AnimatedImplementation';
import React from 'react';
export default {
...AnimatedImplementation,
/* $FlowFixMe[incompatible-call] createAnimatedComponent expects to receive
* types. Plain intrinsic components can't be typed like this */
div: (AnimatedImplementation.createAnimatedComponent('div'): $FlowFixMe),
/* $FlowFixMe[incompatible-call] createAnimatedComponent expects to receive
* types. Plain intrinsic components can't be typed like this */
span: (AnimatedImplementation.createAnimatedComponent('span'): $FlowFixMe),
/* $FlowFixMe[incompatible-call] createAnimatedComponent expects to receive
* types. Plain intrinsic components can't be typed like this */
img: (AnimatedImplementation.createAnimatedComponent('img'): $FlowFixMe),
div: AnimatedImplementation.createAnimatedComponent<
React.PropsOf<'div'>,
mixed,
>(
/* $FlowFixMe[incompatible-call] createAnimatedComponent expects to receive
* types. Plain intrinsic components can't be typed like this */
'div',
) as AnimatedComponentType<React.PropsOf<'div'>>,
span: AnimatedImplementation.createAnimatedComponent<
React.PropsOf<'span'>,
mixed,
>(
/* $FlowFixMe[incompatible-call] createAnimatedComponent expects to receive
* types. Plain intrinsic components can't be typed like this */
'span',
) as AnimatedComponentType<React.PropsOf<'span'>>,
img: AnimatedImplementation.createAnimatedComponent<
React.PropsOf<'img'>,
mixed,
>(
/* $FlowFixMe[incompatible-call] createAnimatedComponent expects to receive
* types. Plain intrinsic components can't be typed like this */
'img',
) as AnimatedComponentType<React.PropsOf<'img'>>,
};
@@ -9,6 +9,7 @@
*/
import type {EventSubscription} from '../../vendor/emitter/EventEmitter';
import type {PlatformConfig} from '../AnimatedPlatformConfig';
import type Animation, {EndCallback} from '../animations/Animation';
import type {InterpolationConfigType} from './AnimatedInterpolation';
import type AnimatedNode from './AnimatedNode';
@@ -131,6 +132,11 @@ export default class AnimatedValue extends AnimatedWithChildren {
return this._value + this._offset;
}
__makeNative(platformConfig: ?PlatformConfig): void {
super.__makeNative(platformConfig);
this.#ensureUpdateSubscriptionExists();
}
#ensureUpdateSubscriptionExists(): void {
if (this.#updateSubscription != null) {
return;
+2 -1
View File
@@ -12,7 +12,8 @@
import type {BlobOptions} from './BlobTypes';
const Blob = require('./Blob');
import Blob from './Blob';
const invariant = require('invariant');
/**
@@ -19,7 +19,7 @@ import * as React from 'react';
import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
export type Props = $ReadOnly<{
children?: ExactReactElement_DEPRECATED<$FlowFixMe>,
children?: React.Node,
nextHeaderLayoutY: ?number,
onLayout: (event: LayoutEvent) => void,
scrollAnimatedValue: Animated.Value,
@@ -105,6 +105,24 @@ type Props = $ReadOnly<{|
barStyle?: ?('default' | 'light-content' | 'dark-content'),
|}>;
type StackProps = {
backgroundColor: ?{
value: Props['backgroundColor'],
animated: boolean,
},
barStyle: ?{
value: Props['barStyle'],
animated: boolean,
},
translucent: Props['translucent'],
hidden: ?{
value: boolean,
animated: boolean,
transition: Props['showHideTransition'],
},
networkActivityIndicatorVisible: Props['networkActivityIndicatorVisible'],
};
/**
* Merges the prop stack with the default values.
*/
@@ -129,7 +147,7 @@ function mergePropsStack(
* Returns an object to insert in the props stack from the props
* and the transition/animation info.
*/
function createStackEntry(props: any): any {
function createStackEntry(props: Props): StackProps {
const animated = props.animated ?? false;
const showHideTransition = props.showHideTransition ?? 'fade';
return {
@@ -203,7 +221,7 @@ function createStackEntry(props: any): any {
* `currentHeight` (Android only) The height of the status bar.
*/
class StatusBar extends React.Component<Props> {
static _propsStack: Array<any> = [];
static _propsStack: Array<StackProps> = [];
static _defaultProps: any = createStackEntry({
backgroundColor:
@@ -218,12 +236,10 @@ class StatusBar extends React.Component<Props> {
});
// Timer for updating the native module values at the end of the frame.
// $FlowFixMe[missing-local-annot]
static _updateImmediate = null;
static _updateImmediate: ?number = null;
// The current merged values from the props stack.
// $FlowFixMe[missing-local-annot]
static _currentValues = null;
static _currentValues: ?StackProps = null;
// TODO(janic): Provide a real API to deal with status bar height. See the
// discussion in #6195.
@@ -371,8 +387,7 @@ class StatusBar extends React.Component<Props> {
return newEntry;
}
// $FlowFixMe[missing-local-annot]
_stackEntry = null;
_stackEntry: ?StackProps = null;
componentDidMount() {
// Every time a StatusBar component is mounted, we push it's prop to a stack
@@ -412,14 +427,14 @@ class StatusBar extends React.Component<Props> {
if (Platform.OS === 'ios') {
if (
!oldProps ||
oldProps.barStyle.value !== mergedProps.barStyle.value
oldProps.barStyle?.value !== mergedProps.barStyle.value
) {
NativeStatusBarManagerIOS.setStyle(
mergedProps.barStyle.value,
mergedProps.barStyle.animated || false,
);
}
if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) {
if (!oldProps || oldProps.hidden?.value !== mergedProps.hidden.value) {
NativeStatusBarManagerIOS.setHidden(
mergedProps.hidden.value,
mergedProps.hidden.animated
@@ -456,7 +471,7 @@ class StatusBar extends React.Component<Props> {
mergedProps.backgroundColor.animated,
);
}
if (!oldProps || oldProps.hidden.value !== mergedProps.hidden.value) {
if (!oldProps || oldProps.hidden?.value !== mergedProps.hidden.value) {
NativeStatusBarManagerAndroid.setHidden(mergedProps.hidden.value);
}
// Activities are not translucent by default, so always set if true.
@@ -13,6 +13,8 @@
import type {InspectorData} from '../Renderer/shims/ReactNativeTypes';
import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
import React from 'react';
const TouchableHighlight = require('../Components/Touchable/TouchableHighlight');
const TouchableWithoutFeedback = require('../Components/Touchable/TouchableWithoutFeedback');
const View = require('../Components/View/View');
@@ -22,7 +24,6 @@ const Text = require('../Text/Text');
const mapWithSeparator = require('../Utilities/mapWithSeparator');
const BoxInspector = require('./BoxInspector');
const StyleInspector = require('./StyleInspector');
const React = require('react');
type Props = $ReadOnly<{|
hierarchy: ?InspectorData['hierarchy'],
+1 -1
View File
@@ -19,6 +19,7 @@ import type {ViewStyleProp} from '../StyleSheet/StyleSheet';
import type {ReactDevToolsAgent} from '../Types/ReactDevToolsTypes';
import SafeAreaView from '../../src/private/components/SafeAreaView_INTERNAL_DO_NOT_USE';
import React from 'react';
const View = require('../Components/View/View');
const PressabilityDebug = require('../Pressability/PressabilityDebug');
@@ -29,7 +30,6 @@ const Platform = require('../Utilities/Platform');
const getInspectorDataForViewAtPoint = require('./getInspectorDataForViewAtPoint');
const InspectorOverlay = require('./InspectorOverlay');
const InspectorPanel = require('./InspectorPanel');
const React = require('react');
const {useState} = React;
@@ -13,10 +13,11 @@
import type {PressEvent} from '../Types/CoreEventTypes';
import type {InspectedElement} from './Inspector';
import React from 'react';
const View = require('../Components/View/View');
const StyleSheet = require('../StyleSheet/StyleSheet');
const ElementBox = require('./ElementBox');
const React = require('react');
type Props = $ReadOnly<{|
inspected?: ?InspectedElement,
@@ -13,6 +13,7 @@
import type {ElementsHierarchy, InspectedElement} from './Inspector';
import SafeAreaView from '../Components/SafeAreaView/SafeAreaView';
import React from 'react';
const ScrollView = require('../Components/ScrollView/ScrollView');
const TouchableHighlight = require('../Components/Touchable/TouchableHighlight');
@@ -22,7 +23,6 @@ const Text = require('../Text/Text');
const ElementProperties = require('./ElementProperties');
const NetworkOverlay = require('./NetworkOverlay');
const PerformanceOverlay = require('./PerformanceOverlay');
const React = require('react');
type Props = $ReadOnly<{|
devtoolsIsOpen: boolean,
@@ -10,11 +10,12 @@
'use strict';
import React from 'react';
const View = require('../Components/View/View');
const StyleSheet = require('../StyleSheet/StyleSheet');
const Text = require('../Text/Text');
const PerformanceLogger = require('../Utilities/GlobalPerformanceLogger');
const React = require('react');
class PerformanceOverlay extends React.Component<{...}> {
render(): React.Node {
+1 -1
View File
@@ -18,6 +18,7 @@ import ModalInjection from './ModalInjection';
import NativeModalManager from './NativeModalManager';
import RCTModalHostView from './RCTModalHostViewNativeComponent';
import {VirtualizedListContextResetter} from '@react-native/virtualized-lists';
import React from 'react';
const ScrollView = require('../Components/ScrollView/ScrollView');
const View = require('../Components/View/View');
@@ -26,7 +27,6 @@ const I18nManager = require('../ReactNative/I18nManager');
const {RootTagContext} = require('../ReactNative/RootTag');
const StyleSheet = require('../StyleSheet/StyleSheet');
const Platform = require('../Utilities/Platform');
const React = require('react');
type ModalEventDefinitions = {
modalDismissed: [{modalID: number}],
@@ -12,8 +12,9 @@
import type {IgnorePattern} from '../LogBox/Data/LogBoxData';
import React from 'react';
const LogBox = require('../LogBox/LogBox').default;
const React = require('react');
type Props = $ReadOnly<{||}>;
@@ -269,68 +269,8 @@ exports[`public API should not change unintentionally Libraries/Animated/Animate
_isUsingNativeDriver: () => boolean,
...
};
declare const spring: (
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
config: SpringAnimationConfig
) => CompositeAnimation;
declare const timing: (
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
config: TimingAnimationConfig
) => CompositeAnimation;
declare const decay: (
value: AnimatedValue | AnimatedValueXY | AnimatedColor,
config: DecayAnimationConfig
) => CompositeAnimation;
declare const sequence: (
animations: Array<CompositeAnimation>
) => CompositeAnimation;
type ParallelConfig = { stopTogether?: boolean, ... };
declare const parallel: (
animations: Array<CompositeAnimation>,
config?: ?ParallelConfig
) => CompositeAnimation;
declare const delay: (time: number) => CompositeAnimation;
declare const stagger: (
time: number,
animations: Array<CompositeAnimation>
) => CompositeAnimation;
type LoopAnimationConfig = {
iterations: number,
resetBeforeIteration?: boolean,
...
};
declare const loop: (
animation: CompositeAnimation,
LoopAnimationConfig
) => CompositeAnimation;
export type { AnimatedNumeric as Numeric };
declare export default {
Value: AnimatedValue,
ValueXY: AnimatedValueXY,
Color: AnimatedColor,
Interpolation: AnimatedInterpolation,
Node: AnimatedNode,
decay: decay,
timing: timing,
spring: spring,
add: $FlowFixMe,
subtract: $FlowFixMe,
divide: $FlowFixMe,
multiply: $FlowFixMe,
modulo: $FlowFixMe,
diffClamp: $FlowFixMe,
delay: delay,
sequence: sequence,
parallel: parallel,
stagger: stagger,
loop: loop,
event: $FlowFixMe,
createAnimatedComponent: createAnimatedComponent,
attachNativeEvent: attachNativeEvent,
forkEvent: $FlowFixMe,
unforkEvent: $FlowFixMe,
Event: AnimatedEvent,
};
declare export default typeof AnimatedImplementation;
"
`;
@@ -342,9 +282,9 @@ exports[`public API should not change unintentionally Libraries/Animated/Animate
exports[`public API should not change unintentionally Libraries/Animated/AnimatedWeb.js 1`] = `
"declare export default {
...AnimatedImplementation,
div: $FlowFixMe,
span: $FlowFixMe,
img: $FlowFixMe,
div: AnimatedComponentType<React.PropsOf<\\"div\\">>,
span: AnimatedComponentType<React.PropsOf<\\"span\\">>,
img: AnimatedComponentType<React.PropsOf<\\"img\\">>,
};
"
`;
@@ -1169,6 +1109,7 @@ declare export default class AnimatedValue extends AnimatedWithChildren {
__attach(): void;
__detach(): void;
__getValue(): number;
__makeNative(platformConfig: ?PlatformConfig): void;
setValue(value: number): void;
setOffset(offset: number): void;
flattenOffset(): void;
@@ -1476,8 +1417,7 @@ export type BlobOptions = {
`;
exports[`public API should not change unintentionally Libraries/Blob/File.js 1`] = `
"declare const Blob: $FlowFixMe;
declare class File extends Blob {
"declare class File extends Blob {
constructor(
parts: Array<Blob | string>,
name: string,
@@ -2450,7 +2390,7 @@ exports[`public API should not change unintentionally Libraries/Components/Scrol
exports[`public API should not change unintentionally Libraries/Components/ScrollView/ScrollViewStickyHeader.js 1`] = `
"export type Props = $ReadOnly<{
children?: ExactReactElement_DEPRECATED<$FlowFixMe>,
children?: React.Node,
nextHeaderLayoutY: ?number,
onLayout: (event: LayoutEvent) => void,
scrollAnimatedValue: Animated.Value,
@@ -2546,11 +2486,28 @@ type Props = $ReadOnly<{|
animated?: ?boolean,
barStyle?: ?(\\"default\\" | \\"light-content\\" | \\"dark-content\\"),
|}>;
type StackProps = {
backgroundColor: ?{
value: Props[\\"backgroundColor\\"],
animated: boolean,
},
barStyle: ?{
value: Props[\\"barStyle\\"],
animated: boolean,
},
translucent: Props[\\"translucent\\"],
hidden: ?{
value: boolean,
animated: boolean,
transition: Props[\\"showHideTransition\\"],
},
networkActivityIndicatorVisible: Props[\\"networkActivityIndicatorVisible\\"],
};
declare class StatusBar extends React.Component<Props> {
static _propsStack: Array<any>;
static _propsStack: Array<StackProps>;
static _defaultProps: any;
static _updateImmediate: $FlowFixMe;
static _currentValues: $FlowFixMe;
static _updateImmediate: ?number;
static _currentValues: ?StackProps;
static currentHeight: ?number;
static setHidden(hidden: boolean, animation?: StatusBarAnimation): void;
static setBarStyle(style: StatusBarStyle, animated?: boolean): void;
@@ -2560,7 +2517,7 @@ declare class StatusBar extends React.Component<Props> {
static pushStackEntry(props: any): any;
static popStackEntry(entry: any): void;
static replaceStackEntry(entry: any, props: any): any;
_stackEntry: $FlowFixMe;
_stackEntry: ?StackProps;
componentDidMount(): void;
componentWillUnmount(): void;
componentDidUpdate(): void;
@@ -5187,8 +5144,7 @@ declare module.exports: ElementBox;
`;
exports[`public API should not change unintentionally Libraries/Inspector/ElementProperties.js 1`] = `
"declare const React: $FlowFixMe;
type Props = $ReadOnly<{|
"type Props = $ReadOnly<{|
hierarchy: ?InspectorData[\\"hierarchy\\"],
style?: ?ViewStyleProp,
frame?: ?Object,
@@ -5203,8 +5159,7 @@ declare module.exports: ElementProperties;
`;
exports[`public API should not change unintentionally Libraries/Inspector/Inspector.js 1`] = `
"declare const React: $FlowFixMe;
export type InspectedElementFrame = TouchedViewDataAtPoint[\\"frame\\"];
"export type InspectedElementFrame = TouchedViewDataAtPoint[\\"frame\\"];
export type InspectedElement = $ReadOnly<{
frame: InspectedElementFrame,
style?: ViewStyleProp,
@@ -5221,8 +5176,7 @@ declare module.exports: Inspector;
`;
exports[`public API should not change unintentionally Libraries/Inspector/InspectorOverlay.js 1`] = `
"declare const React: $FlowFixMe;
type Props = $ReadOnly<{|
"type Props = $ReadOnly<{|
inspected?: ?InspectedElement,
onTouchPoint: (locationX: number, locationY: number) => void,
|}>;
@@ -5232,8 +5186,7 @@ declare module.exports: InspectorOverlay;
`;
exports[`public API should not change unintentionally Libraries/Inspector/InspectorPanel.js 1`] = `
"declare const React: $FlowFixMe;
type Props = $ReadOnly<{|
"type Props = $ReadOnly<{|
devtoolsIsOpen: boolean,
inspecting: boolean,
setInspecting: (val: boolean) => void,
@@ -5316,8 +5269,7 @@ declare module.exports: NetworkOverlay;
`;
exports[`public API should not change unintentionally Libraries/Inspector/PerformanceOverlay.js 1`] = `
"declare const React: $FlowFixMe;
declare class PerformanceOverlay extends React.Component<{ ... }> {
"declare class PerformanceOverlay extends React.Component<{ ... }> {
render(): React.Node;
}
declare module.exports: PerformanceOverlay;
@@ -6492,8 +6444,7 @@ declare export function getTextColor(opacity?: number): string;
`;
exports[`public API should not change unintentionally Libraries/Modal/Modal.js 1`] = `
"declare const React: $FlowFixMe;
type OrientationChangeEvent = $ReadOnly<{|
"type OrientationChangeEvent = $ReadOnly<{|
orientation: \\"portrait\\" | \\"landscape\\",
|}>;
export type Props = $ReadOnly<{|
@@ -9566,8 +9517,7 @@ declare module.exports: WebSocketInterceptor;
`;
exports[`public API should not change unintentionally Libraries/YellowBox/YellowBoxDeprecated.js 1`] = `
"declare const React: $FlowFixMe;
type Props = $ReadOnly<{||}>;
"type Props = $ReadOnly<{||}>;
declare module.exports: Class<React.Component<Props>> & {
ignoreWarnings($ReadOnlyArray<IgnorePattern>): void,
install(): void,
@@ -2045,6 +2045,7 @@ public final class com/facebook/react/defaults/DefaultReactHost {
public abstract class com/facebook/react/defaults/DefaultReactNativeHost : com/facebook/react/ReactNativeHost {
protected fun <init> (Landroid/app/Application;)V
public fun clear ()V
protected fun getJSEngineResolutionAlgorithm ()Lcom/facebook/react/JSEngineResolutionAlgorithm;
protected fun getReactPackageTurboModuleManagerDelegateBuilder ()Lcom/facebook/react/ReactPackageTurboModuleManagerDelegate$Builder;
protected fun getUIManagerProvider ()Lcom/facebook/react/bridge/UIManagerProvider;
@@ -4041,6 +4042,8 @@ public abstract class com/facebook/react/uimanager/BaseViewManager : com/faceboo
public abstract class com/facebook/react/uimanager/BaseViewManagerDelegate : com/facebook/react/uimanager/ViewManagerDelegate {
protected final field mViewManager Lcom/facebook/react/uimanager/BaseViewManager;
public fun <init> (Lcom/facebook/react/uimanager/BaseViewManager;)V
public synthetic fun kotlinCompat$receiveCommand (Landroid/view/View;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V
public synthetic fun kotlinCompat$setProperty (Landroid/view/View;Ljava/lang/String;Ljava/lang/Object;)V
public fun receiveCommand (Landroid/view/View;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V
public fun setProperty (Landroid/view/View;Ljava/lang/String;Ljava/lang/Object;)V
}
@@ -5231,8 +5234,10 @@ public abstract class com/facebook/react/uimanager/ViewManager : com/facebook/re
}
public abstract interface class com/facebook/react/uimanager/ViewManagerDelegate {
public abstract fun receiveCommand (Landroid/view/View;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V
public abstract fun setProperty (Landroid/view/View;Ljava/lang/String;Ljava/lang/Object;)V
public abstract synthetic fun kotlinCompat$receiveCommand (Landroid/view/View;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V
public abstract synthetic fun kotlinCompat$setProperty (Landroid/view/View;Ljava/lang/String;Ljava/lang/Object;)V
public fun receiveCommand (Landroid/view/View;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;)V
public fun setProperty (Landroid/view/View;Ljava/lang/String;Ljava/lang/Object;)V
}
public class com/facebook/react/uimanager/ViewManagerPropertyUpdater {
@@ -1,50 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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.hermes.reactexecutor;
import com.facebook.jni.HybridData;
import com.facebook.react.bridge.JavaScriptExecutor;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.soloader.SoLoader;
import javax.annotation.Nullable;
public class HermesExecutor extends JavaScriptExecutor {
private static String mode_;
static {
loadLibrary();
}
public static void loadLibrary() throws UnsatisfiedLinkError {
if (mode_ == null) {
// libhermes must be loaded explicitly to invoke its JNI_OnLoad.
SoLoader.loadLibrary("hermes");
SoLoader.loadLibrary("hermes_executor");
// libhermes_executor is built differently for Debug & Release so we load the proper mode.
mode_ = ReactBuildConfig.DEBUG ? "Debug" : "Release";
}
}
HermesExecutor(@Nullable RuntimeConfig config, boolean enableDebugger, String debuggerName) {
super(
config == null
? initHybridDefaultConfig(enableDebugger, debuggerName)
: initHybrid(enableDebugger, debuggerName, config.getHeapSizeMB()));
}
@Override
public String getName() {
return "HermesExecutor" + mode_;
}
private static native HybridData initHybridDefaultConfig(
boolean enableDebugger, String debuggerName);
private static native HybridData initHybrid(
boolean enableDebugger, String debuggerName, long heapSizeMB);
}
@@ -0,0 +1,58 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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.hermes.reactexecutor
import com.facebook.jni.HybridData
import com.facebook.jni.annotations.DoNotStrip
import com.facebook.react.bridge.JavaScriptExecutor
import com.facebook.react.common.build.ReactBuildConfig
import com.facebook.soloader.SoLoader
public class HermesExecutor
internal constructor(config: RuntimeConfig?, enableDebugger: Boolean, debuggerName: String) :
JavaScriptExecutor(
config?.let { initHybrid(enableDebugger, debuggerName, it.heapSizeMB) }
?: initHybridDefaultConfig(enableDebugger, debuggerName)) {
override fun getName(): String = "HermesExecutor$mode"
public companion object {
private var mode: String? = null
init {
loadLibrary()
}
@JvmStatic
@Throws(UnsatisfiedLinkError::class)
public fun loadLibrary() {
if (mode == null) {
// libhermes must be loaded explicitly to invoke its JNI_OnLoad.
SoLoader.loadLibrary("hermes")
SoLoader.loadLibrary("hermes_executor")
// libhermes_executor is built differently for Debug & Release so we load the proper mode.
mode = if (ReactBuildConfig.DEBUG) "Debug" else "Release"
}
}
@DoNotStrip
@JvmStatic
private external fun initHybridDefaultConfig(
enableDebugger: Boolean,
debuggerName: String
): HybridData?
@DoNotStrip
@JvmStatic
private external fun initHybrid(
enableDebugger: Boolean,
debuggerName: String,
heapSizeMB: Long
): HybridData?
}
}
@@ -1,57 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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.hermes.reactexecutor;
import com.facebook.hermes.instrumentation.HermesSamplingProfiler;
import com.facebook.react.bridge.JavaScriptExecutor;
import com.facebook.react.bridge.JavaScriptExecutorFactory;
public class HermesExecutorFactory implements JavaScriptExecutorFactory {
private static final String TAG = "Hermes";
private final RuntimeConfig mConfig;
private boolean mEnableDebugger = true;
private String mDebuggerName = "";
public HermesExecutorFactory() {
this(null);
}
public HermesExecutorFactory(RuntimeConfig config) {
mConfig = config;
}
public void setEnableDebugger(boolean enableDebugger) {
mEnableDebugger = enableDebugger;
}
public void setDebuggerName(String debuggerName) {
mDebuggerName = debuggerName;
}
@Override
public JavaScriptExecutor create() {
return new HermesExecutor(mConfig, mEnableDebugger, mDebuggerName);
}
@Override
public void startSamplingProfiler() {
HermesSamplingProfiler.enable();
}
@Override
public void stopSamplingProfiler(String filename) {
HermesSamplingProfiler.dumpSampledTraceToFile(filename);
HermesSamplingProfiler.disable();
}
@Override
public String toString() {
return "JSIExecutor+HermesRuntime";
}
}
@@ -0,0 +1,42 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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.hermes.reactexecutor
import com.facebook.hermes.instrumentation.HermesSamplingProfiler.disable
import com.facebook.hermes.instrumentation.HermesSamplingProfiler.dumpSampledTraceToFile
import com.facebook.hermes.instrumentation.HermesSamplingProfiler.enable
import com.facebook.react.bridge.JavaScriptExecutor
import com.facebook.react.bridge.JavaScriptExecutorFactory
public class HermesExecutorFactory
@JvmOverloads
public constructor(private val config: RuntimeConfig? = null) : JavaScriptExecutorFactory {
private var enableDebugger = true
private var debuggerName = ""
public fun setEnableDebugger(enableDebugger: Boolean) {
this.enableDebugger = enableDebugger
}
public fun setDebuggerName(debuggerName: String) {
this.debuggerName = debuggerName
}
override fun create(): JavaScriptExecutor = HermesExecutor(config, enableDebugger, debuggerName)
override fun startSamplingProfiler() {
enable()
}
override fun stopSamplingProfiler(filename: String) {
dumpSampledTraceToFile(filename)
disable()
}
override fun toString(): String = "JSIExecutor+HermesRuntime"
}
@@ -175,4 +175,12 @@ public object DefaultReactHost {
}
return reactNativeHost.toReactHost(context)
}
/**
* Cleanup function for brownfield scenarios where you want to remove the references kept by
* reactHost after destroying the RN instance.
*/
internal fun invalidate() {
reactHost = null
}
}
@@ -76,6 +76,11 @@ protected constructor(
null -> null
}
override fun clear() {
super.clear()
DefaultReactHost.invalidate()
}
/**
* Returns whether the user wants to use the New Architecture or not.
*
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<3e10f8d2f623da3b7b502d8fa78f82a4>>
* @generated SignedSource<<2c321a7a8e811dc238a75f76180843b9>>
*/
/**
@@ -244,6 +244,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun useAlwaysAvailableJSErrorHandling(): Boolean = accessor.useAlwaysAvailableJSErrorHandling()
/**
* If true, focusing in ReactEditText will mainly use stock Android requestFocus() behavior. If false it will use legacy custom focus behavior.
*/
@JvmStatic
public fun useEditTextStockAndroidFocusBehavior(): Boolean = accessor.useEditTextStockAndroidFocusBehavior()
/**
* Should this application enable the Fabric Interop Layer for Android? If yes, the application will behave so that it can accept non-Fabric components and render them on Fabric. This toggle is controlling extra logic such as custom event dispatching that are needed for the Fabric Interop Layer to work correctly.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<497bbb23778fe0f9763e9bfa715ea3aa>>
* @generated SignedSource<<e724939eaa9fa53c9b25c8a5a1e3196d>>
*/
/**
@@ -56,6 +56,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
private var loadVectorDrawablesOnImagesCache: Boolean? = null
private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null
private var useEditTextStockAndroidFocusBehaviorCache: Boolean? = null
private var useFabricInteropCache: Boolean? = null
private var useImmediateExecutorInAndroidBridgelessCache: Boolean? = null
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
@@ -390,6 +391,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
return cached
}
override fun useEditTextStockAndroidFocusBehavior(): Boolean {
var cached = useEditTextStockAndroidFocusBehaviorCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.useEditTextStockAndroidFocusBehavior()
useEditTextStockAndroidFocusBehaviorCache = cached
}
return cached
}
override fun useFabricInterop(): Boolean {
var cached = useFabricInteropCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<d801f87c988fbd921e2379f236e1711f>>
* @generated SignedSource<<a7f3ca986725fa85a6926c9e7966669b>>
*/
/**
@@ -100,6 +100,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun useAlwaysAvailableJSErrorHandling(): Boolean
@DoNotStrip @JvmStatic public external fun useEditTextStockAndroidFocusBehavior(): Boolean
@DoNotStrip @JvmStatic public external fun useFabricInterop(): Boolean
@DoNotStrip @JvmStatic public external fun useImmediateExecutorInAndroidBridgeless(): Boolean
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<5de2cfc00f486b7d07266939ce18a397>>
* @generated SignedSource<<85d40be44d053b58a74ad76467c8e5e9>>
*/
/**
@@ -95,6 +95,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun useAlwaysAvailableJSErrorHandling(): Boolean = false
override fun useEditTextStockAndroidFocusBehavior(): Boolean = true
override fun useFabricInterop(): Boolean = false
override fun useImmediateExecutorInAndroidBridgeless(): Boolean = true
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<f1ed4107e24ced5d2673bfb065573062>>
* @generated SignedSource<<18d5c2ffa66a36e364bc358a144534ec>>
*/
/**
@@ -60,6 +60,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
private var loadVectorDrawablesOnImagesCache: Boolean? = null
private var traceTurboModulePromiseRejectionsOnAndroidCache: Boolean? = null
private var useAlwaysAvailableJSErrorHandlingCache: Boolean? = null
private var useEditTextStockAndroidFocusBehaviorCache: Boolean? = null
private var useFabricInteropCache: Boolean? = null
private var useImmediateExecutorInAndroidBridgelessCache: Boolean? = null
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
@@ -430,6 +431,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun useEditTextStockAndroidFocusBehavior(): Boolean {
var cached = useEditTextStockAndroidFocusBehaviorCache
if (cached == null) {
cached = currentProvider.useEditTextStockAndroidFocusBehavior()
accessedFeatureFlags.add("useEditTextStockAndroidFocusBehavior")
useEditTextStockAndroidFocusBehaviorCache = cached
}
return cached
}
override fun useFabricInterop(): Boolean {
var cached = useFabricInteropCache
if (cached == null) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<3cd802bdd1d383ea0668e43319d53b3f>>
* @generated SignedSource<<4f90c47ea6f23c2ebfae1f35790c4af5>>
*/
/**
@@ -95,6 +95,8 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun useAlwaysAvailableJSErrorHandling(): Boolean
@DoNotStrip public fun useEditTextStockAndroidFocusBehavior(): Boolean
@DoNotStrip public fun useFabricInterop(): Boolean
@DoNotStrip public fun useImmediateExecutorInAndroidBridgeless(): Boolean
@@ -23,8 +23,8 @@ public abstract class BaseViewManagerDelegate<
T : View, U : BaseViewManager<T, out LayoutShadowNode>>(
@Suppress("NoHungarianNotation") @JvmField protected val mViewManager: U
) : ViewManagerDelegate<T> {
@Suppress("DEPRECATION")
override public fun setProperty(view: T, propName: String?, value: Any?) {
@Suppress("ACCIDENTAL_OVERRIDE", "DEPRECATION")
override public fun setProperty(view: T, propName: String, value: Any?) {
when (propName) {
ViewProps.ACCESSIBILITY_ACTIONS ->
mViewManager.setAccessibilityActions(view, value as ReadableArray?)
@@ -146,6 +146,7 @@ public abstract class BaseViewManagerDelegate<
}
}
override public fun receiveCommand(view: T, commandName: String?, args: ReadableArray?): Unit =
@Suppress("ACCIDENTAL_OVERRIDE")
override public fun receiveCommand(view: T, commandName: String, args: ReadableArray?): Unit =
Unit
}
@@ -41,6 +41,9 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
private static final String NAME = ViewManager.class.getSimpleName();
private boolean mIsDelegateLoaded = false;
private @Nullable ViewManagerDelegate<T> mDelegate = null;
/**
* For View recycling: we store a Stack of unused, dead Views. This is null by default, and when
* null signals that View Recycling is disabled. `enableViewRecycling` must be explicitly called
@@ -88,7 +91,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
* @param props {@link ReactStylesDiffMap} props to update the view with
*/
public void updateProperties(@NonNull T viewToUpdate, ReactStylesDiffMap props) {
final ViewManagerDelegate<T> delegate = getDelegate();
final ViewManagerDelegate<T> delegate = getOrCreateViewManagerDelegate();
if (delegate != null) {
ViewManagerPropertyUpdater.updateProps(delegate, viewToUpdate, props);
} else {
@@ -109,11 +112,18 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
* @return an instance of {@link ViewManagerDelegate} if the props of the view managed by this
* view manager should be set via this delegate
*/
@Nullable
protected ViewManagerDelegate<T> getDelegate() {
protected @Nullable ViewManagerDelegate<T> getDelegate() {
return null;
}
private @Nullable ViewManagerDelegate<T> getOrCreateViewManagerDelegate() {
if (!mIsDelegateLoaded) {
mDelegate = getDelegate();
mIsDelegateLoaded = true;
}
return mDelegate;
}
/** Creates a view with knowledge of props and state. */
public @NonNull T createView(
int reactTag,
@@ -306,7 +316,7 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
* @param args optional arguments for the command
*/
public void receiveCommand(@NonNull T root, String commandId, @Nullable ReadableArray args) {
final ViewManagerDelegate<T> delegate = getDelegate();
final ViewManagerDelegate<T> delegate = getOrCreateViewManagerDelegate();
if (delegate != null) {
delegate.receiveCommand(root, commandId, args);
}
@@ -22,20 +22,42 @@ public interface ViewManagerDelegate<T : View> {
/**
* Sets a property on a view managed by this view manager.
*
* We mark this method as synthetic / hide it from JVM so Java callers will call the deprecated
* version and overrides work correctly.
*
* @param view the view to set the property on
* @param propName the name of the property to set (NOTE: should be `String` but is kept as
* `String?` to avoid breaking changes)
* @param propName the name of the property to set
* @param value the value to set the property to
*/
public fun setProperty(view: T, propName: String?, value: Any?)
@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("kotlinCompat\$setProperty")
@JvmSynthetic
public fun setProperty(view: T, propName: String, value: Any?)
@Suppress("INAPPLICABLE_JVM_NAME")
@Deprecated(message = "propName is not nullable, please update your method signature")
@JvmName("setProperty")
public fun javaCompat_setProperty(view: T, propName: String?, value: Any?): Unit =
setProperty(view, checkNotNull(propName), value)
/**
* Executes a command from JS to the view
*
* We mark this method as synthetic / hide it from JVM so Java callers will call the deprecated
* version and overrides work correctly.
*
* @param view the view to execute the command on
* @param commandName the name of the command to execute (NOTE: should be `String` but is kept as
* `String?` to avoid breaking changes)
* @param commandName the name of the command to execute
* @param args the arguments to pass to the command
*/
public fun receiveCommand(view: T, commandName: String?, args: ReadableArray?)
@Suppress("INAPPLICABLE_JVM_NAME")
@JvmName("kotlinCompat\$receiveCommand")
@JvmSynthetic
public fun receiveCommand(view: T, commandName: String, args: ReadableArray?)
@Suppress("INAPPLICABLE_JVM_NAME")
@Deprecated(message = "commandName is not nullable, please update your method signature")
@JvmName("receiveCommand")
public fun javaCompat_receiveCommand(view: T, commandName: String?, args: ReadableArray?): Unit =
receiveCommand(view, checkNotNull(commandName), args)
}
@@ -11,9 +11,11 @@ import android.content.Context;
import android.content.res.Resources;
import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.core.util.Preconditions;
import com.facebook.common.logging.FLog;
import com.facebook.common.util.UriUtil;
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
@@ -27,10 +29,11 @@ import com.facebook.yoga.YogaConstants;
import java.util.Locale;
/** Shadow node that represents an inline image. Loading is done using Fresco. */
@Nullsafe(Nullsafe.Mode.LOCAL)
class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineImageShadowNode {
private @Nullable Uri mUri;
private ReadableMap mHeaders;
private @Nullable ReadableMap mHeaders;
private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
private final @Nullable Object mCallerContext;
private float mWidth = YogaConstants.UNDEFINED;
@@ -46,8 +49,10 @@ class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineImageShad
@ReactProp(name = "src")
public void setSource(@Nullable ReadableArray sources) {
final String source =
(sources == null || sources.size() == 0) ? null : sources.getMap(0).getString("uri");
final @Nullable String source =
(sources == null || sources.size() == 0 || sources.getType(0) != ReadableType.Map)
? null
: Preconditions.checkNotNull(sources.getMap(0)).getString("uri");
Uri uri = null;
if (source != null) {
try {
@@ -70,7 +75,7 @@ class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineImageShad
}
@ReactProp(name = "headers")
public void setHeaders(ReadableMap headers) {
public void setHeaders(@Nullable ReadableMap headers) {
mHeaders = headers;
}
@@ -109,7 +114,7 @@ class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineImageShad
return mUri;
}
public ReadableMap getHeaders() {
public @Nullable ReadableMap getHeaders() {
return mHeaders;
}
@@ -15,14 +15,15 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.core.util.Preconditions;
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.DraweeHolder;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.modules.fresco.ReactNetworkImageRequest;
import com.facebook.react.uimanager.PixelUtil;
@@ -40,6 +41,7 @@ import com.facebook.react.views.text.internal.span.TextInlineImageSpan;
* <p>Note: It borrows code from DynamicDrawableSpan and if that code updates how it computes size
* or draws, we need to update this as well.
*/
@Nullsafe(Nullsafe.Mode.LOCAL)
class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
private @Nullable Drawable mDrawable;
@@ -51,8 +53,8 @@ class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
private int mTintColor;
private Uri mUri;
private int mWidth;
private ReadableMap mHeaders;
private String mResizeMode;
private @Nullable ReadableMap mHeaders;
private @Nullable String mResizeMode;
private @Nullable TextView mTextView;
@@ -62,10 +64,10 @@ class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
int width,
int tintColor,
@Nullable Uri uri,
ReadableMap headers,
@Nullable ReadableMap headers,
AbstractDraweeControllerBuilder draweeControllerBuilder,
@Nullable Object callerContext,
String resizeMode) {
@Nullable String resizeMode) {
mDraweeHolder = new DraweeHolder(GenericDraweeHierarchyBuilder.newInstance(resources).build());
mDraweeControllerBuilder = draweeControllerBuilder;
mCallerContext = callerContext;
@@ -116,7 +118,8 @@ class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
return mWidth;
}
public void setTextView(TextView textView) {
@Override
public void setTextView(@Nullable TextView textView) {
mTextView = textView;
}
@@ -135,18 +138,20 @@ class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
ImageRequestBuilder imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(mUri);
ImageRequest imageRequest =
ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, mHeaders);
mDraweeHolder.getHierarchy().setActualImageScaleType(getResizeMode(mResizeMode));
DraweeController draweeController =
mDraweeControllerBuilder
.reset()
.setOldController(mDraweeHolder.getController())
.setCallerContext(mCallerContext)
.setImageRequest(imageRequest)
.build();
mDraweeHolder
.getHierarchy()
.setActualImageScaleType(ImageResizeMode.toScaleType(mResizeMode));
mDraweeControllerBuilder.reset();
mDraweeControllerBuilder.setOldController(mDraweeHolder.getController());
if (mCallerContext != null) {
mDraweeControllerBuilder.setCallerContext(mCallerContext);
}
mDraweeControllerBuilder.setImageRequest(imageRequest);
DraweeController draweeController = mDraweeControllerBuilder.build();
mDraweeHolder.setController(draweeController);
mDraweeControllerBuilder.reset();
mDrawable = mDraweeHolder.getTopLevelDrawable();
mDrawable = Preconditions.checkNotNull(mDraweeHolder.getTopLevelDrawable());
mDrawable.setBounds(0, 0, mWidth, mHeight);
if (mTintColor != 0) {
mDrawable.setColorFilter(mTintColor, PorterDuff.Mode.SRC_IN);
@@ -168,10 +173,6 @@ class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
canvas.restore();
}
private ScalingUtils.ScaleType getResizeMode(String resizeMode) {
return ImageResizeMode.toScaleType(resizeMode);
}
@Override
public int getWidth() {
return mWidth;
@@ -1,24 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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.internal;
import com.facebook.react.uimanager.LayoutShadowNode;
import com.facebook.react.views.text.internal.span.TextInlineImageSpan;
import com.facebook.yoga.YogaNode;
/** Base class for {@link YogaNode}s that represent inline images. */
public abstract class ReactTextInlineImageShadowNode extends LayoutShadowNode {
/**
* Build a {@link TextInlineImageSpan} from this node. This will be added to the TextView in place
* of this node.
*/
public abstract TextInlineImageSpan buildInlineImageSpan();
public ReactTextInlineImageShadowNode() {}
}
@@ -0,0 +1,21 @@
/*
* Copyright (c) Meta Platforms, Inc. and 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.internal
import com.facebook.react.uimanager.LayoutShadowNode
import com.facebook.react.views.text.internal.span.TextInlineImageSpan
import com.facebook.yoga.YogaNode
/** Base class for [YogaNode]s that represent inline images. */
internal abstract class ReactTextInlineImageShadowNode : LayoutShadowNode() {
/**
* Build a [TextInlineImageSpan] from this node. This will be added to the TextView in place of
* this node.
*/
public abstract fun buildInlineImageSpan(): TextInlineImageSpan
}
@@ -50,6 +50,7 @@ import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactSoftExceptionLogger;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.build.ReactBuildConfig;
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags;
import com.facebook.react.uimanager.BackgroundStyleApplicator;
import com.facebook.react.uimanager.LengthPercentage;
import com.facebook.react.uimanager.LengthPercentageType;
@@ -145,7 +146,9 @@ public class ReactEditText extends AppCompatEditText {
public ReactEditText(Context context) {
super(context);
setFocusableInTouchMode(false);
if (!ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior()) {
setFocusableInTouchMode(false);
}
mInputMethodManager =
(InputMethodManager)
@@ -188,7 +191,9 @@ public class ReactEditText extends AppCompatEditText {
// selection on accessibility click to undo that.
setSelection(length);
}
return requestFocusInternal();
return ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior()
? requestFocusProgramatically()
: requestFocusInternal();
}
return super.performAccessibilityAction(host, action, args);
}
@@ -338,7 +343,10 @@ public class ReactEditText extends AppCompatEditText {
@Override
public void clearFocus() {
setFocusableInTouchMode(false);
boolean useStockFocusBehavior = ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior();
if (!useStockFocusBehavior) {
setFocusableInTouchMode(false);
}
super.clearFocus();
hideSoftKeyboard();
}
@@ -349,7 +357,9 @@ public class ReactEditText extends AppCompatEditText {
// is a controlled component, which means its focus is controlled by JS, with two exceptions:
// autofocus when it's attached to the window, and responding to accessibility events. In both
// of these cases, we call requestFocusInternal() directly.
return isFocused();
return ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior()
? super.requestFocus(direction, previouslyFocusedRect)
: isFocused();
}
private boolean requestFocusInternal() {
@@ -360,6 +370,20 @@ public class ReactEditText extends AppCompatEditText {
if (getShowSoftInputOnFocus()) {
showSoftKeyboard();
}
return focused;
}
// For cases like autoFocus, or ref.focus() where we request focus programatically and not through
// interacting with the EditText directly (like clicking on it). We cannot use stock
// requestFocus() because it will not pop up the soft keyboard, only clicking the input will do
// that. This method will eventually replace requestFocusInternal()
private boolean requestFocusProgramatically() {
boolean focused = super.requestFocus(View.FOCUS_DOWN, null);
if (isInTouchMode() && getShowSoftInputOnFocus()) {
showSoftKeyboard();
}
return focused;
}
@@ -632,7 +656,11 @@ public class ReactEditText extends AppCompatEditText {
// VisibleForTesting from {@link TextInputEventsTestCase}.
public void requestFocusFromJS() {
requestFocusInternal();
if (ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior()) {
requestFocusProgramatically();
} else {
requestFocusInternal();
}
}
/* package */ void clearFocusFromJS() {
@@ -1079,7 +1107,11 @@ public class ReactEditText extends AppCompatEditText {
}
if (mAutoFocus && !mDidAttachToWindow) {
requestFocusInternal();
if (ReactNativeFeatureFlags.useEditTextStockAndroidFocusBehavior()) {
requestFocusProgramatically();
} else {
requestFocusInternal();
}
}
mDidAttachToWindow = true;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7c3853858da56eb5f471abccf9dcbf55>>
* @generated SignedSource<<63ebe186ccd5ee30fc654aa8d90f27f9>>
*/
/**
@@ -255,6 +255,12 @@ class ReactNativeFeatureFlagsProviderHolder
return method(javaProvider_);
}
bool useEditTextStockAndroidFocusBehavior() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useEditTextStockAndroidFocusBehavior");
return method(javaProvider_);
}
bool useFabricInterop() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useFabricInterop");
@@ -493,6 +499,11 @@ bool JReactNativeFeatureFlagsCxxInterop::useAlwaysAvailableJSErrorHandling(
return ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling();
}
bool JReactNativeFeatureFlagsCxxInterop::useEditTextStockAndroidFocusBehavior(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::useEditTextStockAndroidFocusBehavior();
}
bool JReactNativeFeatureFlagsCxxInterop::useFabricInterop(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::useFabricInterop();
@@ -677,6 +688,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"useAlwaysAvailableJSErrorHandling",
JReactNativeFeatureFlagsCxxInterop::useAlwaysAvailableJSErrorHandling),
makeNativeMethod(
"useEditTextStockAndroidFocusBehavior",
JReactNativeFeatureFlagsCxxInterop::useEditTextStockAndroidFocusBehavior),
makeNativeMethod(
"useFabricInterop",
JReactNativeFeatureFlagsCxxInterop::useFabricInterop),
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<77b4ed5aa33290ba9da1719544e974cb>>
* @generated SignedSource<<fdb23cf034dea348c661f59718f07291>>
*/
/**
@@ -138,6 +138,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool useAlwaysAvailableJSErrorHandling(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool useEditTextStockAndroidFocusBehavior(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
static bool useFabricInterop(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
@@ -25,6 +25,7 @@ import com.facebook.react.bridge.BridgeReactContext
import com.facebook.react.bridge.CatalystInstance
import com.facebook.react.bridge.JavaOnlyMap
import com.facebook.react.bridge.ReactTestHelper.createMockCatalystInstance
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsForTests
import com.facebook.react.uimanager.DisplayMetricsHolder
import com.facebook.react.uimanager.ReactStylesDiffMap
import com.facebook.react.uimanager.ThemedReactContext
@@ -58,6 +59,7 @@ class ReactTextInputPropertyTest {
@Before
fun setup() {
ReactNativeFeatureFlagsForTests.setUp()
context = BridgeReactContext(RuntimeEnvironment.getApplication())
catalystInstanceMock = createMockCatalystInstance()
context.initializeWithInstance(catalystInstanceMock)
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<7d301656072183649246db8fa738fc4d>>
* @generated SignedSource<<58c69846193598ce0c3666c37b8a185f>>
*/
/**
@@ -170,6 +170,10 @@ bool ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling() {
return getAccessor().useAlwaysAvailableJSErrorHandling();
}
bool ReactNativeFeatureFlags::useEditTextStockAndroidFocusBehavior() {
return getAccessor().useEditTextStockAndroidFocusBehavior();
}
bool ReactNativeFeatureFlags::useFabricInterop() {
return getAccessor().useFabricInterop();
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<eee9560521020eb75fa84c6e0cef31a3>>
* @generated SignedSource<<1d578508c3cd69bbf9616a811508a03e>>
*/
/**
@@ -219,6 +219,11 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static bool useAlwaysAvailableJSErrorHandling();
/**
* If true, focusing in ReactEditText will mainly use stock Android requestFocus() behavior. If false it will use legacy custom focus behavior.
*/
RN_EXPORT static bool useEditTextStockAndroidFocusBehavior();
/**
* Should this application enable the Fabric Interop Layer for Android? If yes, the application will behave so that it can accept non-Fabric components and render them on Fabric. This toggle is controlling extra logic such as custom event dispatching that are needed for the Fabric Interop Layer to work correctly.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<a360603ae99888aa172cc1b85d3893e4>>
* @generated SignedSource<<42e2ae5cbfb15c17a7d60a771128858a>>
*/
/**
@@ -677,6 +677,24 @@ bool ReactNativeFeatureFlagsAccessor::useAlwaysAvailableJSErrorHandling() {
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::useEditTextStockAndroidFocusBehavior() {
auto flagValue = useEditTextStockAndroidFocusBehavior_.load();
if (!flagValue.has_value()) {
// This block is not exclusive but it is not necessary.
// If multiple threads try to initialize the feature flag, we would only
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(36, "useEditTextStockAndroidFocusBehavior");
flagValue = currentProvider_->useEditTextStockAndroidFocusBehavior();
useEditTextStockAndroidFocusBehavior_ = flagValue;
}
return flagValue.value();
}
bool ReactNativeFeatureFlagsAccessor::useFabricInterop() {
auto flagValue = useFabricInterop_.load();
@@ -686,7 +704,7 @@ bool ReactNativeFeatureFlagsAccessor::useFabricInterop() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(36, "useFabricInterop");
markFlagAsAccessed(37, "useFabricInterop");
flagValue = currentProvider_->useFabricInterop();
useFabricInterop_ = flagValue;
@@ -704,7 +722,7 @@ bool ReactNativeFeatureFlagsAccessor::useImmediateExecutorInAndroidBridgeless()
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(37, "useImmediateExecutorInAndroidBridgeless");
markFlagAsAccessed(38, "useImmediateExecutorInAndroidBridgeless");
flagValue = currentProvider_->useImmediateExecutorInAndroidBridgeless();
useImmediateExecutorInAndroidBridgeless_ = flagValue;
@@ -722,7 +740,7 @@ bool ReactNativeFeatureFlagsAccessor::useNativeViewConfigsInBridgelessMode() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(38, "useNativeViewConfigsInBridgelessMode");
markFlagAsAccessed(39, "useNativeViewConfigsInBridgelessMode");
flagValue = currentProvider_->useNativeViewConfigsInBridgelessMode();
useNativeViewConfigsInBridgelessMode_ = flagValue;
@@ -740,7 +758,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimisedViewPreallocationOnAndroid() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(39, "useOptimisedViewPreallocationOnAndroid");
markFlagAsAccessed(40, "useOptimisedViewPreallocationOnAndroid");
flagValue = currentProvider_->useOptimisedViewPreallocationOnAndroid();
useOptimisedViewPreallocationOnAndroid_ = flagValue;
@@ -758,7 +776,7 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(40, "useOptimizedEventBatchingOnAndroid");
markFlagAsAccessed(41, "useOptimizedEventBatchingOnAndroid");
flagValue = currentProvider_->useOptimizedEventBatchingOnAndroid();
useOptimizedEventBatchingOnAndroid_ = flagValue;
@@ -776,7 +794,7 @@ bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(41, "useRawPropsJsiValue");
markFlagAsAccessed(42, "useRawPropsJsiValue");
flagValue = currentProvider_->useRawPropsJsiValue();
useRawPropsJsiValue_ = flagValue;
@@ -794,7 +812,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(42, "useRuntimeShadowNodeReferenceUpdate");
markFlagAsAccessed(43, "useRuntimeShadowNodeReferenceUpdate");
flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate();
useRuntimeShadowNodeReferenceUpdate_ = flagValue;
@@ -812,7 +830,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(43, "useTurboModuleInterop");
markFlagAsAccessed(44, "useTurboModuleInterop");
flagValue = currentProvider_->useTurboModuleInterop();
useTurboModuleInterop_ = flagValue;
@@ -830,7 +848,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.
markFlagAsAccessed(44, "useTurboModules");
markFlagAsAccessed(45, "useTurboModules");
flagValue = currentProvider_->useTurboModules();
useTurboModules_ = flagValue;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<8eb2b5d6dd367826ff7bc899afbdea60>>
* @generated SignedSource<<8423497c73f5315fdc3e8b4fa0bdc8c2>>
*/
/**
@@ -68,6 +68,7 @@ class ReactNativeFeatureFlagsAccessor {
bool loadVectorDrawablesOnImages();
bool traceTurboModulePromiseRejectionsOnAndroid();
bool useAlwaysAvailableJSErrorHandling();
bool useEditTextStockAndroidFocusBehavior();
bool useFabricInterop();
bool useImmediateExecutorInAndroidBridgeless();
bool useNativeViewConfigsInBridgelessMode();
@@ -88,7 +89,7 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;
std::array<std::atomic<const char*>, 45> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 46> accessedFeatureFlags_;
std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> completeReactInstanceCreationOnBgThreadOnAndroid_;
@@ -126,6 +127,7 @@ class ReactNativeFeatureFlagsAccessor {
std::atomic<std::optional<bool>> loadVectorDrawablesOnImages_;
std::atomic<std::optional<bool>> traceTurboModulePromiseRejectionsOnAndroid_;
std::atomic<std::optional<bool>> useAlwaysAvailableJSErrorHandling_;
std::atomic<std::optional<bool>> useEditTextStockAndroidFocusBehavior_;
std::atomic<std::optional<bool>> useFabricInterop_;
std::atomic<std::optional<bool>> useImmediateExecutorInAndroidBridgeless_;
std::atomic<std::optional<bool>> useNativeViewConfigsInBridgelessMode_;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<e38a0e9474ac349a4b8153862470c856>>
* @generated SignedSource<<c7b0a50bce07d6e2556b5780e0f22595>>
*/
/**
@@ -171,6 +171,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}
bool useEditTextStockAndroidFocusBehavior() override {
return true;
}
bool useFabricInterop() override {
return false;
}
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<e5e8a3b63e42ed4b5cab143d46d20260>>
* @generated SignedSource<<179524938d2e6148ef87835844c4135e>>
*/
/**
@@ -369,6 +369,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
return ReactNativeFeatureFlagsDefaults::useAlwaysAvailableJSErrorHandling();
}
bool useEditTextStockAndroidFocusBehavior() override {
auto value = values_["useEditTextStockAndroidFocusBehavior"];
if (!value.isNull()) {
return value.getBool();
}
return ReactNativeFeatureFlagsDefaults::useEditTextStockAndroidFocusBehavior();
}
bool useFabricInterop() override {
auto value = values_["useFabricInterop"];
if (!value.isNull()) {
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<36bfe0037e4dba3b6eb6e95075914fce>>
* @generated SignedSource<<a36169cf43b41914533e7b5c17ec053c>>
*/
/**
@@ -61,6 +61,7 @@ class ReactNativeFeatureFlagsProvider {
virtual bool loadVectorDrawablesOnImages() = 0;
virtual bool traceTurboModulePromiseRejectionsOnAndroid() = 0;
virtual bool useAlwaysAvailableJSErrorHandling() = 0;
virtual bool useEditTextStockAndroidFocusBehavior() = 0;
virtual bool useFabricInterop() = 0;
virtual bool useImmediateExecutorInAndroidBridgeless() = 0;
virtual bool useNativeViewConfigsInBridgelessMode() = 0;
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<f5a1ea8dd3d64e435b6954c39dacb76a>>
* @generated SignedSource<<81f3e20643ddb2612eaa9276bb75e70e>>
*/
/**
@@ -224,6 +224,11 @@ bool NativeReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling(
return ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling();
}
bool NativeReactNativeFeatureFlags::useEditTextStockAndroidFocusBehavior(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::useEditTextStockAndroidFocusBehavior();
}
bool NativeReactNativeFeatureFlags::useFabricInterop(
jsi::Runtime& /*runtime*/) {
return ReactNativeFeatureFlags::useFabricInterop();
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<fc3960bfa407d1fc123ee4c71eac644a>>
* @generated SignedSource<<0852372c6b328f128319949a01aa8787>>
*/
/**
@@ -109,6 +109,8 @@ class NativeReactNativeFeatureFlags
bool useAlwaysAvailableJSErrorHandling(jsi::Runtime& runtime);
bool useEditTextStockAndroidFocusBehavior(jsi::Runtime& runtime);
bool useFabricInterop(jsi::Runtime& runtime);
bool useImmediateExecutorInAndroidBridgeless(jsi::Runtime& runtime);
@@ -45,7 +45,7 @@ using NativeIntersectionObserverEntry =
// rootRect
RectAsTuple,
// intersectionRect
std::optional<RectAsTuple>,
RectAsTuple,
// isIntersectingAboveThresholds
bool,
// time
@@ -5,21 +5,6 @@
require_relative './helpers.rb'
# It builds the codegen CLI if it is not present
#
# Parameters:
# - react_native_path: the path to the react native installation
# - relative_installation_root: the path to the relative installation root of the pods
# - dir_manager: a class that implements the `Dir` interface. Defaults to `Dir`, the Dependency can be injected for testing purposes.
# @throws an error if it could not find the codegen folder.
def build_codegen!(react_native_path, relative_installation_root, dir_manager: Dir)
codegen_repo_path = "#{basePath(react_native_path, relative_installation_root)}/../react-native-codegen"
return unless dir_manager.exist?(codegen_repo_path) && !dir_manager.exist?("#{codegen_repo_path}/lib")
Pod::UI.puts "[Codegen] building #{codegen_repo_path}"
system("#{codegen_repo_path}/scripts/oss/build.sh")
end
# keeping the run_codegen! method for testing purposes
def run_codegen!(
app_path,
@@ -390,6 +390,15 @@ const definitions: FeatureFlagDefinitions = {
purpose: 'release',
},
},
useEditTextStockAndroidFocusBehavior: {
defaultValue: true,
metadata: {
description:
'If true, focusing in ReactEditText will mainly use stock Android requestFocus() behavior. If false it will use legacy custom focus behavior.',
expectedReleaseValue: true,
purpose: 'release',
},
},
useFabricInterop: {
defaultValue: false,
metadata: {
@@ -618,12 +627,13 @@ const definitions: FeatureFlagDefinitions = {
},
},
useInsertionEffectsForAnimations: {
defaultValue: true,
defaultValue: false,
metadata: {
dateAdded: '2024-09-12',
description:
'Changes construction of the animation graph to `useInsertionEffect` instead of `useLayoutEffect`.',
expectedReleaseValue: true,
purpose: 'release',
purpose: 'experimentation',
},
},
useRefsForTextInputState: {
@@ -96,8 +96,6 @@ def use_react_native! (
ReactNativePodsUtils.warn_if_not_on_arm64()
build_codegen!(prefix, relative_path_from_current)
# The Pods which should be included in all projects
pod 'FBLazyVector', :path => "#{prefix}/Libraries/FBLazyVector"
pod 'RCTRequired', :path => "#{prefix}/Libraries/Required"
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<3037cf1c938dae492b656333cec9633c>>
* @generated SignedSource<<a88e25ee1e5bb8a324ff861c0703b9aa>>
* @flow strict
*/
@@ -87,6 +87,7 @@ export type ReactNativeFeatureFlags = $ReadOnly<{
loadVectorDrawablesOnImages: Getter<boolean>,
traceTurboModulePromiseRejectionsOnAndroid: Getter<boolean>,
useAlwaysAvailableJSErrorHandling: Getter<boolean>,
useEditTextStockAndroidFocusBehavior: Getter<boolean>,
useFabricInterop: Getter<boolean>,
useImmediateExecutorInAndroidBridgeless: Getter<boolean>,
useNativeViewConfigsInBridgelessMode: Getter<boolean>,
@@ -176,7 +177,7 @@ export const shouldUseSetNativePropsInFabric: Getter<boolean> = createJavaScript
/**
* Changes construction of the animation graph to `useInsertionEffect` instead of `useLayoutEffect`.
*/
export const useInsertionEffectsForAnimations: Getter<boolean> = createJavaScriptFlagGetter('useInsertionEffectsForAnimations', true);
export const useInsertionEffectsForAnimations: Getter<boolean> = createJavaScriptFlagGetter('useInsertionEffectsForAnimations', false);
/**
* Enable a variant of TextInput that moves some state to refs to avoid unnecessary re-renders
@@ -331,6 +332,10 @@ export const traceTurboModulePromiseRejectionsOnAndroid: Getter<boolean> = creat
* In Bridgeless mode, use the always available javascript error reporting pipeline.
*/
export const useAlwaysAvailableJSErrorHandling: Getter<boolean> = createNativeFlagGetter('useAlwaysAvailableJSErrorHandling', false);
/**
* If true, focusing in ReactEditText will mainly use stock Android requestFocus() behavior. If false it will use legacy custom focus behavior.
*/
export const useEditTextStockAndroidFocusBehavior: Getter<boolean> = createNativeFlagGetter('useEditTextStockAndroidFocusBehavior', true);
/**
* Should this application enable the Fabric Interop Layer for Android? If yes, the application will behave so that it can accept non-Fabric components and render them on Fabric. This toggle is controlling extra logic such as custom event dispatching that are needed for the Fabric Interop Layer to work correctly.
*/
@@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<37e95652ef5d824bb05e78ebdb051e43>>
* @generated SignedSource<<9fd249e6c81d4aaa9793c003d986524c>>
* @flow strict
*/
@@ -60,6 +60,7 @@ export interface Spec extends TurboModule {
+loadVectorDrawablesOnImages?: () => boolean;
+traceTurboModulePromiseRejectionsOnAndroid?: () => boolean;
+useAlwaysAvailableJSErrorHandling?: () => boolean;
+useEditTextStockAndroidFocusBehavior?: () => boolean;
+useFabricInterop?: () => boolean;
+useImmediateExecutorInAndroidBridgeless?: () => boolean;
+useNativeViewConfigsInBridgelessMode?: () => boolean;
@@ -14,13 +14,13 @@ import type MutationObserverType from '../MutationObserver';
import View from '../../../../../Libraries/Components/View/View';
import setUpMutationObserver from '../../../setup/setUpMutationObserver';
import ensureInstance from '../../../utilities/ensureInstance';
import ReactNativeElement from '../../dom/nodes/ReactNativeElement';
import * as Fantom from '@react-native/fantom';
import nullthrows from 'nullthrows';
import * as React from 'react';
import '../../../../../Libraries/Core/InitializeCore.js';
import ensureInstance from '../../../utilities/ensureInstance';
declare const MutationObserver: Class<MutationObserverType>;
@@ -0,0 +1,71 @@
/**
* Copyright (c) Meta Platforms, Inc. and 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
* @oncall react_native
* @fantom_flags enableLongTaskAPI:true
*/
import setUpPerformanceObserver from '../../../setup/setUpPerformanceObserver';
import ensureInstance from '../../../utilities/ensureInstance';
import {PerformanceMark} from '../UserTiming';
import {runWorkLoop} from '@react-native/fantom';
import '../../../../../Libraries/Core/InitializeCore.js';
setUpPerformanceObserver();
describe('User Timing API', () => {
describe('performance.mark()', () => {
it('reports marks to observers', () => {
const callback = jest.fn();
const observer = new PerformanceObserver(callback);
observer.observe({type: 'mark'});
expect(callback).not.toHaveBeenCalled();
const mark1Detail = Symbol('mark1Detail');
performance.mark('mark1', {
startTime: 100,
detail: mark1Detail,
});
const mark2Detail = Symbol('mark2Detail');
performance.mark('mark2', {
startTime: 200,
detail: mark2Detail,
});
expect(callback).not.toHaveBeenCalled();
runWorkLoop();
expect(callback).toHaveBeenCalledTimes(1);
const entries = callback.mock.lastCall[0].getEntries();
expect(entries.length).toBe(2);
const mark1 = ensureInstance(entries[0], PerformanceMark);
const mark2 = ensureInstance(entries[1], PerformanceMark);
expect(mark1.entryType).toBe('mark');
expect(mark1.name).toBe('mark1');
expect(mark1.startTime).toBe(100);
expect(mark1.duration).toBe(0);
// This doesn't work through PerformanceObserver yet
// expect(mark1.detail).toBe(mark1Detail);
expect(mark2.entryType).toBe('mark');
expect(mark2.name).toBe('mark2');
expect(mark2.startTime).toBe(200);
expect(mark2.duration).toBe(0);
// This doesn't work through PerformanceObserver yet
// expect(mark2.detail).toBe(mark2Detail);
});
});
});
@@ -10,13 +10,14 @@
import invariant from 'invariant';
import * as React from 'react';
import {useEffect} from 'react';
import {DeviceEventEmitter, NativeModules, View} from 'react-native';
import NativeAccessibilityManager from 'react-native/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager';
const {TestModule} = NativeModules;
class AccessibilityManagerTest extends React.Component<{...}> {
componentDidMount(): void {
function AccessibilityManagerTest(): React.Node {
useEffect(() => {
invariant(
NativeAccessibilityManager,
"NativeAccessibilityManager doesn't exist",
@@ -36,16 +37,20 @@ class AccessibilityManagerTest extends React.Component<{...}> {
accessibilityExtraExtraLarge: 11.0,
accessibilityExtraExtraExtraLarge: 12.0,
});
DeviceEventEmitter.addListener('didUpdateDimensions', update => {
TestModule.markTestPassed(update.window.fontScale === 4.0);
});
}
render(): React.Node {
return <View />;
}
const subscription = DeviceEventEmitter.addListener(
'didUpdateDimensions',
update => {
TestModule.markTestPassed(update.window.fontScale === 4.0);
},
);
return () => {
subscription.remove();
};
}, []);
return <View />;
}
AccessibilityManagerTest.displayName = 'AccessibilityManagerTest';
module.exports = AccessibilityManagerTest;
export default AccessibilityManagerTest;
@@ -10,65 +10,49 @@
'use strict';
const React = require('react');
const ReactNative = require('react-native');
import * as React from 'react';
import {useEffect, useState} from 'react';
import {NativeModules, StyleSheet, Text, View} from 'react-native';
const {Text, View, StyleSheet} = ReactNative;
const {TestModule} = ReactNative.NativeModules;
const {TestModule} = NativeModules;
type Props = $ReadOnly<{|
type Props = $ReadOnly<{
shouldThrow?: boolean,
waitOneFrame?: boolean,
|}>;
}>;
type State = {|
done: boolean,
|};
function IntegrationTestHarnessTest(props: Props): React.Node {
const [done, setDone] = useState(false);
class IntegrationTestHarnessTest extends React.Component<Props, State> {
state: State = {
done: false,
};
componentDidMount() {
if (this.props.waitOneFrame) {
requestAnimationFrame(this.runTest);
} else {
this.runTest();
}
}
runTest: () => void = () => {
if (this.props.shouldThrow) {
throw new Error('Throwing error because shouldThrow');
}
if (!TestModule) {
throw new Error('RCTTestModule is not registered.');
} else if (!TestModule.markTestCompleted) {
throw new Error('RCTTestModule.markTestCompleted not defined.');
}
this.setState({done: true}, () => {
useEffect(() => {
const runTest = () => {
if (props.shouldThrow) {
throw new Error('Throwing error because shouldThrow');
}
if (!TestModule) {
throw new Error('RCTTestModule is not registered.');
} else if (!TestModule.markTestCompleted) {
throw new Error('RCTTestModule.markTestCompleted not defined.');
}
setDone(true);
TestModule.markTestCompleted();
});
};
};
render(): React.Node {
return (
<View style={styles.container}>
<Text>
{
/* $FlowFixMe[incompatible-type] (>=0.54.0 site=react_native_fb,react_
* native_oss) This comment suppresses an error found when Flow v0.54
* was deployed. To see the error delete this comment and run Flow.
*/
// $FlowFixMe[unsafe-addition]
this.constructor.displayName + ': '
}
{this.state.done ? 'Done' : 'Testing...'}
</Text>
</View>
);
}
if (props.waitOneFrame) {
requestAnimationFrame(runTest);
} else {
runTest();
}
}, [props.shouldThrow, props.waitOneFrame]);
return (
<View style={styles.container}>
<Text>
{IntegrationTestHarnessTest.name + ': '}
{done ? 'Done' : 'Testing...'}
</Text>
</View>
);
}
const styles = StyleSheet.create({
@@ -78,6 +62,4 @@ const styles = StyleSheet.create({
},
});
IntegrationTestHarnessTest.displayName = 'IntegrationTestHarnessTest';
module.exports = IntegrationTestHarnessTest;
export default IntegrationTestHarnessTest;
@@ -32,11 +32,14 @@ const TESTS = [
require('./GlobalEvalWithSourceUrlTest'),
];
TESTS.forEach(
/* $FlowFixMe[incompatible-call] (>=0.54.0 site=react_native_fb,react_native_
* oss) This comment suppresses an error found when Flow v0.54 was deployed.
* To see the error delete this comment and run Flow. */
test => AppRegistry.registerComponent(test.displayName, () => test),
TESTS.forEach(test =>
AppRegistry.registerComponent(
test.displayName || test.name || '',
/* $FlowFixMe[incompatible-call] (>=0.54.0 site=react_native_fb,react_native_
* oss) This comment suppresses an error found when Flow v0.54 was deployed.
* To see the error delete this comment and run Flow. */
() => test,
),
);
// Modules required for integration tests
@@ -78,7 +81,9 @@ class IntegrationTestsApp extends React.Component<{...}, $FlowFixMeState> {
* deployed. To see the error, delete this comment and run Flow.
*/
style={styles.row}>
<Text style={styles.testName}>{test.displayName}</Text>
<Text style={styles.testName}>
{test.displayName || test.name}
</Text>
</TouchableOpacity>,
<View style={styles.separator} />,
])}
@@ -169,84 +169,107 @@ export default function MyNativeView(props: {}): React.Node {
<Text style={{color: 'green', textAlign: 'center'}}>
Opacity: {opacity.toFixed(1)}
</Text>
<Button
title="Change Background"
onPress={() => {
let nextBGColor =
currentBGColor + 1 >= colors.length ? 0 : currentBGColor + 1;
let newColor = colors[nextBGColor];
RNTMyNativeViewCommands.callNativeMethodToChangeBackgroundColor(
// $FlowFixMe[incompatible-call]
ref.current,
newColor,
);
callNativeMethodToChangeBackgroundColor(legacyRef.current, newColor);
setCurrentBGColor(nextBGColor);
}}
/>
<Button
title="Add Overlays"
onPress={() => {
let randomColorId = Math.floor(Math.random() * 5);
let overlayColors = [
colors[randomColorId],
colors[(randomColorId + 1) % 5],
];
RNTMyNativeViewCommands.callNativeMethodToAddOverlays(
// $FlowFixMe[incompatible-call]
ref.current,
overlayColors,
);
callNativeMethodToAddOverlays(legacyRef.current, overlayColors);
}}
/>
<Button
title="Remove Overlays"
onPress={() => {
RNTMyNativeViewCommands.callNativeMethodToRemoveOverlays(
// $FlowFixMe[incompatible-call]
ref.current,
);
callNativeMethodToRemoveOverlays(legacyRef.current);
}}
/>
<Button
title="Set Opacity"
onPress={() => {
setOpacity(computeNextOpacity(opacity));
setArrayValues([
Math.floor(Math.random() * 100),
Math.floor(Math.random() * 100),
Math.floor(Math.random() * 100),
]);
}}
/>
<Button
title="Console.log Measure"
onPress={() => {
ref.current?.measure((x, y, width, height) => {
console.log(x, y, width, height);
});
legacyRef.current?.measure((x, y, width, height) => {
setLegacyMeasure({x, y, width, height});
});
legacyRef.current?.measureInWindow((x, y, width, height) => {
setLegacyMeasureInWindow({x, y, width, height});
});
if (containerRef.current) {
legacyRef.current?.measureLayout(
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-between',
}}>
<Button
title="Change Background"
onPress={() => {
let nextBGColor =
currentBGColor + 1 >= colors.length ? 0 : currentBGColor + 1;
let newColor = colors[nextBGColor];
RNTMyNativeViewCommands.callNativeMethodToChangeBackgroundColor(
// $FlowFixMe[incompatible-call]
containerRef.current,
(x, y, width, height) => {
setLegacyMeasureLayout({x, y, width, height});
},
ref.current,
newColor,
);
}
}}
/>
callNativeMethodToChangeBackgroundColor(
legacyRef.current,
newColor,
);
setCurrentBGColor(nextBGColor);
}}
/>
<Button
title="Set Opacity"
onPress={() => {
setOpacity(computeNextOpacity(opacity));
setArrayValues([
Math.floor(Math.random() * 100),
Math.floor(Math.random() * 100),
Math.floor(Math.random() * 100),
]);
}}
/>
<Button
title="Add Overlays"
onPress={() => {
let randomColorId = Math.floor(Math.random() * 5);
let overlayColors = [
colors[randomColorId],
colors[(randomColorId + 1) % 5],
];
RNTMyNativeViewCommands.callNativeMethodToAddOverlays(
// $FlowFixMe[incompatible-call]
ref.current,
overlayColors,
);
callNativeMethodToAddOverlays(legacyRef.current, overlayColors);
}}
/>
<Button
title="Remove Overlays"
onPress={() => {
RNTMyNativeViewCommands.callNativeMethodToRemoveOverlays(
// $FlowFixMe[incompatible-call]
ref.current,
);
callNativeMethodToRemoveOverlays(legacyRef.current);
}}
/>
<Button
title="Console.log Measure"
onPress={() => {
ref.current?.measure((x, y, width, height) => {
console.log(x, y, width, height);
});
legacyRef.current?.measure((x, y, width, height) => {
setLegacyMeasure({x, y, width, height});
});
legacyRef.current?.measureInWindow((x, y, width, height) => {
setLegacyMeasureInWindow({x, y, width, height});
});
if (containerRef.current) {
legacyRef.current?.measureLayout(
// $FlowFixMe[incompatible-call]
containerRef.current,
(x, y, width, height) => {
setLegacyMeasureLayout({x, y, width, height});
},
);
}
}}
/>
<Button
title="Test setNativeProps"
onPress={() => {
const newCRIndex =
cornerRadiusIndex + 1 >= cornerRadiuses.length
? 0
: cornerRadiusIndex + 1;
setCornerRadiusIndex(newCRIndex);
legacyRef.current?.setNativeProps({
cornerRadius: cornerRadiuses[newCRIndex],
});
}}
/>
</View>
<Text style={{color: 'green', textAlign: 'center'}}>
&gt; Interop Layer Measurements &lt;
</Text>
@@ -271,19 +294,6 @@ export default function MyNativeView(props: {}): React.Node {
<Text style={{color: 'green', textAlign: 'center'}}>
Legacy Style Event Fired {legacyStyleEventCount} times
</Text>
<Button
title="Test setNativeProps"
onPress={() => {
const newCRIndex =
cornerRadiusIndex + 1 >= cornerRadiuses.length
? 0
: cornerRadiusIndex + 1;
setCornerRadiusIndex(newCRIndex);
legacyRef.current?.setNativeProps({
cornerRadius: cornerRadiuses[newCRIndex],
});
}}
/>
</View>
);
}
@@ -12,8 +12,8 @@
import type {PressEvent} from 'react-native/Libraries/Types/CoreEventTypes';
const React = require('react');
const {Pressable, StyleSheet, Text} = require('react-native');
import React from 'react';
import {Pressable, StyleSheet, Text} from 'react-native';
type Props = $ReadOnly<{|
testID?: string,
@@ -22,17 +22,15 @@ type Props = $ReadOnly<{|
onPress?: ?(event: PressEvent) => mixed,
|}>;
class RNTesterButton extends React.Component<Props> {
render(): React.Node {
return (
<Pressable
testID={this.props.testID}
onPress={this.props.onPress}
style={({pressed}) => [styles.button, pressed && styles.pressed]}>
<Text testID={this.props.textTestID}>{this.props.children}</Text>
</Pressable>
);
}
function RNTesterButton(props: Props): React.Node {
return (
<Pressable
testID={props.testID}
onPress={props.onPress}
style={({pressed}) => [styles.button, pressed && styles.pressed]}>
<Text testID={props.textTestID}>{props.children}</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
@@ -51,4 +49,4 @@ const styles = StyleSheet.create({
},
});
module.exports = RNTesterButton;
export default RNTesterButton;
@@ -9,9 +9,9 @@
*/
import {RNTesterThemeContext} from './RNTesterTheme';
import RNTesterTitle from './RNTesterTitle';
import {useContext} from 'react';
const RNTesterTitle = require('./RNTesterTitle');
const React = require('react');
const {SafeAreaView, ScrollView, StyleSheet, View} = require('react-native');
@@ -9,33 +9,34 @@
*/
import {RNTesterThemeContext} from './RNTesterTheme';
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
const React = require('react');
const {StyleSheet, Text, View} = require('react-native');
type Props = $ReadOnly<{
title: string,
}>;
class RNTesterTitle extends React.Component<$FlowFixMeProps> {
render(): React.Node {
return (
<RNTesterThemeContext.Consumer>
{theme => {
return (
<View
style={[
styles.container,
{
borderColor: theme.SeparatorColor,
backgroundColor: theme.TertiaryGroupedBackgroundColor,
},
]}>
<Text style={[styles.text, {color: theme.LabelColor}]}>
{this.props.title}
</Text>
</View>
);
}}
</RNTesterThemeContext.Consumer>
);
}
function RNTesterTitle({title}: Props): React.Node {
return (
<RNTesterThemeContext.Consumer>
{theme => {
return (
<View
style={[
styles.container,
{
borderColor: theme.SeparatorColor,
backgroundColor: theme.TertiaryGroupedBackgroundColor,
},
]}>
<Text style={[styles.text, {color: theme.LabelColor}]}>
{title}
</Text>
</View>
);
}}
</RNTesterThemeContext.Consumer>
);
}
const styles = StyleSheet.create({
@@ -53,4 +54,4 @@ const styles = StyleSheet.create({
},
});
module.exports = RNTesterTitle;
export default RNTesterTitle;
@@ -12,6 +12,7 @@
import RNTesterText from '../components/RNTesterText';
import React from 'react';
import {useState} from 'react';
import {Image, TouchableHighlight, View} from 'react-native';
function Basic(): React.Node {
@@ -105,116 +106,97 @@ function ClippedByText(): React.Node {
);
}
type ChangeSizeState = {|
width: number,
|};
class ChangeImageSize extends React.Component<mixed, ChangeSizeState> {
state: ChangeSizeState = {
width: 50,
};
render(): React.Node {
return (
<View>
<TouchableHighlight
onPress={() => {
this.setState({width: this.state.width === 50 ? 100 : 50});
}}>
<RNTesterText style={{fontSize: 15}}>
Change Image Width (width={this.state.width})
</RNTesterText>
</TouchableHighlight>
<RNTesterText>
This is an
<Image
source={{
uri: 'https://picsum.photos/50',
width: this.state.width,
height: 50,
}}
style={{
width: this.state.width,
height: 50,
}}
/>
inline image
function ChangeImageSize(): React.Node {
const [width, setWidth] = useState(50);
return (
<View>
<TouchableHighlight
onPress={() => {
setWidth(width === 50 ? 100 : 50);
}}>
<RNTesterText style={{fontSize: 15}}>
Change Image Width (width={width})
</RNTesterText>
</View>
);
}
</TouchableHighlight>
<RNTesterText>
This is an
<Image
source={{
uri: 'https://picsum.photos/50',
width,
height: 50,
}}
style={{
width,
height: 50,
}}
/>
inline image
</RNTesterText>
</View>
);
}
class ChangeViewSize extends React.Component<mixed, ChangeSizeState> {
state: ChangeSizeState = {
width: 50,
};
function ChangeViewSize(): React.Node {
const [width, setWidth] = useState(50);
return (
<View>
<TouchableHighlight
onPress={() => {
setWidth(width === 50 ? 100 : 50);
}}>
<RNTesterText style={{fontSize: 15}}>
Change View Width (width={width})
</RNTesterText>
</TouchableHighlight>
<RNTesterText>
This is an
<View
style={{
width,
height: 50,
backgroundColor: 'steelblue',
}}
/>
inline view
</RNTesterText>
</View>
);
}
render(): React.Node {
return (
<View>
<TouchableHighlight
onPress={() => {
this.setState({width: this.state.width === 50 ? 100 : 50});
}}>
<RNTesterText style={{fontSize: 15}}>
Change View Width (width={this.state.width})
</RNTesterText>
</TouchableHighlight>
<RNTesterText>
This is an
function ChangeInnerViewSize(): React.Node {
const [width, setWidth] = useState(50);
return (
<View>
<TouchableHighlight
onPress={() => {
setWidth(width === 50 ? 100 : 50);
}}>
{/* When updating `width`, it's important that the only thing that
changes is the width of the pink inline view. When we do this, we
demonstrate a bug in RN Android where the pink view doesn't get
rerendered and remains at its old size. If other things change
(e.g. we display `width` as text somewhere) it could circumvent
the bug and cause the pink view to be rerendered at its new size. */}
<RNTesterText style={{fontSize: 15}}>
Change Pink View Width
</RNTesterText>
</TouchableHighlight>
<RNTesterText>
This is an
<View style={{width: 125, height: 75, backgroundColor: 'steelblue'}}>
<View
style={{
width: this.state.width,
width,
height: 50,
backgroundColor: 'steelblue',
backgroundColor: 'pink',
}}
/>
inline view
</RNTesterText>
</View>
);
}
}
class ChangeInnerViewSize extends React.Component<mixed, ChangeSizeState> {
state: ChangeSizeState = {
width: 50,
};
render(): React.Node {
return (
<View>
<TouchableHighlight
onPress={() => {
this.setState({width: this.state.width === 50 ? 100 : 50});
}}>
{/* When updating `state.width`, it's important that the only thing that
changes is the width of the pink inline view. When we do this, we
demonstrate a bug in RN Android where the pink view doesn't get
rerendered and remains at its old size. If other things change
(e.g. we display `state.width` as text somewhere) it could circumvent
the bug and cause the pink view to be rerendered at its new size. */}
<RNTesterText style={{fontSize: 15}}>
Change Pink View Width
</RNTesterText>
</TouchableHighlight>
<RNTesterText>
This is an
<View style={{width: 125, height: 75, backgroundColor: 'steelblue'}}>
<View
style={{
width: this.state.width,
height: 50,
backgroundColor: 'pink',
}}
/>
</View>
inline view
</RNTesterText>
</View>
);
}
</View>
inline view
</RNTesterText>
</View>
);
}
module.exports = {
@@ -11,109 +11,90 @@
'use strict';
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import type {AppStateValues} from 'react-native/Libraries/AppState/AppState';
import type {EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter';
import RNTesterText from '../../components/RNTesterText';
import React from 'react';
import {useEffect, useState} from 'react';
import {AppState, Platform, View} from 'react-native';
class AppStateSubscription extends React.Component<
$FlowFixMeProps,
$FlowFixMeState,
> {
state: {
appState: ?string,
eventsDetected: Array<string>,
memoryWarnings: number,
previousAppStates: Array<?(any | string)>,
} = {
appState: AppState.currentState,
previousAppStates: [],
memoryWarnings: 0,
eventsDetected: [],
};
type Props = {
detectEvents?: boolean,
showCurrentOnly?: boolean,
showMemoryWarnings?: boolean,
};
_subscriptions: ?Array<EventSubscription>;
function AppStateSubscription(props: Props) {
const [currentAppState, setCurrentAppState] = useState<?string>(
AppState.currentState,
);
const [previousAppStates, setPreviousAppStates] = useState<string[]>([]);
const [memoryWarnings, setMemoryWarnings] = useState<number>(0);
const [eventsDetected, setEventsDetected] = useState<string[]>([]);
componentDidMount() {
this._subscriptions = [
AppState.addEventListener('change', this._handleAppStateChange),
AppState.addEventListener('memoryWarning', this._handleMemoryWarning),
useEffect(() => {
const subscriptions = [
AppState.addEventListener('change', handleAppStateChange),
AppState.addEventListener('memoryWarning', handleMemoryWarning),
];
if (Platform.OS === 'android') {
this._subscriptions.push(
AppState.addEventListener('focus', this._handleFocus),
AppState.addEventListener('blur', this._handleBlur),
subscriptions.push(
AppState.addEventListener('focus', handleFocus),
AppState.addEventListener('blur', handleBlur),
);
}
}
componentWillUnmount() {
if (this._subscriptions != null) {
for (const subscription of this._subscriptions) {
subscription.remove();
}
}
}
return () => {
subscriptions.forEach(subscription => subscription.remove());
};
}, []);
_handleMemoryWarning = () => {
this.setState({memoryWarnings: this.state.memoryWarnings + 1});
const handleMemoryWarning = () => {
setMemoryWarnings(prev => prev + 1);
};
_handleBlur = () => {
const eventsDetected = this.state.eventsDetected.slice();
eventsDetected.push('blur');
this.setState({eventsDetected});
const handleBlur = () => {
setEventsDetected(prev => [...prev, 'blur']);
};
_handleFocus = () => {
const eventsDetected = this.state.eventsDetected.slice();
eventsDetected.push('focus');
this.setState({eventsDetected});
const handleFocus = () => {
setEventsDetected(prev => [...prev, 'focus']);
};
_handleAppStateChange = (appState: AppStateValues) => {
const previousAppStates = this.state.previousAppStates.slice();
previousAppStates.push(this.state.appState);
this.setState({
appState,
previousAppStates,
});
const handleAppStateChange = (appState: string) => {
setPreviousAppStates(prev => [...prev, appState]);
setCurrentAppState(appState);
};
render(): React.Node {
if (this.props.showMemoryWarnings) {
return (
<View>
<RNTesterText>{this.state.memoryWarnings}</RNTesterText>
</View>
);
}
if (this.props.showCurrentOnly) {
return (
<View>
<RNTesterText>{this.state.appState}</RNTesterText>
</View>
);
}
if (this.props.detectEvents) {
return (
<View>
<RNTesterText>
{JSON.stringify(this.state.eventsDetected)}
</RNTesterText>
</View>
);
}
if (props.showMemoryWarnings) {
return (
<View>
<RNTesterText>
{JSON.stringify(this.state.previousAppStates)}
</RNTesterText>
<RNTesterText>{memoryWarnings}</RNTesterText>
</View>
);
}
if (props.showCurrentOnly) {
return (
<View>
<RNTesterText>{currentAppState}</RNTesterText>
</View>
);
}
if (props.detectEvents) {
return (
<View>
<RNTesterText>{JSON.stringify(eventsDetected)}</RNTesterText>
</View>
);
}
return (
<View>
<RNTesterText>{JSON.stringify(previousAppStates)}</RNTesterText>
</View>
);
}
exports.title = 'AppState';
@@ -10,179 +10,181 @@
'use strict';
import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet';
import RNTesterBlock from '../../components/RNTesterBlock';
import RNTesterPage from '../../components/RNTesterPage';
import RNTesterText from '../../components/RNTesterText';
import React from 'react';
import {StyleSheet, View} from 'react-native';
class Circle extends React.Component<$FlowFixMeProps> {
render(): React.Node {
const size = this.props.size || 20;
const backgroundColor = this.props.bgColor || '#527fe4';
return (
<View
style={{
borderRadius: size / 2,
backgroundColor: backgroundColor,
width: size,
height: size,
margin: 1,
}}
/>
);
}
type CicleProps = $ReadOnly<{
backgroundColor?: string,
size?: number,
}>;
function Circle({
backgroundColor = '#527fe4',
size = 20,
}: CicleProps): React.Node {
return (
<View
style={{
borderRadius: size / 2,
backgroundColor: backgroundColor,
width: size,
height: size,
margin: 1,
}}
/>
);
}
class CircleBlock extends React.Component<$FlowFixMeProps> {
render(): React.Node {
const circleStyle = {
flexDirection: 'row',
backgroundColor: '#f6f7f8',
borderWidth: 0.5,
borderColor: '#d6d7da',
marginBottom: 2,
};
return (
<View style={[circleStyle, this.props.style]}>{this.props.children}</View>
);
}
type CircleBlockProps = $ReadOnly<{
children: React.Node,
style: ViewStyleProp,
}>;
function CircleBlock({children, style}: CircleBlockProps): React.Node {
const circleStyle = {
flexDirection: 'row',
backgroundColor: '#f6f7f8',
borderWidth: 0.5,
borderColor: '#d6d7da',
marginBottom: 2,
};
return <View style={[circleStyle, style]}>{children}</View>;
}
class LayoutExample extends React.Component<$FlowFixMeProps> {
render(): React.Node {
const fiveColoredCircles = [
<Circle bgColor="#527fe4" key="blue" />,
<Circle bgColor="#D443E3" key="violet" />,
<Circle bgColor="#FF9049" key="orange" />,
<Circle bgColor="#FFE649" key="yellow" />,
<Circle bgColor="#7FE040" key="green" />,
];
function LayoutExample(): React.Node {
const fiveColoredCircles = [
<Circle backgroundColor="#527fe4" key="blue" />,
<Circle backgroundColor="#D443E3" key="violet" />,
<Circle backgroundColor="#FF9049" key="orange" />,
<Circle backgroundColor="#FFE649" key="yellow" />,
<Circle backgroundColor="#7FE040" key="green" />,
];
return (
<RNTesterPage title={this.props.navigator ? null : 'Layout'}>
<RNTesterBlock title="Flex Direction">
<RNTesterText>row</RNTesterText>
<CircleBlock style={{flexDirection: 'row'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>row-reverse</RNTesterText>
<CircleBlock style={{flexDirection: 'row-reverse'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>column</RNTesterText>
<CircleBlock style={{flexDirection: 'column'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>column-reverse</RNTesterText>
<CircleBlock style={{flexDirection: 'column-reverse'}}>
{fiveColoredCircles}
</CircleBlock>
<View
style={[
styles.overlay,
{position: 'absolute', top: 15, left: 160},
]}>
<RNTesterText style={{color: 'black'}}>
{'top: 15, left: 160'}
</RNTesterText>
</View>
</RNTesterBlock>
return (
<RNTesterPage title={'Layout'}>
<RNTesterBlock title="Flex Direction">
<RNTesterText>row</RNTesterText>
<CircleBlock style={{flexDirection: 'row'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>row-reverse</RNTesterText>
<CircleBlock style={{flexDirection: 'row-reverse'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>column</RNTesterText>
<CircleBlock style={{flexDirection: 'column'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>column-reverse</RNTesterText>
<CircleBlock style={{flexDirection: 'column-reverse'}}>
{fiveColoredCircles}
</CircleBlock>
<View
style={[styles.overlay, {position: 'absolute', top: 15, left: 160}]}>
<RNTesterText style={{color: 'black'}}>
{'top: 15, left: 160'}
</RNTesterText>
</View>
</RNTesterBlock>
<RNTesterBlock title="Justify Content - Main Direction">
<RNTesterText>flex-start</RNTesterText>
<CircleBlock style={{justifyContent: 'flex-start'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>center</RNTesterText>
<CircleBlock style={{justifyContent: 'center'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>flex-end</RNTesterText>
<CircleBlock style={{justifyContent: 'flex-end'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>space-between</RNTesterText>
<CircleBlock style={{justifyContent: 'space-between'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>space-around</RNTesterText>
<CircleBlock style={{justifyContent: 'space-around'}}>
{fiveColoredCircles}
</CircleBlock>
</RNTesterBlock>
<RNTesterBlock title="Align Items - Other Direction">
<RNTesterText>flex-start</RNTesterText>
<CircleBlock style={{alignItems: 'flex-start', height: 30}}>
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={8} />
</CircleBlock>
<RNTesterText>center</RNTesterText>
<CircleBlock style={{alignItems: 'center', height: 30}}>
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={8} />
</CircleBlock>
<RNTesterText>flex-end</RNTesterText>
<CircleBlock style={{alignItems: 'flex-end', height: 30}}>
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={8} />
</CircleBlock>
</RNTesterBlock>
<RNTesterBlock title="Flex Wrap">
<CircleBlock style={{flexWrap: 'wrap'}}>
{'oooooooooooooooo'.split('').map((char, i) => (
<Circle key={i} />
))}
</CircleBlock>
</RNTesterBlock>
</RNTesterPage>
);
}
<RNTesterBlock title="Justify Content - Main Direction">
<RNTesterText>flex-start</RNTesterText>
<CircleBlock style={{justifyContent: 'flex-start'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>center</RNTesterText>
<CircleBlock style={{justifyContent: 'center'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>flex-end</RNTesterText>
<CircleBlock style={{justifyContent: 'flex-end'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>space-between</RNTesterText>
<CircleBlock style={{justifyContent: 'space-between'}}>
{fiveColoredCircles}
</CircleBlock>
<RNTesterText>space-around</RNTesterText>
<CircleBlock style={{justifyContent: 'space-around'}}>
{fiveColoredCircles}
</CircleBlock>
</RNTesterBlock>
<RNTesterBlock title="Align Items - Other Direction">
<RNTesterText>flex-start</RNTesterText>
<CircleBlock style={{alignItems: 'flex-start', height: 30}}>
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={8} />
</CircleBlock>
<RNTesterText>center</RNTesterText>
<CircleBlock style={{alignItems: 'center', height: 30}}>
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={8} />
</CircleBlock>
<RNTesterText>flex-end</RNTesterText>
<CircleBlock style={{alignItems: 'flex-end', height: 30}}>
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={10} />
<Circle size={20} />
<Circle size={17} />
<Circle size={12} />
<Circle size={15} />
<Circle size={8} />
</CircleBlock>
</RNTesterBlock>
<RNTesterBlock title="Flex Wrap">
<CircleBlock style={{flexWrap: 'wrap'}}>
{'oooooooooooooooo'.split('').map((char, i) => (
<Circle key={i} />
))}
</CircleBlock>
</RNTesterBlock>
</RNTesterPage>
);
}
const styles = StyleSheet.create({
@@ -10,51 +10,41 @@
import RNTesterText from '../../components/RNTesterText';
import React from 'react';
import {useEffect, useState} from 'react';
import {DeviceEventEmitter, View} from 'react-native';
import {type EventSubscription} from 'react-native/Libraries/vendor/emitter/EventEmitter';
class OrientationChangeExample extends React.Component<{...}, $FlowFixMeState> {
_orientationSubscription: EventSubscription;
state:
| any
| {
currentOrientation: string,
isLandscape: boolean,
orientationDegrees: number,
} = {
const OrientationChangeExample = (): React.Node => {
const [state, setState] = useState({
currentOrientation: '',
orientationDegrees: 0,
isLandscape: false,
};
});
componentDidMount() {
this._orientationSubscription = DeviceEventEmitter.addListener(
useEffect(() => {
const onOrientationChange = (orientation: Object) => {
setState({
currentOrientation: orientation.name,
orientationDegrees: orientation.rotationDegrees,
isLandscape: orientation.isLandscape,
});
};
const orientationSubscription = DeviceEventEmitter.addListener(
'namedOrientationDidChange',
this._onOrientationChange,
onOrientationChange,
);
}
componentWillUnmount() {
this._orientationSubscription.remove();
}
return () => {
orientationSubscription.remove();
};
}, []);
_onOrientationChange = (orientation: Object) => {
this.setState({
currentOrientation: orientation.name,
orientationDegrees: orientation.rotationDegrees,
isLandscape: orientation.isLandscape,
});
};
render(): React.Node {
return (
<View>
<RNTesterText>{JSON.stringify(this.state)}</RNTesterText>
</View>
);
}
}
return (
<View>
<RNTesterText>{JSON.stringify(state)}</RNTesterText>
</View>
);
};
exports.title = 'OrientationChangeExample';
exports.category = 'Basic';
+52 -26
View File
@@ -85,40 +85,66 @@ async function testRNTesterIOS(
} version of RNTester iOS with the new Architecture enabled`,
);
// if everything succeeded so far, we can launch Metro and the app
// start the Metro server in a separate window
launchPackagerInSeparateWindow(pwd().toString());
// remember that for this to be successful
// you should have run bundle install once
// in your local setup
if (argv.hermes === true && ciArtifacts != null) {
const hermesURL = await ciArtifacts.artifactURLHermesDebug();
const hermesZipPath = path.join(ciArtifacts.baseTmpPath(), 'hermes.zip');
// download hermes source code from manifold
ciArtifacts.downloadArtifact(hermesURL, hermesZipPath);
// GHA zips by default the artifacts.
const outputFolder = path.join(ciArtifacts.baseTmpPath(), 'hermes');
exec(`rm -rf ${outputFolder}`);
exec(`unzip ${hermesZipPath} -d ${outputFolder}`);
const hermesPath = path.join(outputFolder, 'hermes-ios-Debug.tar.gz');
console.info(`Downloaded Hermes in ${hermesPath}`);
exec(
`HERMES_ENGINE_TARBALL_PATH=${hermesPath} RCT_NEW_ARCH_ENABLED=1 bundle exec pod install --ansi`,
if (ciArtifacts != null) {
const appOutputFolder = path.join(
ciArtifacts.baseTmpPath(),
'RNTester.app',
);
exec(`rm -rf ${appOutputFolder}`);
if (argv.hermes === true) {
// download hermes App
const hermesAppUrl = await ciArtifacts.artifactURLForHermesRNTesterApp();
const hermesAppZipPath = path.join(
ciArtifacts.baseTmpPath(),
'RNTesterAppHermes.zip',
);
ciArtifacts.downloadArtifact(hermesAppUrl, hermesAppZipPath);
exec(`unzip ${hermesAppZipPath} -d ${appOutputFolder}`);
} else {
// download JSC app
const hermesAppUrl = await ciArtifacts.artifactURLForJSCRNTesterApp();
const hermesAppZipPath = path.join(
ciArtifacts.baseTmpPath(),
'RNTesterAppJSC.zip',
);
ciArtifacts.downloadArtifact(hermesAppUrl, hermesAppZipPath);
exec(`unzip ${hermesAppZipPath} -d ${appOutputFolder}`);
}
// boot device
const bootedDevice = String(
exec('xcrun simctl list | grep "iPhone 16 Pro" | grep Booted', {
silent: true,
}),
).trim();
if (!bootedDevice || bootedDevice.length === 0) {
exec('xcrun simctl boot "iPhone 16 Pro"');
}
// install app on device
exec(`xcrun simctl install booted ${appOutputFolder}`);
// launch the app on iOS simulator
exec('xcrun simctl launch booted com.meta.RNTester.localDevelopment');
} else {
exec(
`USE_HERMES=${
argv.hermes === true ? 1 : 0
} CI=${onReleaseBranch.toString()} RCT_NEW_ARCH_ENABLED=1 bundle exec pod install --ansi`,
);
// launch the app on iOS simulator
exec(
'npx react-native run-ios --scheme RNTester --simulator "iPhone 15 Pro"',
);
}
// if everything succeeded so far, we can launch Metro and the app
// start the Metro server in a separate window
launchPackagerInSeparateWindow(pwd().toString());
// launch the app on iOS simulator
exec(
'npx react-native run-ios --scheme RNTester --simulator "iPhone 15 Pro"',
);
}
/**
@@ -201,7 +227,7 @@ async function testRNTesterAndroid(
* - @onReleaseBranch whether we are on a release branch or not
*/
async function testRNTester(
circleCIArtifacts /*:Unwrap<ReturnType<typeof setupGHAArtifacts>> */,
ciArtifacts /*:Unwrap<ReturnType<typeof setupGHAArtifacts>> */,
onReleaseBranch /*: boolean */,
) {
// FIXME: make sure that the commands retains colors
@@ -210,9 +236,9 @@ async function testRNTester(
pushd('packages/rn-tester');
if (argv.platform === 'ios') {
await testRNTesterIOS(circleCIArtifacts, onReleaseBranch);
await testRNTesterIOS(ciArtifacts, onReleaseBranch);
} else {
await testRNTesterAndroid(circleCIArtifacts);
await testRNTesterAndroid(ciArtifacts);
}
popd();
}
@@ -214,6 +214,14 @@ async function artifactURLForHermesRNTesterAPK(
return getArtifactURL('rntester-hermes-debug');
}
async function artifactURLForJSCRNTesterApp() /*: Promise<string> */ {
return getArtifactURL('RNTesterApp-NewArch-JSC-Debug');
}
async function artifactURLForHermesRNTesterApp() /*: Promise<string> */ {
return getArtifactURL('RNTesterApp-NewArch-Hermes-Debug');
}
async function artifactURLForMavenLocal() /*: Promise<string> */ {
return getArtifactURL('maven-local');
}
@@ -247,6 +255,8 @@ module.exports = {
downloadArtifact,
artifactURLForJSCRNTesterAPK,
artifactURLForHermesRNTesterAPK,
artifactURLForJSCRNTesterApp,
artifactURLForHermesRNTesterApp,
artifactURLForMavenLocal,
artifactURLHermesDebug,
artifactURLForReactNative,