Compare commits

...
Author SHA1 Message Date
Devmate BotandFacebook GitHub Bot 666252e08a xplat/js/react-native-github/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm
Reviewed By: javache

Differential Revision: D83144241
2025-09-25 02:39:11 -07:00
Moti ZilbermanandFacebook GitHub Bot f599e2a613 Fix custom prebuilt binary handling in unstable_prepareDebuggerShell (#53927)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53927

Changelog: [Internal]

Fixes a bug that broke `unstable_prepareDebuggerShell` (and therefore the RNDT shell) in OSS.

Reviewed By: vzaidman

Differential Revision: D83178777

fbshipit-source-id: cfd93b14e2a94e36d8a3ee9f4605036a4279ef8c
2025-09-25 02:29:11 -07:00
Alex HuntandFacebook GitHub Bot b577679746 Update DevTools windowKey to a sha256 hash (#53923)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53923

Motivated by feedback on D83070252. This prevents us from including decodable information about debug targets in these values.

Changelog: [Internal]

Reviewed By: motiz88

Differential Revision: D83139401

fbshipit-source-id: 01b01d23e4dfb06e400729b8cedf1fe2e098b209
2025-09-25 01:22:58 -07:00
Alex HuntandFacebook GitHub Bot 88f05b219c Fix build for debugger-shell (#53924)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53924

Fix failing `yarn build` runs following D83070252.

Changelog: [Internal]

Reviewed By: motiz88

Differential Revision: D83161092

fbshipit-source-id: 3e9e984699750add82794281a387eac0534da60d
2025-09-25 01:22:58 -07:00
Sam ZhouandFacebook GitHub Bot dc3736893d Deploy 0.286.0 to xplat (#53929)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53929

[changelog](https://github.com/facebook/flow/blob/main/Changelog.md)
Changelog: [Internal]

Reviewed By: gkz

Differential Revision: D83192932

fbshipit-source-id: 0457464a1ae1907a6906a26faa3ff319f01f9356
2025-09-24 18:25:10 -07:00
Vitali ZaidmanandFacebook GitHub Bot 3a954caf4f don't require projectRoot in devMiddleware (#53921)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53921

Changelog: [Internal] `devMiddleware` removed the unused option `projectRoot`

This option was used only in a dead branch of the code inside `InspectorProxy`.

The scenario where it appeared was enabling resolving script sources (`Debugger.getScriptSource`) starting with `file://` which were coming from the file system. However, we don't seem to ever point scripts at the filesystem this way.

Reviewed By: huntie

Differential Revision: D82739662

fbshipit-source-id: 9a130eaa83cb94ae0e36a5a1102c56ff8a36cffc
2025-09-24 12:47:24 -07:00
Calix TangandFacebook GitHub Bot 2dfb36e3c6 Simplify VirtualViewContainer hysteresis window logic (#53914)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53914

Pulls hysteresis window computation out of for loop. Simplify the remaining code.

Changelog: [Internal] - Same as general summary.

Reviewed By: lunaleaps

Differential Revision: D83005735

fbshipit-source-id: 824863c649406a750d44b31ac92878505ab61596
2025-09-24 10:05:34 -07:00
Christoph PurrerandFacebook GitHub Bot 10b45b6200 Add Unit Tests (#53913)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53913

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D83091947

fbshipit-source-id: 63baf543b180070591d4779b1203909359aec132
2025-09-24 08:56:01 -07:00
Alex HuntandFacebook GitHub Bot 430765b071 Update SafeAreaViewExample to lazily require deprecated API (#53922)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53922

Minor change motivated by restoring a clean JS console on startup for RNTester.

Changelog: [Internal]

Reviewed By: cipolleschi

Differential Revision: D83145673

fbshipit-source-id: be64b057b842f4922328f5bc62dc001d016fd0b7
2025-09-24 06:05:26 -07:00
generatedunixname537391475639613andFacebook GitHub Bot ed6aa0f25a xplat/js/react-native-github/packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.cpp (#53919)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53919

Reviewed By: javache

Differential Revision: D83044510

fbshipit-source-id: df05c27f5863b6eac6c37ebe75343b30e515be7a
2025-09-24 05:15:26 -07:00
Alex HuntandFacebook GitHub Bot 8027067322 Implement saved window positioning per target (#53910)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53910

NOTE: Resubmission of D82236159 — The `electron-store` dependency is now replaced with a local implementation.

As titled. A long awaited quality of life improvement that we can now deliver with our desktop shell.

Window arrangements are saved per [`windowKey`](https://github.com/facebook/react-native/blob/da7bf9c54567aae62ff355b79e66f511cb382065/packages/dev-middleware/src/middleware/openDebuggerMiddleware.js#L193), mapping to each previously opened debugger target.

**Limitations**

- Does not save/restore macOS fullscreen app state.

Changelog: [Internal]

Reviewed By: motiz88

Differential Revision: D83070252

fbshipit-source-id: a77f106b6db31571313acd0270b87703e4de049d
2025-09-24 04:59:43 -07:00
Ruslan ShestopalyukandFacebook GitHub Bot eb9e94256e Fix potential attempt to execute a task after shut down in TaskDispatchThread (#53900)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53900

# Changelog:
[Internal] -

There is a crash reported, which looks like it may be potentially caused by some scenarios when we are trying to execute a scheduled task after the TaskDispatchThread instance had been quit.

This adds a missing extra check in the corresponding code to avoid such scenarios.

Reviewed By: christophpurrer, lenaic

Differential Revision: D83050169

fbshipit-source-id: 0ee0fa5848b070c2dc3dd92dbad4e6d5996734b3
2025-09-24 04:27:30 -07:00
Kacper KafaraandFacebook GitHub Bot dc4a6d2c7e Add invalidation callback for non-recycled component instances on iOS (#53708)
Summary:
Since the view recycling is optional on iOS [since 0.74](https://github.com/facebook/react-native/commit/613a5a75977d84333df7cbd5701e01a7ab5a3385) when a view (with disabled view recycling) is unmounted / destroyed there is no lifecycle callback for a component view to notify it of such event. Currently we (`react-native-screens`) are forced to scan mutation list of every mounting transaction in every of ours container components. Components with view recycling turned on, get `prepareForRecycle` callback on Fabric & on old architecture, there was `invalidate` message sent (`RCTInvalidating` protocol). It would be nice & useful to have something like this for components with view recycling disabled, or enabled but not recycled due to pool being full.

In particular in `react-native-screens` we need an information that the component is being destroyed to release retained resources (view controllers & others).

I have concern regarding naming of this method, as it could collide / be mistaken with `invalidate` method of `RCTInvalidating` protocol, but naming is hard & I don't see a name that fits better 😄 Open for suggestions!

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[IOS] [ADDED] - Add invalidation callback for non-recycled component instances

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

Test Plan:
Apply this patch to `RNTMyNativeViewComponentView.mm`:

```objective-c

 diff --git a/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.mm b/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.mm
index 2eb7bff28e..8464da603b 100644
 --- a/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.mm
+++ b/packages/rn-tester/NativeComponentExample/ios/RNTMyNativeViewComponentView.mm
@@ -123,6 +123,16 @@ using namespace facebook::react;
   [_view removeOverlays];
 }

+- (void)invalidate
+{
+  NSLog(@"RCTComponentViewProtocol invalidate called");
+}
+
++ (BOOL)shouldBeRecycled
+{
+  return NO;
+}
+
 - (void)fireLagacyStyleEvent
 {
   RNTMyNativeViewEventEmitter::OnLegacyStyleEvent value = {"Legacy Style Event Fired."};

```

& render `MyNativeView` in any of the RNTester screens / examples. Unmount the view & observe the log in XCode.

https://github.com/user-attachments/assets/be3f67bb-73e0-4af2-9ca1-f2eb9f3347bb

(called twice, because there are two components rendered at a time)

Reviewed By: javache

Differential Revision: D83139361

Pulled By: cipolleschi

fbshipit-source-id: 17ef964648ac44b583503b6b00fc5dd457887061
2025-09-24 04:26:38 -07:00
Jakub PiaseckiandFacebook GitHub Bot 417e068220 Relayout surfaces on font scale change (#53770)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53770

Changelog: [ANDROID][FIXED] - Request layout on attached surfaces when font scale changes

Reviewed By: rshest

Differential Revision: D82422608

fbshipit-source-id: c087054a709f8d31a298cd8d83363fac1e23d03a
2025-09-24 04:16:33 -07:00
Riccardo CipolleschiandFacebook GitHub Bot dc132a4fd4 Crash the app when Legacy Arch is enabled (#53911)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53911

This change mimics what we implemented on Android to crash the app.

This is in general never going t be triggered. It will be triggered only if users are actually going through the old way to initialize React Native, i.e. by using the RCTRootView class which creates thebridge, or if they are creating the bridge themselves.

## Changelog:
[iOS][Added] - Crash the app if they force the legacy architecture.

Reviewed By: RSNara, cortinico

Differential Revision: D83066377

fbshipit-source-id: 0907effceb9a3655ec8d6bde8e0986f50f1ab663
2025-09-24 02:45:46 -07:00
Moti ZilbermanandFacebook GitHub Bot 18ba21149a Run prebuilt standalone shell directly from fbsource on laptops (#53878)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53878

Changelog: [Internal]

Adds the `prebuiltBinaryPath` option to `unstable_spawnDebuggerShellWithArgs` and `unstable_prepareDebuggerShell`, for advanced integrations that need to change how the React Native DevTools prebuilt binary is distributed.

Reviewed By: huntie

Differential Revision: D82956699

fbshipit-source-id: 30f9c461c7d8f22a553f278bbe42b86742c98da7
2025-09-24 00:22:32 -07:00
Calix TangandFacebook GitHub Bot 53f89bacd4 VirtualView v2 support in HorizontalScrollView native component (Android) (#53890)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53890

Changelog: [Internal] -  Adds support for VirtualView v2 in Android HorizontalScrollView native component by implementing VirtualViewContainer interface. Only on Android because iOS equivalent native components are already set up to support virtualview v2 on horizontal scrollviews.

## Changes in Detail

Adds necessary changes to Android `HorizontalScrollView` native component to support the experimental version of VirtualView.

Reviewed By: lunaleaps

Differential Revision: D82783403

fbshipit-source-id: 1e55eb054ab098af5ca8dd526b27c574025943c4
2025-09-23 16:06:40 -07:00
Devan BuggayandFacebook GitHub Bot 14dc03e2bd Genalize focus/blur behavior in JS (#53829)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53829

Forwards along focus and blur calls to their respective native commands, leaving the TextInput path intact for now.

There are a few ways places to implement this, all with different trade offs. I decided to leave TextInputState.js intact and instead only go down the original path if the focused/blurred element is a TextInput by using the registered inputs in TextInputState. This revealed a subtle issue where the TextInputs aren't registered in time for the ref callback, meaning you can't focus them there if you rely on the registered list.

Changelog: [Internal]

Reviewed By: shwanton

Differential Revision: D82676628

fbshipit-source-id: d39c92dfc99ec4b5e100203bb43c8a4f9c80a649
2025-09-23 14:37:56 -07:00
Andrew DatsenkoandFacebook GitHub Bot 22002bb70c Allow to disable coverage via flag & disable it for benchmarks (#53912)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53912

Changelog: [Internal]
Add new fantom flag `fantom_disable_coverage` to be used in tests that are sensitive to things like memory allocation.
Also disable coverage for any benchmark test.

Reviewed By: arushikesarwani94

Differential Revision: D83070065

fbshipit-source-id: a885e79e3d0c88cfb7adef30cb60ab46a617edac
2025-09-23 13:40:31 -07:00
Devan BuggayandFacebook GitHub Bot b00d3be572 Make perf overlay more transparent (#53904)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53904

Adds more transparency to the background of the perf overlay, we got some feedback about it visually obscuring elements behind it.

{F1982191377}

{F1982191388}

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D83037721

fbshipit-source-id: e70c799ea7942c6aea886e9a3580e324c4238048
2025-09-23 12:53:43 -07:00
Devan BuggayandFacebook GitHub Bot 4acb3d3e7c Remove "Background" from perf overlay title (#53903)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53903

Removes unnecessary "background" from title, narrowing the width of the overlay.
{F1982191268}

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D83036209

fbshipit-source-id: 0a11f38e544e3d667a9a1fb957e351716f625f3e
2025-09-23 12:53:43 -07:00
Alex HuntandFacebook GitHub Bot f4b6131850 Harden lifecycle handling for Perf Monitor (#53905)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53905

Updates `PerfMonitorOverlayManager` so that it is minimally and correctly integrated in the `DevSupportManagerBase` reload cycle — attempting to fix a bug where the background profiling state on startup / subsequent packager connections would be out of sync.

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D83058519

fbshipit-source-id: 9a9bb32d3215ccf722aa39ca0ca943449f7ae62e
2025-09-23 11:47:50 -07:00
generatedunixname89002005287564andFacebook GitHub Bot b9e6e349f5 Fix CQS signal readability-avoid-const-params-in-decls in xplat/js/react-native-github/packages [B] (#53902)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53902

Reviewed By: javache

Differential Revision: D83033554

fbshipit-source-id: 85b48fb7051e3f58ee00cd6a160086701c66d7a2
2025-09-23 08:40:16 -07:00
React Native BotandFacebook GitHub Bot 1c2b9f9206 Add changelog for v0.82.0-rc.4 (#53886)
Summary:
Add Changelog for 0.82.0-rc.4

## Changelog:
[Internal] - Add Changelog for 0.82.0-rc.4

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

Test Plan: N/A

Reviewed By: fabriziocucci

Differential Revision: D82993264

Pulled By: vzaidman

fbshipit-source-id: e1aba15613d5e62fcd503e15c878697adc088816
2025-09-23 05:00:38 -07:00
generatedunixname89002005287564andFacebook GitHub Bot 1c5fb903fd Fix CQS signal readability-avoid-const-params-in-decls in xplat/js/react-native-github/packages [A] (#53897)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53897

Reviewed By: javache

Differential Revision: D83033417

fbshipit-source-id: 4aa2bfd49433a1f9c741241dcffe714b5091506b
2025-09-23 04:18:47 -07:00
Vitali ZaidmanandFacebook GitHub Bot 6936bd9f6b Dismiss DevLoadingView toast on touch (#53885)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53885

Changelog: [General][Added] DevServer banners can now be closed on tap. On iOS, don't close them after 15s anymore.

Banners, on iOS, but not Android, are currently closed after 15s since {D47478373} where it was introduced to deal with the banner telling users they need to connect to Metro stuck forever.

Instead of closing it after 15 seconds, allow the users on both Android and iOS to close it via a touch.

Reviewed By: huntie

Differential Revision: D82727997

fbshipit-source-id: 5aa2af78a4dbcd95b69423d52421900d4ab35244
2025-09-23 02:06:18 -07:00
generatedunixname1395667395051502andFacebook GitHub Bot 8c2f9e47fa Update React Native DevTools binaries
Summary:
Automated update of React Native DevTools binaries
bypass-github-export-checks
Changelog: [Internal]

Reviewed By: robhogan

Differential Revision: D83031681

fbshipit-source-id: 0290d423b758ce42cd9a9c8cccc0f2cf16ad992b
2025-09-23 01:46:27 -07:00
Gabriel DonadelandFacebook GitHub Bot ee811a82ec Add changelog for v0.81.4 (#53720)
Summary:
Add Changelog for 0.81.4

## Changelog:
[Internal] - Add Changelog for 0.81.4

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

Test Plan: N/A

Reviewed By: cortinico

Differential Revision: D83013088

Pulled By: arushikesarwani94

fbshipit-source-id: 3693bf6582543465102cea5dbd7dd17dffe0a272
2025-09-23 01:19:46 -07:00
Marco WangandFacebook GitHub Bot 2e55154665 Deploy 0.285.0 to xplat (#53895)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53895

[changelog](https://github.com/facebook/flow/blob/main/Changelog.md)
Changelog: [Internal]

Reviewed By: SamChou19815

Differential Revision: D83000230

fbshipit-source-id: 7c070358623e9b68043bb8666f5c9dfc632ff2fb
2025-09-22 22:42:28 -07:00
Sam ZhouandFacebook GitHub Bot 5c369aa34c Add annotations to fix future natural inference errors in xplat/js: 6/n (#53894)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53894

Changelog: [Internal]

Reviewed By: marcoww6

Differential Revision: D83000736

fbshipit-source-id: 3ba5c59d9b2f7b967c0dccd24a73056430153bdc
2025-09-22 21:55:34 -07:00
Arushi KesarwaniandFacebook GitHub Bot 2065c31800 Updating ReactAndroid.api to unblock stable (#53891)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53891

D82726743 missed updating the ReactAndroid.api which was blocking fbandroid/stable:

https://www.internalfb.com/sandcastle/workflow/797137134054937206

Hence ran `buck2 run //xplat/js/scripts/rn-api:generate-rn-api-metadata` to update

Changelog: [Android][Fixed] - Fixed ReactAndroid.api

Reviewed By: mdvacca, sumkit, jorge-cab

Differential Revision: D83001140

fbshipit-source-id: 85e4f2005a28a3c98999198284133e4af1eaed89
2025-09-22 18:32:51 -07:00
David VaccaandFacebook GitHub Bot 5684546251 Delete LayoutAnimation (#53785)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53785

LayoutAnimation is part of legacy architecture and unused, let's delete it

changelog: [internal] internal

Reviewed By: cortinico

Differential Revision: D82235542

fbshipit-source-id: c0e2f08bcdffb9c5e102df7cca799f3a25296afe
2025-09-22 17:45:08 -07:00
David VaccaandFacebook GitHub Bot f09f4a779e Remove code from public LayoutAnimationController class (#53784)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53784

LayoutAnimation is part of legacy architecture, I'm deleting the code used from its non supported public APIs

changelog: [internal] internal

Reviewed By: shwanton

Differential Revision: D82235545

fbshipit-source-id: 9665c57b68eba9d958d3f8b9dd4224558cc8e9f6
2025-09-22 17:45:08 -07:00
David VaccaandFacebook GitHub Bot ec5bc3b285 Delete LayoutAnimation tests (#53783)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53783

LayoutAnimation is part of legacy architecture, I'm deleting unused tests

changelog: [internal] internal

Reviewed By: shwanton

Differential Revision: D82254268

fbshipit-source-id: df53215f126e37d8422ece46552596c31b11f61b
2025-09-22 17:45:08 -07:00
Christoph PurrerandFacebook GitHub Bot 46c75c1043 Add ImagePrefetching feature flag for JNI calls (#53865)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53865

This adds an additional feature flag to enable/disable image prefetch requests via JNI batching

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D82871006

fbshipit-source-id: 6cd2577f26e6d4c906e7be2f62a397177691538f
2025-09-22 17:04:55 -07:00
Vitali ZaidmanandFacebook GitHub Bot e3bf881ae6 remove connection hints from being logged for the user (#53884)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53884

Changelog: [Internal]

Now that there's a clear display for when HMR is disconnected, we don't want to show messages regardless devices connection and disconnection to the DevServer because they are too partial.

Reviewed By: huntie

Differential Revision: D82727105

fbshipit-source-id: 32dd077f85d2044f89ae2d8d60a37c0ec6cccbbf
2025-09-22 15:55:25 -07:00
Sam ZhouandFacebook GitHub Bot e4368154a5 Turn on react.ref_as_prop=experimental.store_ref_in_props
Summary: Changelog: [Internal]

Reviewed By: marcoww6

Differential Revision: D82932016

fbshipit-source-id: a391bdc06eef60d3054b8440c4ccfbaf62bc931a
2025-09-22 14:46:56 -07:00
Vitali ZaidmanandFacebook GitHub Bot 4148746941 add disconnection message (#53883)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53883

Changelog: [General][Added] - new banner added to indicate that Fast Refresh has lost connection, and that the app needs to be restarted to reconnect

When HMR were getting disconnected, we were not giving any indication for the user.

This lead to situations were the connection is re-established, but HMR is still disconnected, which is unexpected for users.

Instead, raise a banner hinting the user to reload the app to reconnect.

Reviewed By: huntie

Differential Revision: D82726853

fbshipit-source-id: d5f264547b2af89e9dc2a9046d063efe1145d690
2025-09-22 13:25:42 -07:00
generatedunixname537391475639613andFacebook GitHub Bot 34f7137cdc xplat/js/react-native-github/packages/react-native/ReactCommon/react/renderer/components/text/RawTextShadowNode.cpp (#53874)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53874

Reviewed By: rshest

Differential Revision: D82804676

fbshipit-source-id: 90a426cfeb4fe264d523dafe56d2d83f1ed3da11
2025-09-22 12:35:11 -07:00
Vitali ZaidmanandFacebook GitHub Bot 4d45e5987c Align Android with iOS in displaying HMR "refreshing" in color (#53846)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53846

Changelog: [Android][Added] - hot reload banner is now displayed in blue background like on iOS

iOS has a colorful "Refreshing..." banner:
 {F1982086204}

While android doesn't respect the color HMR asks it to set up for the banner:
 {F1982086218}

Reviewed By: cortinico

Differential Revision: D82726743

fbshipit-source-id: 4042851f5a8fd7d4f238f25e2d83f77144742de9
2025-09-22 11:41:38 -07:00
Andrew DatsenkoandFacebook GitHub Bot 2e4da10b52 fix coverage patterns (#53881)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53881

Changelog: [Internal]
To make sure that coverage is insertect correctly when run in different metro setup where patterns do not match perfectly, we need to add glob prefix

Reviewed By: sammy-SC

Differential Revision: D82968565

fbshipit-source-id: c2676ef4c774411938039fc5b98a3b953f6ec916
2025-09-22 10:48:45 -07:00
Riccardo CipolleschiandFacebook GitHub Bot b10faf6c02 Create the orchestration function to coordinate the creation of the hard links (#53642)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53642

## Context

One of the quirk of SwiftPM is that the packages has to have access to the headers they need. Usually this is solved by properly setting the header_search_path. However, in  SwiftPM, we are not allowed to use headers search path that escape the package itself (basically, header search path can't start with `../`).

To work around this limitation we are recreating the correct Header structure by using hardlinks to the actual headers.

## Changed

In this change we are adding a function that is used to orchestrate the helpers function defined in previous changes.

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D81778457

fbshipit-source-id: b4ab8c902d6d7e6ca4b89ccbab75c1b5d84ce00a
2025-09-22 10:14:58 -07:00
Riccardo CipolleschiandFacebook GitHub Bot c6395eccd4 add function hard links for headers from ReactCodegen (#53640)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53640

## Context

One of the quirk of SwiftPM is that the packages has to have access to the headers they need. Usually this is solved by properly setting the header_search_path. However, in  SwiftPM, we are not allowed to use headers search path that escape the package itself (basically, header search path can't start with `../`).

To work around this limitation we are recreating the correct Header structure by using hardlinks to the actual headers.

## Changed

In this change we are adding an helper function to create hard links to Codegen Headers so that other libraries can access them.

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D81778450

fbshipit-source-id: e9f62f1c81ce8a635cc880007f495de342342a25
2025-09-22 10:14:58 -07:00
Riccardo CipolleschiandFacebook GitHub Bot 515c735347 Add function to create hard links for headers of the third-party dependencies (#53638)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53638

## Context

One of the quirk of SwiftPM is that the packages has to have access to the headers they need. Usually this is solved by properly setting the header_search_path. However, in  SwiftPM, we are not allowed to use headers search path that escape the package itself (basically, header search path can't start with `../`).

To work around this limitation we are recreating the correct Header structure by using hardlinks to the actual headers.

## Changed

In this change we are adding an helper function that creates links for the ThirdPartyDependencies that React native and libraries might need to access.

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D81778459

fbshipit-source-id: b8f9f207a0fbe2265e2861bf508516946905b472
2025-09-22 10:14:58 -07:00
Riccardo CipolleschiandFacebook GitHub Bot 6807231120 Create function to create hardlink to header required to build React Native Core (#53635)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53635

## Context

One of the quirk of SwiftPM is that the packages has to have access to the headers they need. Usually this is solved by properly setting the header_search_path. However, in  SwiftPM, we are not allowed to use headers search path that escape the package itself (basically, header search path can't start with `../`).

To work around this limitation we are recreating the correct Header structure by using hardlinks to the actual headers.

## Changed

In this change we did two things:
1. we move the helper functions to a headers-utils.js file (and the tests to the `headers-utils-test.js` file)
2. we added a function that coordinates the creation of the header links *and added tests for it)

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D81778464

fbshipit-source-id: fd8eb5a7af55db0a08c4d299c5470058d5424768
2025-09-22 10:14:58 -07:00
Riccardo CipolleschiandFacebook GitHub Bot fc4a692b8e Create utility function to create the right folder structure for headers in the ReactCommon folder (#53631)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53631

## Context

One of the quirk of SwiftPM is that the packages has to have access to the headers they need. Usually this is solved by properly setting the header_search_path. However, in  SwiftPM, we are not allowed to use headers search path that escape the package itself (basically, header search path can't start with `../`).

To work around this limitation we are recreating the correct Header structure by using hardlinks to the actual headers.

## Changed

In this change we are adding an helper function that creates links for the ReactCommon folder that has a complex structure and complex mapping requirements

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D81778470

fbshipit-source-id: e0f4001048fcde0e988fc3a05b53efb1de70460b
2025-09-22 10:14:58 -07:00
Riccardo CipolleschiandFacebook GitHub Bot 8db93abf12 Create utility function to create the right folder structure for headers in the ReactApple folder (#53629)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53629

## Context

One of the quirk of SwiftPM is that the packages has to have access to the headers they need. Usually this is solved by properly setting the header_search_path. However, in  SwiftPM, we are not allowed to use headers search path that escape the package itself (basically, header search path can't start with `../`).

To work around this limitation we are recreating the correct Header structure by using hardlinks to the actual headers.

## Changed

In this change we are adding a function to properly create the header structure for the headers in ReactApple that requires a special case.

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D81778471

fbshipit-source-id: 095d901dce139cf8221251f952f474be943a5ab3
2025-09-22 10:14:58 -07:00
Riccardo CipolleschiandFacebook GitHub Bot 7cd3328b21 Create script to create hard links for headers from a source path to a destination path (#53620)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53620

## Context

One of the quirk of SwiftPM is that the packages has to have access to the headers they need. Usually this is solved by properly setting the header_search_path. However, in  SwiftPM, we are not allowed to use headers search path that escape the package itself (basically, header search path can't start with `../`).

To work around this limitation we are recreating the correct Header structure by using hardlinks to the actual headers.

## Changed

In this change we are adding an helper function that creates links between a source folder and a destination folder.

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D81778469

fbshipit-source-id: 3954bc219f32ea53744393a83f3179beeaca95b3
2025-09-22 10:14:58 -07:00
Riccardo CipolleschiandFacebook GitHub Bot 072b105f52 Add function to extract headers from a folder (#53737)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53737

This change add a utility function to extract headers (both .h and .hpp) from a folder. It also allow to exclude some specific folders (e.g.: `tests`, non supported platforms, ...)

## Context
SwiftPM is very picky in how the header structure must be.
In order to preserve the import/include statements as much as possible when building from source, we can recreate the header structure in a temporary folder inside the react-native package using symlinks.

In this way, users can still modify the headers and build RNTester and HelloWorld using SwiftPM without breaking changes.

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D82205692

fbshipit-source-id: 4fa6dee2ae4790c583beb96a959b0c3045c7b50a
2025-09-22 10:14:58 -07:00
Riccardo CipolleschiandFacebook GitHub Bot c1827fcd04 Add simple function to handle symlinks (#53736)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53736

This change adds a simple function that manages symlinks. This is used through the stack of changes to avoid code repetition.

## Context
SwiftPM is very picky in how the header structure must be.
In order to preserve the import/include statements as much as possible when building from source, we can recreate the header structure in a temporary folder inside the react-native package using symlinks.

In this way, users can still modify the headers and build RNTester and HelloWorld using SwiftPM without breaking changes.

## Changelog:
[Internal] -

Reviewed By: cortinico

Differential Revision: D82202860

fbshipit-source-id: 0baa348c84f966a2e1eeb85b008f8e653bffe96c
2025-09-22 10:14:58 -07:00
Nicola CortiandFacebook GitHub Bot 0915833f7c Follow-up from previous transform matrix fix (#53876)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53876

This is just a couple of small nits after D82836192

Changelog:
[Internal] [Changed] -

Reviewed By: javache

Differential Revision: D82953710

fbshipit-source-id: 1a98c54a110ee1a72225de331bfe2efa4e4225c0
2025-09-22 09:48:59 -07:00
Pieter De BaetsandFacebook GitHub Bot 57a1820c85 Remove unused RCTHermesInstance field (#53858)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53858

We only use static methods from `HermesInstance`

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D82816061

fbshipit-source-id: 515dad2e8d6e0a6f6ac26f93d5a86aedf875f93e
2025-09-22 08:47:33 -07:00
Nick LefeverandFacebook GitHub Bot e1a6c38cc1 Fix overflow with Props 2.0 in horizonal scroll view (#53872)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53872

This diff fixes the mismatch between the overflow initial value between the horizontal scroll view component initialization and the React core props instance initial value by applying the same correction as for the vertical scroll view component.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D82919365

fbshipit-source-id: 70e40f56ffa3ea87fa74035c885608f633890610
2025-09-22 04:19:36 -07:00
Nick LefeverandFacebook GitHub Bot e314f6161a Fix scrollview overflow prop not set with Props 2.0 (#53871)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53871

The props defined in `YogaStylableProps` define the overflow to be set to `Overflow::Visible` by default.

The scroll view initialized the overflow setting to `Overflow.SCROLL`. This meant that Props 2.0 would only set the overflow prop if it was different from Visible, leading to the scroll view not being configured correctly when asking for the overflow to be visible.

This diff assigns the correct initial value to the scrollview overflow setting only when enabling Props 2.0 to avoid any unexpected behavior changes when not using Props 2.0.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D82919286

fbshipit-source-id: d5368500cc4504164d6fdf7cf60042a9d5792853
2025-09-22 04:19:36 -07:00
Nicola CortiandFacebook GitHub Bot ce243df972 Correctly implement transform: matrix with 2d matrices (#53860)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53860

Fixes https://github.com/facebook/react-native/issues/53639

I've realized that our docs and validation logic states that we do support
3x3 matrixes (for 2d transforms). However they're not properly processed
as the values are just copied into a 4x4 matrix.

This can be verified by applying the 3x3 identity matrix on any transform.

I'm fixing it by correctly populating the 4x4 matrix getting the values from the 3x3 matrix in input.

Changelog:
[General] [Fixed] - 9-element (2d) transform matrix are not correctly working

Reviewed By: christophpurrer

Differential Revision: D82836192

fbshipit-source-id: 12029b37ffd8375fff48ea7f9386b849dfe96a62
2025-09-22 03:28:31 -07:00
David VaccaandFacebook GitHub Bot 23b2b99c4b Fix incorrect validation of feature flags in DefaultNewArchitectureEntryPoint.loadWithFeatureFlags() method (#53863)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53863

In this diff I'm fixing an incorrect validation of feature flags in DefaultNewArchitectureEntryPoint.loadWithFeatureFlags() method.

changelog: [internal] internal

Reviewed By: cortinico

Differential Revision: D82841006

fbshipit-source-id: 6f50f2475255d7b841d9224bc8808119dcc68aec
2025-09-22 02:34:59 -07:00
Sam ZhouandFacebook GitHub Bot 5ef054921c Turn on react.ref_as_prop=experimental.store_ref_in_props_but_remove_ref_in_react_element_config in fbsource (#53870)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53870

Changelog: [Internal]

Reviewed By: jbrown215

Differential Revision: D82913848

fbshipit-source-id: c23f564404143535622fab3133d092d1fb566711
2025-09-21 14:04:21 -07:00
Sam ZhouandFacebook GitHub Bot 71b7dd8519 Prepare createAnimatedComponent API for flow's upcoming better react 19 ref-as-prop support (#53869)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53869

This is a prep step to enable better Flow support for react 19 ref-as-prop. While it causes changes in the ReactNativeApi.d.ts snapshot, it should preserve the existing type behavior, since in the TS version, the ref prop will be excluded anyways: https://github.com/facebook/react-native/blob/a4d43290c82e8ad93f03b304a78cdf0eaf41fba1/packages/react-native/ReactNativeApi.d.ts#L1434

Changelog: [Internal]

Reviewed By: jbrown215

Differential Revision: D82916014

fbshipit-source-id: 2e62aab493dcf6f8f5e382c0739060c88e6f7ed5
2025-09-21 10:49:53 -07:00
Sam ZhouandFacebook GitHub Bot 5b544c7cd8 Simplify some RN types (#53868)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53868

This is a prep step to enable better Flow support for react 19 ref-as-prop. While it causes changes in the ReactNativeApi.d.ts snapshot, this diff simply inlines what these `React.ElementRef` evaluates into.

Changelog: [Internal]

Reviewed By: jbrown215

Differential Revision: D82915646

fbshipit-source-id: 64179eac7dde91381361fb9f1053d58100d864c3
2025-09-21 10:49:53 -07:00
Alex HuntandFacebook GitHub Bot a4d43290c8 Tweak Dev Menu appearance for iOS 26 (#53844)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53844

Small UI tweaks that help when scanning more visually spread out alert actions on iOS 26.

- Use bold (iOS 26 style) alert title.
- Differentiate "Cancel" actions with red system style.

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D82731784

fbshipit-source-id: 0a0215fc75a4832e742e22328d5e21eee3808972
2025-09-20 03:23:31 -07:00
Nikita LutsenkoandFacebook GitHub Bot 7fb90c3f1b jsi | Remove unnecessary semicolons. (#53864)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53864

Changelog: [Internal] Removed unnecessary semicolons, improving code quality.

Reviewed By: cortinico

Differential Revision: D82828986

fbshipit-source-id: aaafc332a1dc5944cb136bf6dd105d68c1c99e8d
2025-09-20 03:15:57 -07:00
Christoph PurrerandFacebook GitHub Bot 362ed179a8 Fix race condition between experimental_prefetchResources and surface stop (#53861)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53861

Changelog: [Internal]

The issue is a race condition in the React Native Fabric mounting system where `experimental_prefetchResources` is called on a `SurfaceMountingManager` after the surface has been stopped.

1.) `experimental_prefetchResources` is called
2.) Concurrently, `stopSurface()` *can be* called, which sets `mThemedReactContext = null`
3.) `experimental_prefetchResources` then tries to access `mThemedReactContext` via `Assertions.assertNotNull(mThemedReactContext)`
4.) Since `mThemedReactContext` is now `null`, the assertion fails and throws an AssertionError

The fix involves adding a guard to check if the surface is stopped before accessing `mThemedReactContext`

Follows existing patterns used by other methods in the same class

https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.java#L201-L213

Reviewed By: lenaic

Differential Revision: D82842572

fbshipit-source-id: 723bad24a075efa219766b0e148080dd42d59fba
2025-09-19 17:27:14 -07:00
Pieter De BaetsandFacebook GitHub Bot fcbe4d1677 Split off MessageQueueThread header to separate target (#53857)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53857

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D82625359

fbshipit-source-id: 7650dcd424299a21388c7bcf6c33c89b9f09171d
2025-09-19 14:02:47 -07:00
Christoph PurrerandFacebook GitHub Bot 390c9d30dc Update ## v0.82.0-rc.0 (#53847)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53847

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D82753924

fbshipit-source-id: a5a2036ccd74cc7f7dd463d82e96f156a4e309e2
2025-09-19 13:46:17 -07:00
Kræn HansenandFacebook GitHub Bot 0198c92c71 Export @react-native/typescript-config/strict shorthand (#53564)
Summary:
Extending a tsconfig seems simpler than adding `compilerOptions` with `customConditions`.

### Before

```jsonc
{
  "extends": "react-native/typescript-config",
  "compilerOptions": {
    // ...
    "customConditions": ["react-native-strict-api", "react-native"]
  }
}
```

### After

```jsonc
{
  "extends": "react-native/typescript-config/strict"
  // ...
}
```

## Changelog:

[GENERAL] [ADDED] - Add `react-native/typescript-config/strict` export enabling the `react-native-strict-api` custom condition.

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

Test Plan:
### `package.json`

```
{
  "name": "react-native-ts-test",
  "private": true,
  "version": "0.1.0",
  "scripts": {
    "build": "tsc --noEmit"
  },
  "devDependencies": {
    "react-native/typescript-config": "^0.81.1",
    "typescript": "^5.9.2",
    "jest": "^30.1.2"
  },
  "dependencies": {
    "react-native": "^0.81.1"
  }
}
```

### `tsconfig.json`

```
{
  "extends": "react-native/typescript-config/strict",
  "include": ["src/index.ts"]
}
```

### `src/index.ts`

```
import { View } from "react-native";
```

Run `npx resolution-explorer` and select "react-native from src/index.ts to node_modules/react-native/types_generated/index.d.ts" to verify the types are resolved correctly.

```
Explicitly specified module resolution kind: 'Bundler'.
Resolving in CJS mode with conditions 'import', 'types', 'react-native-strict-api'.
File '/Users/kraen.hansen/Repositories/react-native-ts-test/src/package.json' does not exist.
Found 'package.json' at '/Users/kraen.hansen/Repositories/react-native-ts-test/package.json'.
Loading module 'react-native' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration, JSON.
Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.
Directory '/Users/kraen.hansen/Repositories/react-native-ts-test/src/node_modules' does not exist, skipping all lookups in it.
Found 'package.json' at '/Users/kraen.hansen/Repositories/react-native-ts-test/node_modules/react-native/package.json'.
Entering conditional exports.
Matched 'exports' condition 'react-native-strict-api'.
Using 'exports' subpath '.' with target './types_generated/index.d.ts'.
File '/Users/kraen.hansen/Repositories/react-native-ts-test/node_modules/react-native/types_generated/index.d.ts' exists - use it as a name resolution result.
'package.json' has a 'peerDependencies' field.
Resolving real path for '/Users/kraen.hansen/Repositories/react-native-ts-test/node_modules/react-native', result
'/Users/kraen.hansen/Repositories/react-native-ts-test/node_modules/react-native'.
Failed to find peerDependency 'types/react'.
Found 'package.json' at '/Users/kraen.hansen/Repositories/react-native-ts-test/node_modules/react/package.json'.
Found peerDependency 'react' with '19.1.1' version.
Resolved under condition 'react-native-strict-api'.
Exiting conditional exports.
Resolving real path for '/Users/kraen.hansen/Repositories/react-native-ts-test/node_modules/react-native/types_generated/index.d.ts', result
'/Users/kraen.hansen/Repositories/react-native-ts-test/node_modules/react-native/types_generated/index.d.ts'.
======== Module name 'react-native' was successfully resolved to
'/Users/kraen.hansen/Repositories/react-native-ts-test/node_modules/react-native/types_generated/index.d.ts' with Package ID
'react-native/types_generated/index.d.ts@0.81.1+react@19.1.1'. ========
```

Reviewed By: robhogan

Differential Revision: D82791201

Pulled By: philIip

fbshipit-source-id: f58d3b8fcf3d7f18dd29eef18a3c8c0cb57d1d78
2025-09-19 13:28:31 -07:00
SimekandFacebook GitHub Bot 34cd61f0d5 fix C++ in-code docs comments to silence warnings (#53835)
Summary:
Address invalid C++ in-code docs comments to silence few warnings. Ref:
* https://www.doxygen.nl/manual/commands.html#cmdtparam

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[INTERNAL][FIXED] - Address invalid C++ in-code docs comments to silence the warnings.

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

Test Plan: Building RNTester app locally does not output the warnings related to in-code docs comments.

Reviewed By: cortinico

Differential Revision: D82791099

Pulled By: philIip

fbshipit-source-id: 2f93bfd4cd303471b2c52fcdf74871e5dee8c06a
2025-09-19 13:12:23 -07:00
David VaccaandFacebook GitHub Bot e349009cb8 Refactor ReactNativeNewArchitectureFeatureFlagsDefaults to remove legacy architecture configuration (#53791)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53791

I'm removing parameter to configure new architecture in ReactNativeNewArchitectureFeatureFlagsDefaults because the new architecture is enabled by default everywhere.

changelog: [internal] internal

Reviewed By: cortinico

Differential Revision: D82241552

fbshipit-source-id: 9c5cee4befc914d95b84b01325485923e17ff6da
2025-09-19 13:01:08 -07:00
David VaccaandFacebook GitHub Bot f847496749 Refactor ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android to enable new arch (#53790)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53790

New architecture should we enabled by default everywhere, Stable releases should use new arch now

changelog: [internal] internal

Reviewed By: cortinico

Differential Revision: D82241551

fbshipit-source-id: 2a1bf14f2f1da6e441a58b083ca5a55618eec256
2025-09-19 13:01:08 -07:00
Sam ZhouandFacebook GitHub Bot 2590cd739a Deploy 0.284.0 to xplat
Summary:
[changelog](https://github.com/facebook/flow/blob/main/Changelog.md)
Changelog: [Internal]

Reviewed By: marcoww6

Differential Revision: D82786580

fbshipit-source-id: 8caa7802025004fce6cb5067c191b681087cb979
2025-09-19 07:33:42 -07:00
Sam ZhouandFacebook GitHub Bot 7ba64ca0f1 Pre-suppress errors for improved typing of Array.{includes,indexOf,lastIndexOf} in xplat
Summary:
In Flow 0.284, we will have a stricter version of `Array<T>.includes`. Instead of accepting `mixed`, we will only accept `T` to help catch logical errors. We did the same for `Array.indexOf` and `Array.lastIndexOf` as well.

This diff pre-suppresses newly discovered errors in part of the codebase.

Changelog: [Internal]

Reviewed By: marcoww6

Differential Revision: D82784398

fbshipit-source-id: 6cb11809844f964e0604d33b9f7a3989074cd1cc
2025-09-19 07:17:14 -07:00
Ruslan LesiutinandFacebook GitHub Bot 0e77015a85 Fix unkown name for Timestamps on Timings track (#53854)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53854

# Changelog: [Internal]

This fixes the unkown names message for TimeStamps on Timings track

Reviewed By: rubennorte

Differential Revision: D82812849

fbshipit-source-id: 91101998b4b7befa08bf0e45cae494765d5f2b6d
2025-09-19 06:53:23 -07:00
Ruslan LesiutinandFacebook GitHub Bot 1b5e8e63b6 Manually preserve ordering for Scheduler and Components tracks (#53853)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53853

# Changelog: [Internal]

Chrome DevTools orders tracks based on the timestamp of the first entry.

For React on Web we emit a few entries to establish the ordering:
https://github.com/facebook/react/blob/6eda534718d09a26d58d65c0a376e05d7e2a3358/packages/react-reconciler/src/ReactFiberPerformanceTrack.js#L57-L96

We are doing the same thing here, but in C++.

Reviewed By: rubennorte

Differential Revision: D82811889

fbshipit-source-id: cfc4060de05a3d74e240f019dbeaa910fa93eb0b
2025-09-19 06:53:23 -07:00
Tim YungandFacebook GitHub Bot 03d9f34a82 RN: Deprecate InteractionManager (#53832)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53832

Deprecates `InteractionManager` by adding a warning when it is imported.

Changelog:
[General][Changed] - InteractionManager has been deprecated and no longer respects interaction handles. Instead, it is now recommended to avoid executing long-running JavaScript tasks by breaking them up into smaller tasks and scheduling them using `requestIdleCallback()`.

Reviewed By: javache

Differential Revision: D82704809

fbshipit-source-id: 99474cd7949abfe323c366b9ab8d8fc195578395
2025-09-19 05:10:47 -07:00
Tim YungandFacebook GitHub Bot 4a1388268d RN: Remove References to InteractionManager (#53830)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53830

Now that `InteractionManager` is deprecated (and no-ops), this removes all remaining references to it — in `Animated` and `PanResponder` — from the React Native repository.

Changelog:
[Internal]

Reviewed By: javache

Differential Revision: D82690242

fbshipit-source-id: d101d47d1f8640f70e2d199492d4345b63663251
2025-09-19 05:10:47 -07:00
generatedunixname1395667395051502andFacebook GitHub Bot b821bc3aba Update React Native DevTools binaries
Summary:
Automated update of React Native DevTools binaries
bypass-github-export-checks
Changelog: [Internal]

Reviewed By: robhogan

Differential Revision: D82813624

fbshipit-source-id: 51fe7a84af2d4f2da7027e1649ec038517f9d561
2025-09-19 04:53:33 -07:00
Moti ZilbermanandFacebook GitHub Bot e16b6470e4 Backout D82236159: [RN][debugger-shell] Implement saved window positioning per target (#53816)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53816

Changelog: [Internal]

D82236159 introduced the first `node_modules` dependency in the Electron part of `react-native/debugger-shell`. This is not currently handled correctly by the build script, so this resulted in an instacrashing binary.

I'm temporarily backing out D82236159 until we have a proper fix for the build script.

Reviewed By: robhogan

Differential Revision: D82632937

fbshipit-source-id: 6c7c182e2a7c89e6ea2761096dcc426dbf2ae5cb
2025-09-19 02:38:00 -07:00
Alex HuntandFacebook GitHub Bot cb7453fb9f Improve Network trace event field coverage (#53840)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53840

After this diff, successful network events are displayed as fully hydrated timespans in the Performance panel network track, with all metadata needed to usefully populate the UI.

**Changes**

Adds:
- `"ResourceFinish"`: `encodedDataLength`, `decodedBodyLength`
- `"ResourceReceiveResponse"`: Populates `data.timing` members, which enables *"Request sent and waiting"* to be rendered correctly in the timeline.

Removes:

- `"ResourceWillSendRequest"` events — very rarely emitted by Chrome and are extraneous for our use case.

Changelog: [Internal]

Reviewed By: hoxyq

Differential Revision: D82636798

fbshipit-source-id: a4b0f0671b97aaadc279ac56d39fee0c95d4ddc7
2025-09-18 14:41:16 -07:00
nishan (o^▽^o)andFacebook GitHub Bot c8e5f9766b fix(iOS): boxShadow + overflow hidden combination affecting pointer event box-none and scale transform. (#52413)
Summary:
This issue is only reproducible with combination of `overflow: hidden` and `boxShadow` i.e. when a [container view](https://github.com/facebook/react-native/blob/2ce7eab5f998788ffa8346b63cc4901d026456ba/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm#L799) is added to the hierarchy.

### Case 1:

```jsx
<Pressable
  pointerEvents="box-none"
  style={{ width: 300, height: 300, boxShadow: "0 0 100px 0 rgba(0, 0, 0, 0.5)", overflow: "hidden" }}
  onPress={() => {
    alert("Tapped");
  }}
/>
```

Here the view has `box-none` but it will still trigger the press event because this [line](https://github.com/facebook/react-native/blob/2ce7eab5f998788ffa8346b63cc4901d026456ba/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm#L658) returns the `_containerView` as `hitView` and this condition gets [fullfilled](https://github.com/facebook/react-native/blob/2ce7eab5f998788ffa8346b63cc4901d026456ba/packages/react-native/React/Fabric/Mounting/ComponentViews/View/RCTViewComponentView.mm#L676) (since it is not self). To fix this issue we should iterate on `self.currentContainerView.subviews`.

### Case 2:

Transform scale clipping child view.

```jsx
<Pressable
  pointerEvents="box-none"
  style={{ width: 300, height: 300, overflow: "hidden",
    transform: [
      { scale: 0.5 },
    ],
    boxShadow: "0 0 100px 0 rgba(0, 0, 0, 0.5)",
  }}
  onPress={() => {
    alert("parent view");
  }}
>
  <Pressable
    style={{
      position: "absolute",
      bottom: 0,
      right: 0,
      backgroundColor: "blue",
      height: 50,
      width: 100,
    }}
    onPress={() => {
      alert("child view");
    }}
  >
    <Text>Press me</Text>
  </Pressable>
</Pressable>;
```

The above style hides the child view on iOS whereas it is visible on android.

| iOS | Android |
   |---|---|
   | <img src="https://github.com/user-attachments/assets/14713ec9-1ae7-4425-9348-946d507188e8" width="200px" /> | <img src="https://github.com/user-attachments/assets/0f6e2368-037d-4b03-8a85-8a08f1578ff6" width="200px" /> |

This happens because `containerView` uses `self.frame` property which gets mutated due to scale transform. So containerView becomes `actualSize * scale * scale` instead of `actualSize * scale` and ends up clipping child views because of overflow hidden. Please checkout the layout hierarchy in the below screenshot. To fix it we need to use `self.bounds` instead of `self.frame` when setting the frame for container.

<img src="https://github.com/user-attachments/assets/9ce41756-f41f-4782-bfc9-b0c281f314b7" width="300px" />

## Changelog:

[IOS] [FIXED] - boxShadow + overflow hidden combination interfering with pointerEvents and transform scale.

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests

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

Test Plan:
Test above example snippets and pointer events examples in RNTester.

cc - joevilches

Reviewed By: cortinico, jorge-cab

Differential Revision: D77872110

Pulled By: joevilches

fbshipit-source-id: e9693c79b47379531510607921ffaa6d6cc5c17b
2025-09-18 14:06:00 -07:00
Nicola CortiandFacebook GitHub Bot 1c5e0ffd9f Do not reset the native artifacts version to 1000.0.0 on release branches (#53817)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53817

What is currently happening, is that the various commits on the release branches like `0.82-stable` are resetting the version of native artifacts to `1000.0.0-<SHA>`.

The reason is that during the `test-all` workflow, we pass the `dry-run` as release type.
That's to prevent the various tools from calling `npm publish` and so on.

The problem is that on the releases branches, the version was already set at branch cut time.
Therefore, we see the version 1000.0.0 reappearing during Android E2E test in the emulator. Similary this is also affecting iOS prebuilds so I'm attempting to fix it here.

Changelog:
[Internal] [Changed] -

Reviewed By: huntie

Differential Revision: D82553599

fbshipit-source-id: 31a52e7df036e700663b3d3dd677973a7a210a30
2025-09-18 10:53:25 -07:00
Alex HuntandFacebook GitHub Bot 5b8827939d Support additional PerformanceResourceTiming fields (#53815)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53815

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D82561777

fbshipit-source-id: f387c4bca2112111e736433af90ada16efd14e8b
2025-09-18 09:57:25 -07:00
Andrew DatsenkoandFacebook GitHub Bot e97ef8f1fb Fix dotslash issue in OD (#53842)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53842

Changelog: [Internal]
There is a conflict between dotslash in node_modules and in OD it does not invoke buck2

Reviewed By: javache

Differential Revision: D82724326

fbshipit-source-id: c90cab58818e0245f8763b729c7e5432735eb05e
2025-09-18 07:39:22 -07:00
Nick LefeverandFacebook GitHub Bot e6390703e7 Fix scroll view FPS listener reset on init (#53838)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53838

The FPS listener is being assigned to all scroll view instances by the scroll view manager. This listener should not be reset when the view is being recycled and should stay assigned at all times.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D82720151

fbshipit-source-id: a2a37bad93efaa6e435725adf16c9ad1b4207ba0
2025-09-18 05:35:09 -07:00
generatedunixname537391475639613andFacebook GitHub Bot aacb9898f2 xplat/js/react-native-github/packages/react-native/ReactCommon/react/utils/TemplateStringLiteral.h (#53836)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53836

Reviewed By: rshest

Differential Revision: D82428779

fbshipit-source-id: 2716784a85c4885fe438348666b4772c2da3c400
2025-09-18 04:56:38 -07:00
Nicola CortiandFacebook GitHub Bot 460394e4b8 Turn on enableSwiftUIBasedFilters in the experimental channel (#53794)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53794

Basically what the title says. This is needed by Expo for experimetation.

Changelog:
[Internal] [Changed] -

Reviewed By: joevilches

Differential Revision: D82530292

fbshipit-source-id: 82ce8b1e8fc8d954cc04ec456ad80f769aedafe7
2025-09-18 04:34:47 -07:00
Nicola CortiandFacebook GitHub Bot 968ec9e093 Unpin version from react-native-android in run_fantom_tests (#53795)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53795

I've published another docker image that should now work and unblock `run_fantom_tests`
so we don't need to pin the version to `v18.0` anymore:
https://github.com/react-native-community/docker-android

Changelog:
[Internal] [Changed] -

Reviewed By: huntie

Differential Revision: D82532516

fbshipit-source-id: 980c2feb053f9d096e70f37bb690e18cc8b87dc0
2025-09-18 04:12:50 -07:00
Alex HuntandFacebook GitHub Bot 6ef351b3ce Move trace event handling into NetworkReporter (#53776)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53776

Refactor and improve how we emit CDP trace events for network requests.

Key changes:
- Split up `PerformanceTracer` methods into discrete trace events.
- Move event calls out of `PerformanceEntryReporter` (upwards) into `NetworkReporter`. This now:
    - Aligns better with the matching source `NetworkReporter` events.
    - Removes metadata pieces from `PerformanceEntryReporter` that weren't part of the Web `PerformanceResourceTiming` API.
- Populate additional fields on `ResourceReceiveResponse`.

Changelog: [Internal]

Reviewed By: hoxyq

Differential Revision: D82433225

fbshipit-source-id: 4fce219f0c86a7257b8df250ef9f2b4ec8bd8de3
2025-09-18 03:01:22 -07:00
Jakub PiaseckiandFacebook GitHub Bot 674fb77d93 Update coordinates for remote artifacts of Hermes V1 (#53822)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53822

Changelog: [GENERAL][FIXED] - Fixed coordinates for Hermes V1 artifacts

Reviewed By: cortinico

Differential Revision: D82639319

fbshipit-source-id: becfab3248f2314af97549eb94feb27b19f5d1af
2025-09-18 01:26:08 -07:00
Devan BuggayandFacebook GitHub Bot 14458d8699 Add focus/blur commands to View (#53828)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53828

Adds focus and blur commands to Android views.

Changelog: [Internal]

Reviewed By: rozele

Differential Revision: D82644681

fbshipit-source-id: 96fa6370e177c91742d285b0b158b77447d105f6
2025-09-18 00:36:55 -07:00
Devan BuggayandFacebook GitHub Bot 2945fa6e0e Hook up focus/blur events (#53827)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53827

Hook up focus/blur events to view.

Changelog: [Internal]

Reviewed By: rozele

Differential Revision: D82146291

fbshipit-source-id: 3cb90d22c00d067099c4c6fac734f27030d87639
2025-09-18 00:36:55 -07:00
Devan BuggayandFacebook GitHub Bot 07b5802ee5 focus/blur event emission (#53826)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53826

Wires up focus/blur events to the base event emitter, gated by enabledImperativeFocus feature flag.

https://docs.google.com/document/d/1L4ViBnXq5hw858VoecZPmJE2llOB97Tjs2VtJ7RHlNI/edit?tab=t.0

Changelog: [Internal]

Reviewed By: rozele

Differential Revision: D82146275

fbshipit-source-id: 4b7bb1336f74bb0de2d7ecf0737dd63067bd558f
2025-09-18 00:36:55 -07:00
Devan BuggayandFacebook GitHub Bot 3e5838086f Add focus/blur commands to View (#53825)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53825

Adds focus/blur commands to View on iOS.
https://docs.google.com/document/d/1L4ViBnXq5hw858VoecZPmJE2llOB97Tjs2VtJ7RHlNI/edit?tab=t.0#heading=h.azm4b33t75uk

Changelog: [Internal]

Reviewed By: rozele

Differential Revision: D82146249

fbshipit-source-id: 582f448f4d7525560ef74a23c0762e86d74550d4
2025-09-18 00:36:55 -07:00
Devan BuggayandFacebook GitHub Bot 596dece4c0 enableImperativeFocus feature flag (#53824)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53824

Creates a new feature flag to control focus/blur commands and event emissions for arbitrary views https://docs.google.com/document/d/1L4ViBnXq5hw858VoecZPmJE2llOB97Tjs2VtJ7RHlNI/edit?tab=t.0#heading=h.azm4b33t75uk

Changelog: [Internal]

Reviewed By: Abbondanzo

Differential Revision: D82146210

fbshipit-source-id: 59f3e6c8740b0c006f8930541205aa15192a9f59
2025-09-18 00:36:55 -07:00
Sam ZhouandFacebook GitHub Bot 4d2e38edd9 Deploy 0.283.0 to xplat (#53820)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53820

[changelog](https://github.com/facebook/flow/blob/main/Changelog.md)
Changelog: [Internal]

Reviewed By: panagosg7

Differential Revision: D82636194

fbshipit-source-id: 620016043bed481e43d0d4216280517c2890bfd7
2025-09-17 09:29:52 -07:00
React Native BotandFacebook GitHub Bot 926af3bc36 Add changelog for v0.82.0-rc.3 (#53813)
Summary:
Add Changelog for 0.82.0-rc.3

## Changelog:
[Internal] - Add Changelog for 0.82.0-rc.3

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

Test Plan: N/A

Reviewed By: cortinico

Differential Revision: D82628336

Pulled By: vzaidman

fbshipit-source-id: 2ade8a48981a70e571e7a8db0e15af0c722f82ba
2025-09-17 06:03:11 -07:00
Vitali ZaidmanandFacebook GitHub Bot de4e01bcc6 add the nodejs type for process.memoryUsage.rss() (#53805)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53805

Changelog: [Internal]

https://nodejs.org/docs/latest-v24.x/api/process.html#processmemoryusagerss

Reviewed By: huntie

Differential Revision: D82550739

fbshipit-source-id: 11026fb82608e004b10426776592f22e67eb0720
2025-09-17 01:24:59 -07:00
Marco WangandFacebook GitHub Bot 7d73d39535 Deploy 0.282.0 to xplat (#53810)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53810

[changelog](https://github.com/facebook/flow/blob/main/Changelog.md)
Changelog: [Internal]

Reviewed By: SamChou19815

Differential Revision: D82597378

fbshipit-source-id: 40d601956d9f69ec8d68a2c324bb3449ee27c931
2025-09-16 23:32:23 -07:00
Eric RozellandFacebook GitHub Bot eba38b831c Fix DefaultNewArchitectureEntryPoint config validation (#53807)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53807

We need to read the values off feature flags before checking them.

## Changelog
[Internal]

Reviewed By: javache

Differential Revision: D82572898

fbshipit-source-id: 09fbc09570c78b41d9c25fb03c5557e390da7cae
2025-09-16 20:20:14 -07:00
David VaccaandFacebook GitHub Bot 18cb4edfa7 Ensure legacy architecture can't be initialized in Android (#53806)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53806

The Legacy architecture of React Native is not supported anymore, let's ensure nobody can initialize it anymore

changelog: [internal] internal

Reviewed By: cortinico

Differential Revision: D82465004

fbshipit-source-id: 099764fb59d906b11cf6ad0cc6208f56df029d19
2025-09-16 17:33:14 -07:00
Sam ZhouandFacebook GitHub Bot dadd7cdaf7 Make ref prop optional in xplat: 1/n (#53801)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53801

Changelog: [Internal]

Reviewed By: panagosg7

Differential Revision: D82507711

fbshipit-source-id: 27c8004c0475765705a01c0b6afb274dab443a38
2025-09-16 09:10:22 -07:00
Tom ScallonandFacebook GitHub Bot 4308185b64 Allow EventEmitters to be reported as optional (#53804)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53804

## Changelog:

[General] [Fixed] - Allow `EventEmitter`s to be optional (for push safety)

Reviewed By: javache

Differential Revision: D82509571

fbshipit-source-id: 801a22b10b2709968009527130cfa890d30a4f3a
2025-09-16 08:59:12 -07:00
Nicola CortiandFacebook GitHub Bot d0d08e4554 Runtime check that NewArchitecture is enabled in DefaultNewArchitectureEntryPoint (#53780)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53780

This is a commit we're going to pick in 0.82 as we want to make sure users cannot invoke `load()`
from `DefaultNewArchitectureEntryPoint` with flags that are not true,true,true.

Changelog:
[Android] [Changed] - Runtime check that NewArchitecture is enabled in DefaultNewArchitectureEntryPoint

Reviewed By: mdvacca

Differential Revision: D82456975

fbshipit-source-id: 749996a3491913cfe400173608218077c3ffbc10
2025-09-16 07:30:55 -07:00
Nicola CortiandFacebook GitHub Bot 4858a0f469 Mark ReactTextInlineImageShadowNode as @LegacyArchitecture (#53735)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53735

This class should have been marked as LegacyArchitecture back then but was forgotten.
I'm doing it now.

Changelog:
[Internal] -

Reviewed By: javache

Differential Revision: D82219780

fbshipit-source-id: 5119b7469733d5d2d4b16e976b09231ad5f71f5f
2025-09-16 07:23:51 -07:00
Vitali ZaidmanandFacebook GitHub Bot f93506fb23 Fix typo in CHANGELOG.md (#53796)
Summary:
Fix typo in CHANGELOG.md

Changelog: [INTERNAL]

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

Test Plan: Fix typo in CHANGELOG.md

Reviewed By: fabriziocucci

Differential Revision: D82535096

Pulled By: vzaidman

fbshipit-source-id: fe93adf86ff48f0095312edbfce7b3ae6984198a
2025-09-16 06:49:03 -07:00
Moti ZilbermanandFacebook GitHub Bot f4aef39563 Revert D82459089: Update React Native DevTools binaries
Differential Revision:
D82459089

Original commit changeset: 3ccf7a1f07da

Original Phabricator Diff: D82459089

fbshipit-source-id: 9ab8827bfb534e5236c37a8a47206f891741a8e0
2025-09-16 05:33:44 -07:00
Ruslan LesiutinandFacebook GitHub Bot af7fc1b424 Update debugger-frontend from 5a792db...8b84a77 (#53789)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/53789

Changelog: [Internal] - Update `react-native/debugger-frontend` from 5a792db...8b84a77

Resyncs `react-native/debugger-frontend` from GitHub - see `rn-chrome-devtools-frontend` [changelog](https://github.com/facebook/react-native-devtools-frontend/compare/5a792db1225adda206313e9bf751198a1ca7851a...8b84a77b2c82c670886ef064dfc92d6bce83e579).

### Changelog

| Commit | Author | Date/Time | Subject |
| ------ | ------ | --------- | ------- |
| [8b84a77b2](https://github.com/facebook/react-native-devtools-frontend/commit/8b84a77b2) | Ruslan Lesiutin (28902667+hoxyq@users.noreply.github.com) | 2025-09-15T17:28:39+01:00 | [fix: avoid race conditions when fetching background trace (#206)](https://github.com/facebook/react-native-devtools-frontend/commit/8b84a77b2) |
| [95bd36ce9](https://github.com/facebook/react-native-devtools-frontend/commit/95bd36ce9) | Ruslan Lesiutin (28902667+hoxyq@users.noreply.github.com) | 2025-09-15T14:45:07+01:00 | [feat: use application display name for trace title (#207)](https://github.com/facebook/react-native-devtools-frontend/commit/95bd36ce9) |

Reviewed By: huntie

Differential Revision: D82464061

fbshipit-source-id: c33db7a535a148f8316730009580aef00afe04f1
2025-09-16 05:18:00 -07:00
Zeya PengandFacebook GitHub Bot 8d03e63265 Revert D82461457: Clean up batchingControlledByJS in NativeAnimated kotlin
Differential Revision:
D82461457

Original commit changeset: a1208720b83e

Original Phabricator Diff: D82461457

fbshipit-source-id: 99416873f66c45ccf61614d3e356e6a777bbad6b
2025-09-16 03:39:45 -07:00
217 changed files with 4856 additions and 2645 deletions
+1 -1
View File
@@ -98,4 +98,4 @@ untyped-import
untyped-type-import
[version]
^0.281.0
^0.286.0
+3
View File
@@ -17,6 +17,9 @@ runs:
- name: Install node dependencies
uses: ./.github/actions/yarn-install
- name: Set React Native Version
# We don't want to set the version for stable branches, because this has been
# already set from the 'create release' commits on the release branch.
if: ${{ !endsWith(github.ref_name, '-stable') }}
shell: bash
run: node ./scripts/releases/set-rn-artifacts-version.js --build-type ${{ inputs.release-type }}
- name: Setup gradle
+1 -2
View File
@@ -383,8 +383,7 @@ jobs:
runs-on: 8-core-ubuntu
needs: [set_release_type]
container:
# Version is pinned to v18.0 to unblock `run_fantom_tests` - see https://github.com/react-native-community/docker-android/pull/242#issuecomment-3280029122
image: reactnativecommunity/react-native-android:v18.0
image: reactnativecommunity/react-native-android:latest
env:
TERM: "dumb"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
+1
View File
@@ -133,6 +133,7 @@ vendor/
# Swift Package build folder
/packages/react-native/.build
/packages/react-native/.swiftpm
/packages/react-native/React/includes/
# @react-native/codegen
/packages/react-native/React/FBReactNativeSpec/
+38 -2
View File
@@ -1,5 +1,40 @@
# Changelog
## v0.81.4
### Fixed
#### iOS specific
- Fix regression that skips artifacts code generation ([f6f5ea0b2e](https://github.com/facebook/react-native/commit/f6f5ea0b2eed894725d8f6e8bd045c99c3182026) by [@kitten](https://github.com/kitten))
- Reapplied "Use autolinking-generated react-native-config output in second step of cocoapods linking that generates artifacts and generated source" ([bb73315a3f](https://github.com/facebook/react-native/commit/bb73315a3fd8cd203c4ddb3ffa10bfec307c7e92) by [@kitten](https://github.com/kitten))
## v0.82.0-rc.4
### Fixed
- **Hermes V1:** Fixed coordinates for Hermes V1 artifacts ([674fb77d93](https://github.com/facebook/react-native/commit/674fb77d93dfe67a5fe90449dc71b195b1851e13) by [@j-piasecki](https://github.com/j-piasecki))
#### iOS specific
- **Switch:** Fix Switch layout to work with iOS26 ([91d427fe52](https://github.com/facebook/react-native/commit/91d427fe52a307f9aa8579912ef956d61808dad2) by [@cipolleschi](https://github.com/cipolleschi))
## v0.82.0-rc.3
### Added
- **Hermes V1:** Added a dependency on hermes-compiler ([0caf8e70d5](https://github.com/facebook/react-native/commit/0caf8e70d53f611a73ad9b55879dfe0a5f036371) by [@j-piasecki](https://github.com/j-piasecki))
### Fixed
#### Android specific
- **Hermes V1:** Changed the coordinates of hermes artifacts when using Hermes V1 ([d0fb33822d](https://github.com/facebook/react-native/commit/d0fb33822de38183895c8b3421f46966909beaf3) by [@j-piasecki](https://github.com/j-piasecki))
#### iOS specific
- **Codegen:** Fix regression that skips artifacts code generation ([f6f5ea0b2e](https://github.com/facebook/react-native/commit/f6f5ea0b2eed894725d8f6e8bd045c99c3182026) by [@kitten](https://github.com/kitten))
## v0.81.3
### Fixed
@@ -66,6 +101,7 @@
- **Error Handling:** Unhandled promises are now handled by ExceptionsManager.handleException, instead of being swallowed as Logbox Warnings. ([c4082c9ce2](https://github.com/facebook/react-native/commit/c4082c9ce208a324c2d011823ca2ba432411aafc) by [@krystofwoldrich](https://github.com/krystofwoldrich))
- **`shouldEmitW3CPointerEvents`:** Migrate `shouldPressibilityUseW3CPointerEventsForHover` to common private feature flags and remove `shouldEmitW3CPointerEvents` flag. ([fb4587780e](https://github.com/facebook/react-native/commit/fb4587780e8d6111139d73598a9a26ff392dee28) by [@coado](https://github.com/coado))
- **TurboModuleUtils:** Remove unused ReactCommon/TurboModuleUtils functions #deepCopyJSIObject and #deepCopyJSIArray ([ead669ade3](https://github.com/facebook/react-native/commit/ead669ade31ee703c407f96c0ce98d8f2991bdc8) by [@christophpurrer](https://github.com/christophpurrer))
- **TurboModules:** Delete old location of CallbackWrapper.h / LongLivedObject.h by ([cb94e71](https://github.com/facebook/react-native/commit/cb94e71845259ae7fa823eb4d21cde74fccd7435) [@christophpurrer](https://github.com/christophpurrer))
#### Android specific
@@ -80,7 +116,7 @@
### Added
- **Animated:** `Animated.CompositeAnomation` is now exposed when using `"react-native-strict-api"` ([024d25794a](https://github.com/facebook/react-native/commit/024d25794a51c94c877c1dfa115a82ebbf559614) by [@huntie](https://github.com/huntie))
- **Animated:** `Animated.CompositeAnimation` is now exposed when using `"react-native-strict-api"` ([024d25794a](https://github.com/facebook/react-native/commit/024d25794a51c94c877c1dfa115a82ebbf559614) by [@huntie](https://github.com/huntie))
- **Animated:** Allow calling createAnimatedNode without batching ([d9d9a49e18](https://github.com/facebook/react-native/commit/d9d9a49e18f3c51caa18cf7da0a1fcd62f1ecf18) by [@zeyap](https://github.com/zeyap))
- **Animated:** Allow filter usage with native animated driver. ([138d0eb01d](https://github.com/facebook/react-native/commit/138d0eb01dbe597261459a37d364d1780c3ef228) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
- **API:** Expose NativeComponentRegistry API as JavaScript root export ([f936780cd5](https://github.com/facebook/react-native/commit/f936780cd5c0c17797f9d2bbc8f5cee81c2eefce) by [@zhongwuzw](https://github.com/zhongwuzw))
@@ -117,7 +153,7 @@
- **AGP:** AGP to 8.12.0 ([742ef3d661](https://github.com/facebook/react-native/commit/742ef3d6615c8c1202e9f683e6127ac97d7a9e23) by [@cortinico](https://github.com/cortinico))
- **DevSupportManager:** DevSupport `openDebugger()` methods now accept a `panel: String?` param. Frameworks directly implementing `DevSupportManager` will need to adjust call signatures. ([9dba7112cf](https://github.com/facebook/react-native/commit/9dba7112cfd09b02300869a77dba3dca16f49a28) by [@huntie](https://github.com/huntie))
- **Kotlin:**Migrated TextAttributeProps to Kotlin. You might need to update your property access to use camelCase instead of Hungarian notation. ([fa921b3c7b](https://github.com/facebook/react-native/commit/fa921b3c7b289800a79196468f993a0eb0bf693f) by [@mateoguzmana](https://github.com/mateoguzmana))
- **Kotlin:** Migrated TextAttributeProps to Kotlin. You might need to update your property access to use camelCase instead of Hungarian notation. ([fa921b3c7b](https://github.com/facebook/react-native/commit/fa921b3c7b289800a79196468f993a0eb0bf693f) by [@mateoguzmana](https://github.com/mateoguzmana))
- **Kotlin:** Migrated ReactBaseTextShadowNode to Kotlin. You might need to update your property access to use camelCase instead of Hungarian notation. ([8ccfff9a46](https://github.com/facebook/react-native/commit/8ccfff9a46f317fd78f478c8b3f180441535d1ca) by [@mateoguzmana](https://github.com/mateoguzmana))
- **Kotlin:** Migrated com.facebook.react.bridge.Arguments to Kotlin. ([2534aeaddb](https://github.com/facebook/react-native/commit/2534aeaddb0490b69dfaba6b8d316616c7e10a9c) by [@mateoguzmana](https://github.com/mateoguzmana))
- **Kotlin:** Migrate `YogaConfig` to Kotlin ([4d5caef76b](https://github.com/facebook/react-native/commit/4d5caef76b83eb7e983364ecc81abb6027e5f98e) by [@mateoguzmana](https://github.com/mateoguzmana))
+19 -16
View File
@@ -3057,30 +3057,30 @@ type util$InspectOptions = {
};
declare type util$ParseArgsOption =
| {|
| $ReadOnly<{|
type: 'boolean',
multiple?: false,
short?: string,
default?: boolean,
|}
| {|
|}>
| $ReadOnly<{|
type: 'boolean',
multiple: true,
short?: string,
default?: Array<boolean>,
|}
| {|
|}>
| $ReadOnly<{|
type: 'string',
multiple?: false,
short?: string,
default?: string,
|}
| {|
|}>
| $ReadOnly<{|
type: 'string',
multiple: true,
short?: string,
default?: Array<string>,
|};
|}>;
type util$ParseArgsOptionToValue<TOption> = TOption['type'] extends 'boolean'
? TOption['multiple'] extends true
@@ -3137,7 +3137,7 @@ declare module 'util' {
declare function stripVTControlCharacters(str: string): string;
declare function parseArgs<
TOptions: {[string]: util$ParseArgsOption} = {||},
TOptions: {+[string]: util$ParseArgsOption} = {||},
>(config: {|
args?: Array<string>,
options?: TOptions,
@@ -3995,13 +3995,16 @@ declare class Process extends events$EventEmitter {
initgroups?: (user: number | string, extra_group: number | string) => void;
kill(pid: number, signal?: string | number): void;
mainModule: Object;
memoryUsage(): {
arrayBuffers: number,
rss: number,
heapTotal: number,
heapUsed: number,
external: number,
...
memoryUsage: {
(): {
arrayBuffers: number,
rss: number,
heapTotal: number,
heapUsed: number,
external: number,
...
},
rss: () => number,
};
nextTick: <T>(cb: (...T) => mixed, ...T) => void;
pid: number;
-41
View File
@@ -1,41 +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.
*
* @flow
* @format
*/
declare module 'electron-store' {
declare export type Schema = any;
declare export type Options = {
+name?: string,
defaults?: Object,
schema?: any,
migrations?: any,
beforeEachMigration?: any,
clearInvalidConfig?: boolean,
serialize?: any,
deserialize?: any,
accessPropertiesByDotNotation?: boolean,
watch?: boolean,
encryptionKey?: string | Buffer | $ReadOnlyArray<number>,
...
};
declare class ElectronStore {
constructor(options?: Options): this;
get(key: string): any;
get(key: string, defaultValue: any): any;
set(key: string, value: any): void;
set(object: Object): void;
has(key: string): boolean;
delete(key: string): void;
clear(): void;
}
declare module.exports: Class<ElectronStore>;
}
+1 -1
View File
@@ -86,7 +86,7 @@
"eslint-plugin-relay": "^1.8.3",
"fb-dotslash": "0.5.8",
"flow-api-translator": "0.32.0",
"flow-bin": "^0.281.0",
"flow-bin": "^0.286.0",
"glob": "^7.1.1",
"hermes-eslint": "0.32.0",
"hermes-transform": "0.32.0",
@@ -119,7 +119,6 @@ async function runServer(
watchFolders,
});
const {middleware, websocketEndpoints} = createDevMiddleware({
projectRoot,
serverBaseUrl: devServerUrl,
logger: createDevMiddlewareLogger(terminalReporter),
});
+2 -2
View File
@@ -1,5 +1,5 @@
@generated SignedSource<<0b54f75686e4893a5444839bf621a317>>
Git revision: 5a792db1225adda206313e9bf751198a1ca7851a
@generated SignedSource<<d090ed9a9e781c82884f22944254ed65>>
Git revision: 8b84a77b2c82c670886ef064dfc92d6bce83e579
Built with --nohooks: false
Is local checkout: false
Remote URL: https://github.com/facebook/react-native-devtools-frontend
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,71 +1,71 @@
#!/usr/bin/env dotslash
// @generated SignedSource<<9df662721aea6e3774a8677e2a6065e4>>
// @generated SignedSource<<80974ea6ac4427cf5fd9f14f6779b5c6>>
{
"name": "React Native DevTools",
"platforms": {
"linux-aarch64": {
"size": 116056584,
"size": 116072551,
"hash": "sha256",
"digest": "fac3912f10e3c373c874be6c4696f11e05cbaa754c116db6ea72189afae5efe6",
"digest": "3fd69eff02f4a41818a7ecb252ab0de449fa1f88fe0dd1de474bd15dd2e63856",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPdlYV_w4y_wxd5Rs8c_F-soLMbY1zwXJjD-JM4TkOtOELyxZGyreTb6dTehp_X6e3qVFZUT05ETRs0MbvqYr4mqdb6dkG9DqNQEVv3TBoHwl7TYSygtHJEs3gXTAtMLYEKW9xXODJlVF-9II7fdTdHU7x7Pyf6NR6S3nv7sKUVD-zKpxF50L2TwUQ"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQOBrLd2GhnOLBe4XfcroGD8Uh8odfhSuE5y5f6WSUCPAD93HJyyUbNxvU8rneUBXRi6SjftdBfU9ggRGlEdLVoTt3bp1bS8C370rWXH5oZIPkX87SovgSPmlCQygx8OQIUmShnoHVMSa3xArpSdXRdOvqNrwiOsmBkmxJXm_NycW502xfhcL6A6d38"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-arm64/React Native DevTools"
},
"linux-x86_64": {
"size": 115929093,
"size": 115924495,
"hash": "sha256",
"digest": "06bbaeb62ae2e0081d184eba42b9f15be0d0b3f4901142b08a8a1430ff83e722",
"digest": "d154ffed0d8a66849da78baebf78e1323ecb8bbeda30d27b82a9b507196266c1",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPENbrxrg0RF_TiyxSY_YVYqC1UfRKj_bMfKb3qHUsIhBlya8n3FkbfJqTXTNdqL4riFRulXS5ecXZprtvk_9kao-zY59r3kiTRwobzF0jnjM507_9UOnEHWzG5ZJYzQyOtS3kQmT0HwZabVj9qw38OB9mk-MPVCZIPZay2PRnIThBzpKDoOOP9"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQPp7lTIJZPh1_Bz1ONneTDc_i5ScY8TLzgHe4DzvYz6e7z-QHdBKhUNbNVBInrYrJaPKPum8FOGcvFW9JsvPNpsdMiAbjivdKQPAEkGOZ-unSOqL1dPPjW-yZYSBGucXmcgQiXVaDhqG3Wcu04JLsFKlKb9QvAZZ-tyN72E8ndAQ0mgDyhzEhwB"
}
],
"format": "tar.gz",
"path": "React Native DevTools-linux-x64/React Native DevTools"
},
"macos-aarch64": {
"size": 110891603,
"size": 110891525,
"hash": "sha256",
"digest": "eeb9cc1399c0c38c429848dbf622f1b46e88d7d97788dcdc4c30a9fcce37705c",
"digest": "b05e1ae5528dcfcff5178d943d90128c9bf28ecd89da4dc303fd4ca748e5fc88",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQN9bd7nbXi-uF_MooJEiUL2jJVifMqgQxZ236aqbSdiJe5Uzjud5ANf0LDAl8GDVVRShd6x4B-gsZ-qRowH0qJikoGatQIkBgyzp4i8ors52etGOIIwdAxdNIng5Vtp441j2_N__btkJqlHcMMbbqvO8fg9oeYTlhMpOx3MLLWXIlG7ix5IFUDiYChf"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQMfoVd8CCoqS0ETntAOKhks2FtIDsyoPEeJHLIc-bxPESxTSHf02xDSSM-vjCG9gBitObq3iZECz1LGwbYS9qrjqXdrf7oljIWzK-eszvQwDe0wzCsywqRXBtLlDBb5h8a1WxjA_scRqoGCDbvk7-XovnJNdmTX4vq0CFb8QUUcEz31sVQ_v5IRjDdF"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"macos-x86_64": {
"size": 117770388,
"size": 117767014,
"hash": "sha256",
"digest": "a65e446e526502b267cbe6800ae031e4e1b5b0aca21412152a66ffe1d3a29410",
"digest": "6aa15f6dc13bea46503fcad1b9ba93b3007ea659abb63a2f6bf9b34c3abf834a",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQN29ukKLZS48QcCU-gms06YFnG-fxxDfrWTup-Z6KoIAP-QEu3sFzrpqeZz4g-jFsh3o-IIoHJsdbu4a2U7ROjPfWGguGJrPK8fdc3iV67Qw1_VAPU13dm0dI1DbSY50ah05wh43jdBG3LGCAYYJ-W8_mZMC3HqM2v-8KVd-DoPT4hOh1s9CCFgEQ"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQM57KwrYx0XeV3M8JrX_StgCFVbMHB5L-ShQfzIdoG4jfz71Z7U7CtK5FZ72Uwzm9wmzx5n0-w_3P8DRd24gvMWUSaN8QNdyxIUxd1n0BqJRYsvsbc8w2YpNeWadcce701zV5dYgQg7PIjPzDSuhYWM_7ih_QtZIBIHUUjCtr0sJBUYZVaqBQag6Q"
}
],
"format": "tar.gz",
"path": "React Native DevTools.app/Contents/MacOS/React Native DevTools"
},
"windows-x86_64": {
"size": 125526370,
"size": 125530089,
"hash": "sha256",
"digest": "26b190c0f85249dee91999e020b8fe7ffd5c007458a2103ed3822558861dbe87",
"digest": "da1747672dd222b1389f6ad9e1c67778ea0bc4e8859ddee23222a92bcaaed48f",
"providers": [
{
"type": "http",
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQO0mdIJx1eYiSDJNiAZ2soaeECILayWnvOeiey-fpS4ydDTreAMfwL4QZ5GZo4-AsGwOXCSdF3hBMM2ufnvw6BDFg5UEiTc4DALJu7o6YBBG4wlVZbI-2kkaXd7u8RhBQPjmhsdcX3sDmCGmSr3WK9EkTRKStE2lb6ilOn-969h4dYWekwUUCSX"
"url": "https://scontent.xx.fbcdn.net/mci_ab/uap/?ab_b=m&ab_page=react_native_devtools_binaries&ab_entry=AQN_2xTT04YUkfSPrA0LaBIHmjUTCCxBkiTgUpb3TUn02lpaFas2x3asL1LeHpZHlUmb_NiLE0PLZYg3T232fdIbmLaquPST7lQpsXDDMG-ykGK7-xxfK5CMU608Pd5Crw5YZBPF3O2PCtiIIcR85tWSqmyWYuoX-PnIhLnBWHjbpNcMcj9RkVqB"
}
],
"format": "tar.gz",
-1
View File
@@ -35,7 +35,6 @@
},
"devDependencies": {
"electron": "37.2.6",
"electron-store": "^8.2.0",
"semver": "^7.1.3"
},
"files": [
@@ -8,13 +8,15 @@
* @format
*/
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
const {BrowserWindow, Menu, app, shell, ipcMain} = require('electron') as any;
const Store = require('electron-store');
import SettingsStore from './SettingsStore.js';
const path = require('path');
const util = require('util');
const appSettings = new Store();
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
const {BrowserWindow, Menu, app, shell, ipcMain} = require('electron') as any;
const appSettings = new SettingsStore();
const windowMetadata = new WeakMap<
typeof BrowserWindow,
$ReadOnly<{
@@ -0,0 +1,128 @@
/**
* 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
* @format
* @oncall react_native
*/
// $FlowFixMe[unclear-type] We have no Flow types for the Electron API.
const {app} = require('electron') as any;
const fs = require('fs');
const path = require('path');
type Options = $ReadOnly<{
name?: string,
defaults?: Object,
}>;
/**
* A data persistence layer for storing application settings, modelled after
* [`electron-store`](https://www.npmjs.com/package/electron-store).
*
* Values are saved in a `config.json` file in `app.getPath('userData')`.
*
* Compatibility:
* - Maintains API and file format compatibility with `electron-store@8.2.0`.
* - Supports the Electron main process only.
*/
export default class SettingsStore {
#defaultValues: Object = {};
path: string;
constructor(options: Options = {}) {
options = {
name: 'config',
...options,
};
this.#defaultValues = {
...this.#defaultValues,
...options.defaults,
};
this.path = path.resolve(
app.getPath('userData'),
`${options.name ?? 'config'}.json`,
);
}
get(key: string, defaultValue?: any): any {
const store = this.store;
return store[key] !== undefined ? store[key] : defaultValue;
}
set(key: string, value: any): void {
const {store} = this;
if (typeof key === 'object') {
const object = key;
for (const [k, v] of Object.entries(object)) {
store[k] = v;
}
} else {
store[key] = value;
}
this.store = store;
}
has(key: string): boolean {
return key in this.store;
}
reset(...keys: Array<string>): void {
for (const key of keys) {
if (this.#defaultValues[key] != null) {
this.set(key, this.#defaultValues[key]);
}
}
}
delete(key: string): void {
const {store} = this;
delete store[key];
this.store = store;
}
clear(): void {
this.store = {};
for (const key of Object.keys(this.#defaultValues)) {
this.reset(key);
}
}
get store(): {[string]: mixed} {
try {
const data = fs.readFileSync(this.path, 'utf8');
const deserializedData = this._deserialize(data);
return {
...((deserializedData: any): {[string]: mixed}),
};
} catch (error) {
if (error?.code === 'ENOENT') {
this._ensureDirectory();
return {};
}
throw error;
}
}
set store(value: mixed): void {
this._ensureDirectory();
this._write(value);
}
_deserialize = (value: string): mixed => JSON.parse(value);
_serialize = (value: mixed): string =>
JSON.stringify(value, undefined, '\t') ?? '';
_ensureDirectory(): void {
fs.mkdirSync(path.dirname(this.path), {recursive: true});
}
_write(value: mixed): void {
const data = this._serialize(value);
fs.writeFileSync(this.path, data, {mode: 0o666});
}
}
@@ -25,7 +25,9 @@ app.setVersion(pkg.version + '-' + buildInfo.revision);
const {
values: {version = false},
} = util.parseArgs({
options: {version: {type: 'boolean'}},
options: {
version: {type: 'boolean'},
},
args: process.argv.slice(app.isPackaged ? 1 : 2),
strict: false,
});
+18 -5
View File
@@ -30,6 +30,7 @@ async function unstable_spawnDebuggerShellWithArgs(
{
mode = 'detached',
flavor = 'prebuilt',
prebuiltBinaryPath,
}: $ReadOnly<{
// In 'syncAndExit' mode, the current process will block until the spawned process exits, and then it will exit
// with the same exit code as the spawned process.
@@ -37,9 +38,13 @@ async function unstable_spawnDebuggerShellWithArgs(
// continue to run normally.
mode?: 'syncThenExit' | 'detached',
flavor?: DebuggerShellFlavor,
prebuiltBinaryPath?: string,
}> = {},
): Promise<void> {
const [binaryPath, baseArgs] = getShellBinaryAndArgs(flavor);
const [binaryPath, baseArgs] = getShellBinaryAndArgs(
flavor,
prebuiltBinaryPath,
);
return new Promise((resolve, reject) => {
const child = spawn(binaryPath, [...baseArgs, ...args], {
@@ -109,14 +114,13 @@ export type DebuggerShellPreparationResult = $ReadOnly<{
*/
async function unstable_prepareDebuggerShell(
flavor: DebuggerShellFlavor,
{prebuiltBinaryPath}: {prebuiltBinaryPath?: string} = {},
): Promise<DebuggerShellPreparationResult> {
const [binaryPath, baseArgs] = getShellBinaryAndArgs(flavor);
try {
switch (flavor) {
case 'prebuilt':
const prebuiltResult = await prepareDebuggerShellFromDotSlashFile(
DEVTOOLS_BINARY_DOTSLASH_FILE,
prebuiltBinaryPath ?? DEVTOOLS_BINARY_DOTSLASH_FILE,
);
if (prebuiltResult.code !== 'success') {
return prebuiltResult;
@@ -128,6 +132,11 @@ async function unstable_prepareDebuggerShell(
flavor as empty;
throw new Error(`Unknown flavor: ${flavor}`);
}
const [binaryPath, baseArgs] = getShellBinaryAndArgs(
flavor,
prebuiltBinaryPath,
);
const {code, stderr} = await spawnAndGetStderr(binaryPath, [
...baseArgs,
'--version',
@@ -149,10 +158,14 @@ async function unstable_prepareDebuggerShell(
function getShellBinaryAndArgs(
flavor: DebuggerShellFlavor,
prebuiltBinaryPath: ?string,
): [string, Array<string>] {
switch (flavor) {
case 'prebuilt':
return [require('fb-dotslash'), [DEVTOOLS_BINARY_DOTSLASH_FILE]];
return [
require('fb-dotslash'),
[prebuiltBinaryPath ?? DEVTOOLS_BINARY_DOTSLASH_FILE],
];
case 'dev':
return [
// NOTE: Internally at Meta, this is aliased to a workspace that is
@@ -21,10 +21,6 @@ import {
withServerForEachTest,
} from './ServerUtils';
import {createHash} from 'crypto';
import fs from 'fs';
import path from 'path';
const fsPromise = fs.promises;
// WebSocket is unreliable when using fake timers.
jest.useRealTimers();
@@ -47,7 +43,6 @@ describe.each(['HTTP', 'HTTPS'])(
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: __dirname,
secure: protocol === 'HTTPS',
});
@@ -472,14 +467,7 @@ describe.each(['HTTP', 'HTTPS'])(
}
});
test('reads source from disk', async () => {
// Should be just 'foo\n', but the newline can get mangled by the OS
// and/or SCM, so let's read the source of truth from disk.
const fileRealContents = await fsPromise.readFile(
path.join(__dirname, '__fixtures__', 'mock-source-file.txt'),
'utf8',
);
test('throws when attempting to pass a filesystem url', async () => {
const {device, debugger_} = await createAndConnectTarget(
serverRef,
autoCleanup.signal,
@@ -490,6 +478,7 @@ describe.each(['HTTP', 'HTTPS'])(
vm: 'bar-vm',
},
);
try {
await sendFromTargetToDebugger(device, debugger_, 'page1', {
method: 'Debugger.scriptParsed',
@@ -500,7 +489,7 @@ describe.each(['HTTP', 'HTTPS'])(
endLine: 0,
startColumn: 0,
endColumn: 0,
hash: createHash('sha256').update(fileRealContents).digest('hex'),
hash: createHash('sha256').update('').digest('hex'),
},
});
const response = await debugger_.sendAndGetResponse({
@@ -511,8 +500,15 @@ describe.each(['HTTP', 'HTTPS'])(
},
});
expect(response.result).toEqual(
expect.objectContaining({scriptSource: fileRealContents}),
expect.objectContaining({
error: {
message: expect.stringContaining(
'Can\'t parse requested URL "__fixtures__/mock-source-file.txt"',
),
},
}),
);
// The device does not receive the getScriptSource request, since it
// is handled by the proxy.
expect(device.wrappedEventParsed).not.toBeCalledWith({
@@ -33,7 +33,6 @@ describe.each(['HTTP', 'HTTPS'])(
protocol => {
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
secure: protocol === 'HTTPS',
});
const autoCleanup = withAbortSignalForEachTest();
@@ -39,7 +39,6 @@ describe('inspector proxy device message middleware', () => {
const createCustomMessageHandler = jest.fn().mockImplementation(() => null);
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: createCustomMessageHandler,
});
@@ -83,7 +82,6 @@ describe('inspector proxy device message middleware', () => {
const createCustomMessageHandler = jest.fn().mockImplementation(() => null);
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: createCustomMessageHandler,
});
const {serverBaseUrl, serverBaseWsUrl} = serverRefUrls(server);
@@ -169,7 +167,6 @@ describe('inspector proxy device message middleware', () => {
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: createCustomMessageHandler,
});
@@ -231,7 +228,6 @@ describe('inspector proxy device message middleware', () => {
const handleDeviceMessage = jest.fn();
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: () => ({
handleDeviceMessage,
handleDebuggerMessage() {},
@@ -264,7 +260,6 @@ describe('inspector proxy device message middleware', () => {
const handleDeviceMessage = jest.fn();
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: () => ({
handleDeviceMessage,
handleDebuggerMessage() {},
@@ -304,7 +299,6 @@ describe('inspector proxy device message middleware', () => {
const handleDebuggerMessage = jest.fn();
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: () => ({
handleDeviceMessage() {},
handleDebuggerMessage,
@@ -341,7 +335,6 @@ describe('inspector proxy device message middleware', () => {
const handleDebuggerMessage = jest.fn();
const {server} = await createServer({
logger: undefined,
projectRoot: '',
unstable_customInspectorMessageHandler: () => ({
handleDeviceMessage() {},
handleDebuggerMessage,
@@ -37,7 +37,6 @@ const PAGE_DEFAULTS = {
describe('inspector-proxy device socket handoff', () => {
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
});
const autoCleanup = withAbortSignalForEachTest();
afterEach(() => {
@@ -27,7 +27,6 @@ jest.useFakeTimers();
describe('inspector proxy HTTP API', () => {
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
});
const autoCleanup = withAbortSignalForEachTest();
afterEach(() => {
@@ -261,7 +260,6 @@ describe('inspector proxy HTTP API', () => {
describe('HTTP vs HTTPS', () => {
const secureServerRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
secure: true,
});
@@ -25,7 +25,6 @@ jest.setTimeout(10000);
describe('inspector proxy React Native reloads', () => {
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
});
const autoCleanup = withAbortSignalForEachTest();
afterEach(() => {
@@ -34,7 +34,6 @@ describe('enableStandaloneFuseboxShell experiment', () => {
};
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
unstable_browserLauncher: BrowserLauncherWithFuseboxShell,
unstable_experiments: {
enableStandaloneFuseboxShell: true,
@@ -17,7 +17,6 @@ jest.setTimeout(10000);
describe('embedder script', () => {
const serverRef = withServerForEachTest({
logger: undefined,
projectRoot: '',
});
test('is always served', async () => {
@@ -24,8 +24,6 @@ import path from 'path';
import serveStaticMiddleware from 'serve-static';
type Options = $ReadOnly<{
projectRoot: string,
/**
* The base URL to the dev server, as reachable from the machine on which
* dev-middleware is hosted. Typically `http://localhost:${metroPort}`.
@@ -78,7 +76,6 @@ type DevMiddlewareAPI = $ReadOnly<{
}>;
export default function createDevMiddleware({
projectRoot,
serverBaseUrl,
logger,
// $FlowFixMe[incompatible-type]
@@ -96,7 +93,6 @@ export default function createDevMiddleware({
);
const inspectorProxy = new InspectorProxy(
projectRoot,
serverBaseUrl,
eventReporter,
experiments,
@@ -28,9 +28,7 @@ import type {
import CdpDebugLogging from './CdpDebugLogging';
import DeviceEventReporter from './DeviceEventReporter';
import * as fs from 'fs';
import invariant from 'invariant';
import * as path from 'path';
import WS from 'ws';
const debug = require('debug')('Metro:InspectorProxy');
@@ -75,7 +73,6 @@ export type DeviceOptions = $ReadOnly<{
name: string,
app: string,
socket: WS,
projectRoot: string,
eventReporter: ?EventReporter,
createMessageMiddleware: ?CreateCustomMessageHandlerFn,
deviceRelativeBaseUrl: URL,
@@ -120,9 +117,6 @@ export default class Device {
// Mapping built from scriptParsed events and used to fetch file content in `Debugger.getScriptSource`.
#scriptIdToSourcePathMapping: Map<string, string> = new Map();
// Root of the project used for relative to absolute source path conversion.
#projectRoot: string;
#deviceEventReporter: ?DeviceEventReporter;
#pagesPollingIntervalId: ReturnType<typeof setInterval>;
@@ -151,7 +145,6 @@ export default class Device {
name,
app,
socket,
projectRoot,
eventReporter,
createMessageMiddleware,
serverRelativeBaseUrl,
@@ -163,7 +156,6 @@ export default class Device {
this.#name = name;
this.#app = app;
this.#deviceSocket = socket;
this.#projectRoot = projectRoot;
this.#serverRelativeBaseUrl = serverRelativeBaseUrl;
this.#deviceRelativeBaseUrl = deviceRelativeBaseUrl;
this.#deviceEventReporter = eventReporter
@@ -880,7 +872,7 @@ export default class Device {
return this.#processDebuggerSetBreakpointByUrl(req, debuggerInfo);
case 'Debugger.getScriptSource':
// Sends response to debugger via side-effect
this.#processDebuggerGetScriptSource(req, socket);
void this.#processDebuggerGetScriptSource(req, socket);
return null;
case 'Network.loadNetworkResource':
// If we're rewriting URLs (to frontend-relative), we don't want to
@@ -965,10 +957,10 @@ export default class Device {
return processedReq;
}
#processDebuggerGetScriptSource(
async #processDebuggerGetScriptSource(
req: CDPRequest<'Debugger.getScriptSource'>,
socket: WS,
): void {
): Promise<void> {
const sendSuccessResponse = (scriptSource: string) => {
const result: {
scriptSource: string,
@@ -1005,33 +997,23 @@ export default class Device {
const pathToSource = this.#scriptIdToSourcePathMapping.get(
req.params.scriptId,
);
if (pathToSource != null) {
const httpURL = this.#tryParseHTTPURL(pathToSource);
if (httpURL) {
// URL is server-relatve, so we should be able to fetch it from here.
this.#fetchText(httpURL).then(
text => sendSuccessResponse(text),
err =>
sendErrorResponse(
`Failed to fetch source url ${pathToSource}: ${err.message}`,
),
try {
const httpURL =
pathToSource == null ? null : this.#tryParseHTTPURL(pathToSource);
if (!httpURL) {
throw new Error(
`Can't parse requested URL ${pathToSource === undefined ? 'undefined' : JSON.stringify(pathToSource)}`,
);
} else {
let file;
try {
file = fs.readFileSync(
path.resolve(this.#projectRoot, pathToSource),
'utf8',
);
} catch (err) {
sendErrorResponse(
`Failed to fetch source file ${pathToSource}: ${err.message}`,
);
}
if (file != null) {
sendSuccessResponse(file);
}
}
const text = await this.#fetchText(httpURL);
sendSuccessResponse(text);
} catch (err) {
sendErrorResponse(
`Failed to fetch source url ${pathToSource === undefined ? 'undefined' : JSON.stringify(pathToSource)} for scriptId ${req.params.scriptId}: ${err.message}`,
);
}
}
@@ -75,9 +75,6 @@ export interface InspectorProxyQueries {
* Main Inspector Proxy class that connects JavaScript VM inside Android/iOS apps and JS debugger.
*/
export default class InspectorProxy implements InspectorProxyQueries {
// Root of the project used for relative to absolute source path conversion.
#projectRoot: string;
// The base URL to the dev server from the dev-middleware host.
#serverBaseUrl: URL;
@@ -101,7 +98,6 @@ export default class InspectorProxy implements InspectorProxyQueries {
#eventLoopPerfTracker: EventLoopPerfTracker;
constructor(
projectRoot: string,
serverBaseUrl: string,
eventReporter: ?EventReporter,
experiments: Experiments,
@@ -109,7 +105,6 @@ export default class InspectorProxy implements InspectorProxyQueries {
customMessageHandler: ?CreateCustomMessageHandlerFn,
trackEventLoopPerf?: boolean = false,
) {
this.#projectRoot = projectRoot;
this.#serverBaseUrl = new URL(serverBaseUrl);
this.#devices = new Map();
this.#eventReporter = eventReporter;
@@ -355,7 +350,6 @@ export default class InspectorProxy implements InspectorProxyQueries {
name: deviceName,
app: appName,
socket,
projectRoot: this.#projectRoot,
eventReporter: this.#eventReporter,
createMessageMiddleware: this.#customMessageHandler,
deviceRelativeBaseUrl,
@@ -372,12 +366,6 @@ export default class InspectorProxy implements InspectorProxyQueries {
this.#devices.set(deviceId, newDevice);
this.#logger?.info(
"Connection established to app='%s' on device='%s'.",
appName,
deviceName,
);
debug(
"Got new device connection: name='%s', app=%s, device=%s, via=%s",
deviceName,
@@ -450,7 +438,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
);
socket.on('close', (code: number, reason: string) => {
this.#logger?.info(
debug(
"Connection closed to device='%s' for app='%s' with code='%s' and reason='%s'.",
deviceName,
appName,
@@ -526,7 +514,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
throw new Error(INTERNAL_ERROR_MESSAGES.UNREGISTERED_DEVICE);
}
this.#logger?.info(
debug(
"Connection established to DevTools for app='%s' on device='%s'.",
device.getApp() || 'unknown',
device.getName() || 'unknown',
@@ -594,7 +582,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
});
socket.on('close', (code: number, reason: string) => {
this.#logger?.info(
debug(
"Connection closed to DevTools for app='%s' on device='%s' with code='%s' and reason='%s'.",
device.getApp() || 'unknown',
device.getName() || 'unknown',
@@ -21,6 +21,7 @@ import type {NextHandleFunction} from 'connect';
import type {IncomingMessage, ServerResponse} from 'http';
import getDevToolsFrontendUrl from '../utils/getDevToolsFrontendUrl';
import {createHash} from 'crypto';
import url from 'url';
const LEGACY_SYNTHETIC_PAGE_TITLE =
@@ -190,11 +191,15 @@ export default function openDebuggerMiddleware({
}
}
if (shouldUseStandaloneFuseboxShell) {
const windowKey = [
serverBaseUrl,
target.webSocketDebuggerUrl,
target.appId,
].join('-');
const windowKey = createHash('sha256')
.update(
[
serverBaseUrl,
target.webSocketDebuggerUrl,
target.appId,
].join('-'),
)
.digest('hex');
if (!browserLauncher.unstable_showFuseboxShell) {
throw new Error(
'Fusebox shell is not supported by the current browser launcher',
@@ -191,6 +191,14 @@ internal object DependencyUtils {
"The hermes-android dependency was modified to use the correct Maven group.",
)
)
} else if (hermesV1Enabled) {
dependencySubstitution.add(
Triple(
"com.facebook.react:hermes-android",
hermesVersionString,
"The hermes-android dependency was modified to use Hermes V1.",
)
)
}
return dependencySubstitution
}
@@ -242,7 +242,7 @@ internal fun readPackageJsonFile(
return packageJson?.let { JsonUtils.fromPackageJson(it) }
}
private const val HERMES_COMPILER_NPM_DIR = "node_modules/hermes-compiler/%OS-BIN%/"
private const val HERMES_COMPILER_NPM_DIR = "node_modules/hermes-compiler/hermesc/%OS-BIN%/"
private const val HERMESC_IN_REACT_NATIVE_DIR = "node_modules/react-native/sdks/hermesc/%OS-BIN%/"
private const val HERMESC_BUILT_FROM_SOURCE_DIR =
"node_modules/react-native/ReactAndroid/hermes-engine/build/hermes/bin/"
@@ -165,8 +165,8 @@ class PathUtilsTest {
@Test
@WithOs(OS.MAC)
fun detectOSAwareHermesCommand_withHermesV1Enabled() {
tempFolder.newFolder("node_modules/hermes-compiler/osx-bin/")
val expected = tempFolder.newFile("node_modules/hermes-compiler/osx-bin/hermesc")
tempFolder.newFolder("node_modules/hermes-compiler/hermesc/osx-bin/")
val expected = tempFolder.newFile("node_modules/hermes-compiler/hermesc/osx-bin/hermesc")
assertThat(detectOSAwareHermesCommand(tempFolder.root, "", hermesV1Enabled = true))
.isEqualTo(expected.toString())
@@ -47,7 +47,7 @@ function combineSchemas(
}
return merged;
},
{modules: {}},
{modules: {} /*:: as SchemaType['modules'] */},
);
return {
@@ -540,7 +540,7 @@ function buildEventEmitterSchema(
return {
name: eventemitterName,
optional: false,
optional: Boolean(property.optional),
typeAnnotation: {
type: 'EventEmitterTypeAnnotation',
typeAnnotation: eventTypeAnnotation,
@@ -873,56 +873,6 @@ describe('Animated', () => {
});
});
describe('Animated Interactions', () => {
let Animated; // eslint-disable-line no-shadow
let InteractionManager;
beforeEach(() => {
jest.mock('../../Interaction/InteractionManager');
Animated = require('../Animated').default;
InteractionManager =
require('../../Interaction/InteractionManager').default;
});
afterEach(() => {
jest.unmock('../../Interaction/InteractionManager');
});
it('registers an interaction by default', () => {
// $FlowFixMe[prop-missing]
InteractionManager.createInteractionHandle.mockReturnValue(777);
const value = new Animated.Value(0);
const callback = jest.fn();
Animated.timing(value, {
toValue: 100,
duration: 100,
useNativeDriver: false,
}).start(callback);
jest.runAllTimers();
expect(InteractionManager.createInteractionHandle).toBeCalled();
expect(InteractionManager.clearInteractionHandle).toBeCalledWith(777);
expect(callback).toBeCalledWith({finished: true});
});
it('does not register an interaction when specified', () => {
const value = new Animated.Value(0);
const callback = jest.fn();
Animated.timing(value, {
toValue: 100,
duration: 100,
isInteraction: false,
useNativeDriver: false,
}).start(callback);
jest.runAllTimers();
expect(InteractionManager.createInteractionHandle).not.toBeCalled();
expect(InteractionManager.clearInteractionHandle).not.toBeCalled();
expect(callback).toBeCalledWith({finished: true});
});
});
describe('Animated Tracking', () => {
it('should track values', () => {
const value1 = new Animated.Value(0);
@@ -14,8 +14,10 @@ import FlatList, {type FlatListProps} from '../../Lists/FlatList';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
// $FlowExpectedError[unclear-type]
export default (createAnimatedComponent(FlatList): component<ItemT = any>(
export default createAnimatedComponent(FlatList) as $FlowFixMe as component<
// $FlowExpectedError[unclear-type]
ItemT = any,
>(
ref?: React.RefSetter<FlatList<ItemT>>,
...props: AnimatedProps<FlatListProps<ItemT>>
));
);
@@ -14,9 +14,10 @@ import Image from '../../Image/Image';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
export default (createAnimatedComponent(
(Image: $FlowFixMe),
): AnimatedComponentType<
export default (createAnimatedComponent<
$FlowFixMe,
React.ElementRef<typeof Image>,
>((Image: $FlowFixMe)): AnimatedComponentType<
React.ElementConfig<typeof Image>,
React.ElementRef<typeof Image>,
>);
@@ -15,7 +15,7 @@ import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
// $FlowFixMe[incompatible-type]
export default (createAnimatedComponent(SectionList): component<
export default createAnimatedComponent(SectionList) as $FlowFixMe as component<
// $FlowExpectedError[unclear-type]
ItemT = any,
// $FlowExpectedError[unclear-type]
@@ -23,4 +23,4 @@ export default (createAnimatedComponent(SectionList): component<
>(
ref?: React.RefSetter<SectionList<ItemT, SectionT>>,
...props: AnimatedProps<SectionListProps<ItemT, SectionT>>
));
);
@@ -14,6 +14,10 @@ import Text, {type TextProps} from '../../Text/Text';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
export default (createAnimatedComponent(
(Text: $FlowFixMe),
): AnimatedComponentType<TextProps, React.ElementRef<typeof Text>>);
export default (createAnimatedComponent<
$FlowFixMe,
React.ElementRef<typeof Text>,
>((Text: $FlowFixMe)): AnimatedComponentType<
TextProps,
React.ElementRef<typeof Text>,
>);
@@ -15,7 +15,8 @@ import View from '../../Components/View/View';
import createAnimatedComponent from '../createAnimatedComponent';
import * as React from 'react';
export default (createAnimatedComponent(View): AnimatedComponentType<
// $FlowFixMe[incompatible-type]
export default createAnimatedComponent(View) as AnimatedComponentType<
ViewProps,
React.ElementRef<typeof View>,
>);
>;
@@ -63,17 +63,29 @@ type PassThroughProps = $ReadOnly<{
passthroughAnimatedPropExplicitValues?: ViewProps | null,
}>;
export type AnimatedProps<Props: {...}> = {
[K in keyof Props]: K extends NonAnimatedProps
? Props[K]
: WithAnimatedValue<Props[K]>,
} & PassThroughProps;
type LooseOmit<O: interface {}, K: $Keys<$FlowFixMe>> = Pick<
O,
Exclude<$Keys<O>, K>,
>;
export type AnimatedBaseProps<Props: {...}> = {
[K in keyof Props]: K extends NonAnimatedProps
? Props[K]
: WithAnimatedValue<Props[K]>,
};
export type AnimatedProps<Props: {...}> = LooseOmit<
{
[K in keyof Props]: K extends NonAnimatedProps
? Props[K]
: WithAnimatedValue<Props[K]>,
},
'ref',
> &
PassThroughProps;
export type AnimatedBaseProps<Props: {...}> = LooseOmit<
{
[K in keyof Props]: K extends NonAnimatedProps
? Props[K]
: WithAnimatedValue<Props[K]>,
},
'ref',
>;
export type AnimatedComponentType<Props: {...}, +Instance = mixed> = component(
ref?: React.RefSetter<Instance>,
@@ -18,7 +18,6 @@ import type {AnimatedNodeConfig} from './AnimatedNode';
import type AnimatedTracking from './AnimatedTracking';
import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper';
import InteractionManager from '../../Interaction/InteractionManager';
import AnimatedInterpolation from './AnimatedInterpolation';
import AnimatedWithChildren from './AnimatedWithChildren';
@@ -312,10 +311,6 @@ export default class AnimatedValue extends AnimatedWithChildren {
* See https://reactnative.dev/docs/animatedvalue#animate
*/
animate(animation: Animation, callback: ?EndCallback): void {
let handle = null;
if (animation.__isInteraction) {
handle = InteractionManager.createInteractionHandle();
}
const previousAnimation = this._animation;
this._animation && this._animation.stop();
this._animation = animation;
@@ -328,9 +323,6 @@ export default class AnimatedValue extends AnimatedWithChildren {
},
result => {
this._animation = null;
if (handle !== null) {
InteractionManager.clearInteractionHandle(handle);
}
callback && callback(result);
},
previousAnimation,
@@ -1690,6 +1690,7 @@ class ScrollView extends React.Component<ScrollViewProps, ScrollViewState> {
return (
<StickyHeaderComponent
key={key}
/* $FlowFixMe[incompatible-type] */
ref={ref => this._setStickyHeaderRef(key, ref)}
nextHeaderLayoutY={this._headerLayoutYs.get(
this._getKeyForIndex(nextIndex, children),
@@ -44,7 +44,7 @@ interface Instance extends React.ElementRef<typeof Animated.View> {
}
const ScrollViewStickyHeader: component(
ref: React.RefSetter<Instance>,
ref?: React.RefSetter<Instance>,
...props: ScrollViewStickyHeaderProps
) = function ScrollViewStickyHeader({
ref: forwardedRef,
@@ -282,7 +282,7 @@ const ScrollViewStickyHeader: component(
const passthroughAnimatedPropExplicitValues =
isFabric && translateY != null
? {
style: {transform: [{translateY: translateY}]},
style: {transform: [{translateY}]},
}
: null;
@@ -303,20 +303,20 @@ const ScrollViewStickyHeader: component(
passthroughAnimatedPropExplicitValues
}>
{cloneElement(child, {
style: styles.fill, // We transfer the child style to the wrapper.
onLayout: undefined, // we call this manually through our this._onLayout
style: styles.fill, // We transfer the child style to the wrapper.
})}
</Animated.View>
);
};
const styles = StyleSheet.create({
header: {
zIndex: 10,
},
fill: {
flex: 1,
},
header: {
zIndex: 10,
},
});
export default ScrollViewStickyHeader;
@@ -449,6 +449,12 @@ function InternalTextInput(props: TextInputProps): React.Node {
before we can get to the long term breaking change.
*/
if (instance != null) {
// Register the input immediately when the ref is set so that focus()
// can be called from ref callbacks
// Double registering during useLayoutEffect is fine, because the underlying
// state is a Set.
TextInputState.registerInput(instance);
// $FlowFixMe[prop-missing] - See the explanation above.
// $FlowFixMe[unsafe-object-assign]
Object.assign(instance, {
@@ -47,15 +47,14 @@ class TouchableBounce extends React.Component<
_createPressabilityConfig(): PressabilityConfig {
return {
android_disableSound: this.props.touchSoundDisabled,
cancelable: !this.props.rejectResponderTermination,
disabled: this.props.disabled,
hitSlop: this.props.hitSlop,
delayLongPress: this.props.delayLongPress,
delayPressIn: this.props.delayPressIn,
delayPressOut: this.props.delayPressOut,
disabled: this.props.disabled,
hitSlop: this.props.hitSlop,
minPressDuration: 0,
pressRectOffset: this.props.pressRetentionOffset,
android_disableSound: this.props.touchSoundDisabled,
onBlur: event => {
if (Platform.isTV) {
this._bounceTo(1, 0.4, 0);
@@ -113,6 +112,7 @@ class TouchableBounce extends React.Component<
this.props.onPressOut(event);
}
},
pressRectOffset: this.props.pressRetentionOffset,
};
}
@@ -123,10 +123,10 @@ class TouchableBounce extends React.Component<
callback?: ?() => void,
) {
Animated.spring(this.state.scale, {
toValue,
velocity,
bounciness,
toValue,
useNativeDriver: true,
velocity,
}).start(callback);
}
@@ -230,6 +230,6 @@ export default (function TouchableBounceWrapper({
}) {
return <TouchableBounce {...props} hostRef={hostRef} />;
} as component(
ref: React.RefSetter<mixed>,
ref?: React.RefSetter<mixed>,
...props: $ReadOnly<Omit<TouchableBounceProps, 'hostRef'>>
));
@@ -21,12 +21,14 @@ const ViewNativeComponent: HostComponent<Props> =
}));
interface NativeCommands {
+focus: (viewRef: HostInstance) => void;
+blur: (viewRef: HostInstance) => void;
+hotspotUpdate: (viewRef: HostInstance, x: number, y: number) => void;
+setPressed: (viewRef: HostInstance, pressed: boolean) => void;
}
export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
supportedCommands: ['hotspotUpdate', 'setPressed'],
supportedCommands: ['focus', 'blur', 'hotspotUpdate', 'setPressed'],
});
/**
+21 -21
View File
@@ -39,6 +39,24 @@ function DebuggingOverlay({
useImperativeHandle(
ref,
() => ({
clearElementsHighlight() {
if (!isNativeComponentReady) {
return;
}
if (nativeComponentRef.current != null) {
Commands.clearElementsHighlights(nativeComponentRef.current);
}
},
highlightElements(elements) {
if (!isNativeComponentReady) {
return;
}
if (nativeComponentRef.current != null) {
Commands.highlightElements(nativeComponentRef.current, elements);
}
},
highlightTraceUpdates(updates) {
if (!isNativeComponentReady) {
return;
@@ -55,24 +73,6 @@ function DebuggingOverlay({
);
}
},
highlightElements(elements) {
if (!isNativeComponentReady) {
return;
}
if (nativeComponentRef.current != null) {
Commands.highlightElements(nativeComponentRef.current, elements);
}
},
clearElementsHighlight() {
if (!isNativeComponentReady) {
return;
}
if (nativeComponentRef.current != null) {
Commands.clearElementsHighlights(nativeComponentRef.current);
}
},
}),
[],
);
@@ -95,14 +95,14 @@ function DebuggingOverlay({
const styles = StyleSheet.create({
overlay: {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
position: 'absolute',
right: 0,
top: 0,
},
});
export default DebuggingOverlay as component(
ref: React.RefSetter<DebuggingOverlayHandle>,
ref?: React.RefSetter<DebuggingOverlayHandle>,
);
+3 -6
View File
@@ -8,11 +8,8 @@
* @format
*/
import type {
AbstractImageAndroid,
AbstractImageIOS,
ImageType as ImageComponent,
} from './ImageTypes.flow';
import type {HostInstance} from '../..';
import type {AbstractImageAndroid, AbstractImageIOS} from './ImageTypes.flow';
import useMergeRefs from '../Utilities/useMergeRefs';
import * as React from 'react';
@@ -33,7 +30,7 @@ export function unstable_getImageComponentDecorator(): ?ImageComponentDecorator
return injectedImageComponentDecorator;
}
type ImageInstance = React.ElementRef<ImageComponent>;
type ImageInstance = HostInstance;
type ImageAttachedCallback = (
imageInstance: ImageInstance,
@@ -8,12 +8,11 @@
* @format
*/
import type {HostInstance} from '../..';
import type {RootTag} from '../Types/RootTagTypes';
import type {ResolvedAssetSource} from './AssetSourceResolver';
import type {ImageProps as ImagePropsType} from './ImageProps';
import type {ImageSource} from './ImageSource';
import typeof ImageViewNativeComponent from './ImageViewNativeComponent';
import typeof TextInlineImageNativeComponent from './TextInlineImageNativeComponent';
import * as React from 'react';
@@ -67,17 +66,14 @@ type ImageComponentStaticsAndroid = $ReadOnly<{
}>;
export type AbstractImageAndroid = component(
ref?: React.RefSetter<
| React.ElementRef<TextInlineImageNativeComponent>
| React.ElementRef<ImageViewNativeComponent>,
>,
ref?: React.RefSetter<HostInstance>,
...props: ImagePropsType
);
export type ImageAndroid = AbstractImageAndroid & ImageComponentStaticsAndroid;
export type AbstractImageIOS = component(
ref?: React.RefSetter<React.ElementRef<ImageViewNativeComponent>>,
ref?: React.RefSetter<HostInstance>,
...props: ImagePropsType
);
+6 -51
View File
@@ -12,7 +12,6 @@
import type {GestureResponderEvent} from '../Types/CoreEventTypes';
const InteractionManager = require('./InteractionManager').default;
const TouchHistoryMath = require('./TouchHistoryMath').default;
const currentCentroidXOfTouchesChangedAfter =
@@ -31,9 +30,6 @@ const currentCentroidY = TouchHistoryMath.currentCentroidY;
* single-touch gestures resilient to extra touches, and can be used to
* recognize simple multi-touch gestures.
*
* By default, `PanResponder` holds an `InteractionManager` handle to block
* long-running JS events from interrupting active gestures.
*
* It provides a predictable wrapper of the responder handlers provided by the
* [gesture responder system](docs/gesture-responder-system.html).
* For each handler, it provides a new `gestureState` object alongside the
@@ -405,9 +401,6 @@ const PanResponder = {
getInteractionHandle: () => ?number,
panHandlers: GestureResponderHandlerMethods,
} {
const interactionState = {
handle: (null: ?number),
};
const gestureState: PanResponderGestureState = {
// Useful for debugging
stateID: Math.random(),
@@ -464,10 +457,6 @@ const PanResponder = {
},
onResponderGrant(event: GestureResponderEvent): boolean {
if (!interactionState.handle) {
interactionState.handle =
InteractionManager.createInteractionHandle();
}
gestureState.x0 = currentCentroidX(event.touchHistory);
gestureState.y0 = currentCentroidY(event.touchHistory);
gestureState.dx = 0;
@@ -482,21 +471,11 @@ const PanResponder = {
},
onResponderReject(event: GestureResponderEvent): void {
clearInteractionHandle(
interactionState,
config.onPanResponderReject,
event,
gestureState,
);
config.onPanResponderReject?.call(undefined, event, gestureState);
},
onResponderRelease(event: GestureResponderEvent): void {
clearInteractionHandle(
interactionState,
config.onPanResponderRelease,
event,
gestureState,
);
config.onPanResponderRelease?.call(undefined, event, gestureState);
PanResponder._initializeGestureState(gestureState);
},
@@ -529,21 +508,11 @@ const PanResponder = {
onResponderEnd(event: GestureResponderEvent): void {
const touchHistory = event.touchHistory;
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
clearInteractionHandle(
interactionState,
config.onPanResponderEnd,
event,
gestureState,
);
config.onPanResponderEnd?.call(undefined, event, gestureState);
},
onResponderTerminate(event: GestureResponderEvent): void {
clearInteractionHandle(
interactionState,
config.onPanResponderTerminate,
event,
gestureState,
);
config.onPanResponderTerminate?.call(undefined, event, gestureState);
PanResponder._initializeGestureState(gestureState);
},
@@ -556,27 +525,13 @@ const PanResponder = {
return {
panHandlers,
getInteractionHandle(): ?number {
return interactionState.handle;
// TODO: Deprecate and delete this method.
return null;
},
};
},
};
function clearInteractionHandle(
interactionState: {handle: ?number, ...},
callback: ?(ActiveCallback | PassiveCallback),
event: GestureResponderEvent,
gestureState: PanResponderGestureState,
) {
if (interactionState.handle) {
InteractionManager.clearInteractionHandle(interactionState.handle);
interactionState.handle = null;
}
if (callback) {
callback(event, gestureState);
}
}
export type PanResponderInstance = ReturnType<(typeof PanResponder)['create']>;
export default PanResponder;
@@ -129,11 +129,13 @@ export function getWithFallback_DEPRECATED<Config: {...}>(
// `getRuntimeConfig == null` when static view configs are disabled
// If `setRuntimeConfigProvider` is not configured, use native reflection.
if (hasNativeViewConfig(name)) {
/* $FlowFixMe[incompatible-type] Extra ref prop */
return get<Config>(name, viewConfigProvider);
}
} else {
// If there is no runtime config, then the native component is unavailable.
if (getRuntimeConfig(name) != null) {
/* $FlowFixMe[incompatible-type] Extra ref prop */
return get<Config>(name, viewConfigProvider);
}
}
@@ -14,6 +14,7 @@ import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
import type {HostInstance} from 'react-native';
import ReactNativeElement from '../../../../src/private/webapis/dom/nodes/ReactNativeElement';
import TextInput from '../../../Components/TextInput/TextInput';
import TextInputState from '../../../Components/TextInput/TextInputState';
import View from '../../../Components/View/View';
import ReactFabricHostComponent from '../ReactFabricHostComponent';
@@ -48,7 +49,7 @@ describe('ReactFabricPublicInstance', () => {
const nodeRef = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(<View ref={nodeRef} />);
root.render(<TextInput ref={nodeRef} />);
});
const node = nullthrows(nodeRef.current);
@@ -73,7 +74,7 @@ describe('ReactFabricPublicInstance', () => {
const ref = createRef<HostInstance>();
Fantom.runTask(() => {
root.render(<View ref={ref} />);
root.render(<TextInput ref={ref} />);
});
const node = nullthrows(ref.current);
+15 -7
View File
@@ -14,29 +14,37 @@ import NativeDevLoadingView from './NativeDevLoadingView';
const COLOR_SCHEME = {
dark: {
refresh: {
backgroundColor: '#2584e8',
textColor: '#ffffff',
},
load: {
backgroundColor: '#fafafa',
textColor: '#242526',
},
},
default: {
refresh: {
backgroundColor: '#2584e8',
textColor: '#ffffff',
},
error: {
backgroundColor: '#1065AF',
textColor: '#ffffff',
},
},
default: {
load: {
backgroundColor: '#404040',
textColor: '#ffffff',
},
refresh: {
backgroundColor: '#2584e8',
textColor: '#ffffff',
},
error: {
backgroundColor: '#1065AF',
textColor: '#ffffff',
},
},
};
export default {
showMessage(message: string, type: 'load' | 'refresh') {
showMessage(message: string, type: 'load' | 'refresh' | 'error') {
if (NativeDevLoadingView) {
const colorScheme =
getColorScheme() === 'dark' ? COLOR_SCHEME.dark : COLOR_SCHEME.default;
+7 -4
View File
@@ -232,8 +232,6 @@ Error: ${e.message}`;
});
client.on('error', data => {
DevLoadingView.hide();
if (data.type === 'GraphNotFoundError') {
client.close();
setHMRUnavailableReason(
@@ -253,8 +251,6 @@ Error: ${e.message}`;
});
client.on('close', closeEvent => {
DevLoadingView.hide();
// https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1
// https://www.rfc-editor.org/rfc/rfc6455.html#section-7.1.5
const isNormalOrUnsetCloseReason =
@@ -296,10 +292,17 @@ function setHMRUnavailableReason(reason: string) {
}
hmrUnavailableReason = reason;
const DevLoadingView = require('./DevLoadingView').default;
DevLoadingView.hide();
// We only want to show a warning if Fast Refresh is on *and* if we ever
// previously managed to connect successfully. We don't want to show
// the warning to native engineers who use cached bundles without Metro.
if (hmrClient.isEnabled() && didConnect) {
DevLoadingView.showMessage(
'Fast Refresh disconnected. Reload app to reconnect.',
'error',
);
console.warn(reason);
// (Not using the `warning` module to prevent a Buck cycle.)
}
+1 -1
View File
@@ -161,7 +161,7 @@ let reactJsInspectorTracing = RNTarget(
name: .reactJsInspectorTracing,
path: "ReactCommon/jsinspector-modern/tracing",
excludedPaths: ["tests"],
dependencies: [.reactNativeDependencies, .reactFeatureFlags, .jsi, .reactOSCompat]
dependencies: [.reactNativeDependencies, .reactFeatureFlags, .reactJsInspectorNetwork, .jsi, .reactOSCompat]
)
/// React-jsinspectornetwork.podspec
@@ -380,6 +380,11 @@ static RCTBridge *RCTCurrentBridgeInstance = nil;
moduleProvider:(RCTBridgeModuleListProvider)block
launchOptions:(NSDictionary *)launchOptions
{
// Only enabld this assertion in OSS
#if COCOAPODS
[RCTBridge throwIfOnLegacyArch];
#endif
if (self = [super init]) {
RCTEnforceNewArchitectureValidation(RCTNotAllowedInBridgeless, self, nil);
_delegate = delegate;
@@ -393,6 +398,17 @@ static RCTBridge *RCTCurrentBridgeInstance = nil;
return self;
}
// Wrap the exception throwing in a static method to avoid the warning: "The code following the exception will never be
// executed". This might create build failures internally where we treat warnings as errors.
+ (void)throwIfOnLegacyArch
{
@throw [NSException
exceptionWithName:NSInternalInconsistencyException
reason:
@"You are trying to initialize the legacy architecture. This is not supported anymore and will be removed in the next version of React Native. Please use the New Architecture instead."
userInfo:nil];
}
RCT_NOT_IMPLEMENTED(-(instancetype)init)
- (void)dealloc
@@ -12,7 +12,7 @@
#import <React/RCTEventEmitter.h>
RCT_EXTERN void RCTEnableAppearancePreference(BOOL enabled);
RCT_EXTERN void RCTOverrideAppearancePreference(NSString *const);
RCT_EXTERN void RCTOverrideAppearancePreference(NSString *);
RCT_EXTERN void RCTUseKeyWindowForSystemStyle(BOOL useMainScreen);
RCT_EXTERN NSString *RCTCurrentOverrideAppearancePreference(void);
RCT_EXTERN NSString *RCTColorSchemePreference(UITraitCollection *traitCollection);
@@ -85,14 +85,6 @@ RCT_EXPORT_MODULE()
dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), self->_initialMessageBlock);
}
- (void)hideBannerAfter:(CGFloat)delay
{
// Cancel previous hide call after the delay.
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hide) object:nil];
// Set new hide call after a delay.
[self performSelector:@selector(hide) withObject:nil afterDelay:delay];
}
- (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor
{
if (!RCTDevLoadingViewGetEnabled() || _hiding) {
@@ -128,6 +120,9 @@ RCT_EXPORT_MODULE()
self->_container = [[UIView alloc] init];
self->_container.backgroundColor = backgroundColor;
self->_container.translatesAutoresizingMaskIntoConstraints = NO;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)];
[self->_container addGestureRecognizer:tapGesture];
self->_container.userInteractionEnabled = YES;
self->_label = [[UILabel alloc] init];
self->_label.translatesAutoresizingMaskIntoConstraints = NO;
@@ -158,8 +153,6 @@ RCT_EXPORT_MODULE()
[self->_label.centerXAnchor constraintEqualToAnchor:self->_container.centerXAnchor],
[self->_label.bottomAnchor constraintEqualToAnchor:self->_container.bottomAnchor constant:-5],
]];
[self hideBannerAfter:15.0];
});
}
@@ -365,11 +365,14 @@ RCT_EXPORT_MODULE()
handler:^(__unused UIAlertAction *action) {
[weakSelf setDefaultJSBundle];
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(__unused UIAlertAction *action) {
return;
}]];
UIAlertAction *configCancelAction =
[UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(__unused UIAlertAction *action) {
return;
}];
[configCancelAction setValue:[UIColor systemRedColor] forKey:@"titleTextColor"];
[alertController addAction:configCancelAction];
[RCTPresentedViewController() presentViewController:alertController animated:YES completion:NULL];
}]];
@@ -390,6 +393,11 @@ RCT_EXPORT_METHOD(show)
_actionSheet = [UIAlertController alertControllerWithTitle:@"React Native Dev Menu" message:nil preferredStyle:style];
NSAttributedString *title =
[[NSAttributedString alloc] initWithString:@"React Native Dev Menu"
attributes:@{NSFontAttributeName : [UIFont boldSystemFontOfSize:17]}];
[_actionSheet setValue:title forKey:@"_attributedTitle"];
NSArray<RCTDevMenuItem *> *items = [self _menuItemsToPresent];
for (RCTDevMenuItem *item in items) {
UIAlertAction *action = [UIAlertAction actionWithTitle:item.title
@@ -399,9 +407,11 @@ RCT_EXPORT_METHOD(show)
[_actionSheet addAction:action];
}
[_actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:[self alertActionHandlerForDevItem:nil]]];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:[self alertActionHandlerForDevItem:nil]];
[cancelAction setValue:[UIColor systemRedColor] forKey:@"titleTextColor"];
[_actionSheet addAction:cancelAction];
_presentedItems = items;
[RCTPresentedViewController() presentViewController:_actionSheet animated:YES completion:nil];
@@ -650,7 +650,9 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
BOOL isPointInside = [self pointInside:point withEvent:event];
BOOL clipsToBounds = self.currentContainerView.clipsToBounds;
UIView *currentContainerView = self.currentContainerView;
BOOL clipsToBounds = currentContainerView.clipsToBounds;
clipsToBounds = clipsToBounds || _layoutMetrics.overflowInset == EdgeInsets{};
@@ -658,8 +660,8 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
return nil;
}
for (UIView *subview in [self.subviews reverseObjectEnumerator]) {
UIView *hitView = [subview hitTest:[subview convertPoint:point fromView:self] withEvent:event];
for (UIView *subview = nullptr in [currentContainerView.subviews reverseObjectEnumerator]) {
UIView *hitView = [subview hitTest:[subview convertPoint:point fromView:currentContainerView] withEvent:event];
if (hitView) {
return hitView;
}
@@ -859,7 +861,7 @@ static RCTBorderStyle RCTBorderStyleFromOutlineStyle(OutlineStyle outlineStyle)
if (_useCustomContainerView) {
if (!_containerView) {
_containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
_containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
for (UIView *subview = nullptr in effectiveContentView.subviews) {
[_containerView addSubview:subview];
}
@@ -1540,6 +1542,62 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
}
}
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
{
if ([commandName isEqualToString:@"focus"]) {
[self focus];
return;
}
if ([commandName isEqualToString:@"blur"]) {
[self blur];
return;
}
}
- (void)focus
{
[self becomeFirstResponder];
}
- (void)blur
{
[self resignFirstResponder];
}
#pragma mark - Focus Events
- (BOOL)becomeFirstResponder
{
if (![super becomeFirstResponder]) {
return NO;
}
if (_eventEmitter && ReactNativeFeatureFlags::enableImperativeFocus()) {
_eventEmitter->onFocus();
}
return YES;
}
- (BOOL)resignFirstResponder
{
if (![super resignFirstResponder]) {
return NO;
}
if (_eventEmitter && ReactNativeFeatureFlags::enableImperativeFocus()) {
_eventEmitter->onBlur();
}
return YES;
}
@end
#ifdef __cplusplus
@@ -111,6 +111,12 @@ typedef NS_OPTIONS(NSInteger, RNComponentViewUpdateMask) {
*/
- (void)prepareForRecycle;
/*
* Called for unmounted components that won't be moved to a recycle pool.
* Useful for releasing any associated resources.
*/
- (void)invalidate;
/*
* Read the last props used to update the view.
*/
@@ -108,6 +108,7 @@ const NSInteger RCTComponentViewRegistryRecyclePoolMaxSize = 1024;
auto &recycledViews = _recyclePool[componentHandle];
if (recycledViews.size() > RCTComponentViewRegistryRecyclePoolMaxSize || !componentViewDescriptor.shouldBeRecycled) {
[componentViewDescriptor.view invalidate];
return;
}
@@ -37,6 +37,8 @@ NS_ASSUME_NONNULL_BEGIN
- (void)prepareForRecycle;
- (void)invalidate;
- (facebook::react::Props::Shared)props;
- (void)setIsJSResponder:(BOOL)isJSResponder;
@@ -129,6 +129,11 @@ using namespace facebook::react;
// Default implementation does nothing.
}
- (void)invalidate
{
// Default implementation does nothing.
}
- (facebook::react::Props::Shared)props
{
RCTAssert(NO, @"props access should be implemented by RCTViewComponentView.");
@@ -61,7 +61,7 @@ RCT_EXTERN CGPathRef RCTPathCreateWithRoundedRect(
CGRect bounds,
RCTCornerInsets cornerInsets,
const CGAffineTransform *transform,
const BOOL inverted);
BOOL inverted);
/**
* Draw a CSS-compliant border as an image. You can determine if it's scalable
@@ -1892,6 +1892,7 @@ public final class com/facebook/react/devsupport/DefaultDevLoadingViewImplementa
public fun <init> (Lcom/facebook/react/devsupport/ReactInstanceDevHelper;)V
public fun hide ()V
public fun showMessage (Ljava/lang/String;)V
public fun showMessage (Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Double;)V
public fun updateProgress (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;)V
}
@@ -2119,6 +2120,7 @@ public abstract interface class com/facebook/react/devsupport/interfaces/DevBund
public abstract interface class com/facebook/react/devsupport/interfaces/DevLoadingViewManager {
public abstract fun hide ()V
public abstract fun showMessage (Ljava/lang/String;)V
public abstract fun showMessage (Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Double;)V
public abstract fun updateProgress (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;)V
}
@@ -5564,7 +5566,7 @@ public final class com/facebook/react/views/scroll/ReactHorizontalScrollContaine
public final class com/facebook/react/views/scroll/ReactHorizontalScrollContainerViewManager$Companion {
}
public class com/facebook/react/views/scroll/ReactHorizontalScrollView : android/widget/HorizontalScrollView, android/view/View$OnLayoutChangeListener, android/view/ViewGroup$OnHierarchyChangeListener, com/facebook/react/uimanager/ReactClippingViewGroup, com/facebook/react/uimanager/ReactOverflowViewWithInset, com/facebook/react/views/scroll/ReactAccessibleScrollView, com/facebook/react/views/scroll/ReactScrollViewHelper$HasFlingAnimator, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollEventThrottle, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollState, com/facebook/react/views/scroll/ReactScrollViewHelper$HasSmoothScroll, com/facebook/react/views/scroll/ReactScrollViewHelper$HasStateWrapper {
public class com/facebook/react/views/scroll/ReactHorizontalScrollView : android/widget/HorizontalScrollView, android/view/View$OnLayoutChangeListener, android/view/ViewGroup$OnHierarchyChangeListener, com/facebook/react/uimanager/ReactClippingViewGroup, com/facebook/react/uimanager/ReactOverflowViewWithInset, com/facebook/react/views/scroll/ReactAccessibleScrollView, com/facebook/react/views/scroll/ReactScrollViewHelper$HasFlingAnimator, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollEventThrottle, com/facebook/react/views/scroll/ReactScrollViewHelper$HasScrollState, com/facebook/react/views/scroll/ReactScrollViewHelper$HasSmoothScroll, com/facebook/react/views/scroll/ReactScrollViewHelper$HasStateWrapper, com/facebook/react/views/scroll/VirtualViewContainer {
public fun <init> (Landroid/content/Context;)V
public fun <init> (Landroid/content/Context;Lcom/facebook/react/views/scroll/FpsListener;)V
public fun abortAnimation ()V
@@ -5594,6 +5596,7 @@ public class com/facebook/react/views/scroll/ReactHorizontalScrollView : android
public fun getScrollEnabled ()Z
public fun getScrollEventThrottle ()I
public fun getStateWrapper ()Lcom/facebook/react/uimanager/StateWrapper;
public fun getVirtualViewContainerState ()Lcom/facebook/react/views/scroll/VirtualViewContainerState;
protected fun handleInterceptedTouchEvent (Landroid/view/MotionEvent;)V
public fun isPartiallyScrolledInView (Landroid/view/View;)Z
protected fun onAttachedToWindow ()V
@@ -328,6 +328,15 @@ public class ReactInstanceManager {
}
registerCxxErrorHandlerFunc();
// Using `if (true)` just to prevent tests / lint errors.
if (true) {
// Legacy architecture of React Native is deprecated and can't be initialized anymore.
// More details on:
// https://github.com/react-native-community/discussions-and-proposals/blob/nc/legacy-arch-removal/proposals/0929-legacy-architecture-removal.md
throw new UnsupportedOperationException(
"ReactInstanceManager.createReactContext is unsupported.");
}
}
private ReactInstanceDevHelper createDevHelperInterface() {
@@ -1446,6 +1455,7 @@ public class ReactInstanceManager {
*/
private ReactApplicationContext createReactContext(
JavaScriptExecutor jsExecutor, JSBundleLoader jsBundleLoader) {
FLog.d(ReactConstants.TAG, "ReactInstanceManager.createReactContext()");
ReactMarker.logMarker(CREATE_REACT_CONTEXT_START, jsExecutor.getName());
@@ -196,9 +196,11 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
private val nodesManagerRef = AtomicReference<NativeAnimatedNodesManager?>()
@Volatile private var currentFrameNumber: Long = 0
private var batchingControlledByJS = false // TODO T71377544: delete
@Volatile private var currentBatchNumber: Long = 0 // frame number at last operations dispatch
@Volatile private var currentFrameNumber: Long = 0 // TODO T71377544: delete
@Volatile private var currentBatchNumber: Long = 0
private var initializedForFabric = false
private var initializedForNonFabric = false
@@ -280,19 +282,22 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
var batchNumber = currentBatchNumber - 1
// The problem we're trying to solve here: we could be in the middle of queueing
// a batch of related animation operations when Fabric flushes a batch of MountItems.
// It's visually bad if we execute half of the animation ops and then wait another frame
// (or more) to execute the rest.
// See mFrameNumber. If the dispatchedFrameNumber drifts too far - that
// is, if no MountItems are scheduled for a while, which can happen if a tree
// is committed but there are no changes - bring these counts back in sync and
// execute any queued operations. This number is arbitrary, but we want it low
// enough that the user shouldn't be able to see this delay in most cases.
currentFrameNumber++
if ((currentFrameNumber - currentBatchNumber) > 2) {
currentBatchNumber = currentFrameNumber
batchNumber = currentBatchNumber
// TODO T71377544: delete this when the JS method is confirmed safe
if (!batchingControlledByJS) {
// The problem we're trying to solve here: we could be in the middle of queueing
// a batch of related animation operations when Fabric flushes a batch of MountItems.
// It's visually bad if we execute half of the animation ops and then wait another frame
// (or more) to execute the rest.
// See mFrameNumber. If the dispatchedFrameNumber drifts too far - that
// is, if no MountItems are scheduled for a while, which can happen if a tree
// is committed but there are no changes - bring these counts back in sync and
// execute any queued operations. This number is arbitrary, but we want it low
// enough that the user shouldn't be able to see this delay in most cases.
currentFrameNumber++
if ((currentFrameNumber - currentBatchNumber) > 2) {
currentBatchNumber = currentFrameNumber
batchNumber = currentBatchNumber
}
}
preOperations.executeBatch(batchNumber, nodesManager)
@@ -479,14 +484,14 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) :
}
}
@Suppress("DEPRECATION")
override fun startOperationBatch() {
// no-op
batchingControlledByJS = true
currentBatchNumber++
}
@Suppress("DEPRECATION")
override fun finishOperationBatch() {
// no-op
batchingControlledByJS = false
currentBatchNumber++
}
override fun createAnimatedNode(tagDouble: Double, config: ReadableMap) {
@@ -774,8 +774,12 @@ public class NativeAnimatedNodesManager(
("Looks like animated nodes graph has ${reason}, there are $activeNodesCount but toposort visited only $updatedNodesCount")
)
if (eventListenerInitializedForFabric && cyclesDetected == 0) {
// TODO T71377544: investigate these SoftExceptions and see if we can remove entirely
// or fix the root cause
ReactSoftExceptionLogger.logSoftException(TAG, ReactNoCrashSoftException(ex))
} else if (eventListenerInitializedForFabric) {
// TODO T71377544: investigate these SoftExceptions and see if we can remove entirely
// or fix the root cause
ReactSoftExceptionLogger.logSoftException(TAG, ReactNoCrashSoftException(ex))
} else {
throw ex
@@ -98,13 +98,7 @@ public object DefaultNewArchitectureEntryPoint {
ReactNativeFeatureFlags.override(ReactNativeFeatureFlagsOverrides_RNOSS_Canary_Android())
}
ReleaseLevel.STABLE -> {
ReactNativeFeatureFlags.override(
ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android(
fabricEnabled,
bridgelessEnabled,
turboModulesEnabled,
)
)
ReactNativeFeatureFlags.override(ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android())
}
}
@@ -125,6 +119,16 @@ public object DefaultNewArchitectureEntryPoint {
privateConcurrentReactEnabled = featureFlags.enableFabricRenderer()
privateBridgelessEnabled = featureFlags.enableBridgelessArchitecture()
val (isValid, errorMessage) =
isConfigurationValid(
privateTurboModulesEnabled,
privateFabricEnabled,
privateBridgelessEnabled,
)
if (!isValid) {
error(errorMessage)
}
DefaultSoLoader.maybeLoadSoLibrary()
}
@@ -158,13 +162,13 @@ public object DefaultNewArchitectureEntryPoint {
fabricEnabled: Boolean,
bridgelessEnabled: Boolean,
): Pair<Boolean, String> =
when {
fabricEnabled && !turboModulesEnabled ->
false to
"fabricEnabled=true requires turboModulesEnabled=true (is now false) - Please update your DefaultNewArchitectureEntryPoint.load() parameters."
bridgelessEnabled && (!turboModulesEnabled || !fabricEnabled) ->
false to
"bridgelessEnabled=true requires (turboModulesEnabled=true AND fabricEnabled=true) - Please update your DefaultNewArchitectureEntryPoint.load() parameters."
else -> true to ""
if (!turboModulesEnabled || !fabricEnabled || !bridgelessEnabled) {
false to
"You cannot load React Native with the New Architecture disabled. " +
"Please use DefaultNewArchitectureEntryPoint.load() instead of " +
"DefaultNewArchitectureEntryPoint.load(turboModulesEnabled=$turboModulesEnabled, " +
"fabricEnabled=$fabricEnabled, bridgelessEnabled=$bridgelessEnabled)"
} else {
true to ""
}
}
@@ -33,10 +33,14 @@ public class DefaultDevLoadingViewImplementation(
private var devLoadingPopup: PopupWindow? = null
override fun showMessage(message: String) {
showMessage(message, color = null, backgroundColor = null)
}
override fun showMessage(message: String, color: Double?, backgroundColor: Double?) {
if (!isEnabled) {
return
}
UiThreadUtil.runOnUiThread { showInternal(message) }
UiThreadUtil.runOnUiThread { showInternal(message, color, backgroundColor) }
}
override fun updateProgress(status: String?, done: Int?, total: Int?) {
@@ -59,7 +63,7 @@ public class DefaultDevLoadingViewImplementation(
}
}
private fun showInternal(message: String) {
private fun showInternal(message: String, color: Double?, backgroundColor: Double?) {
if (devLoadingPopup?.isShowing == true) {
// already showing
return
@@ -84,13 +88,19 @@ public class DefaultDevLoadingViewImplementation(
currentActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val view = inflater.inflate(R.layout.dev_loading_view, null) as TextView
view.text = message
if (color != null) {
view.setTextColor(color.toInt())
}
if (backgroundColor != null) {
view.setBackgroundColor(backgroundColor.toInt())
}
view.setOnClickListener { hideInternal() }
val popup =
PopupWindow(
view,
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
)
popup.isTouchable = false
popup.showAtLocation(currentActivity.window.decorView, Gravity.NO_GRAVITY, 0, topOffset)
devLoadingView = view
devLoadingPopup = popup
@@ -78,7 +78,6 @@ import java.io.File
import java.net.MalformedURLException
import java.net.URL
import java.util.Locale
import javax.inject.Provider
public abstract class DevSupportManagerBase(
protected val applicationContext: Context,
@@ -185,6 +184,7 @@ public abstract class DevSupportManagerBase(
}
private var perfMonitorOverlayManager: PerfMonitorOverlayManager? = null
private var perfMonitorInitialized = false
private var tracingStateProvider: TracingStateProvider? = null
init {
@@ -222,13 +222,6 @@ public abstract class DevSupportManagerBase(
perfMonitorOverlayManager =
PerfMonitorOverlayManager(
reactInstanceDevHelper,
Provider {
val context = reactInstanceDevHelper.currentActivity
if (context == null || context.isFinishing) {
return@Provider null
}
context
},
{ openDebugger(DebuggerFrontendPanelName.PERFORMANCE.toString()) },
)
}
@@ -552,14 +545,16 @@ public abstract class DevSupportManagerBase(
}
override fun onNewReactContextCreated(reactContext: ReactContext) {
resetCurrentContext(reactContext)
if (reactInstanceDevHelper is PerfMonitorDevHelper) {
if (!perfMonitorInitialized && reactInstanceDevHelper is PerfMonitorDevHelper) {
perfMonitorOverlayManager?.let { manager ->
reactInstanceDevHelper.inspectorTarget?.addPerfMonitorListener(manager)
}
perfMonitorOverlayManager?.enable()
perfMonitorOverlayManager?.startBackgroundTrace()
perfMonitorInitialized = true
}
resetCurrentContext(reactContext)
}
override fun onReactInstanceDestroyed(reactContext: ReactContext) {
@@ -877,8 +872,6 @@ public abstract class DevSupportManagerBase(
devLoadingViewManager?.showMessage("Reloading...")
}
perfMonitorOverlayManager?.reset()
devServerHelper.openPackagerConnection(
javaClass.simpleName,
object : PackagerCommandListener {
@@ -928,7 +921,7 @@ public abstract class DevSupportManagerBase(
hideRedboxDialog()
hideDevOptionsDialog()
devLoadingViewManager?.hide()
perfMonitorOverlayManager?.reset()
perfMonitorOverlayManager?.disable()
devServerHelper.closePackagerConnection()
}
@@ -11,6 +11,8 @@ package com.facebook.react.devsupport.interfaces
public interface DevLoadingViewManager {
public fun showMessage(message: String)
public fun showMessage(message: String, color: Double?, backgroundColor: Double?)
public fun updateProgress(status: String?, done: Int?, total: Int?)
public fun hide()
@@ -7,11 +7,15 @@
package com.facebook.react.devsupport.perfmonitor
import android.app.Activity
/**
* Interface implemented by [com.facebook.react.runtime.ReactHostImplDevHelper] exposing additional
* hooks used to implement the V2 Perf Monitor overlay (experimental).
*/
internal interface PerfMonitorDevHelper {
public val currentActivity: Activity?
/**
* The inspector target object. Matches the lifetime of the ReactHost. May be null if modern JS
* debugging is disabled.
@@ -7,42 +7,24 @@
package com.facebook.react.devsupport.perfmonitor
import android.content.Context
import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.devsupport.interfaces.TracingState
import javax.inject.Provider
internal class PerfMonitorOverlayManager(
private val devHelper: PerfMonitorDevHelper,
private val contextProvider: Provider<Context?>,
private val onRequestOpenDevTools: () -> Unit,
) : PerfMonitorUpdateListener {
private var enabled: Boolean = false
private var initialized: Boolean = false
private var view: PerfMonitorOverlayView? = null
private var tracingState: TracingState = TracingState.ENABLEDINCDPMODE
private fun init() {
if (initialized || !enabled) {
return
}
UiThreadUtil.runOnUiThread {
val context = contextProvider.get() ?: return@runOnUiThread
view = PerfMonitorOverlayView(context, ::handleRecordingButtonPress)
// Start background tracing
devHelper.inspectorTarget?.resumeBackgroundTrace()
view?.show()
initialized = true
}
}
/** Enable the Perf Monitor overlay. Will be shown when updates are received. */
/** Enable the Perf Monitor overlay. */
fun enable() {
enabled = true
init()
UiThreadUtil.runOnUiThread {
val context = devHelper.currentActivity ?: return@runOnUiThread
view = PerfMonitorOverlayView(context, ::handleRecordingButtonPress)
}
}
/** Disable the Perf Monitor overlay. Will remain hidden when updates are received. */
@@ -52,24 +34,31 @@ internal class PerfMonitorOverlayManager(
enabled = false
}
/** Reset the Perf Monitor overlay, e.g. after a reload. */
fun reset() {
// Update with current recording state
onRecordingStateChanged(
devHelper.inspectorTarget?.getTracingState() ?: TracingState.ENABLEDINCDPMODE
)
/** Start background trace recording. */
fun startBackgroundTrace() {
if (!enabled) {
return
}
devHelper.inspectorTarget?.let { target ->
target.resumeBackgroundTrace()
onRecordingStateChanged(target.getTracingState())
}
}
override fun onRecordingStateChanged(state: TracingState) {
tracingState = state
view?.updateRecordingState(state)
UiThreadUtil.runOnUiThread {
view?.updateRecordingState(state)
view?.show()
}
}
private fun handleRecordingButtonPress() {
when (tracingState) {
TracingState.ENABLEDINBACKGROUNDMODE -> {
devHelper.inspectorTarget?.let {
if (!it.pauseAndAnalyzeBackgroundTrace()) {
devHelper.inspectorTarget?.let { target ->
if (!target.pauseAndAnalyzeBackgroundTrace()) {
onRequestOpenDevTools()
}
}
@@ -55,11 +55,11 @@ internal class PerfMonitorOverlayView(
if (state == TracingState.ENABLEDINBACKGROUNDMODE) {
(statusIndicator.background as GradientDrawable).setColor(Color.RED)
statusLabel.text = "Background Profiling Active"
statusLabel.text = "Profiling Active"
tooltipLabel.text = "Press ☰ to open"
} else {
(statusIndicator.background as GradientDrawable).setColor(Color.GRAY)
statusLabel.text = "Background Profiling Stopped"
statusLabel.text = "Profiling Stopped"
tooltipLabel.text = "Press ☰ to restart"
}
dialog.show()
@@ -164,7 +164,7 @@ internal class PerfMonitorOverlayView(
shape = GradientDrawable.RECTANGLE
setColor(Color.BLACK)
cornerRadius = dpToPx(14.5f)
alpha = (0.8 * 255).toInt()
alpha = (0.4 * 255).toInt()
setStroke(dpToPx(1f).toInt(), COLOR_OVERLAY_BORDER)
}
showDividers = LinearLayout.SHOW_DIVIDER_MIDDLE
@@ -821,6 +821,9 @@ public class SurfaceMountingManager {
@UnstableReactNativeAPI
public void experimental_prefetchResources(
int surfaceId, String componentName, MapBuffer params) {
if (isStopped()) {
return;
}
mViewManagerRegistry
.get(componentName)
.experimental_prefetchResources(
@@ -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<<f089964c958dfcac00f83c3371ccbefc>>
* @generated SignedSource<<6b632ac7553ae149fa42a67efde5acfa>>
*/
/**
@@ -180,6 +180,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun enableImagePrefetchingAndroid(): Boolean = accessor.enableImagePrefetchingAndroid()
/**
* When enabled, Android will build and initiate image prefetch requests on ImageShadowNode::layout and batch them together in a single JNI call
*/
@JvmStatic
public fun enableImagePrefetchingJNIBatchingAndroid(): Boolean = accessor.enableImagePrefetchingJNIBatchingAndroid()
/**
* When enabled, Android will initiate image prefetch requested on ImageShadowNode::layout on the UI thread
*/
@@ -192,6 +198,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean = accessor.enableImmediateUpdateModeForContentOffsetChanges()
/**
* Enable ref.focus() and ref.blur() for all views, not just TextInput.
*/
@JvmStatic
public fun enableImperativeFocus(): Boolean = accessor.enableImperativeFocus()
/**
* This is to fix the issue with interop view manager where component descriptor lookup is causing ViewManager to preload.
*/
@@ -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<<912dec895495052328e7e52b94a6738a>>
* @generated SignedSource<<c228bdbf6120b4715f49e03c04918a7c>>
*/
/**
@@ -45,8 +45,10 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null
private var enableIOSViewClipToPaddingBoxCache: Boolean? = null
private var enableImagePrefetchingAndroidCache: Boolean? = null
private var enableImagePrefetchingJNIBatchingAndroidCache: Boolean? = null
private var enableImagePrefetchingOnUiThreadAndroidCache: Boolean? = null
private var enableImmediateUpdateModeForContentOffsetChangesCache: Boolean? = null
private var enableImperativeFocusCache: Boolean? = null
private var enableInteropViewManagerClassLookUpOptimizationIOSCache: Boolean? = null
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
@@ -319,6 +321,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun enableImagePrefetchingJNIBatchingAndroid(): Boolean {
var cached = enableImagePrefetchingJNIBatchingAndroidCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.enableImagePrefetchingJNIBatchingAndroid()
enableImagePrefetchingJNIBatchingAndroidCache = cached
}
return cached
}
override fun enableImagePrefetchingOnUiThreadAndroid(): Boolean {
var cached = enableImagePrefetchingOnUiThreadAndroidCache
if (cached == null) {
@@ -337,6 +348,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun enableImperativeFocus(): Boolean {
var cached = enableImperativeFocusCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.enableImperativeFocus()
enableImperativeFocusCache = cached
}
return cached
}
override fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean {
var cached = enableInteropViewManagerClassLookUpOptimizationIOSCache
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<<ba1e53d93b9fdaf298a034543bc44a57>>
* @generated SignedSource<<26dce1945df5641ab84cbca9eaf2b10f>>
*/
/**
@@ -78,10 +78,14 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun enableImagePrefetchingAndroid(): Boolean
@DoNotStrip @JvmStatic public external fun enableImagePrefetchingJNIBatchingAndroid(): Boolean
@DoNotStrip @JvmStatic public external fun enableImagePrefetchingOnUiThreadAndroid(): Boolean
@DoNotStrip @JvmStatic public external fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean
@DoNotStrip @JvmStatic public external fun enableImperativeFocus(): Boolean
@DoNotStrip @JvmStatic public external fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean
@DoNotStrip @JvmStatic public external fun enableLayoutAnimationsOnAndroid(): 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<<7601cbcde75ff19ef0fe67f6faef2549>>
* @generated SignedSource<<11051ece1b61fd4bf4ca003a3b7fc4f9>>
*/
/**
@@ -73,10 +73,14 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun enableImagePrefetchingAndroid(): Boolean = false
override fun enableImagePrefetchingJNIBatchingAndroid(): Boolean = false
override fun enableImagePrefetchingOnUiThreadAndroid(): Boolean = false
override fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean = false
override fun enableImperativeFocus(): Boolean = false
override fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean = false
override fun enableLayoutAnimationsOnAndroid(): Boolean = 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<<3a13f8e35423b634ed4ef46fbac3c1e9>>
* @generated SignedSource<<66fa583c37021750123a483ab0ccb030>>
*/
/**
@@ -49,8 +49,10 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
private var enableIOSTextBaselineOffsetPerLineCache: Boolean? = null
private var enableIOSViewClipToPaddingBoxCache: Boolean? = null
private var enableImagePrefetchingAndroidCache: Boolean? = null
private var enableImagePrefetchingJNIBatchingAndroidCache: Boolean? = null
private var enableImagePrefetchingOnUiThreadAndroidCache: Boolean? = null
private var enableImmediateUpdateModeForContentOffsetChangesCache: Boolean? = null
private var enableImperativeFocusCache: Boolean? = null
private var enableInteropViewManagerClassLookUpOptimizationIOSCache: Boolean? = null
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
@@ -348,6 +350,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}
override fun enableImagePrefetchingJNIBatchingAndroid(): Boolean {
var cached = enableImagePrefetchingJNIBatchingAndroidCache
if (cached == null) {
cached = currentProvider.enableImagePrefetchingJNIBatchingAndroid()
accessedFeatureFlags.add("enableImagePrefetchingJNIBatchingAndroid")
enableImagePrefetchingJNIBatchingAndroidCache = cached
}
return cached
}
override fun enableImagePrefetchingOnUiThreadAndroid(): Boolean {
var cached = enableImagePrefetchingOnUiThreadAndroidCache
if (cached == null) {
@@ -368,6 +380,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
return cached
}
override fun enableImperativeFocus(): Boolean {
var cached = enableImperativeFocusCache
if (cached == null) {
cached = currentProvider.enableImperativeFocus()
accessedFeatureFlags.add("enableImperativeFocus")
enableImperativeFocusCache = cached
}
return cached
}
override fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean {
var cached = enableInteropViewManagerClassLookUpOptimizationIOSCache
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<<4feeb3c1789d8169dd93bee7ae1ff1ac>>
* @generated SignedSource<<dffc5db0f80501f6246f9d6087c6fb4a>>
*/
/**
@@ -25,5 +25,7 @@ public open class ReactNativeFeatureFlagsOverrides_RNOSS_Experimental_Android :
override fun enableAccessibilityOrder(): Boolean = true
override fun enableSwiftUIBasedFilters(): Boolean = true
override fun preventShadowTreeCommitExhaustion(): Boolean = true
}
@@ -7,16 +7,10 @@
package com.facebook.react.internal.featureflags
public class ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android(
private val fabricEnabled: Boolean,
private val bridgelessEnabled: Boolean,
private val turboModulesEnabled: Boolean,
) : ReactNativeNewArchitectureFeatureFlagsDefaults(bridgelessEnabled) {
override fun useFabricInterop(): Boolean = bridgelessEnabled || fabricEnabled
public class ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android() :
ReactNativeNewArchitectureFeatureFlagsDefaults() {
override fun enableFabricRenderer(): Boolean = bridgelessEnabled || fabricEnabled
override fun useTurboModules(): Boolean = bridgelessEnabled || turboModulesEnabled
override fun useFabricInterop(): Boolean = true
override fun useShadowNodeStateOnClone(): 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<<143b568248e68033efaefc3f178ff6db>>
* @generated SignedSource<<f26998daf87c8b90c2ec822c8316b134>>
*/
/**
@@ -73,10 +73,14 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun enableImagePrefetchingAndroid(): Boolean
@DoNotStrip public fun enableImagePrefetchingJNIBatchingAndroid(): Boolean
@DoNotStrip public fun enableImagePrefetchingOnUiThreadAndroid(): Boolean
@DoNotStrip public fun enableImmediateUpdateModeForContentOffsetChanges(): Boolean
@DoNotStrip public fun enableImperativeFocus(): Boolean
@DoNotStrip public fun enableInteropViewManagerClassLookUpOptimizationIOS(): Boolean
@DoNotStrip public fun enableLayoutAnimationsOnAndroid(): Boolean
@@ -20,9 +20,11 @@ package com.facebook.react.internal.featureflags
* When the new architecture is enabled, we want to set the default values of the flags for Fabric,
* TurboModules and Bridgeless as enabled by default.
*/
public open class ReactNativeNewArchitectureFeatureFlagsDefaults(
private val newArchitectureEnabled: Boolean = true
) : ReactNativeFeatureFlagsDefaults() {
public open class ReactNativeNewArchitectureFeatureFlagsDefaults() :
ReactNativeFeatureFlagsDefaults() {
private val newArchitectureEnabled: Boolean = true
override fun enableBridgelessArchitecture(): Boolean = newArchitectureEnabled
override fun enableFabricRenderer(): Boolean = newArchitectureEnabled
@@ -31,7 +31,9 @@ internal class DevLoadingModule(reactContext: ReactApplicationContext) :
}
override fun showMessage(message: String, color: Double?, backgroundColor: Double?) {
UiThreadUtil.runOnUiThread { devLoadingViewManager?.showMessage(message) }
UiThreadUtil.runOnUiThread {
devLoadingViewManager?.showMessage(message, color, backgroundColor)
}
}
override fun hide() {
@@ -648,6 +648,10 @@ public class ReactHostImpl(
if (currentReactContext != null) {
if (ReactNativeFeatureFlags.enableFontScaleChangesUpdatingLayout()) {
DisplayMetricsHolder.initDisplayMetrics(currentReactContext)
synchronized(attachedSurfaces) {
attachedSurfaces.forEach { surface -> surface.view?.requestLayout() }
}
}
val appearanceModule = currentReactContext.getNativeModule(AppearanceModule::class.java)
@@ -1,137 +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.
*/
@file:Suppress("DEPRECATION")
package com.facebook.react.uimanager.layoutanimation
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.AccelerateInterpolator
import android.view.animation.Animation
import android.view.animation.BaseInterpolator
import android.view.animation.DecelerateInterpolator
import android.view.animation.Interpolator
import android.view.animation.LinearInterpolator
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.common.annotations.VisibleForTesting
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
import com.facebook.react.uimanager.IllegalViewOperationException
/**
* Class responsible for parsing and converting layout animation data into native [Animation] in
* order to animate layout when a valid configuration has been supplied by the application.
*/
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
@Deprecated(
message = "This class is part of Legacy Architecture and will be removed in a future release",
level = DeprecationLevel.WARNING,
)
internal abstract class AbstractLayoutAnimation {
var interpolator: Interpolator? = null
var delayMs: Int = 0
var animatedProperty: AnimatedPropertyType? = null
var durationMs: Int = 0
internal abstract fun isValid(): Boolean
/**
* Create an animation object for the current animation type, based on the view and final screen
* coordinates. If the application-supplied configuration does not specify an animation definition
* for this types, or if the animation definition is invalid, returns null.
*/
internal abstract fun createAnimationImpl(
view: View,
x: Int,
y: Int,
width: Int,
height: Int,
): Animation?
fun reset() {
animatedProperty = null
durationMs = 0
delayMs = 0
interpolator = null
}
fun initializeFromConfig(data: ReadableMap, globalDuration: Int) {
animatedProperty =
if (data.hasKey("property")) {
AnimatedPropertyType.fromString(data.getString("property").orEmpty())
} else {
null
}
durationMs = if (data.hasKey("duration")) data.getInt("duration") else globalDuration
delayMs = if (data.hasKey("delay")) data.getInt("delay") else 0
require(data.hasKey("type")) { "Missing interpolation type." }
interpolator =
getInterpolator(InterpolatorType.fromString(data.getString("type").orEmpty()), data)
if (!isValid()) {
throw IllegalViewOperationException("Invalid layout animation : $data")
}
}
/**
* Create an animation object to be used to animate the view, based on the animation config
* supplied at initialization time and the new view position and size.
*
* @param view the view to create the animation for
* @param x the new X position for the view
* @param y the new Y position for the view
* @param width the new width value for the view
* @param height the new height value for the view
*/
fun createAnimation(view: View, x: Int, y: Int, width: Int, height: Int): Animation? {
if (!isValid()) {
return null
}
return createAnimationImpl(view, x, y, width, height)?.apply {
val slowdownFactor = if (SLOWDOWN_ANIMATION_MODE) 10 else 1
duration = (durationMs * slowdownFactor).toLong()
startOffset = (delayMs * slowdownFactor).toLong()
interpolator = this@AbstractLayoutAnimation.interpolator
}
}
companion object {
init {
LegacyArchitectureLogger.assertLegacyArchitecture(
"AbstractLayoutAnimation",
LegacyArchitectureLogLevel.ERROR,
)
}
// Forces animation to be playing 10x slower, used for debug purposes.
private const val SLOWDOWN_ANIMATION_MODE = false
private val INTERPOLATOR: Map<InterpolatorType, BaseInterpolator> =
mapOf(
InterpolatorType.LINEAR to LinearInterpolator(),
InterpolatorType.EASE_IN to AccelerateInterpolator(),
InterpolatorType.EASE_OUT to DecelerateInterpolator(),
InterpolatorType.EASE_IN_EASE_OUT to AccelerateDecelerateInterpolator(),
)
@VisibleForTesting
fun getInterpolator(type: InterpolatorType, params: ReadableMap): Interpolator {
val interpolator =
if (type == InterpolatorType.SPRING) {
SimpleSpringInterpolator(SimpleSpringInterpolator.getSpringDamping(params))
} else {
INTERPOLATOR[type]
}
requireNotNull(interpolator) { "Missing interpolator for type : $type" }
return interpolator
}
}
}
@@ -1,42 +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.
*/
@file:Suppress("DEPRECATION")
package com.facebook.react.uimanager.layoutanimation
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
/**
* Enum representing the different view properties that can be used when animating layout for view
* creation.
*/
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
@Deprecated(
message = "This class is part of Legacy Architecture and will be removed in a future release",
level = DeprecationLevel.WARNING,
)
internal enum class AnimatedPropertyType {
OPACITY,
SCALE_X,
SCALE_Y,
SCALE_XY;
companion object {
@JvmStatic
fun fromString(name: String): AnimatedPropertyType {
return when (name) {
"opacity" -> OPACITY
"scaleX" -> SCALE_X
"scaleY" -> SCALE_Y
"scaleXY" -> SCALE_XY
else -> throw IllegalArgumentException("Unsupported animated property: $name")
}
}
}
}
@@ -1,96 +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.
*/
@file:Suppress("DEPRECATION")
package com.facebook.react.uimanager.layoutanimation
import android.view.View
import android.view.animation.Animation
import android.view.animation.ScaleAnimation
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
import com.facebook.react.uimanager.IllegalViewOperationException
/** Class responsible for default layout animation, i.e animation of view creation and deletion. */
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
@Deprecated(
message = "This class is part of Legacy Architecture and will be removed in a future release",
level = DeprecationLevel.WARNING,
)
internal abstract class BaseLayoutAnimation : AbstractLayoutAnimation() {
abstract fun isReverse(): Boolean
override fun isValid(): Boolean = durationMs > 0 && animatedProperty != null
override fun createAnimationImpl(view: View, x: Int, y: Int, width: Int, height: Int): Animation {
animatedProperty?.let {
return when (it) {
AnimatedPropertyType.OPACITY -> {
val fromValue = if (isReverse()) view.alpha else 0.0f
val toValue = if (isReverse()) 0.0f else view.alpha
OpacityAnimation(view, fromValue, toValue)
}
AnimatedPropertyType.SCALE_XY -> {
val fromValue = if (isReverse()) 1.0f else 0.0f
val toValue = if (isReverse()) 0.0f else 1.0f
ScaleAnimation(
fromValue,
toValue,
fromValue,
toValue,
Animation.RELATIVE_TO_SELF,
.5f,
Animation.RELATIVE_TO_SELF,
.5f,
)
}
AnimatedPropertyType.SCALE_X -> {
val fromValue = if (isReverse()) 1.0f else 0.0f
val toValue = if (isReverse()) 0.0f else 1.0f
ScaleAnimation(
fromValue,
toValue,
1f,
1f,
Animation.RELATIVE_TO_SELF,
.5f,
Animation.RELATIVE_TO_SELF,
0f,
)
}
AnimatedPropertyType.SCALE_Y -> {
val fromValue = if (isReverse()) 1.0f else 0.0f
val toValue = if (isReverse()) 0.0f else 1.0f
ScaleAnimation(
1f,
1f,
fromValue,
toValue,
Animation.RELATIVE_TO_SELF,
0f,
Animation.RELATIVE_TO_SELF,
.5f,
)
}
}
} ?: throw IllegalViewOperationException("Missing animated property from animation config")
}
private companion object {
init {
LegacyArchitectureLogger.assertLegacyArchitecture(
"BaseLayoutAnimation",
LegacyArchitectureLogLevel.ERROR,
)
}
}
}
@@ -1,43 +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.
*/
@file:Suppress("DEPRECATION")
package com.facebook.react.uimanager.layoutanimation
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
/**
* Enum representing the different interpolators that can be used in layout animation configuration.
*/
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
@Deprecated(
message = "This class is part of Legacy Architecture and will be removed in a future release",
level = DeprecationLevel.WARNING,
)
internal enum class InterpolatorType {
LINEAR,
EASE_IN,
EASE_OUT,
EASE_IN_EASE_OUT,
SPRING;
companion object {
@JvmStatic
fun fromString(name: String): InterpolatorType {
return when (name.lowercase()) {
"linear" -> LINEAR
"easein" -> EASE_IN
"easeout" -> EASE_OUT
"easeineaseout" -> EASE_IN_EASE_OUT
"spring" -> SPRING
else -> throw IllegalArgumentException("Unsupported interpolation type : $name")
}
}
}
}
@@ -9,19 +9,12 @@
package com.facebook.react.uimanager.layoutanimation
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.Animation.AnimationListener
import com.facebook.react.bridge.Callback
import com.facebook.react.bridge.ReadableMap
import com.facebook.react.bridge.UiThreadUtil.assertOnUiThread
import com.facebook.react.bridge.UiThreadUtil.getUiThreadHandler
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger.assertLegacyArchitecture
import com.facebook.react.uimanager.layoutanimation.LayoutAnimationType.Companion.toString
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
import javax.annotation.concurrent.NotThreadSafe
/**
@@ -36,75 +29,27 @@ import javax.annotation.concurrent.NotThreadSafe
level = DeprecationLevel.WARNING,
)
public open class LayoutAnimationController {
private val layoutCreateAnimation: AbstractLayoutAnimation = LayoutCreateAnimation()
private val layoutUpdateAnimation: AbstractLayoutAnimation = LayoutUpdateAnimation()
private val layoutDeleteAnimation: AbstractLayoutAnimation = LayoutDeleteAnimation()
private val layoutHandlers = SparseArray<LayoutHandlingAnimation?>(0)
private var shouldAnimateLayout = false
private var maxAnimationDuration: Long = -1
private var completionRunnable: Runnable? = null
public fun initializeFromConfig(config: ReadableMap?, completionCallback: Callback?) {
if (config == null) {
reset()
return
}
shouldAnimateLayout = false
val globalDuration = if (config.hasKey("duration")) config.getInt("duration") else 0
if (config.hasKey(toString(LayoutAnimationType.CREATE))) {
layoutCreateAnimation.initializeFromConfig(
config.getMap(toString(LayoutAnimationType.CREATE))!!,
globalDuration,
)
shouldAnimateLayout = true
}
if (config.hasKey(toString(LayoutAnimationType.UPDATE))) {
layoutUpdateAnimation.initializeFromConfig(
config.getMap(toString(LayoutAnimationType.UPDATE))!!,
globalDuration,
)
shouldAnimateLayout = true
}
if (config.hasKey(toString(LayoutAnimationType.DELETE))) {
layoutDeleteAnimation.initializeFromConfig(
config.getMap(toString(LayoutAnimationType.DELETE))!!,
globalDuration,
)
shouldAnimateLayout = true
}
if (shouldAnimateLayout && completionCallback != null) {
completionRunnable = Runnable { completionCallback.invoke(java.lang.Boolean.TRUE) }
}
LegacyArchitectureLogger.assertLegacyArchitecture(
"LayoutAnimationController",
LegacyArchitectureLogLevel.ERROR,
)
}
public open fun reset() {
layoutCreateAnimation.reset()
layoutUpdateAnimation.reset()
layoutDeleteAnimation.reset()
completionRunnable = null
shouldAnimateLayout = false
maxAnimationDuration = -1
for (i in layoutHandlers.size() - 1 downTo 0) {
val animation = layoutHandlers.valueAt(i)
if (!animation!!.isValid()) {
layoutHandlers.removeAt(i)
}
}
LegacyArchitectureLogger.assertLegacyArchitecture(
"LayoutAnimationController",
LegacyArchitectureLogLevel.ERROR,
)
}
public open fun shouldAnimateLayout(viewToAnimate: View?): Boolean {
// if view parent is null, skip animation: view have been clipped, we don't want animation to
// resume when view is re-attached to parent, which is the standard android animation behavior.
// If there's a layout handling animation going on, it should be animated nonetheless since the
// ongoing animation needs to be updated.
if (viewToAnimate == null) {
return false
}
return ((shouldAnimateLayout && viewToAnimate.parent != null) ||
layoutHandlers[viewToAnimate.id] != null)
LegacyArchitectureLogger.assertLegacyArchitecture(
"LayoutAnimationController",
LegacyArchitectureLogLevel.ERROR,
)
return false
}
/**
@@ -119,57 +64,10 @@ public open class LayoutAnimationController {
* @param height the new height value for the view
*/
public open fun applyLayoutUpdate(view: View, x: Int, y: Int, width: Int, height: Int) {
assertOnUiThread()
val reactTag = view.id
// Update an ongoing animation if possible, otherwise the layout update would be ignored as
// the existing animation would still animate to the old layout.
val existingAnimation = layoutHandlers[reactTag]
if (existingAnimation != null) {
if (!existingAnimation.isValid()) {
layoutHandlers.remove(reactTag)
} else {
existingAnimation.onLayoutUpdate(x, y, width, height)
return
}
}
// Determine which animation to use : if view is initially invisible, use create animation,
// otherwise use update animation. This approach is easier than maintaining a list of tags
// for recently created views.
val layoutAnimation =
if ((view.width == 0 || view.height == 0)) layoutCreateAnimation else layoutUpdateAnimation
val animation = layoutAnimation.createAnimation(view, x, y, width, height)
if (animation is LayoutHandlingAnimation) {
animation.setAnimationListener(
object : AnimationListener {
override fun onAnimationStart(animation: Animation) {
layoutHandlers.put(reactTag, animation as LayoutHandlingAnimation)
}
override fun onAnimationEnd(animation: Animation) {
layoutHandlers.remove(reactTag)
}
override fun onAnimationRepeat(animation: Animation) = Unit
}
)
} else {
view.layout(x, y, x + width, y + height)
}
if (animation != null) {
val animationDuration = animation.duration
if (animationDuration > maxAnimationDuration) {
maxAnimationDuration = animationDuration
scheduleCompletionCallback(animationDuration)
}
view.startAnimation(animation)
}
LegacyArchitectureLogger.assertLegacyArchitecture(
"LayoutAnimationController",
LegacyArchitectureLogLevel.ERROR,
)
}
/**
@@ -181,59 +79,9 @@ public open class LayoutAnimationController {
* view.
*/
public open fun deleteView(view: View, listener: LayoutAnimationListener) {
assertOnUiThread()
val animation =
layoutDeleteAnimation.createAnimation(view, view.left, view.top, view.width, view.height)
if (animation != null) {
disableUserInteractions(view)
animation.setAnimationListener(
object : AnimationListener {
override fun onAnimationStart(anim: Animation) = Unit
override fun onAnimationRepeat(anim: Animation) = Unit
override fun onAnimationEnd(anim: Animation) {
listener.onAnimationEnd()
}
}
)
val animationDuration = animation.duration
if (animationDuration > maxAnimationDuration) {
scheduleCompletionCallback(animationDuration)
maxAnimationDuration = animationDuration
}
view.startAnimation(animation)
} else {
listener.onAnimationEnd()
}
}
/** Disables user interactions for a view and all it's subviews. */
private fun disableUserInteractions(view: View) {
view.isClickable = false
if (view is ViewGroup) {
for (i in 0 until view.childCount) {
disableUserInteractions(view.getChildAt(i))
}
}
}
private fun scheduleCompletionCallback(delayMillis: Long) {
if (completionRunnable != null) {
val completionHandler = getUiThreadHandler()
completionHandler.removeCallbacks(completionRunnable!!)
completionHandler.postDelayed(completionRunnable!!, delayMillis)
}
}
private companion object {
init {
assertLegacyArchitecture("LayoutAnimationController", LegacyArchitectureLogLevel.ERROR)
}
LegacyArchitectureLogger.assertLegacyArchitecture(
"LayoutAnimationController",
LegacyArchitectureLogLevel.ERROR,
)
}
}
@@ -1,46 +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.
*/
@file:Suppress("DEPRECATION")
package com.facebook.react.uimanager.layoutanimation
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
/**
* Enum representing the different animation type that can be specified in layout animation config.
*/
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
@Deprecated(
message = "This class is part of Legacy Architecture and will be removed in a future release",
level = DeprecationLevel.WARNING,
)
internal enum class LayoutAnimationType {
CREATE,
UPDATE,
DELETE;
companion object {
init {
LegacyArchitectureLogger.assertLegacyArchitecture(
"LayoutAnimationType",
LegacyArchitectureLogLevel.ERROR,
)
}
@JvmStatic
fun toString(type: LayoutAnimationType): String {
return when (type) {
CREATE -> "create"
UPDATE -> "update"
DELETE -> "delete"
}
}
}
}
@@ -1,33 +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.
*/
@file:Suppress("DEPRECATION")
package com.facebook.react.uimanager.layoutanimation
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
/**
* Class responsible for handling layout view creation animation, applied to view whenever a valid
* config was supplied for the layout animation of CREATE type.
*/
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
internal class LayoutCreateAnimation : BaseLayoutAnimation() {
override fun isReverse(): Boolean = false
private companion object {
init {
LegacyArchitectureLogger.assertLegacyArchitecture(
"LayoutCreateAnimation",
LegacyArchitectureLogLevel.ERROR,
)
}
}
}
@@ -1,37 +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.
*/
@file:Suppress("DEPRECATION")
package com.facebook.react.uimanager.layoutanimation
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
/**
* Class responsible for handling layout view deletion animation, applied to view whenever a valid
* config was supplied for the layout animation of DELETE type.
*/
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
@Deprecated(
message = "This class is part of Legacy Architecture and will be removed in a future release",
level = DeprecationLevel.WARNING,
)
internal class LayoutDeleteAnimation : BaseLayoutAnimation() {
override fun isReverse(): Boolean = true
private companion object {
init {
LegacyArchitectureLogger.assertLegacyArchitecture(
"LayoutDeleteAnimation",
LegacyArchitectureLogLevel.ERROR,
)
}
}
}
@@ -1,42 +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.
*/
@file:Suppress("DEPRECATION")
package com.facebook.react.uimanager.layoutanimation
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
/** Interface for an animation type that takes care of updating the view layout. */
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
@Deprecated(
message = "This class is part of Legacy Architecture and will be removed in a future release",
level = DeprecationLevel.WARNING,
)
internal interface LayoutHandlingAnimation {
/**
* Notifies the animation of a layout update in case one occurs during the animation. This avoids
* animating the view to the old layout since it's no longer correct; instead the animation should
* update and do whatever it can so that the final layout is correct.
*
* @param x the new X position for the view
* @param y the new Y position for the view
* @param width the new width value for the view
* @param height the new height value for the view
*/
fun onLayoutUpdate(x: Int, y: Int, width: Int, height: Int)
/**
* Returns whether the animation is valid and should be used. Because layout animations generally
* hold {@link java.lang.ref.WeakReference<android.view.View>} objects, it's possible that the
* view has been garbage collected. In this case, the animation should not be used.
*
* @return true if the animation is valid and can be used, false otherwise
*/
fun isValid(): Boolean
}

Some files were not shown because too many files have changed in this diff Show More