Compare commits

...
Author SHA1 Message Date
Vojtech Novak da65b27f92 fix IOException in BuildCodegenCLITask 2024-11-28 16:55:40 +01:00
Kudo ChienandFacebook GitHub Bot 24fee29f7a Add useColorScheme mock test (#47988)
Summary:
add a jest test to test when `useColorScheme` is not mocked. following up https://github.com/facebook/react-native/pull/47629#issuecomment-2491534678

## Changelog:

[GENERAL] [ADDED] - Add useColorScheme mock test

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

Test Plan: ci passed

Reviewed By: javache

Differential Revision: D66573172

Pulled By: blakef

fbshipit-source-id: 820227f6fc4e18a968b3181fad8f534a716f1e9e
2024-11-28 05:05:31 -08:00
Rubén NorteandFacebook GitHub Bot 6ae49ee9e3 Improve error messages in tests (#47994)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47994

Changelog: [internal]

This adds a few hacks to improve errors messages in Fantom tests. Before, we were only logging the error message. After this, we log the message and the full (unsymbolicated for now) stack, including a pretty print of the exact location of the error.

For errors thrown from `expect` functions, the stack trace is modified to remove the "infra" lines from the stack.

The next step is symbolicating the errors using source maps generated by metro.

Reviewed By: javache

Differential Revision: D66555063

fbshipit-source-id: 17bd23cb30429a17e99f13f934c45e001120bbb3
2024-11-28 04:31:20 -08:00
Jorge Cabiedes AcostaandFacebook GitHub Bot ce9f5345e3 Fix Android ensureNoOverlap function and revise implementation (#47989)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47989

- Fixing Android's ensureNoOverlap algorithm. (For real this time)
- Improve verbiage for `ensureNoOverlap` function.

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66514729

fbshipit-source-id: 99908deee2232cc125bb0998ae7acd636a1f7e10
2024-11-27 19:57:55 -08:00
Arushi KesarwaniandFacebook GitHub Bot 5da7089e35 NIT: Updating docstring for DefaultReactHost for missing arguments (#47992)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47992

TSIA

Changelog: [Internal]

Reviewed By: shwanton

Differential Revision: D66552119

fbshipit-source-id: 6dcd461fcea1444a58db4f98316bf8878ae98781
2024-11-27 17:26:19 -08:00
Arushi KesarwaniandFacebook GitHub Bot 762bcc6073 NIT: Updating docstring for DefaultReactHost to match the arguments. (#47991)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47991

TSIA

Changelog: [Internal]

Reviewed By: shwanton

Differential Revision: D66550256

fbshipit-source-id: b3c18032a421fd9f0bd69c142e72d884f96340f8
2024-11-27 17:26:19 -08:00
Alex HuntandFacebook GitHub Bot 7f57018e25 Add profiling_target_registered event, log to terminal (#47968)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47968

Updates the Inspector Proxy to report + log when a profiling build target (experimental) is registered. This notifies the developer that debugging is available for these app(s), which will not otherwise fetch development bundles from Metro.

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D66501771

fbshipit-source-id: e06dee279158094ad5c70bf8e6a90e7c983de48a
2024-11-27 11:42:31 -08:00
Alex HuntandFacebook GitHub Bot b95631ed7f Enable identifying profiling builds on proxy registration (#47967)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47967

(Android only) Updates `jsinspector-modern` to enable identifying profiling builds (experimental) when registering the debug target with the Inspector Proxy.

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D66501768

fbshipit-source-id: bbe2b9a2c7c014c952ef5ee49284a161dbeefb09
2024-11-27 11:42:31 -08:00
Alex HuntandFacebook GitHub Bot b9762d568a Enable identifying profiling builds over CDP (#47966)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47966

Updates `jsinspector-modern` to enable identifying profiling builds (experimental) to the frontend over CDP.

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D66501770

fbshipit-source-id: 9d079da862a59d5e2dc6f970e7418339620e1451
2024-11-27 11:42:31 -08:00
Rubén NorteandFacebook GitHub Bot a36dbae486 Optimize performance of ReactNativeElement constructor (#47983)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47983

Changelog: [internal]

This mitigates some performance regressions caused by the migration from `ReactFabricHostComponent` to `ReactNativeElement` (enabling the DOM APIs).

Those regressions were caused by 2 main things:
1. By the use of a class hierarchy and having to call `super()`, which we transpile to a very complex code to ensure it's spec compliant.
2. By the use of private fields (`#viewConfig`) which are significantly slower than a regular field with the `_` naming convention (`_viewConfig`) processed by our custom transform.

This mitigates those problems by using the `_` convention and refactoring the class hierarchy to avoid the use of `super()` while preserving the Flow typing and most of the existing implementation.

Reviewed By: javache, andrewdacenko

Differential Revision: D66540756

fbshipit-source-id: db6aa18c12194b18e3a69e9979621d0feae6186a
2024-11-27 11:24:31 -08:00
Jakub RomanczykandFacebook GitHub Bot 881d8a720f refactor(community-cli-plugin): use node builtin fetch (#47397)
Summary:
Removed `node-fetch` in favour of node builtin fetch to get rid of the deprecated `punycode` warning when using Node 22.

`react-native/community-cli-plugin` already requires Node >= 18 where it was made available by default (without `--experimental-fetch` flag).

This change is similar to the one made in https://github.com/facebook/react-native/pull/45227

## Changelog:

[GENERAL] [CHANGED] - Drop node-fetch in favor of Node's built-in fetch from undici in `react-native/community-cli-plugin`

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

Test Plan: tests pass

Reviewed By: blakef

Differential Revision: D66512595

Pulled By: NickGerleman

fbshipit-source-id: c4e01baf388f9fae8cea7b4bfe25034bff28b461
2024-11-27 10:39:39 -08:00
Joe VilchesandFacebook GitHub Bot 1d909efa23 Align order of params between calculateLayoutInternal and calculateLayoutImpl (#47975)
Summary:
X-link: https://github.com/facebook/yoga/pull/1755

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

I've been working with callsites here and its annoying if you switch these that you need to move these params around too. Let's just make them the same order

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66519836

fbshipit-source-id: 2e98e671270a053c6e62372e2003f1ca67774ec9
2024-11-26 22:48:24 -08:00
Phillip PanandFacebook GitHub Bot 3c09d6bfce allow bindings installer to be passed down to DefaultReactHost (#47944)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47944

Changelog: [Internal]

adding an option to pass down bindings installer from product layer

Reviewed By: mlord93

Differential Revision: D66477349

fbshipit-source-id: 9462cbe0b1fcee875c18de0426c0c1b02f086ff1
2024-11-26 19:20:56 -08:00
Joe VilchesandFacebook GitHub Bot 40c194cf47 Camel case LengthValue in Node.cpp (#47971)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47971

X-link: https://github.com/facebook/yoga/pull/1754

This was annoying me

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66510734

fbshipit-source-id: d1b952f2e82e7018b16dc0c572d9b98aec18c0e5
2024-11-26 15:23:08 -08:00
Alex HuntandFacebook GitHub Bot 24f010d5b5 Update unstable-react-profiling to use PerftestDevSupportManager (#47715)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47715

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D66167302

fbshipit-source-id: 23e6154eedd36c2011062de3195887cba7af8a72
2024-11-26 12:48:37 -08:00
Andrei MarchenkoandFacebook GitHub Bot df7b6ae092 fix item disappearing with scroll in VirtualizedList (#47965)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47965

Changelog: [General] [Changed] - fix item disappearing with scroll in VirtualizedList

It was caused because the function `computeWindowedRenderLimits` collapsed the current window size to just 1 element. So, users start scroll current window increase from {left:0, right:5 } -> {left:0, right:6 } and after some edge cases the window collapsed to `{left:6, right:6 }` which cause to remove all elements and recreate them later. As a result users have a lot of lags and blank pages.

The diff fixes the collapsing window size to 1 element. Also fix other decreasing `left` position even if windowSize more than current amount of elements.

Reviewed By: NickGerleman

Differential Revision: D66334188

fbshipit-source-id: 2162d00d03d64ab6325c0492d87449051e68a4e9
2024-11-26 10:44:30 -08:00
Rob HoganandFacebook GitHub Bot 016f44518e Changelog for 0.77.0-rc.0 (#47958)
Summary:
Changelog as generated by rnx-kit + manual fixes.

Changelog: [Internal]

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

Reviewed By: rshest, blakef

Differential Revision: D66498590

Pulled By: robhogan

fbshipit-source-id: 81efda2615f8e61be5f5922511362946f3ba3c6b
2024-11-26 08:06:18 -08:00
Dmitry RykunandFacebook GitHub Bot 69356b7f21 Introduce ImageRequestParams (#47723)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47723

Identity of `ImageRequest` is based on `ImageSource` and a subset of `ImageProps`. If any of those change, the request must be recreated and resubmitted.

Currently, the relevant subset of ImageProps is represented by a single `blurRadius` prop. This list will grow in the future. In order to simplify adding new props to the image request, we introduce the `ImageRequestParams` type that will wrap all the relevant props.

The alternative approach to pass `ImageProps` directly to `ImageManager` is worse because it would introduce dependency cycle between `ImageManager` and the `Image` component, and also it would require to store the props in State, which is bad.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D66172570

fbshipit-source-id: d6853bf8dcecd6e76ac90ccb2079d102a3015988
2024-11-26 07:27:02 -08:00
Dmitry RykunandFacebook GitHub Bot a6b2355b8d Introduce Android ImageManger (#47721)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47721

This diff splits Cxx ImageManger into Cxx and Android variants. They both are currently no-op, but the Android one will be used for image prefetching, just as `RCTImageManager.mm` for iOS.
Changelog: [Internal]

Reviewed By: javache

Differential Revision: D65753319

fbshipit-source-id: 774ff09b6b397facee7f645706dd97ba6d1177d7
2024-11-26 04:22:09 -08:00
Pieter De BaetsandFacebook GitHub Bot 8869fa4c2c Fix stale reference to ReactViewGroup#mAllChildren (#47950)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47950

`addInArray` may reallocate `mAllChildren` so it's not correct to store this reference.

Changelog: [Internal]

Reviewed By: tdn120

Differential Revision: D66474532

fbshipit-source-id: 90ce2fcbf8ff236501ed47b2acc413e54ef8b82a
2024-11-26 04:00:14 -08:00
Pieter De BaetsandFacebook GitHub Bot 84adf268e1 Add more diagnostics for subview clipping crash (#47937)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47937

Changelog: [Internal]

Reviewed By: tdn120

Differential Revision: D66469161

fbshipit-source-id: d32f0592787ecae850854b2ff04d7c703ee8ec2e
2024-11-26 04:00:14 -08:00
Sam ZhouandFacebook GitHub Bot d86412dcc6 prepare for primitive literal changes (#47943)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47943

Changelog: [Internal]

Reviewed By: panagosg7

Differential Revision: D66461724

fbshipit-source-id: b526ed1617667b70337472f4dad4e19f152a266b
2024-11-26 00:07:32 -08:00
Jorge Cabiedes AcostaandFacebook GitHub Bot f70c3cae5b Fix border disappearing when only one edge is transparent (#47940)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47940

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

Border was disappearing when only one edge had an alpha of 0. This was due to clipping conditional

Changelog: [Internal]

Reviewed By: shwanton, NickGerleman

Differential Revision: D66397736

fbshipit-source-id: 8937323ad16e0c6e98a55051f244c08ef54c96eb
2024-11-25 18:15:25 -08:00
Jorge Cabiedes AcostaandFacebook GitHub Bot 96e66e7b48 Add unit tests for CompositeBackgroundDrawable layer ordering optimization (#47913)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47913

CompositeBackgroundDrawable has some logic for inserting the layers that are not set through the constructor. This unit test makes sure they are being properly ordered.

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66381515

fbshipit-source-id: 514979a4a97fa159c1d1c3c923afe969eafc21c3
2024-11-25 16:48:39 -08:00
Sam ZhouandFacebook GitHub Bot cb7cd89a10 Deploy 0.255.0 to xplat (#47941)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47941

Changelog: [Internal]

Reviewed By: pieterv

Differential Revision: D66477998

fbshipit-source-id: f4d1dbe506d6c42751fade897637031f0a43aa29
2024-11-25 16:06:09 -08:00
Brett LavallaandFacebook GitHub Bot f363b43856 Make color value of ShadowStyleSpan public (#47934)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47934

This property needs to be made public for later diffs in this stack.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D66338915

fbshipit-source-id: f4896f8404e3d7eed7255e0f923ab5eec9a1291e
2024-11-25 15:45:57 -08:00
danandFacebook GitHub Bot fe7e97a2fd Fix ScrollView centerContent losing taps and causing jitter on iOS (#47591)
Summary:
The React Native `<ScrollView>` has a peculiar `centerContent` prop. It solves a common need — keeping the image "centered" while it's not fully zoomed in (but then allowing full panning after it's sufficiently zoomed in).

This prop sort of works but it has a few wonky behaviors:

- If you start tapping immediately after pinch (and don't stop), the taps will not be recognized until a second after you stop tapping. I suspect this is because the existing `centerContent` implementation hijacks the `contentOffset` setter, but the calling UIKit code _does not know_ it's being hijacked, and so the calling UIKit code _thinks_ it needs to do a momentum animation. This (invisible) momentum animation causes the scroll view to keep eating the tap touches.
- While you're zooming in, once you cross the threshold where `contentOffset` hijacking stops adjusting values, there will be a sudden visual jump during the pinch. This is because the "real" `contentOffset` tracks the accumulated translation from the pinch gesture, and once it gets taken into account with no "correction", the new offset snaps into place.
- While not sufficiently pinched in, the vertical axis is completely rigid. It does not have the natural rubber banding.

The solution to all of these issues is described [here](https://petersteinberger.com/blog/2013/how-to-center-uiscrollview/). Instead of hijacking `contentOffset`, it is more reliable to track zooming, child view, and frame changes, and adjust `contentInsets` instead. This solves all three issues:

- UIKit isn't confused by the content offset changing from under it so it doesn't mistrigger a faux momentum animation.
- There is no sudden jump because it's the insets that are being adjusted.
- Rubber banding just works.

## 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] [FIXED] - Fixed centerContent losing taps and causing jitter

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

Test Plan:
I'm extracting this from [a patch we're applying to Bluesky](https://github.com/bluesky-social/social-app/blob/2ef697fe3d7dec198544ed6834553f33b95790b3/patches/react-native%2B0.74.1.patch). I'll be honest — I have not tested this in isolation, and it likely requires some testing to get merged in. I do not, unfortuntately, have the capacity to do it myself so this is more of a "throw over the wall" kind of patch. Maybe it will be helpful to somebody else.

I've tested these in our real open source app (https://github.com/bluesky-social/social-app/pull/6298). You can reproduce it in any of the lightboxes in the feed or the profile.

### Before the fix

Observe the failing tap gestures, sudden jump while pinching, lack of rubber banding.

https://github.com/user-attachments/assets/c9883201-c9f0-4782-9b80-8e0a9f77c47c

### After the fix

Observe the natural iOS behavior.

https://github.com/user-attachments/assets/c025e1df-6963-40ba-9e28-d48bfa5e631d

Unfortunately I do not have the capacity to verify this fix in other scenarios outside of our app.

Reviewed By: sammy-SC

Differential Revision: D66093472

Pulled By: javache

fbshipit-source-id: 064f0415b8093ff55cb51bdebab2a46ee97f8fa9
2024-11-25 14:56:02 -08:00
Jorge Cabiedes AcostaandFacebook GitHub Bot 2a2f58ad9d Add mixBlendMode to iterator style parser (#47292)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47292

If we don't add the prop to the iterator style parser then since fabric is not parsing the prop we are not properly creating the stacking context for when a prop has a mix-blend-mode set

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D65166886

fbshipit-source-id: 7b5bce82e81bf0c566ccd4620852ae877ccbf376
2024-11-25 13:12:12 -08:00
Jorge Cabiedes AcostaandFacebook GitHub Bot b41fb6c88e Add fabric check to drawChild function (#47293)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47293

We missed fabric check for the mix-blend-mode conditional on `drawChildren` adding it now

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D65167244

fbshipit-source-id: 1af5dc1979fb79c453ba0f27c0385a94dc539a55
2024-11-25 13:12:12 -08:00
Dmitry RykunandFacebook GitHub Bot 8d83da6460 Introduce experimental image prefetching API (#47755)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47755

TIA.
Changelog: [Internal]

Reviewed By: tdn120

Differential Revision: D65596686

fbshipit-source-id: 9fbd57caa2fdeab0bdf68e7919b1f65179634a9d
2024-11-25 12:40:09 -08:00
Jorge Cabiedes AcostaandFacebook GitHub Bot 81a94f4f14 Forward fix incorrect elliptical border radius (#47931)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47931

tsia

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66388179

fbshipit-source-id: 5c614cf52e834f664bb9f59767b2e172c51af620
2024-11-25 11:10:02 -08:00
Mateo GuzmánandFacebook GitHub Bot 81cb166d10 fix(image): [android] cache control headers are being overwritten (#47922)
Summary:
While trying to write some test cases for `ReactOkHttpNetworkFetcher`, I found that the cache control headers are not being sent over the network request correctly. These cache control headers are always being overwritten by the rest of the headers hence all the logic to set this custom cache control doesn't seem to be working as expected.

As per the [Request headers](https://github.com/square/okhttp/blob/2832a9e532ecbc6f1f84b3a07e8e64b75372789c/okhttp/src/main/kotlin/okhttp3/Request.kt#L256) docs, this seems to be the explanation:

> /** Removes all headers on this builder and adds [headers]. */
    open fun headers(headers: Headers) = commonHeaders(headers)

With the new approach by setting the headers first, we ensure that the cache control headers don't get overwritten but they would get added on top of the passed headers.

Notice that currently it seems to be overwriting these headers even if there are not headers passed from the Image component (AKA null/empty).

See my reproduction example in the test plan.

## Changelog:

[ANDROID] [FIXED] - ReactOkHttpNetworkFetcher – cache control headers getting overwritten by the rest of the headers

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

Test Plan:
By creating the following component, we log the request headers using `FLog` with the previous and the new approach. See the difference on the outputs below:

Component:
```tsx
<Image
  source={{
    uri: 'https://www.facebook.com/assets/fb_lite_messaging/E2EE-settings@3x.png?cacheBust=reload',
    cache: 'reload',
    headers: {
      'some-header': 'some-header-value',
    },
  }}
/>
```

Setting the `headers` last (current approach):

```kt
val request =
        Request.Builder()
            .cacheControl(cacheControlBuilder.build())
            .url(uri.toString())
            .headers(headers)
            .get()
            .build()
FLog.w("RequestHeaders", request.headers.toString())
```

Output (notice that the Cache-Control header is not present):
```bash
RequestHeaders  com.facebook.react.uiapp  W  some-header: some-header-value
```

<img width="561" alt="image" src="https://github.com/user-attachments/assets/797cd90a-2064-4772-99cc-5f9d39d73361">

 ---

New approach by setting the `headers` first:

```kt
val request =
        Request.Builder()
            .headers(headers)
            .cacheControl(cacheControlBuilder.build())
            .url(uri.toString())
            .get()
            .build()
FLog.w("RequestHeaders", request.headers.toString())
```

Output (Cache-Control is present now along with the passed headers):
```bash
RequestHeaders  com.facebook.react.uiapp   W  some-header: some-header-value
Cache-Control: no-cache, no-store
```

<img width="556" alt="image" src="https://github.com/user-attachments/assets/1b9f7865-926e-496b-ad3a-36e19ae92188">

Reviewed By: rshest

Differential Revision: D66446820

Pulled By: javache

fbshipit-source-id: 2640ea4b0e678a7aa919b919b0b44bedc0da0af4
2024-11-25 07:34:51 -08:00
Joe VilchesandFacebook GitHub Bot 2781888d22 Back out "Modify private apis to set, store, and get intrinsic sizing keywords" (#47895)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47895

X-link: https://github.com/facebook/yoga/pull/1750

These APIs were only added so that we could do TDD as we work on intrinsic sizing functionality. As of right now they do nothing. We are aiming on publishing a new version of Yoga soon so for the time being we are going to back these out so as not to confuse anyone with this new functionality. Ideally we get to a point where we have some temporary experimental header to stage these in but this is a bit time sensitive so just backing out for now

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66332307

fbshipit-source-id: 1d596964e0c893091c541988506e8b80fa6d1957
2024-11-25 00:40:03 -08:00
Joe VilchesandFacebook GitHub Bot 04e44f30f7 Back out "Update public API for intrinsic sizing setters" (#47896)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47896

X-link: https://github.com/facebook/yoga/pull/1752

These APIs were only added so that we could do TDD as we work on intrinsic sizing functionality. As of right now they do nothing. We are aiming on publishing a new version of Yoga soon so for the time being we are going to back these out so as not to confuse anyone with this new functionality. Ideally we get to a point where we have some temporary experimental header to stage these in but this is a bit time sensitive so just backing out for now

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66332309

fbshipit-source-id: 793f77dad021fa5e57b52c36ae954307636bcbf0
2024-11-25 00:40:03 -08:00
Jorge Cabiedes AcostaandFacebook GitHub Bot 24b0ded3cf Enable mix-blend-mode on ReactRootView so blending works with app background (#47336)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47336

Before mix-blend-mode would not blend with the background color due to it not being a ViewGroup. This adds the mix-blend-mode logic to ReactRootView so blending works

Changelog:
[Android][Fixed] - Enable mix-blend-mode on ReactRootView so blending works with app background

Reviewed By: NickGerleman

Differential Revision: D65156543

fbshipit-source-id: b3628b667573d0b56c74214e40d21c656fda495a
2024-11-24 15:33:35 -08:00
Aryan Dev ShourieandFacebook GitHub Bot 30e75a51f3 Fixed a typo in README for better clarity and understanding (#47918)
Summary:
I was just going through the README file, and I felt that the word "repo" seems a bit informal. Thus I made the correction and made it "repository".

## Changelog:

[General] [Changed] - Fixed a typo in the README file.

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

Test Plan: No specific Test Plan for these changes, as it is just a typo fix in README.md

Reviewed By: fkgozali

Differential Revision: D66414686

Pulled By: arushikesarwani94

fbshipit-source-id: 578530d2dcdf046a90bf5a5bc32ba68e8f496c81
2024-11-23 20:44:34 -08:00
Panos VekrisandFacebook GitHub Bot d4d1eb9bb1 Deploy 0.254.2 to xplat (#47912)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47912

Changelog: [Internal]

Reviewed By: SamChou19815

Differential Revision: D66379853

fbshipit-source-id: 3a7677c5a71ef74e509ed43be87e455aed0cbaa7
2024-11-22 21:48:38 -08:00
Ramanpreet NaraandFacebook GitHub Bot 1fed2cfdef bugfix: Only handle first javascript fatal error (#47914)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47914

This was a bug in the original diff: D66193194.

If a fatal js error happens, we should only drop subsequent **fatal** js errors. It's fine to report soft errors.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D66392706

fbshipit-source-id: c51bae186184c54faa9bce065b81b442607e751b
2024-11-22 18:10:23 -08:00
David VaccaandFacebook GitHub Bot 5dd712fc08 Deprecate NotThreadSafeViewHierarchyUpdateDebugListener (#47747)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47747

Deprecate NotThreadSafeViewHierarchyUpdateDebugListener as won't be available in new arch and will be deleted

changelog: [internal] internal

Reviewed By: javache

Differential Revision: D66216730

fbshipit-source-id: 88f3346ad38b80a710d9df4ba08b63887048c8cd
2024-11-22 17:56:31 -08:00
David VaccaandFacebook GitHub Bot 0c47e1351f Remove @DeprecatedInNewArchitecture annotation from ReactPropGroup (#47746)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47746

Remove DeprecatedInNewArchitecture annotation from ReactPropGroup since this annotation is not deprecated in new arch

changelog: [internal] internal

Reviewed By: javache

Differential Revision: D66216727

fbshipit-source-id: 252bae58557b51c9fbfb1deab4edc7c50511a005
2024-11-22 17:56:31 -08:00
David VaccaandFacebook GitHub Bot f03e75d9be Remove DeprecatedInNewArchitecture for ReactPropHolder annotation (#47745)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47745

Remove DeprecatedInNewArchitecture for ReactPropHolder annotation

ReactProp is still used in new arch, we might remove this annotation in the future but it will be independent of new arch

changelog: [internal] internal

Reviewed By: javache

Differential Revision: D66216729

fbshipit-source-id: 3f64858ab4fa60b09978b18b17200ae488e229ce
2024-11-22 17:56:31 -08:00
Thomas NardoneandFacebook GitHub Bot 6a472c5cf2 Remove ReactViewGroup.getBackgroundColor() (#47906)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47906

There are no usages in the repo.  External usages should be using [BackgroundStyleApplicator](https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt#L82).

Changelog: [Android][Breaking] Removed ReactViewGroup.getBackgroundColor()

Reviewed By: NickGerleman

Differential Revision: D66368623

fbshipit-source-id: bf173efc7e40d3d8a5d55ba0f82eed49b4cb2746
2024-11-22 17:52:32 -08:00
Eric RozellandFacebook GitHub Bot a05d573f9e Guard against surface manager exceptions (#47910)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47910

It seems there could be a race where a commit is being processed on the JS thread after the surface has been removed from the mounting manager. Since we don't actually need to retrieve the default paddings in these cases, there's no reason we need an enforced read of the SurfaceMountingManager.

## Changelog

[Internal]

Reviewed By: javache

Differential Revision: D66369969

fbshipit-source-id: 44ccdc9beafdbd0ac47457fb01c4114348c1a316
2024-11-22 15:22:54 -08:00
Eric RozellandFacebook GitHub Bot e344b4914c Unconditionally clear static LongLivedObjectCollection (#47891)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47891

Various C++ utilities for handling callbacks and promises rely on the static LongLivedObjectCollection. Even if a host platform injects it's TurboModuleBinding with a custom LongLivedObjectCollection, there's no guarantee that the platform is not also using C++ TurboModules that use the static LongLivedObjectCollection. Clearing both collections solves issues for TurboModuleBindings with custom LongLivedObjectCollections that also have cross platform C++ TurboModules that use the static collection.

## Changelog

[Internal]

Reviewed By: javache

Differential Revision: D66324044

fbshipit-source-id: a5a973087c35fc00240e40ba757d49125473daf4
2024-11-22 15:20:10 -08:00
Maddie LordandFacebook GitHub Bot 450d982844 onHostDestroy, only set EnableDevSupport to false if the current activity is the one being destroyed (#47907)
Summary:
Changelog: [Internal]

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

EnableDevSupport is set to false on lifecyle events like onPause and onHostDestroy, and set to true on events like onResume and onCreate.

In apps like AMA and Twilight, there is first a loginActivity, which then calls the mainActivity. After mainActivity is created, loginActivity is destroyed. This causes enableDevSupport to always be false because onDestroy for loginActivity is triggered after onCreate for mainActivity.

Reviewed By: RSNara, alanleedev

Differential Revision: D66124018

fbshipit-source-id: e40a5b24cf73000b0bfeaa1d8e3902718b281410
2024-11-22 12:48:33 -08:00
Tom ScallonandFacebook GitHub Bot 162208d264 Support defining multiple CxxReactPackages from a single lambda (#47897)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47897

Changelog: [Internal]

In some situations, we want to provide multiple `CxxReactModules` from a single lambda. Currently, this is painful -- this change makes it less so.

Reviewed By: tdn120

Differential Revision: D66337573

fbshipit-source-id: ed57ad6ca2b98d4787aca7da3714c05c3d03b649
2024-11-22 12:09:12 -08:00
Luna WeiandFacebook GitHub Bot a77d8d9d50 Support rn_rootThreshold on IntersectionObserver (viewAreaCoveragePercentThreshold) (#47908)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47908

Changelog: [General][Added] - Add support for `rn_rootThreshold` in Intersection Observer

`rn_rootThreshold` is a custom IntersectionObserver option and not part of the IntersectionObserver spec. We are adding it because it covers a specific use-case for measuring viewability that is robust for `target`s that are larger than the viewport or specified `root`.

The threshold ratio is of the intersection area (of `root` and `target`) to the total area of the `root`.

 {F1960832959}
Source - EX314979

`rn_rootThreshold` is an optional threshold and can be combined with the `thresholds` option. An intersection will fire if any specified thresholds is met.

Note: If you use specify a `rn_rootThreshold`, the default `threshold` is no longer applied

The main use case of `rn_rootThreshold` is being able to specify a level of viewability independent of `target` size. For example, a `target` that is larger than the `root` (commonly the viewport) will not trigger the IntersectionObserver for a `threshold` of `1`. Setting `rn_rootThreshold` of `1`, will trigger once the item takes full size of the `root`.';

Reviewed By: yungsters

Differential Revision: D66031119

fbshipit-source-id: 7bdc871dc5b4e6c0edc7d6e17a0a0cfd51c4fe81
2024-11-22 11:50:36 -08:00
Thomas NardoneandFacebook GitHub Bot 0b22b955f1 ReactViewGroup - utilize onViewAdded/Removed (#47890)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47890

The fix in [#40859](https://github.com/facebook/react-native/pull/40859) overrode every possible add or remove to ensure completeness, but all paths should also call onViewAdded/onViewRemoved via:
- `addView`/`addViewInLayout` -> [addViewInner](https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-15.0.0_r5/core/java/android/view/ViewGroup.java#5310)
- `removeView`/`removeViewInLayout` -> [removeViewInternal](https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-15.0.0_r5/core/java/android/view/ViewGroup.java#5606)
- `removeViews`/`removeViewsInLayout` -> [removeViewsInternal](https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-15.0.0_r5/core/java/android/view/ViewGroup.java#5714)

Changelog: [Android][Changed] Consolidated ReactViewGroup add/remove overrides

Reviewed By: javache

Differential Revision: D66320586

fbshipit-source-id: aaf16af5ad87789f575fcb79dcf31f5686002b2d
2024-11-22 10:27:09 -08:00
Thomas NardoneandFacebook GitHub Bot 3d1a505da5 ReactViewGroup - extract method for parent check (#47878)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47878

Make it clearer what we're checking, and provide a single point of code where we could potentially improve the logic.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D66302526

fbshipit-source-id: a0e6d1004aef25897e9633fe930915ba585c1cb5
2024-11-22 10:27:09 -08:00
Thomas NardoneandFacebook GitHub Bot f1d7016be9 ReactViewGroup cleanup (#47674)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47674

Small changes that can be done in Java and make a Kotlin conversion more seamless.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D66033963

fbshipit-source-id: 666302f132b98019f1013a335a2c59c7a4f31836
2024-11-22 10:27:09 -08:00
Rob HoganandFacebook GitHub Bot 74995bc90a dev-middleware: Generalise URL rewriting, don't only rewrite for Android emulators (#47880)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47880

The previous diffs in this stack have aimed to make URL rewriting by inspector-proxy robust to any configuration of device->server, debugger->server and server->server connections.

Though rewriting was originally introduced to support Android emulator networking, we can now expand it to cover other use cases, like the device reaching the server over an internet address not reachable from the dev machine, or the debugger routing to the server through a tunnel on a different port, without needing CORS workarounds.

Changelog
[General][Fixed] dev-middleware: Rewrite URLs in the inspector proxy to cover all configurations, not just Android emulators.

Reviewed By: huntie

Differential Revision: D66247355

fbshipit-source-id: e9201ebc1f7f5fe2119c71cd4d7b4ca895645404
2024-11-22 10:26:43 -08:00
Pieter De BaetsandFacebook GitHub Bot aec7a66ae8 Remove deprecated ReactModuleInfo constructor (#47681)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47681

These were deprecated back in D49262824, so should be safe to remove now.

Changelog: [Android][Removed] Removed hasConstants constructor from ReactModuleInfo

Reviewed By: mdvacca

Differential Revision: D66127070

fbshipit-source-id: 3bd441c96597598470f16c7770c4dfa4ada563a0
2024-11-22 08:05:41 -08:00
Pieter De BaetsandFacebook GitHub Bot bf5c98cf5e Remove deprecated TurboReactPackage (#47680)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47680

This was deprecated in D50128456 so should be safe to remove now.

Changelog: [Android][Removed] Removed TurboReactPackage, which was replaced by BaseReactPackage

Reviewed By: mdvacca

Differential Revision: D66127067

fbshipit-source-id: a4090ab439cf99dc693622b8da2c0cffa247ad24
2024-11-22 08:05:41 -08:00
zhongwuzwandFacebook GitHub Bot 89f93dc921 Fabric: Fixes high contrast color when not specified (#47418)
Summary:
Fixes the high contrast color when not specified. Previously, if we didn't specify highContrastLight or highContrastDark, it would create a UIColor with an alpha of 0, which is not what we expected. We should fall back to the dark or light color instead.

## Changelog:

[IOS] [FIXED] - Fabric: Fixes high contrast color when not specified

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

Test Plan:
1. Enable color contrast in iPhone's settings.
2. Open PlatformColor example in RNTester. See dynamic colors
3. color shows correctly
![image](https://github.com/user-attachments/assets/a71b8743-b397-4a11-b287-ec117b1ba243)

Before:
![image](https://github.com/user-attachments/assets/6a12824b-f77c-4979-a232-c1c97554e53c)

Reviewed By: javache

Differential Revision: D66303078

Pulled By: cipolleschi

fbshipit-source-id: 63a0d2bc94eea438d4f69643d09825b74575188b
2024-11-22 07:16:24 -08:00
Andrew CoatesandFacebook GitHub Bot e6848ba5ba Fixes to bridging/base.h for MSVC compatibility (#47882)
Summary:
Attempting to use the various bridging template and generated C++ Specs for native modules in a project compiling with MSVC does not build.

For the fromJs I had to add `std::move` - otherwise it could not cast.

The supportsFromJs and supportsToJs are changed to address an IntelliSense issue where the template specialization cannot have default members.

## Changelog:
[GENERAL] [FIXED] - Fix C++ bridging template compatibility with MSVC

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

Test Plan: It continues to build on Android/iOS builds.  And it also builds with MSVC for react-native-windows and other out of tree platforms that use MSVC.

Reviewed By: cipolleschi

Differential Revision: D66360833

Pulled By: javache

fbshipit-source-id: bf97db1cd247a383eb86cac31c601e8ab3400fd2
2024-11-22 06:55:58 -08:00
Blake FriedmanandFacebook GitHub Bot e4fc27ec4d Add changelog for 0.76.3 (#47893)
Summary:
Add changelog for 0.76.3

Changelog: [Internal] - Add changelog for 0.76.3

bypass-github-export-checks

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

Test Plan: N/A

Reviewed By: cipolleschi

Differential Revision: D66329466

Pulled By: blakef

fbshipit-source-id: e399175e198d11e2a5c0492fa1869797b50ef26f
2024-11-22 05:55:25 -08:00
Samuel SuslaandFacebook GitHub Bot bb78142011 fix code comment for collapsable prop (#47881)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47881

changelog: [internal]

collapsable prop is not only for android.

Reviewed By: NickGerleman

Differential Revision: D66299356

fbshipit-source-id: 1c7435c77ef029fea55346f4ca16b5c81022b85a
2024-11-22 05:45:13 -08:00
Riccardo CipolleschiandFacebook GitHub Bot 677d82d818 Disable E2E Tests on RNTester (#47903)
Summary:
E2E tests for Android RNTester in GHA are flaky and they prevent CI to be green on main.
Given that the Branch cut is happening on Monday and that I'll be away for a week, it's better to disable them.

I'm planning to work a bit on those today and more once I'm back

## Changelog:
[Internal] - Temporarily disable E2E tests for Android

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

Test Plan: GHA

Reviewed By: javache

Differential Revision: D66359177

Pulled By: cipolleschi

fbshipit-source-id: a0064418af607953cf46445613796c18fb6e1389
2024-11-22 05:14:22 -08:00
oddlyspacedandFacebook GitHub Bot 8dc2c90ce5 chore(Android): convert systeminfo module classes to kotlin (#47616)
Summary:
Saw a lot of PRs and push to convert existing Java code to Kotlin, and wanted to contribute to the cause. This is a starting point for me so I can understand more about the Java to Kotlin conversion process for ReactAndroid package.

## Changelog:
- Converted AndroidInfoHelpers to Kotlin class
- Converted AndroidInfoModule to Kotlin object and updated usage of it across the package

Pick one each for the category and type tags:

[ANDROID] [CHANGED] - Migrated systeminfo module code from Java to Kotlin

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

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

Test Plan: Verified build on local dev environment.

Reviewed By: NickGerleman

Differential Revision: D66258996

Pulled By: javache

fbshipit-source-id: e0958c0be735f54cb20c7daeee1526059edaabcc
2024-11-22 03:35:36 -08:00
Pieter De BaetsandFacebook GitHub Bot d424bb9d7c Convert com.facebook.testutils.shadows to Kotlin (#47487)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47487

Changelog: [Android][Deprecated] Deprecated shadows for ReadableNative[Map|Array].[Readable|Writable]

Reviewed By: rshest

Differential Revision: D65597417

fbshipit-source-id: 61f649c32fb91a13af075aa65869093f31d218e3
2024-11-22 01:53:48 -08:00
Pieter De BaetsandFacebook GitHub Bot eb5fbdf134 Convert com.facebook.react.bridge.WritableNativeArray to Kotlin (#47486)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47486

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D65596952

fbshipit-source-id: 462432af819ed9a7fba515cee54055d737d2584e
2024-11-22 01:53:48 -08:00
Pieter De BaetsandFacebook GitHub Bot 145c72f816 Convert com.facebook.react.bridge.ReadableNativeArray to Kotlin (#47484)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47484

Small change to types in the base class: all non-primitives return optional from ReadableArray, which matches the semantics in ReadableMap. We already rely on this in some cases, but the current nullability annotations were incorrect, and null values from the array would be passed through from `getMap` and `getArray`.

Changelog: [Android][Breaking] ReadableArray non-primitive getters are now correctly typed as optional

Reviewed By: Abbondanzo

Differential Revision: D65596278

fbshipit-source-id: 5574e9000b07de292bd0da5f1b071aac0eb331d6
2024-11-22 01:53:48 -08:00
Phillip PanandFacebook GitHub Bot 3575e21f73 fix extraModulesForBridge: in interop
Summary:
Changelog: [Internal]

the delegate of TMM is RCTInstance, but RCTInstance doesn't forward all of the APIs and we aren't protected by the compiler because of the optional in TMMDelegate

i found that this backwards compat API did not actually get set up correctly and was never working in the first place... this is why we should avoid optional

long term, TMMDelegate needs to be pushed down to the infra layer and not exist in product, cc blakef

Reviewed By: javache

Differential Revision: D66148789

fbshipit-source-id: 925a6d4ebb6ba6bfb0b1aec6710695e7551ba475
2024-11-21 23:02:15 -08:00
Thomas NardoneandFacebook GitHub Bot e2c621c5fc ReactViewGroup - fix setBorderRadius javadoc (#47892)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47892

Update to match the method so it doesn't show as an error in the IDE.

Changelog:[Internal]

Reviewed By: jorge-cab

Differential Revision: D66326667

fbshipit-source-id: f81bdc7763862fc06440b27e417e0b53ad7774da
2024-11-21 19:00:06 -08:00
Ramanpreet NaraandFacebook GitHub Bot e4d8c96786 Correct message annotation on early js errors (#47889)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47889

## Context
When is the runtime ready?
- After the main bundle finishes executing **without** raising a fatal javascript error

## Changes
Let's decorate all errors reported while the runtime is not ready as "[runtime not ready]".

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D66316907

fbshipit-source-id: e48542af4f84d4cc3a6ce8f667dbaa10c30c19a8
2024-11-21 16:00:44 -08:00
David VaccaandFacebook GitHub Bot fd1d6b8c65 Remove DeprecatedInNewArchitecture for ReactProp annotation (#47744)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47744

Remove DeprecatedInNewArchitecture for ReactProp annotation

ReactProp is still used in new arch, we might remove this annotation in the future but it will be independent of new arch

changelog: [internal] internal

Reviewed By: javache

Differential Revision: D66216728

fbshipit-source-id: 86d9aeb2932cbf34c57a7a850da0ced5268447bf
2024-11-21 15:45:21 -08:00
David VaccaandFacebook GitHub Bot fb737ca7d3 Deprecate ReactContext.getFabricUIManager() method (#47743)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47743

Deprecate ReactContext.getFabricUIManager() method

changelog: [Android][Deprecated] ReactContext.getFabricUIManager() method

Reviewed By: shwanton

Differential Revision: D66216427

fbshipit-source-id: 0e716921a6fc65ad1ccfcab71640174515ae4f67
2024-11-21 15:45:21 -08:00
David VaccaandFacebook GitHub Bot 3baf562df0 Migrate SurfaceDelegate to Kotlin (#47687)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47687

Migrate SurfaceDelegate to Kotlin

changelog: [internal] internal

Reviewed By: javache

Differential Revision: D66134455

fbshipit-source-id: 35e6a5c590c1f8eb0060f8f44680b9134ea127c1
2024-11-21 15:45:21 -08:00
Ramanpreet NaraandFacebook GitHub Bot c02e3b1c60 Only handle the first javascript fatal error (#47783)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47783

After the first javascript fatal, the runtime starts tearing down. And it becomes invalid. So, subsequent js fatals will most likely be just noise. Let's filter them out.

This impacts bridgeless mode: both the javascript and c++ pipeline.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D66193194

fbshipit-source-id: 61a731850f7ac4f00bfac24e3260673bf94ba8ed
2024-11-21 14:09:08 -08:00
Jorge Cabiedes AcostaandFacebook GitHub Bot 451ff70da4 implement correct border-radius scaling on overlapping radii (#47886)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47886

We were not scaling border radii properly when they overlap.

We were relying on Android's handling of the issue which is not compliant with the web algorithm leading to **visible gaps between layers when the radii overlapped**

We are now following web spec https://www.w3.org/TR/css-backgrounds-3/#corner-overlap

Changelog: [Android] [Added] Add overlapping radii resolution logic preventing incorrect rendering

Reviewed By: NickGerleman

Differential Revision: D66269809

fbshipit-source-id: 4ab7025dc1e41be6205ff6b828617e1e222536a9
2024-11-21 14:01:02 -08:00
Sam ZhouandFacebook GitHub Bot 12550f05c5 Deploy 0.254.1 to xplat (#47887)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47887

Changelog: [Internal]

Reviewed By: alexmckenley

Differential Revision: D66315470

fbshipit-source-id: 16b8fca3412fc2fcea3be8dfd0c760d97c56d734
2024-11-21 13:13:10 -08:00
Matthew HoranandFacebook GitHub Bot 68db74205a Fix asynchronous access to KeyboardAvoidingEvent event in onLayout handler (#47798)
Summary:
The `onLayout` handler of the `KeyboardAvoidingView` view is async due to the `await AccessibilityInfo.prefersCrossFadeTransitions` in `_relativeKeyboardHeight`.

A connected `onLayout` handler will be unable to access the event. Call `persist()` on the event so that it can be accessed asynchronously.

## Changelog:

[GENERAL] [FIXED] - Accessing KeyboardAvoidingEvent event in onLayout handler

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

Test Plan:
The following should not produce an error:
```
import * as React from 'react';
import {
  KeyboardAvoidingView,
  SafeAreaView,
  TextInput
} from 'react-native';

export default function() {
  return (
    <SafeAreaView>
      <KeyboardAvoidingView onLayout={(event) => console.log(event)} behavior="padding">
        <TextInput />
      </KeyboardAvoidingView>
    </SafeAreaView>
  );
}
```

Reviewed By: cipolleschi

Differential Revision: D66306085

Pulled By: dmytrorykun

fbshipit-source-id: 9ccf00db79947670ddc7de74a47cc6dc27455fc0
2024-11-21 12:10:17 -08:00
Rob HoganandFacebook GitHub Bot 5da7ebf99a dev-middleware: Don't assume device-relative and debugger-relative URLs have the same port (#47876)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47876

Currently, if a device is connected to the bundler via, say, `http://10.0.2.2:8081` (Android default), and a debugger is opened on `http://localhost:8081`, we rewrite hostnames `10.0.2.2.`<->`localhost` so that URLs are correct relative to each.

However, if the debugger is on a different port or protocol, this breaks down - because we only rewrite hostnames.

This fixes that by using the debugger's connecting `Host` header and `encrypted` state to derive the base URL of the server relative to the frontend. We then update the rewriting logic to use this actual full origin (protocol + host) in place of the device-relative origin.

Changelog:
[General][Fixed] dev-middleware: Fix URL rewriting where device and debugger reach the server on different ports/protocols.

Reviewed By: huntie

Differential Revision: D66077627

fbshipit-source-id: 01f6565149caa34b1e9e50dd58deb0122485657c
2024-11-21 11:39:20 -08:00
Rob HoganandFacebook GitHub Bot aae3e03e57 dev-middleware: Refactor urlRegex rewriting, regex-escape IP4 addresses (#47872)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47872

Largely a refactoring to the way we currently rewrite `url`/`urlRegex` in `Debugger.setBreakpointByURL` CDP requests (debugger->target).

Rewriting regexes is fragile, it only really works if we can assume `'localhost'` appears literally and that ports and protocols don't need changing. The intention here is to freeze the current behaviour so as not to break anyone relying on it (if anyone is), and decouple it from more robust rewriting we want to generalise.

Also adds simple regex escaping to host names (always IPv4 addresses) we inject into regex patterns, since the previous approach could've led to false matches in unlikely edge cases.

Changelog:
[General][Fixed] dev-middleware: Regex-escape IP addresses in urlRegex replacements

Reviewed By: huntie

Differential Revision: D66238782

fbshipit-source-id: 4cd0029081d68c193e36d3713057ffdc7ef0656f
2024-11-21 10:09:41 -08:00
Rubén NorteandFacebook GitHub Bot 6c581c9b9b Allow JS_DIR path to be relative to cwd (#47877)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47877

Changelog: [internal]

Reviewed By: sammy-SC

Differential Revision: D66302814

fbshipit-source-id: 55d6f86d098673e28fad71a43863f2041810d04b
2024-11-21 09:14:45 -08:00
Pieter VanderwerffandFacebook GitHub Bot ae09827b15 Deploy 0.254.0 to xplat (#47810)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47810

Changelog: [Internal]

Reviewed By: SamChou19815

Differential Revision: D66278779

fbshipit-source-id: 01dec1dc844607afa8f650c5acdebc6d5d5739d2
2024-11-21 08:26:07 -08:00
Kudo ChienandFacebook GitHub Bot ce838a4bcf Fix lazy import error from jest and Appearance.js (#47629)
Summary:
currently running jest test, it shows an error:

```
ReferenceError: You are trying to `import` a file after the Jest environment has been torn down. From __tests__/App.test.tsx.

      at getState (node_modules/react-native/Libraries/Utilities/Appearance.js:18:26)
      at addChangeListener (node_modules/react-native/Libraries/Utilities/Appearance.js:71:19)
      at subscribe (node_modules/react-native/Libraries/Utilities/useColorScheme.js:10:66)
      at subscribeToStore (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:6232:10)
      at commitHookEffectListMount (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13038:26)
      at commitPassiveMountOnFiber (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14461:11)
      at commitPassiveMountEffects_complete (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14421:9)
      at commitPassiveMountEffects_begin (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14408:7)
      at commitPassiveMountEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:14396:3)
      at flushPassiveEffectsImpl (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:16287:3)
      at flushPassiveEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:16236:14)
      at node_modules/react-test-renderer/cjs/react-test-renderer.development.js:16051:9
      at workLoop (node_modules/scheduler/cjs/scheduler.development.js:266:34)
      at flushWork (node_modules/scheduler/cjs/scheduler.development.js:239:14)
      at Immediate.performWorkUntilDeadline [as _onImmediate] (node_modules/scheduler/cjs/scheduler.development.js:533:21)
```

it is a regression from https://github.com/facebook/react-native/issues/46123 that to have a lazy require.

this pr tries to mock `useColorScheme` to return `light`. i think we don't necessarily test the color scheme changes in jest runtime. originally `useColorScheme` also returns `light` because of [this statement](https://github.com/facebook/react-native/blob/9a60038a40e16925ea1adeb3e3c937c22a615485/packages/react-native/Libraries/Utilities/Appearance.js#L77-L83)

## Changelog:

[GENERAL] [FIXED] - Fixed jest error from Appearance.js

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

Test Plan:
```sh
$ npx react-native-community/cli init RN0762 --pm bun --version 0.76.2
$ cd RN0762
$ bun test run
```

Reviewed By: cipolleschi

Differential Revision: D66297456

Pulled By: huntie

fbshipit-source-id: 80d1460532e76bd1815c66964547b50d7f7b3558
2024-11-21 07:46:14 -08:00
Blake FriedmanandFacebook GitHub Bot 6460d2b3e7 Support Windows sdkmanager.bat (#47874)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47874

We should be searching for the .bat file on Windows to remain compatible with some user setups.

Changelog: [Android][Fixed] look for sdkmanager.bat

Reviewed By: cipolleschi

Differential Revision: D66295240

fbshipit-source-id: 6b79a9aa40f77ed9c5b3d6ad92b1a62e78159223
2024-11-21 07:19:35 -08:00
Riccardo CipolleschiandFacebook GitHub Bot b8419b2eed Include autolinkin.h in OnLoad.cpp only if it exists (#47875)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47875

The old architecture looks broken because in the OnLoad.cpp file we try to include the autolinking.h header which is only generated when the New Architecture is enabled.

This fix guards the include and the usage of the function provided by the autolinking so that the old architecture should work as well.

## Changelog
[Internal] - Include autolinkin.h in OnLoad.cpp only if it exists

Reviewed By: blakef

Differential Revision: D66295318

fbshipit-source-id: 18461e6b70ac92af57b805bef51c0df49db02283
2024-11-21 05:55:58 -08:00
Alex HuntandFacebook GitHub Bot 3de9892353 Skip hermes-parser under Babel for non-Flow JS code (#47568)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47568

Resolves https://github.com/facebook/hermes/issues/1549.

Changelog:
[General][Fixed] - When using Babel with plain JavaScript files, support for additional user syntax plugins should be fixed (now uses Babel's parser instead of hermes-parser). There is no change for JS files annotated with `flow`, where extended JS syntax remains unsupported.

Reviewed By: blakef

Differential Revision: D65816797

fbshipit-source-id: 9f05e86019548ac8727ee65c2e2c417d78a406d8
2024-11-21 05:41:39 -08:00
Alex HuntandFacebook GitHub Bot 113337f269 Update hermes-parser and related packages in fbsource to 0.25.1 (#47573)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47573

Bump hermes-parser and related packages to [0.25.1](https://github.com/facebook/hermes/blob/main/tools/hermes-parser/js/CHANGELOG.md).

Changelog: [Internal]

Reviewed By: robhogan

Differential Revision: D65816542

fbshipit-source-id: cb445eb77790fb2632d3bc318c6eb59f097b1518
2024-11-21 05:41:39 -08:00
SantiagoandFacebook GitHub Bot 7d63235086 Fix Appearance.setColorScheme(null) not resetting color scheme value (#47739)
Summary:
Fixes https://github.com/facebook/react-native/issues/47725

Calling Appearance.setColorScheme(null) or Appearance.setColorScheme(undefined) no longer resets the color scheme useColorScheme returns like on previous rn versions.

## 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
-->

[GENERAL] [FIXED] - Fix `Appearance.setColorScheme(null)` not resetting color scheme value

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

Test Plan: Repo with a patch ready to test: https://github.com/sangonz193/react-native-color-scheme-patch

Reviewed By: yungsters

Differential Revision: D66230236

Pulled By: cipolleschi

fbshipit-source-id: cc668acb1fde6d30f2706fc0ab7dee5cea1c3b14
2024-11-21 04:43:46 -08:00
Rubén NorteandFacebook GitHub Bot 9f604dbd43 Watch changes in C++ files (#47871)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47871

Changelog: [internal]

No need to keep going back to save test files when we change C++ files and need to re-run tests :)

Reviewed By: javache

Differential Revision: D66293212

fbshipit-source-id: dc232e1d3f7f8ae1578e894ce14bd21ccf3c8ade
2024-11-21 03:58:36 -08:00
Rubén NorteandFacebook GitHub Bot 92a476661c Add flag to force running tests in optimized mode (#47870)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47870

Changelog: [internal]

This flag allows us to run optimized mode by using the right buck modes for the Fantom CLI, using minified + dev in Metro and building bytecode using Buck as well.

It's disabled by default but in the future we can enable it based on the configuration in the test file (e.g.: if it's a benchmark) or we can run tests in both modes by default to catch problems caused by the differences between environments.

Reviewed By: rshest

Differential Revision: D66292709

fbshipit-source-id: d25294b739ff6a67507990241784b838d5b30dcd
2024-11-21 03:58:36 -08:00
Abdelhafidh BelaliaandFacebook GitHub Bot 550b0c0ed1 TextLayout: take full width if text wrapped (#47435)
Summary:
### Problem
The calculated width for a multiline text is based on the longest line. However it does not account for text that wraps.

**Example** if numberOfLines=1 and the text wraps

```
+---------------------------+
This is a long text that
will wrap
+---------------------------+
```

The TextView will render
```
+---------------------------+
This is a long text t...
+---------------------------+
```

because the `calculatedWidth` took the width of the first line.

Also see https://github.com/facebook/react-native/pull/41770#issuecomment-2453611554 for additional context.

### Solution

If the text wraps, take the whole width.

```
+---------------------------+
This is a long text that w...
+---------------------------+
```

Fixes https://github.com/facebook/react-native/issues/39722
Fixes https://github.com/facebook/yoga/issues/1730

## Changelog:

[GENERAL] [FIXED] - Fix text not taking full width

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

Test Plan:
```tsx
        <Text
          numberOfLines={1}
          style={{
            backgroundColor: 'red',
            alignSelf: 'flex-start',
            color: 'white',
            fontSize: 34,
          }}>
          {'This is a long text that will wrap.'}
        </Text>
        <Text
          numberOfLines={3}
          style={{
            backgroundColor: 'red',
            alignSelf: 'flex-start',
            color: 'white',
            fontSize: 34,
          }}>
          {
            '1\n\ntest\nThis is a long text that will wrap.This is a long text that will wrap.This is a long text that will wrap.\n'
          }
        </Text>
        <Text
          numberOfLines={3}
          style={{
            backgroundColor: 'red',
            alignSelf: 'flex-start',
            color: 'white',
            fontSize: 34,
          }}>
          {
            '1\n\nThis is a long text that will wrap.This is a long text that will wrap.This is a long text that will wrap.\n'
          }
        </Text>
```
1. Verify that the first and third text take full width
2. Verify that the second text does not take full width

| Before | After |
|:------:|:-----:|
|   <img width="480" alt="Screenshot 2024-11-05 at 9 00 24 PM" src="https://github.com/user-attachments/assets/b8d765c0-f4b1-42c6-afc7-75862c52612a">     |    <img width="480" alt="Screenshot 2024-11-05 at 9 01 49 PM" src="https://github.com/user-attachments/assets/f1534c14-a56a-4d44-8edc-4d9f75166cb2">   |

Reviewed By: NickGerleman

Differential Revision: D65521732

Pulled By: realsoelynn

fbshipit-source-id: 0bb0bb306445e73e8b24ff4c02921739d15ee07e
2024-11-21 03:16:30 -08:00
Dmitry RykunandFacebook GitHub Bot 105ad855d9 Fix ViewConfig validation error after merging defaultSrc into defaultSource for RCTImageView (#47754)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47754

The `./resolveAssetSource` processor was added to the `defaultSource` prop in the `RCTImageView` static view config in D65819218.
To match this in native view config, we're adding the `customType = "ImageSource"` hint to the view config infra, so it knows to assign correct processor to the native view config in runtime.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D66228921

fbshipit-source-id: d0e0cd9e2f5cc0ba5b3a7002f7ade3f45305a2ac
2024-11-21 03:12:21 -08:00
Riccardo CipolleschiandFacebook GitHub Bot 880dea858e Bump Podfile.lock for Folly (#47868)
Summary:
RNTester jobs are failing because we bumped folly to the recent version but we didn't update the podfile.lock

## Changelog:
[Internal] - Bump Podfile.lock to new Folly version

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

Test Plan: GHA

Reviewed By: robhogan

Differential Revision: D66292931

Pulled By: cipolleschi

fbshipit-source-id: 19cbe1321d2891135aa9777823e9dff2916b16dc
2024-11-21 02:33:29 -08:00
Riccardo CipolleschiandFacebook GitHub Bot 0eb9472c69 Allow downgrading CMake to build hermesc on Windows (#47867)
Summary:
CI is failing to build HermesC on windows due to a version mismatch of the CMake already installed

## Changelog:
[Internal] - Fix Windows CI for HermesC

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

Test Plan: GHA

Reviewed By: robhogan

Differential Revision: D66292617

Pulled By: cipolleschi

fbshipit-source-id: 5e8f4f45e33fbdd9ff163b4e8a09cb98d4366dc7
2024-11-21 02:20:30 -08:00
David VaccaandFacebook GitHub Bot ac0dbe1ea2 Migrate ReactClippingProhibitedView to Kotlin (#47752)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47752

Migrate ReactClippingProhibitedView to Kotlin

changelog: [internal] internal

Reviewed By: javache

Differential Revision: D66217071

fbshipit-source-id: e7559db5c3f2795b78f51c3bd5a3f521eb54b70d
2024-11-20 23:08:03 -08:00
David VaccaandFacebook GitHub Bot a2523a24c7 Migrate ReactCompoundView to kotlin (#47748)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47748

Migrate ReactCompoundView to kotlin

changelog: [internal] internal

Reviewed By: javache

Differential Revision: D66217094

fbshipit-source-id: 238c20c907880f4251c9b5926ad486cfff55a3b0
2024-11-20 23:08:03 -08:00
Jakub PiaseckiandFacebook GitHub Bot aa53bde21b Fix the nodes' owners not being updated when display: contents is used (#47733)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47733

In https://github.com/facebook/yoga/pull/1729 I moved the cleanup of `display: contents` nodes to happen before all the early returns, but that change also made it be called **before** `cloneChildrenIfNeeded`. It actually needs to be called after `cloneChildrenIfNeeded` to make sure that children of `display: contents` nodes are properly owned.

It also needs to be called in every short-path, so it's being called in four places in this PR. Please let me know whether it's ok or not.

X-link: https://github.com/facebook/yoga/pull/1743

Reviewed By: NickGerleman

Differential Revision: D65953902

Pulled By: zeyap

fbshipit-source-id: 0b18a5651f19c23564f5b3aa2a50833426e9ca5f
2024-11-20 20:01:50 -08:00
phuccvx12andFacebook GitHub Bot 73a2be1243 Fix: Correct Layout Behavior for Combined align-content and align-items (#47732)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47732

This pull request addresses the issue where combining align-content and align-items properties resulted in incorrect layout behavior in Yoga version 3.1.0, as reported in [Issue https://github.com/facebook/yoga/issues/1739](https://github.com/facebook/yoga/issues/1739).

# Changes Made:

Alignment Logic Update: Modified the alignment calculations to ensure that the combination of align-content and align-items properties produces the expected layout, consistent with CSS Flexbox standards and previous Yoga versions.

Test Cases Added: Introduced new test cases to cover scenarios involving various combinations of align-content and align-items properties to prevent future regressions.

# Testing:

All existing tests pass successfully.

New test cases confirm that the layout behaves as expected when align-content and align-items are used together.

# Impact:

This fix ensures that layouts using both align-content and align-items properties render correctly, aligning with the behavior observed in Yoga version 1.19.0 and standard web browsers.

X-link: https://github.com/facebook/yoga/pull/1742

Reviewed By: joevilches

Differential Revision: D65953882

Pulled By: zeyap

fbshipit-source-id: 7e12a21b1d442b35c3f3536cad32dc4b82130d15
2024-11-20 19:59:42 -08:00
David VaccaandFacebook GitHub Bot 17502dd743 Migrate ReactCompoundViewGroup to kotlin (#47751)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47751

Migrate ReactCompoundViewGroup to kotlin

changelog: [internal] internal

Reviewed By: javache

Differential Revision: D66217251

fbshipit-source-id: b24b4ed984670e18256dda758bfa1d783badd536
2024-11-20 18:51:34 -08:00
NishanandFacebook GitHub Bot 221d1eceda fix: start and end points linear gradient algorithm (#47003)
Summary:
- Current implementation does not follow CSS spec for rectangle boxes with corner angles. It is using non spec compliant algorithm to calculate start and end points. This PR follows the spec compliant algorithm to implement and makes sure Web, iOS and Android gradients are identical with corner angles.
- Also, currently it is using `CAGradientLayer` which does not support spec compliant start and end points i.e. start and end point can be outside of rectangle bounds. This leads to inconsistent gradients on iOS for corner angles compared to web and android. So this PR replaces it with `CGGradient`.
- I have also moved some files to make it easier to add more background image types in future.

## Changelog:

[GENERAL] [FIXED] - Linear gradient start and end point algorithm.

<!-- 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/47003

Test Plan:
- Added multiple gradient example which should be identical in all platforms (Web, iOS and Android) and tested thoroughly on all platforms. I think some visual test cases can help here.
- I have referred to [blink's](https://github.com/chromium/chromium/blob/main/third_party/blink/renderer/core/css/css_gradient_value.cc) implementation.

## Aside

Took a while to understand the [spec](https://www.w3.org/TR/css-images-3/#corner-gradient-example), but felt great after getting it. Gradients should be 100% identical on all platforms now. Sorry i missed testing cornered angles + rectangles earlier and I found out it is inconsistent on platforms just this weekend  😅

<img width="1389" alt="Screenshot 2024-10-14 at 12 24 45 AM" src="https://github.com/user-attachments/assets/2f61eb87-502b-4b8c-88f3-d8a3cca9a7a3">

Reviewed By: joevilches

Differential Revision: D64497127

Pulled By: jorge-cab

fbshipit-source-id: 2647176ae2ee74b6c71f9061465b07dccdabcfc1
2024-11-20 17:17:52 -08:00
Joe VilchesandFacebook GitHub Bot 6d8fd49832 Remove trivial private api calls in YogaLayoutableShadowNode.cpp (#47735)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47735

We are trying to remove or minimize private header usage in YogaLayoutableShadowNode.cpp and YogaLayoutableShadowNode.h. There are a few "trivial" ones, meaning some private call maps 1:1 to an existing public API, so I just opt to use that instead

Changelog: [Internal]

Reviewed By: NickGerleman

Differential Revision: D66131948

fbshipit-source-id: 7068021513703d1c142d3c298f4804e4e8b81ee2
2024-11-20 17:06:01 -08:00
Tom Van LaerhovenandFacebook GitHub Bot 13780126d3 Fix generated EventEmitter code for nested objects in arrays. (#47514)
Summary:
This PR fixes the code for generating EventEmitter C++ code in case nested objects in arrays are used.

```typescript
export interface NativeProps extends ViewProps {
  onEvent: DirectEventHandler<
    Readonly<{
      payloadArray: Readonly<
        {
          obj: Readonly<{ str: string }>
        }[]
      >
    }>
  >;
}

export default codegenNativeComponent<NativeProps>('SomeComponent');
```

In this case the generated `EventEmitters.cpp` code would contain:

```c
obj.setProperty(runtime, "str", payloadArrayValue,obj.str);
```

while

```c
obj.setProperty(runtime, "str", payloadArrayValue.obj.str);
```

is expected.

## 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
-->

[GENERAL] [FIXED] - Codegen: Support nested objects in arrays

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

Test Plan: Tested with the reproduction case above to verify correct output.

Reviewed By: javache

Differential Revision: D65848670

Pulled By: elicwhite

fbshipit-source-id: 0021e87bc7213fff615465cab8554cc1a2159522
2024-11-20 16:25:34 -08:00
Andrei MarchenkoandFacebook GitHub Bot aafe696453 turn on by default optimization for memoization of virtualized list cells (#47724)
Summary:
Changelog: [General] [Changed] - Fix unnececary rerenders of VirtualizedListCells with strictMode={true}

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

Reviewed By: sammy-SC

Differential Revision: D66123469

fbshipit-source-id: 295e10add51bc1c319b8b8e3a9f4874c5e5a386d
2024-11-20 16:00:03 -08:00
Nick GerlemanandFacebook GitHub Bot 6e06a810f0 Fix possible NSRangeException when updating typing attributes in response to new text content (#47737)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47737

We may see an NSRangeException when setting new AttributedString content, where setting the AttributedString itself changes selection (before we mutate it later).

It seems like the selection here is not in a good state yet in regards to the AttributedString backing exposed (since we are reading it while modifying it). So let's fold the logic for updating typing attributes into the collection of ignored work from non-user-selection updates, since programatically setting an AttributedString will already trigger updating typing attributes.

I also added a nil check here, which is unrelated to the crash, but it seems like we should have it for safety...

Changelog:
[iOS][Fixed] - Fix possible NSRangeException when updating typing attributes in response to new text content

Reviewed By: cipolleschi

Differential Revision: D66202986

fbshipit-source-id: fded492b5022c5fef5b9563f93a57549d06a7020
2024-11-20 14:05:33 -08:00
Alan LeeandFacebook GitHub Bot 48ea6867a9 update targetSdk to 35 (#47738)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47738

- updating targetSdk to 35 for RN Android and helloworld
- **Note:** `tagetSdk` of RN Android does not have effect on the app's targetSdk. App can set `targetSdk` regardless of what RN targetSdk is. Updating the targetSdk just signals that RN Android has been tested with targetSdk 35 and apps can choose to support lower targetSdk as needed.

Changelog:
[Android][Changed] updating targetSdk to 35 (apps can still choose their own targetSdk regardless of RN version)

Reviewed By: NickGerleman

Differential Revision: D66209381

fbshipit-source-id: 2f26e8f605a383ff662e4b1d65611f186a7d7979
2024-11-20 11:06:31 -08:00
Alan LeeandFacebook GitHub Bot 7733c335eb Align HermesBadge to bottom to avoid overlap with status bar (#47734)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47734

- With forced edge-to-edge on Android 15 targetSdk 35, `HermesBadge` overlaps with the top status bar.
- Move the location of the HermesBadge to align with bottom of the header so we can avoid UI overlap with minimal changes to the template.

Changelog: [Internal]

Reviewed By: cipolleschi

Differential Revision: D66183918

fbshipit-source-id: 6e9eff337660a133349a2813e9ee033a8d2b749e
2024-11-20 11:06:31 -08:00
Alan LeeandFacebook GitHub Bot de82b15b0d Remove NewAppScreen from public API test (#47707)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47707

NewAppScreen should be removed from public API test

Changelog: [Internal]

Reviewed By: cipolleschi, blakef

Differential Revision: D66165484

fbshipit-source-id: 2b72a874e443447a2b444921f25cec729bcb89c5
2024-11-20 11:06:31 -08:00
Riccardo CipolleschiandFacebook GitHub Bot 102062fbc7 Extract RCTAppDependencyProvider in a separate pod (#47761)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47761

When breaking the last dependency, we created the `RCTApDependencyProvider` in the Codegen pod.

This is not an issue per sè. The problem comes in with the new template in Swift: ReactCodegen contains some headers with some C++ code that Swift can't really process.

That's why most libraries started failing in jobs like [this one](https://github.com/facebook/react-native/actions/runs/11906196751/job/33177904733): the template app was not able to load the `ReactCodegen` pod in the Swift app delegate.

Given that the app delegate only have to actually load the RCTAppDependencyProvider, I extracted that class in its own pod: ReactAppDependencyProvider.

The name of the pod does not follow the React-RCTXXX structure because that will create issues with the import statements and the `use_frameworks!`  use case.

> [!NOTE]
> We need to update the template and change the `import ReactCodegen` to `import ReactAppDependencyProvider`

## Changelog:
[iOS][Added] - Extract RCTAppDependencyProvider in the ReactAppDependencyProvider pod

Reviewed By: blakef

Differential Revision: D66241941

fbshipit-source-id: 6b888109c65d9560fff322ec84a16da78fbcd64b
2024-11-20 10:51:56 -08:00
Rubén NorteandFacebook GitHub Bot 105beed569 Fix bugs in MutationObserver (#47760)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47760

Changelog: [internal]

(this is internal because this API isn't enabled in OSS yet)

This fixes 2 bugs in `MutationObserver`:
1. Incorrectly reporting updates for the same node multiple times, if changes are observable by different targets in the same observer.
2. Incorrectly ignoring observations of subsequent targets in a given observer.

These were caught when migrating the unit tests for `MutationObserver` that were mocking Fabric to a Fantom integration test that uses the whole C++ infra.

Reviewed By: sammy-SC

Differential Revision: D66232571

fbshipit-source-id: b6e967ca4deaa1a69d35f14d4f921103fec2bbaf
2024-11-20 10:00:48 -08:00
Rubén NorteandFacebook GitHub Bot 43554b5a0f Expose NodeList and MutationRecord in global scope (#47759)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47759

Changelog: [internal]

These interfaces should be available in the global scope, so this exposes them in their setup modules.

Reviewed By: javache

Differential Revision: D66232574

fbshipit-source-id: 191c579ffce3fb8b4b454b5c5725661ff160a46f
2024-11-20 10:00:48 -08:00
Rubén NorteandFacebook GitHub Bot b2f624d054 Add flag to print Fantom logs in Jest output (#47758)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47758

Changelog: [internal]

This helps with debugging when adding logs in native code. By default they're logged to stderr and not shown in the Jest output, but we can opt into getting them with this new flag.

Reviewed By: sammy-SC

Differential Revision: D66232572

fbshipit-source-id: d507fa4438ae46988fafc92123d0954ab3d27631
2024-11-20 10:00:48 -08:00
zhongwuzwandFacebook GitHub Bot e573929d6c Fabric: Adjusts the weight according to the font name (#47742)
Summary:
Fixes another font weight issue mentioned in https://github.com/facebook/react-native/issues/47656#issuecomment-2486282496. We can get the weight from font name if user not specify weight.

esbenvb Is this work for you ?

## Changelog:

[IOS] [FIXED] - Fabric: Adjusts the weight according to the font name

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

Test Plan: Demo in https://github.com/facebook/react-native/issues/47656#issuecomment-2486282496.

Reviewed By: cipolleschi

Differential Revision: D66236128

Pulled By: javache

fbshipit-source-id: d325a7fee28681a1e95fa0341cb7a16fcd9918c0
2024-11-20 09:25:48 -08:00
Alex HuntandFacebook GitHub Bot 01b40789ee Update build script to minimally support subpath patterns (#47673)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47673

Update shared monorepo build script:
- Refactor entry point discovery and file iteration
- Add support for "exports" subpath patterns (skip considering as entry point with warning)

This is required for the incoming migration of `react-native-codegen` to this build setup (D51465053).

Changelog: [Internal]

Reviewed By: robhogan

Differential Revision: D66121262

fbshipit-source-id: 0deb2c2b26de442ee348ef9de54a1fa144368b6f
2024-11-20 09:21:13 -08:00
Samuel SuslaandFacebook GitHub Bot d2723b8ed7 delete feature flag useSetNativePropsInNativeAnimationsInFabric
Summary: changelog: [internal]

Reviewed By: dmytrorykun

Differential Revision: D66230767

fbshipit-source-id: 8f133a313e42a5dc7136e88a3ce68835d420ced9
2024-11-20 07:25:56 -08:00
Rob HoganandFacebook GitHub Bot 69400be4fc dev-middleware: Only rewrite hostnames if they match device connection hosts (#47685)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47685

Currently, we assume any URL with a hostname of `10.0.2.2` or `10.0.3.2` (device-relative) is eligible for rewriting to `localhost` (frontend-relative), because we assume the device is an Android emulator. We rewrite these URLs between device and dev machine so that the rewritten URLs are reachable from the dev machine.

This diff narrows this logic so that we'll only rewrite URLs where the hostname matches the pre-existing list *and* this matches the host the device is actually connected on, according to its headers from the original connection.

The main motivation for this change is to unblock removing assumptions about device-reachable vs server-reachable hosts. Later in the stack we'll drop the hardcoded listing of `10.0.2.2` etc in favour of identifying URLs that target the dev server, from whatever network.

There's also an edge case fix here that `10.0.2.2` etc might actually refer to a remote LAN server, and not be an Android emulator's alias for for an emulator host.

Changelog:
[General][Fixed] RN DevTools: Don't assume 10.0.2.2 is an alias for localhost unless it's used to establish a connection to the server

Reviewed By: huntie

Differential Revision: D66058704

fbshipit-source-id: bad28717b0c9b1ca43e2ea3391cef13f87892e6c
2024-11-20 06:56:21 -08:00
Dmitry RykunandFacebook GitHub Bot d658ff521d Add missing Android-only props to ImageProps (#47719)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47719

There is a subset of `ImageProps` that are used by Android but not used by iOS. They were missing in the `ImageProps.h`. It was fine when they were only consumed by the Android mounting layer. But it becomes a problem if we want to write some shared C++ code based on those props.
This diff adds those props to the corresponding C++ type.
This should have no practical effect for both platforms.
Changelog: [Internal]

Reviewed By: javache

Differential Revision: D65426569

fbshipit-source-id: dc1c9fe4a6e0e62e62f84b9b249e1c7d253290f5
2024-11-20 06:34:35 -08:00
Simon KruegerandFacebook GitHub Bot 4dd8d3db57 Use folly::fileops qualified name lookup (#47608)
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/47608

This is a codemod. It was automatically generated and will be landed once it is approved and tests are passing in sandcastle.
You have been added as a reviewer by Sentinel or Butterfly.

Autodiff project: fileops2
Autodiff partition: xplat.js.react-native-github.packages.react-native.ReactCommon.cxxreact
Autodiff bookmark: ad.fileops2.xplat.js.react-native-github.packages.react-native.ReactCommon.cxxreact

This updates `open`, `close`, `read`, `write`, and `pipe` call sites to use
`folly::fileops` qualified name lookup.

This is the 2nd phase in a 3-phase change to remove folly's global definitions
of the posix functions that conflict with windows CRT.
The 1st phase created namespaces for folly's posix functions. The 2nd phase
updates callsites to use the qualified name of folly's  `open`, `close`,
`read`, `write`, and `pipe`  functions. The 3rd and final phase will remove
folly's globally defined posix functions and have windows CRT define them
again.

**What is the reason for this change?**
Folly's global definitions of posix functions on Windows causes `#include`
order issues if folly is not included first.

For example, when `gtest/gtest.h` is included before folly, gtest includes
`windows.h` and that declares `open`, `read`, and `chdir`, which creates
ambiguous references to folly's `open`, `read`, and `chdir`.

Another example is where posix functions go undeclared when
`folly/portability/windows.h` is included without other portability headers
(e.g., `folly/portability/unistd.h`). `folly/portability/windows.h` includes
`windows.h` in a way that only underscore versions of the posix functions are
available (e.g., `_open`, `_close`).

These issues create friction for windows development.

**Background: What is the purpose of `folly::portability::{fcntl,stdlib,sysstat,unistd}`?**
It is a portability layer to make posix functions available and behave
consistently across platforms. Some posix functions don't exist on windows
(e.g., `sysconf`). Some other posix functions, folly changes to adapt behavior
across platforms. For example, on windows folly defines `open`, `read`,
`write`, and `close` functions to work with sockets. Folly makes these
functions available in the global scope for convenience.

Changelog: [Internal]

Reviewed By: javache

Differential Revision: D65855147

fbshipit-source-id: b06863330ca213b9d1bffe0ee85e0fbf1bc8a845
2024-11-20 06:27:34 -08:00
273 changed files with 4737 additions and 3269 deletions
+2 -1
View File
@@ -44,6 +44,7 @@ packages/react-native/flow/
[options]
enums=true
as_const=true
casting_syntax=both
emoji=true
@@ -95,4 +96,4 @@ untyped-import
untyped-type-import
[version]
^0.253.0
^0.255.0
@@ -43,7 +43,7 @@ runs:
shell: powershell
run: |
if (-not(Test-Path -Path $Env:HERMES_WS_DIR\win64-bin\hermesc.exe)) {
choco install --no-progress cmake --version 3.14.7
choco install --no-progress cmake --version 3.14.7 --allow-downgrade
if (-not $?) { throw "Failed to install CMake" }
cd $Env:HERMES_WS_DIR\icu
+3 -1
View File
@@ -421,7 +421,9 @@ jobs:
run-e2e-tests: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
test_e2e_android_rntester:
if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
# Temporarily disable RNTester tests on Android as they are quite flaky and they make CI always red
# if: ${{ github.ref == 'refs/heads/main' || contains(github.ref, 'stable') || inputs.run-e2e-tests }}
if: ${{ contains(github.ref, 'stable') || inputs.run-e2e-tests }}
runs-on: ubuntu-latest
needs: [build_android]
strategy:
+392
View File
@@ -1,5 +1,397 @@
# Changelog
## v0.77.0-rc.0
### Breaking
- Bridgeless: Make NativeModules.foo load turbomodules (unset turboModuleProxy in bridgeless). ([cc5f17d5a2](https://github.com/facebook/react-native/commit/cc5f17d5a2b185de1e7dec2a56a97b088e4c7a81) by [@RSNara](https://github.com/RSNara))
- dev-middleware: Frameworks should specify `serverBaseUrl` relative to the middleware host. ([acf384a72e](https://github.com/facebook/react-native/commit/acf384a72e599691e4c9d53043f1801da01c58fd) by [@robhogan](https://github.com/robhogan))
- `position` of sticky headers on `ScrollView` will now be taken into account ([cbab004eb9](https://github.com/facebook/react-native/commit/cbab004eb94f8312e9b10dae1502d3ca8632a006) by [@joevilches](https://github.com/joevilches))
- Remove ReactFabricInternals module ([0c21db360c](https://github.com/facebook/react-native/commit/0c21db360cecc6a3265eea50d628106c58b67af8) by [@huntie](https://github.com/huntie))
- Make ReactDebugOverlayTags, DebugOverlayTags, Printer, PrinterHolder, NoopPrinter internal ([623d481991](https://github.com/facebook/react-native/commit/623d4819915e7e6fafb8006c8e3b3b796e394974) by [@cortinico](https://github.com/cortinico))
- More spec compliant absolute positioning ([0a2dec175e](https://github.com/facebook/react-native/commit/0a2dec175e92185943907f3e1f6073bae6cd663d) by [@NickGerleman](https://github.com/NickGerleman))
- Native looping animation will not send React state update every time it finishes. ([4b035d820d](https://github.com/facebook/react-native/commit/4b035d820d3f1c3c9a98ce4f55bcc95a7ab064bf) by [@dmytrorykun](https://github.com/dmytrorykun))
#### Android specific
- Removed ReactViewGroup.getBackgroundColor() ([6a472c5cf2](https://github.com/facebook/react-native/commit/6a472c5cf25d72f72ec7e261282d611a5ab0a662) by Thomas Nardone)
- ReadableArray non-primitive getters are now correctly typed as optional ([145c72f816](https://github.com/facebook/react-native/commit/145c72f8163048f0eee30d5ce850911f5dad865c) by [@javache](https://github.com/javache))
- Remove jsBundleLoader from DefaultReactHost.getDefaultReactHost() ([fbe4c0ed34](https://github.com/facebook/react-native/commit/fbe4c0ed347156a7ea24da29e09083a499c80cf5) by [@mdvacca](https://github.com/mdvacca))
- Reduce visibility of TaskCompletionSource class ([4f55161132](https://github.com/facebook/react-native/commit/4f551611326d63b6fb5cd53e63d536c2c6f04647) by [@mdvacca](https://github.com/mdvacca))
- Stable API - Make ImageStoreManager internal ([846c4b1ea2](https://github.com/facebook/react-native/commit/846c4b1ea2d139e3f3cbafa2f8ddbf159e3322e4) by [@arushikesarwani94](https://github.com/arushikesarwani94))
- Stable API - Make SwipeRefreshLayoutManager internal ([d02da992a4](https://github.com/facebook/react-native/commit/d02da992a4c0893313b9f059a8be228f43fffa7a) by Thomas Nardone)
- Undo breaking change of UiManager.eventDispatcher return type ([7817ab5de2](https://github.com/facebook/react-native/commit/7817ab5de2ce324df734a5dfd705f2454937328f) by [@cortinico](https://github.com/cortinico))
- Stable API - Make classes inside `com.facebook.react.views.progressbar` internal ([46526fc2fe](https://github.com/facebook/react-native/commit/46526fc2fe1dd0ce937fad35469b64b9fb05eaa2) by [@cortinico](https://github.com/cortinico))
- Undo breaking change of UiManager.eventDispatcher return type ([dbe509a23a](https://github.com/facebook/react-native/commit/dbe509a23a974f16804aefea055a24c06910b259) by [@cortinico](https://github.com/cortinico))
- Stable API - Make OkHttpCallUtil internal ([abd118a719](https://github.com/facebook/react-native/commit/abd118a719fe0aeb13f980729ff9ce5fb8358b83) by [@arushikesarwani94](https://github.com/arushikesarwani94))
- Stable API - Make SimpleSettableFuture internal ([3dec672398](https://github.com/facebook/react-native/commit/3dec672398729cd668aff92249f1fdde231fb928) by [@arushikesarwani94](https://github.com/arushikesarwani94))
- Stable API - Make `ClipboardModule` internal ([10f6d5adb5](https://github.com/facebook/react-native/commit/10f6d5adb538a9b20043312fc09b192759100d63) by [@cortinico](https://github.com/cortinico))
- Reduce visibility of ReactVirtualTextShadowNode to internal ([496b0a8729](https://github.com/facebook/react-native/commit/496b0a8729b41266683fdd84de5618b23d06ce3d) by [@mdvacca](https://github.com/mdvacca))
- Reduce visibility of ReactVirtualTextViewManager to internal ([4a119c4c3a](https://github.com/facebook/react-native/commit/4a119c4c3ac9bf4b234e2942a27a6efd68a801cc) by [@mdvacca](https://github.com/mdvacca))
- Stable API - Make classes in `com.facebook.react.views.safeareaview` internal ([39dfbadd5d](https://github.com/facebook/react-native/commit/39dfbadd5d3468d079bf3b039401237c6e7f363c) by [@cortinico](https://github.com/cortinico))
- Stable API - Make ClipboardModule internal ([a72c35f98c](https://github.com/facebook/react-native/commit/a72c35f98ccd1a49d367678b46a29c814ad5de43) by [@cortinico](https://github.com/cortinico))
- Undo a breaking change on ReactViewGroup constructor ([bbe714e487](https://github.com/facebook/react-native/commit/bbe714e487fb51c61820fdc5d89c9782da79b657) by [@cortinico](https://github.com/cortinico))
- Stable API - Make NativeModulePerfLogger internal ([d7d5de9f96](https://github.com/facebook/react-native/commit/d7d5de9f9630e7dcd0194830d7ccb32f167b619c) by [@cortinico](https://github.com/cortinico))
- Make `DevLoadingModule` internal ([8c50bf0beb](https://github.com/facebook/react-native/commit/8c50bf0beb17ced7fdafeae7a734edfc03e6e0b2) by [@cortinico](https://github.com/cortinico))
- Stable API - Convert to Kotlin and make internal `NotThreadSafeViewHierarchyUpdateDebugListener` ([287e200332](https://github.com/facebook/react-native/commit/287e20033207df5e59d199a347b7ae2b4cd7a59e) by [@cortinico](https://github.com/cortinico))
- Rename DevSupportManagerBase.getCurrentContext() -> getCurrentReactContext() ([0e7ba9094e](https://github.com/facebook/react-native/commit/0e7ba9094ea573d1512b2dc71e46f55b24201b7a) by [@RSNara](https://github.com/RSNara))
- Make DevSupportManagerBase.getCurrentReactContext() public ([5a6a42c7d0](https://github.com/facebook/react-native/commit/5a6a42c7d029d44799cb907c0ca3c8aa38fa1770) by [@RSNara](https://github.com/RSNara))
- Reduce visibility of ReactUnimplementedViewManager to internal ([fe656be26e](https://github.com/facebook/react-native/commit/fe656be26e0d71bf2505032578dbea54af36b2c5) by [@mdvacca](https://github.com/mdvacca))
- Stable API - Make InteropModuleRegistry internal ([cba1d4bae7](https://github.com/facebook/react-native/commit/cba1d4bae7285ba160b05f31ca18cfa0b91e9ef5) by [@cortinico](https://github.com/cortinico))
- Stable API - Make ReactDevToolsSettingsManagerModule and ReactDevToolsRuntimeSettingsModule internal ([d7550293a2](https://github.com/facebook/react-native/commit/d7550293a2530f02f75b4249b7e6003edaf28ac9) by [@cortinico](https://github.com/cortinico))
- Added JSBundleLoader as parameter of DefaultReactHost ([143b9d172c](https://github.com/facebook/react-native/commit/143b9d172ca755e2457e8dfc6009eeef2475a4a1) by [@mdvacca](https://github.com/mdvacca))
- Deleting deprecated CompositeReactPackage ([2cb5198f1b](https://github.com/facebook/react-native/commit/2cb5198f1b589a57a4cfd3cc40a9ed6224fc5d75) by [@mdvacca](https://github.com/mdvacca))
- Make ReactHost.createSurface() method non nullable ([70c7616535](https://github.com/facebook/react-native/commit/70c761653564653bdfcb77a8c5ef3608dafcf5d7) by [@mdvacca](https://github.com/mdvacca))
- Stable API - Make AppStateModule internal ([dbf09fbe58](https://github.com/facebook/react-native/commit/dbf09fbe5823d77556b451317c14f833735067d9) by [@cortinico](https://github.com/cortinico))
- Undo breaking change on UIManager eventDispatcher accessor ([dc1a498d39](https://github.com/facebook/react-native/commit/dc1a498d3974680f2257efd8ff9ec3f989204c68) by [@cortinico](https://github.com/cortinico))
- Make `AccessibilityInfoModule` internal ([7168a9d1a2](https://github.com/facebook/react-native/commit/7168a9d1a2ed7459ebb056ebe45d86de791013e3) by [@cortinico](https://github.com/cortinico))
- Undo breaking change on ViewManagerDelegate.kt String params ([2d2bb9c588](https://github.com/facebook/react-native/commit/2d2bb9c58824af34392bda196fbf0be17498cc05) by [@cortinico](https://github.com/cortinico))
- Add 3 methods to ReactInstanceDevHelper ([c867aba2f3](https://github.com/facebook/react-native/commit/c867aba2f3dd7773be9d2ee0827bcd69481a394e) by [@cortinico](https://github.com/cortinico))
- Add test case for set opacity in new arch examples ([848471b69f](https://github.com/facebook/react-native/commit/848471b69f59094780ace25c6963e480d94ec5c3) by [@poonamjain96](https://github.com/poonamjain96))
- Add test for Console.log measure in new-arch-examples ([8cf27e8b6f](https://github.com/facebook/react-native/commit/8cf27e8b6f112d646111ddaba0b5036cafac3299) by [@poonamjain96](https://github.com/poonamjain96))
- Remove Deprecated DefaultDevSupportManagerFactory.create() ([f25abe51ce](https://github.com/facebook/react-native/commit/f25abe51ce93b97ef1fe97af5fc76f13a5a6ff03) by [@cortinico](https://github.com/cortinico))
- Remove BaseViewManagerInterface ([7fb3d830be](https://github.com/facebook/react-native/commit/7fb3d830beae3daf431ac90e9326b744ff8300a1) by [@NickGerleman](https://github.com/NickGerleman))
- Chore: test case added for Image ([d0e5053528](https://github.com/facebook/react-native/commit/d0e50535287088030e60e131691c8d9ed1d57989) by [@sarthak-d11](https://github.com/sarthak-d11))
- Remove ReactNativeFlipper object, deprecated in 0.75 ([d1a256f51a](https://github.com/facebook/react-native/commit/d1a256f51a43f465823bdfb8a70fae5f92473d7c) by [@cortinico](https://github.com/cortinico))
- Add test for background color and border width in text.yml ([fa62b7e1ed](https://github.com/facebook/react-native/commit/fa62b7e1ed00c69819d85819c6209fb42bedb233) by [@muskan27797](https://github.com/muskan27797))
- Added Submit Application test to button.yml ([699f73a6b0](https://github.com/facebook/react-native/commit/699f73a6b0734fe716b01d263e9579bca38c4652) by [@shubhamguptadream11](https://github.com/shubhamguptadream11))
- Use BackgroundStyleApplicator when setting background color in BaseViewManager ([309cdea337](https://github.com/facebook/react-native/commit/309cdea337101cfe2212cfb6abebf1e783e43282) by [@NickGerleman](https://github.com/NickGerleman))
- Delete useTurboModules, enableFabricRenderer and enableBridgelessArchitecture fields from ReactFeatureFlags class ([10a33e0479](https://github.com/facebook/react-native/commit/10a33e04793befbeab6ae82d4068b1ebd7fdffd0) by [@mdvacca](https://github.com/mdvacca))
- Remove ReactViewBackgroundManager and ReactViewBackgroundDrawable ([51673e41ae](https://github.com/facebook/react-native/commit/51673e41ae12f06b2b378e048094ad39ca30c317) by [@NickGerleman](https://github.com/NickGerleman))
#### iOS specific
- Use the RCTDependencyProvider in the RCTAppDelegate, breaking the dependency with Codegen ([b91626af26](https://github.com/facebook/react-native/commit/b91626af2626bf611958b1e7d0dd0b7338ccc29e) by [@cipolleschi](https://github.com/cipolleschi))
- Delete experimental API RCTConstants.RCTGetMemoryPressureUnloadLevel ([d79dc48abd](https://github.com/facebook/react-native/commit/d79dc48abd2e65e4d203e488f99eb554c473a1fc) by [@mdvacca](https://github.com/mdvacca))
- ([6fc500ee99](https://github.com/facebook/react-native/commit/6fc500ee9942e51519545c1ba1026bacad03dc61) by [@philIip](https://github.com/philIip))
- ([538bff710f](https://github.com/facebook/react-native/commit/538bff710f7afb4afa7ce91f20074668ad5c739d) by [@philIip](https://github.com/philIip))
- Replace uses of `CGColorRef` with UIColor to avoid manual memory management ([b70709dbc2](https://github.com/facebook/react-native/commit/b70709dbc27c75c69e9fd2b082ffa27e7e8db7fd) by [@Saadnajmi](https://github.com/Saadnajmi))
- Cocoapods decide the C++ version for iOS pods ([bd50c4a460](https://github.com/facebook/react-native/commit/bd50c4a460a01dad3cd7cade8191273563675d24) by [@cipolleschi](https://github.com/cipolleschi))
- Delete partialBatchDidFlush ([a777a8937e](https://github.com/facebook/react-native/commit/a777a8937ee165993d7d9b35c7c981fe6698f9dc) by [@philIip](https://github.com/philIip))
- We deprecated RCTRuntimeExecutor in 0.76, so let's get rid of the code now. ([cf8d09b279](https://github.com/facebook/react-native/commit/cf8d09b279c4bd667d96f9445c1c0b9acb0a0dfc) by [@philIip](https://github.com/philIip))
- Unbreak `RCTHermesInstance` constructor breaking change ([aec6666bfa](https://github.com/facebook/react-native/commit/aec6666bfabf93cde70fa869b3eea68590998dee) by [@tido64](https://github.com/tido64))
### Added
- Add FuseboxPerfettoDataSource to emit Fusebox traces using Perfetto ([ef0ea4d834](https://github.com/facebook/react-native/commit/ef0ea4d834ec61c5deede487b46a787a363f6a64) by Benoit Girard)
- Add support for `rn_rootThreshold` in Intersection Observer ([a77d8d9d50](https://github.com/facebook/react-native/commit/a77d8d9d50e69a6a4563737c2ce68d26204eda7f) by [@lunaleaps](https://github.com/lunaleaps))
- Codegen: Support negative values in enums ([177bf4d043](https://github.com/facebook/react-native/commit/177bf4d043ce862911e477e0f0039214d8541cfd) by [@okwasniewski](https://github.com/okwasniewski))
- Use the TypeScript key in syntax to restrict permissions and types of results ([0244710c4b](https://github.com/facebook/react-native/commit/0244710c4b1e5016069ec9f7b8e7116ff51f59f1) by [@qnnp-me](https://github.com/qnnp-me))
- Image `resizeMode` and `objectFit` support for `'none'`. ([d8cfd98070](https://github.com/facebook/react-native/commit/d8cfd98070cbccc5e8a49446d76bdc2cb0c6939f) by [@mateoguzmana](https://github.com/mateoguzmana))
- Add NumberLiteralTypeAnnotation support ([dd472101b7](https://github.com/facebook/react-native/commit/dd472101b76a964b7a64f0bb84d967f702500cad) by [@elicwhite](https://github.com/elicwhite))
- Eliminate usage of more than 1-arg `React.AbstractComponent` in React codebase ([6205aad81e](https://github.com/facebook/react-native/commit/6205aad81ef8154a106fa253a1f4b00aee568650) by [@SamChou19815](https://github.com/SamChou19815))
- Added support for `display: contents` ([e7a3f479fe](https://github.com/facebook/react-native/commit/e7a3f479fe37a5d503770bafc03c80b1c2dcb8f7) by [@j-piasecki](https://github.com/j-piasecki))
- Added the missing `announceForAccessibilityWithOptions` function mock in the `packages/react-native/jest/setup.js` file. ([4ae999b90b](https://github.com/facebook/react-native/commit/4ae999b90b2a67233890d30a8bff0dbdd58364f2) by [@ChrisMattew](https://github.com/ChrisMattew))
- Add support for reload-to-profile in Fusebox (Part 2 of 2: JS) ([4df224ca6d](https://github.com/facebook/react-native/commit/4df224ca6df9dc593ab7090520578f27c520f361) by [@EdmondChuiHW](https://github.com/EdmondChuiHW))
- Add JS layer for new text content type cellular EID and cellular IMEI ([118c1f7035](https://github.com/facebook/react-native/commit/118c1f7035cfcadb567b1ccd40d85c751dd65162) by [@cipolleschi](https://github.com/cipolleschi))
- Add support for reload-to-profile in Fusebox. (Part 1 of 2: native) ([91a40a28de](https://github.com/facebook/react-native/commit/91a40a28de3f74a389c6e6ad05fb917d58fc072d) by [@EdmondChuiHW](https://github.com/EdmondChuiHW))
- Add cli --help details to combine-js-toschema-cli.js ([e4814b0d6d](https://github.com/facebook/react-native/commit/e4814b0d6d981cf96eef2803e8f20548263ea0e4) by [@blakef](https://github.com/blakef))
- Codegen for Native Modules now supports string literals ([d2f3f06826](https://github.com/facebook/react-native/commit/d2f3f06826e2287ad5f5dc4e27201fc5dc9fcd5c) by [@elicwhite](https://github.com/elicwhite))
- Codegen now supports Union Types in NativeModules ([3af126b562](https://github.com/facebook/react-native/commit/3af126b562cf7e0828906a4fe0ac79a886b557e6) by [@elicwhite](https://github.com/elicwhite))
- Updated FlatList setNativeProps type ([b0ac99b477](https://github.com/facebook/react-native/commit/b0ac99b47781e3b68bee2ff737b109f58eeeba78) by [@JDMathew](https://github.com/JDMathew))
- Added Jest mocks for `NativeAnimatedModule` ([fd355308fa](https://github.com/facebook/react-native/commit/fd355308faa2da30d4e0d68ae9b4d136d2a5f1c3) by [@yungsters](https://github.com/yungsters))
- Added `HostInstance` type to represent the instance of a `HostComponent<T>`. ([e24f9917c2](https://github.com/facebook/react-native/commit/e24f9917c25ed8c32c6e01d50a5fa49fe66a6ee1) by [@yungsters](https://github.com/yungsters))
- Export `DevMenu` from `react-native` ([e12c0d9551](https://github.com/facebook/react-native/commit/e12c0d95516924b5e6ca4f0d5ebcadb42bb19f30) by [@frankcalise](https://github.com/frankcalise))
- Removed `experimental` prefix and fully released `mixBlendMode` prop ([d2c48f3b1a](https://github.com/facebook/react-native/commit/d2c48f3b1a2a15e9832ea3240c19aea5186ceb24) by [@jorge-cab](https://github.com/jorge-cab))
- Add Playground to RNTester for testing out features & submitting reproducers. ([256adcab7b](https://github.com/facebook/react-native/commit/256adcab7b02e8a80227d44b76d1a74d8c4973de) by [@shwanton](https://github.com/shwanton))
- Add color formatting to codegen output ([1747f57c67](https://github.com/facebook/react-native/commit/1747f57c6708ffa59ea511f9fbbacf37364fde72) by [@okwasniewski](https://github.com/okwasniewski))
- Added overlayColor prop to modal component for customisable background overlay ([4e1d7015c1](https://github.com/facebook/react-native/commit/4e1d7015c1d4e2703133b1347ed97a0cc93b1318) by [@shubhamguptadream11](https://github.com/shubhamguptadream11))
- Created an experimental optimization to improve memoization within `Animated` to improve product performance ([dc84d00db6](https://github.com/facebook/react-native/commit/dc84d00db64b78234e91c2b73f4d4fce8782cd02) by [@yungsters](https://github.com/yungsters))
- Expose missing text content type to JS ([d3d48cb357](https://github.com/facebook/react-native/commit/d3d48cb357e55b1f2ae0042a5960451fbe5ff5c7) by [@cipolleschi](https://github.com/cipolleschi))
- Created an experimental (unstable) method for allowlisting props when using `Animated` ([f3f652daab](https://github.com/facebook/react-native/commit/f3f652daabc4a1d374190165ac38715ad31a5214) by [@yungsters](https://github.com/yungsters))
- Upgrade Flow to 0.245.2 ([1f65bf9545](https://github.com/facebook/react-native/commit/1f65bf9545cd84bbf1be7a7a91cb0b4f8b4b47ba) by [@SamChou19815](https://github.com/SamChou19815))
#### Android specific
- Image `force-cache` caching control option ([a0be88fd72](https://github.com/facebook/react-native/commit/a0be88fd727898d4626ca51876d0bfb4e50dcb77) by [@mateoguzmana](https://github.com/mateoguzmana))
- Add overlapping radii resolution logic preventing incorrect rendering ([451ff70da4](https://github.com/facebook/react-native/commit/451ff70da422beefccfff5b87024145003bb49ff) by [@jorge-cab](https://github.com/jorge-cab))
- Marked ReactPackage#getModule as stable. ([8fba7ebb5e](https://github.com/facebook/react-native/commit/8fba7ebb5e874d001dc5c16eb4229054a2ef4812) by [@javache](https://github.com/javache))
- ReactDelegate and ReactActivityDelegate#getCurrentReactContext can be used to access the current context ([fe8cc62824](https://github.com/facebook/react-native/commit/fe8cc62824372229d90445b2769fed9c08604a7e) by [@javache](https://github.com/javache))
- Add exceptionHandler as a parameter of DefaultReactHost.getDefaultReactHost() method ([7a5a10c95c](https://github.com/facebook/react-native/commit/7a5a10c95ce6af1964ce5bd273c0c6513fb78a1e) by [@mdvacca](https://github.com/mdvacca))
- Logic to check for grayscale mode on android ([e70202e606](https://github.com/facebook/react-native/commit/e70202e606be3101da33d28f5403443c3e84749e) by [@oddlyspaced](https://github.com/oddlyspaced))
- TextTransform ktx ([7794d7af43](https://github.com/facebook/react-native/commit/7794d7af43b90b581574361af102f67ad7961a5e) by Thomas Nardone)
- Add navigationBarTranslucent prop to Modal component ([7a6c7a462a](https://github.com/facebook/react-native/commit/7a6c7a462a7898e13327438a6603d83a39147abb) by [@zoontek](https://github.com/zoontek))
- Trigger Java GC on app reload ([de3c1ee097](https://github.com/facebook/react-native/commit/de3c1ee097f7041d6f9754a55a45cea80fd25813) by [@mrousavy](https://github.com/mrousavy))
- Add cmake arguments to support 16KB page size for native libraries ([65cdd5b82c](https://github.com/facebook/react-native/commit/65cdd5b82ce7652630b1920fa3a48c8f256c7983) by [@alanleedev](https://github.com/alanleedev))
- Enabling basic `Image` cache control for Android ([e5dd7d68bf](https://github.com/facebook/react-native/commit/e5dd7d68bf264669fc5c4ce5e69b24249d28558b) by [@mateoguzmana](https://github.com/mateoguzmana))
- Add OnLayoutChange API for scroll views ([d825a4d712](https://github.com/facebook/react-native/commit/d825a4d712a1ba53c0f4209c9da5d51578209a6d) by Thomas Nardone)
- React Activity exposes ReactHost ([d78cb78b15](https://github.com/facebook/react-native/commit/d78cb78b15a520f3bebcdf00b82b26bf120f4180) by [@shwanton](https://github.com/shwanton))
- Added PixelUtil extensions for Int and Long ([9406a09f87](https://github.com/facebook/react-native/commit/9406a09f871d3efa66e3d10237a6d1fd08ddee0b) by Thomas Nardone)
- Add boxShadow support to BaseViewManager ([b69a92e2c9](https://github.com/facebook/react-native/commit/b69a92e2c95990fcfa95a6ab7b7260ac492f942c) by [@NickGerleman](https://github.com/NickGerleman))
- Test: pressable test cases ([3102a58df3](https://github.com/facebook/react-native/commit/3102a58df38d96f3dacef0530e4dbb399037fcd2) by [@deepanshushuklad11](https://github.com/deepanshushuklad11))
- Added showcase for Android `resizeMethod` options when applied to a large image ([768a1d8664](https://github.com/facebook/react-native/commit/768a1d86649e391964d404a15733c227c57c0d38) by [@Abbondanzo](https://github.com/Abbondanzo))
- Adds a new `resizeMethod`, `none`, which disables downsampling for an image ([6202319ed5](https://github.com/facebook/react-native/commit/6202319ed544e4d23f1f327ff5334c480af3819d) by [@Abbondanzo](https://github.com/Abbondanzo))
- Add Modal Testing to modal.yml ([1a2532b1fc](https://github.com/facebook/react-native/commit/1a2532b1fc32ec989e05576121b5e669697d29af) by [@ahmedbilal008](https://github.com/ahmedbilal008))
- Add a new Fresco decoder for XML resource types ([118b7c18a6](https://github.com/facebook/react-native/commit/118b7c18a6f827dabb00522bbd6a2416e1bf99da) by [@Abbondanzo](https://github.com/Abbondanzo))
- Added `isHighTextContrastEnabled()` to `AccessibilityInfo` to read `ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED` setting value ([d4ea147b41](https://github.com/facebook/react-native/commit/d4ea147b41e4d22253f80be8b74731dcf0439302) by Ariel Lin)
- Outline properties `outline-width`, `outline-color`, `outline-style` & `outline-offset` ([17faac4170](https://github.com/facebook/react-native/commit/17faac417035f2cc5f12ec60a46270991be0989a) by [@jorge-cab](https://github.com/jorge-cab))
- Flag in ReactFragment to allow unmounting a surface without destroying ReactHost. ([bb3ec4d6c3](https://github.com/facebook/react-native/commit/bb3ec4d6c342d3afcb109e8c65f99e7693c962b5) by [@rozele](https://github.com/rozele))
- ReactDelegate `unloadApp` methods for unmounting surfaces without destroying ReactHost ([38593c440e](https://github.com/facebook/react-native/commit/38593c440e949a9b52df0a6821b80ac47b19a693) by [@rozele](https://github.com/rozele))
- New feature flag for line height calculation ([f338e7c0a1](https://github.com/facebook/react-native/commit/f338e7c0a1072974b5ac76567c8d1d06f5b7c1e2) by [@mellyeliu](https://github.com/mellyeliu))
- Adds support for importing XML assets as images ([2e80f5acf1](https://github.com/facebook/react-native/commit/2e80f5acf11cd9726921a00a58700cab9e0bb0a7) by [@Abbondanzo](https://github.com/Abbondanzo))
#### iOS specific
- Image `only-if-cached` cache control option ([dc9db01665](https://github.com/facebook/react-native/commit/dc9db01665308ac931967326abfc86deb9ae7e2a) by [@mateoguzmana](https://github.com/mateoguzmana))
- TextInput `inputAccessoryViewButtonLabel` prop ([32931466ed](https://github.com/facebook/react-native/commit/32931466ed7e3d8d9eeeb65f12ce146e123870ba) by [@mateoguzmana](https://github.com/mateoguzmana))
- Fix: Correct Layout Behavior for Combined align-content and align-items ([73a2be1243](https://github.com/facebook/react-native/commit/73a2be12437c93bbd138e0d63cd45d834529a3c4) by [@phuccvx12](https://github.com/phuccvx12))
- Extract RCTAppDependencyProvider in the ReactAppDependencyProvider pod ([102062fbc7](https://github.com/facebook/react-native/commit/102062fbc7d6a5c81192562c3ccb87bc4222a0cf) by [@cipolleschi](https://github.com/cipolleschi))
- Pass the `RCTAppDependencyProvider` to the `RCTAppDelegate` ([95fc906930](https://github.com/facebook/react-native/commit/95fc906930ece9b30482eb1f0924d7e8614af7c6) by [@cipolleschi](https://github.com/cipolleschi))
- Introduce the RCTAppDependencyProvider to minimize the changes required y the users ([41c2502b36](https://github.com/facebook/react-native/commit/41c2502b3650e238b0a5d86b5044abcb538b76e3) by [@cipolleschi](https://github.com/cipolleschi))
- Add RCTDependencyProvider protocol ([f2b3716426](https://github.com/facebook/react-native/commit/f2b371642684682916522dc82adee93464ba31fe) by [@cipolleschi](https://github.com/cipolleschi))
- Added `disabledButtonTintColor` prop to ActionSheetIOS ([089c87e22e](https://github.com/facebook/react-native/commit/089c87e22e9f431d0e7f35292dce2e36fa86d09a) by [@henninghall](https://github.com/henninghall))
- Scroll the cursor into view when text input is focused ([e021e50d53](https://github.com/facebook/react-native/commit/e021e50d537884a55a9f5bea931adb19e9069dd6) by [@dominictb](https://github.com/dominictb))
- Introduce RCTArchConfiguratorProtocol ([ec0dbb729d](https://github.com/facebook/react-native/commit/ec0dbb729d3774184dee83efbff5f9beebce72ce) by [@okwasniewski](https://github.com/okwasniewski))
- Introduce RCTUIConfiguratorProtocol ([8850736188](https://github.com/facebook/react-native/commit/8850736188321f13c7bdeadedeed15c759ad72c1) by [@okwasniewski](https://github.com/okwasniewski))
- TvOS support for Hermes artifacts ([f673759c83](https://github.com/facebook/react-native/commit/f673759c83fed130964ea7dfe677c04608b8e64d) by [@douglowder](https://github.com/douglowder))
- Add `CallInvoker` to `BindingsInstaller` ([87bae7f734](https://github.com/facebook/react-native/commit/87bae7f7349976cfc269b25584330c4d3d897d79) by [@mrousavy](https://github.com/mrousavy))
- Added `isDarkerSystemColorsEnabled()` to `AccessibilityInfo` to read "Increase Contrast" setting value ([af3bee6511](https://github.com/facebook/react-native/commit/af3bee6511fe72fda7415bf974f937012b3eefec) by Ariel Lin)
- Expose RCT_NEW_ARCH_ENABLED to Swift ([d24507611d](https://github.com/facebook/react-native/commit/d24507611de7fefc71286fd54b2c909d98a4bf27) by [@okwasniewski](https://github.com/okwasniewski))
- Add `systemCyan` and `systemMint` colors on iOS ([4caf548a9f](https://github.com/facebook/react-native/commit/4caf548a9f2e485aef9cbaeeb0a666cf9b9d3e59) by [@EvanBacon](https://github.com/EvanBacon))
- Outline properties `outline-width`, `outline-color`, `outline-style` & `outline-offset` ([1288e38423](https://github.com/facebook/react-native/commit/1288e38423f93ed57737dd9b40ad55696494d6f4) by [@jorge-cab](https://github.com/jorge-cab))
- Declare supportedInterfaceOrientations only on iOS ([40c5e6b64a](https://github.com/facebook/react-native/commit/40c5e6b64a1d82b5b481717b9086340eca2aaef9) by [@okwasniewski](https://github.com/okwasniewski))
- New text content type cellular EID and cellular IMEI ([14e0d0dffb](https://github.com/facebook/react-native/commit/14e0d0dffb9ee8b1d41d60ccbcfd63d53bfe4d48) by [@pasc0al](https://github.com/pasc0al))
- User-configurable BUNDLE_NAME when building bundles ([f8287e25e1](https://github.com/facebook/react-native/commit/f8287e25e11d56beb66ace414ca5f8a6a32405a9) by [@fivecar](https://github.com/fivecar))
- Line break mode for TextInput components. **This includes JS APIs for the new mode.** ([ce2d34f194](https://github.com/facebook/react-native/commit/ce2d34f19451c91a90f0bd820064208912c86092) by [@shubhamguptadream11](https://github.com/shubhamguptadream11))
### Changed
- Fixed a typo in the README file. ([30e75a51f3](https://github.com/facebook/react-native/commit/30e75a51f3af7fbad83e4b002526b69bba021753) by [@Aryan2727-debug](https://github.com/Aryan2727-debug))
- Fix unnececary rerenders of VirtualizedListCells with strictMode={true} ([aafe696453](https://github.com/facebook/react-native/commit/aafe696453186d0e87ae96d0bca4c6650234d222) by [@Tom910](https://github.com/Tom910))
- The `AnimatedNode` graph will not occur during the insertion effect phase, which means animations can now be reliably started during layout effects. ([316170ce8d](https://github.com/facebook/react-native/commit/316170ce8d0aac1df3261c792b9f768665d134c5) by [@yungsters](https://github.com/yungsters))
- AttributedString `appendFragment` and `prependFragment` take an rval instead of a const ref; append/prependAttributedString have been removed ([2c31fe99e1](https://github.com/facebook/react-native/commit/2c31fe99e1cc5bfdb393d4f5c70231a042ea67ef) by [@javache](https://github.com/javache))
- Improved AttributedText generation for raw text nodes. ([2f7957f2fd](https://github.com/facebook/react-native/commit/2f7957f2fd424fdaa980d99a4ff05eb3237d662e) by [@javache](https://github.com/javache))
- Callbacks passed to `animation.start(<callback>)` will be scheduled for execution in a microtask. Previously, there were certain scenarios in which the callback could be synchronously executed by `start`. ([090501d26d](https://github.com/facebook/react-native/commit/090501d26d83be5c5d2df885c60d05ec133d7a54) by [@yungsters](https://github.com/yungsters))
- Optimized the performance of updating `Animated` components. ([f0ffcd4f5d](https://github.com/facebook/react-native/commit/f0ffcd4f5dfeab794fbfa3257bb9a8fd793ff2bc) by [@yungsters](https://github.com/yungsters))
- Bump serve-static to 1.16.2 to fix CVE-2024-43800 ([50e38cc9f1](https://github.com/facebook/react-native/commit/50e38cc9f1e6713228a91ad50f426c4f65e65e1a) by [@cortinico](https://github.com/cortinico))
- Bump Folly to 2024.10.14.00 ([37375d8aba](https://github.com/facebook/react-native/commit/37375d8aba0869531567426466478b0de9a1aea3) by [@alanleedev](https://github.com/alanleedev))
- `useMergeRefs` and components using it (e.g. `Pressable`) now support ref cleanup functions. ([01e210fd28](https://github.com/facebook/react-native/commit/01e210fd28bc961e8c1b5fa454b3c947adda296c) by [@yungsters](https://github.com/yungsters))
- : Update Metro to 0.81.0 ([0902b0af75](https://github.com/facebook/react-native/commit/0902b0af75ba30ec9d4abeda71769d0685637afa) by [@robhogan](https://github.com/robhogan))
- Animations started with incompatible `useNativeDriver` and `AnimatedValue` configurations will now synchronously fail. Previously, spring and timing animations with non-zero delays would throw the error asynchronously. ([fd8cf19625](https://github.com/facebook/react-native/commit/fd8cf1962585aa49e8921475d89c1a5c2423c51c) by [@yungsters](https://github.com/yungsters))
- The `Animation` superclass no longer exposes `__onEnd` as a property. Subclasses must instead invoke `super.start(…)` in their `start()` implementation. ([b3fe06b268](https://github.com/facebook/react-native/commit/b3fe06b2685e526fe2bc420a902a3ccd4e1381df) by [@yungsters](https://github.com/yungsters))
- Simplified Flow types to use `HostInstance` (which changing nominal types). ([177697f539](https://github.com/facebook/react-native/commit/177697f539ec68a47cbb8f57260cebe701589ef1) by [@yungsters](https://github.com/yungsters))
- Upgrade React DevTools to 6.0.0. ([ed4f6d6891](https://github.com/facebook/react-native/commit/ed4f6d68910677ab050e3fef5aaa87e42d582fe0) by [@hoxyq](https://github.com/hoxyq))
- Fix: use public instance in Fiber renderer and expose it from getInspectorDataForViewAtPoint (#31068) ([633ad4933e](https://github.com/facebook/react-native/commit/633ad4933e9514d4168d6dcdb7e56c9a1859482a) by [@hoxyq](https://github.com/hoxyq))
- Get react-native package name from package.json in codegen script ([65575e8399](https://github.com/facebook/react-native/commit/65575e8399a08841a0ccbc5b28cafeee6d41714c) by [@okwasniewski](https://github.com/okwasniewski))
- Bring back shouldSkipStateUpdatesForLoopingAnimations feature flag ([6e0e712c2a](https://github.com/facebook/react-native/commit/6e0e712c2a680cf4b4de1ee5fb25cc5282b242c5) by [@dmytrorykun](https://github.com/dmytrorykun))
- AnimatedNode (and its subclasses) once again implement `toJSON()`. ([7bd4a54968](https://github.com/facebook/react-native/commit/7bd4a5496815943b031b68ca46792560d8d798d8) by [@yungsters](https://github.com/yungsters))
- Do not print Bridgeless Mode is enabled on console anymore ([f3a969f38d](https://github.com/facebook/react-native/commit/f3a969f38d7a2c74bf63ee05c4c819c0873059a9) by [@cortinico](https://github.com/cortinico))
- Bump main to 0.77-main ([120558c0cd](https://github.com/facebook/react-native/commit/120558c0cd6ae50156d2f7b958d3a29fd7ae4623) by [@cipolleschi](https://github.com/cipolleschi))
- Improved the performance of unmounting (and updating, when an enclosing Activity becomes hidden) Animated components ([46abda55b9](https://github.com/facebook/react-native/commit/46abda55b9749dc171e0fec551ba83c027818eb7) by Royi Hagigi)
- AnimatedNode (and its subclasses) no longer implement `toJSON()`. ([fe6228512e](https://github.com/facebook/react-native/commit/fe6228512e076820c9c11869cfe24b19d1abfb58) by [@yungsters](https://github.com/yungsters))
- Animated now resolves `style` to the original prop value if it contains no `AnimatedNode` instances. Previously, it would resolve to a flattened style object. ([ca234ba10e](https://github.com/facebook/react-native/commit/ca234ba10e8d06630da7ea00aac515b222137645) by [@yungsters](https://github.com/yungsters))
- Bump Metro dependencies to 0.81.0-alpha.0 ([40f98b5eee](https://github.com/facebook/react-native/commit/40f98b5eeef18bb9c20a9a2762d0b1d648c4ae91) by [@robhogan](https://github.com/robhogan))
#### Android specific
- Consolidated ReactViewGroup add/remove overrides ([0b22b955f1](https://github.com/facebook/react-native/commit/0b22b955f1494f0e7441a01dd19b3fdf5e20c3dc) by Thomas Nardone)
- Migrated systeminfo module code from Java to Kotlin ([8dc2c90ce5](https://github.com/facebook/react-native/commit/8dc2c90ce5f4b30f4729560aed2412e6d29f39fa) by [@oddlyspaced](https://github.com/oddlyspaced))
- Updating targetSdk to 35 (apps can still choose their own targetSdk regardless of RN version) ([48ea6867a9](https://github.com/facebook/react-native/commit/48ea6867a96bd16dc7aed9af5a8e9ce12a487c22) by [@alanleedev](https://github.com/alanleedev))
- Invocations to JS will now invoke their callbacks immediately if the instance is ready. Surface starts will not wait for the main thread to become available to dispatch the work in JS. ([9fa4845136](https://github.com/facebook/react-native/commit/9fa4845136969ec95ce5615b7ea78feaf0f7f109) by [@javache](https://github.com/javache))
- TurboModules marked as requiring eager init will now be constructed on the mqt_native thread to increase concurrency in React Native init. ([663b5f9d19](https://github.com/facebook/react-native/commit/663b5f9d19a905520bd0aef62cda890f76ef9b6e) by [@javache](https://github.com/javache))
- Reduce visibility of Continuation to internal, although this interface wasn't being exposed in any public API ([7b21b9e69c](https://github.com/facebook/react-native/commit/7b21b9e69c6176c7f66af0e479623ed1c2be0d62) by [@mdvacca](https://github.com/mdvacca))
- Update documentation for ReactHost.destroy() APIs ([443bc32dc4](https://github.com/facebook/react-native/commit/443bc32dc49a86534fce1d6ec0e31c97b8f33053) by [@mdvacca](https://github.com/mdvacca))
- Deprecate CatalystInstance in old architecture ([3e27ef1f6e](https://github.com/facebook/react-native/commit/3e27ef1f6e024bba8725a3bd64e2648ffd6af496) by [@mdvacca](https://github.com/mdvacca))
- Deprecate BridgelessCatalystInstance class ([72bd840dd3](https://github.com/facebook/react-native/commit/72bd840dd3dc7b6e3e88a74ac9ddb000a0cb3a60) by [@mdvacca](https://github.com/mdvacca))
- AGP to 8.7.2 ([e1a1cead43](https://github.com/facebook/react-native/commit/e1a1cead434a6856b2b018274876b9ba8eab706a) by [@cortinico](https://github.com/cortinico))
- Migrate ReactFeatureFlags to Kotlin ([4076dbfc86](https://github.com/facebook/react-native/commit/4076dbfc8651fcd193b886bf63b23728fad466d7) by [@mdvacca](https://github.com/mdvacca))
- Android NDK to 27.1 ([ba061a5d18](https://github.com/facebook/react-native/commit/ba061a5d18176fd455c3aa6350127506dac05211) by [@alanleedev](https://github.com/alanleedev))
- Migrate MainReactPackage to Kotlin (and make it final) ([7bbac8ee27](https://github.com/facebook/react-native/commit/7bbac8ee27daf092b580b57c2c7ee46d2723cd09) by [@cortinico](https://github.com/cortinico))
- Bump fbjni to 0.7.0 ([1c002c7b4e](https://github.com/facebook/react-native/commit/1c002c7b4ea4f22729920e54a9032402247ea350) by [@alanleedev](https://github.com/alanleedev))
- Fresco to 3.4.0 ([091025e18b](https://github.com/facebook/react-native/commit/091025e18b1dc5212031e3ed06bfb6c450e788e2) by [@cortinico](https://github.com/cortinico))
- Bump Kotlin 1.9.x to 2.0.x ([972c2c864c](https://github.com/facebook/react-native/commit/972c2c864c0b563163a36080a13908d1c0a3fb87) by [@cortinico](https://github.com/cortinico))
- Fix: change opacity logic from random to decrement by -0.20 ([af4907025e](https://github.com/facebook/react-native/commit/af4907025ef358c312d469118a52699dcf14507d) by [@sarthak-d11](https://github.com/sarthak-d11))
- Bump Android Gradle Plugin (AGP) to 8.7.0 ([cbc0978bb6](https://github.com/facebook/react-native/commit/cbc0978bb65dcfd2a18a54201c845785a626b1b3) by [@cortinico](https://github.com/cortinico))
- Improve FpsDebugFrameCallback.getTotalTimeMS() accuracy ([d54c25fdae](https://github.com/facebook/react-native/commit/d54c25fdaee4d2642cdbca812b61c6973d3f203d) by [@aamagda](https://github.com/aamagda))
- Update Fresco from 3.2.0 to 3.3.0 ([86d92e41d2](https://github.com/facebook/react-native/commit/86d92e41d2e129d12589848f75dfe2b2db09ed1a) by [@Abbondanzo](https://github.com/Abbondanzo))
- Disabling `outline` props on Android to stay consistent with iOS ([7ab0002799](https://github.com/facebook/react-native/commit/7ab0002799d52a876a8cdd32f25ebef6d431650e) by [@jorge-cab](https://github.com/jorge-cab))
- Gradle to 8.10.1 ([90f89a830a](https://github.com/facebook/react-native/commit/90f89a830acced9e6b8e80ef58aefd7e2c9666a8) by [@cortinico](https://github.com/cortinico))
#### iOS specific
- Make `prefetchImageWithMetadata`'s `queryRootName` nullable in the spec ([4dd60acb7d](https://github.com/facebook/react-native/commit/4dd60acb7ddc2811453e84e3567c1a114fa5e6f9) by [@TheRogue76](https://github.com/TheRogue76))
- Change how components automatically register ([8becc2514d](https://github.com/facebook/react-native/commit/8becc2514d484c99b51ea76f479f06a8fcdd8265) by [@cipolleschi](https://github.com/cipolleschi))
- Stop generating the RCTThirdPartyLibraryComponentProvider ([60b9d3d89e](https://github.com/facebook/react-native/commit/60b9d3d89eba90a945070646c6220b3c03b3aeba) by [@cipolleschi](https://github.com/cipolleschi))
- `RCTSurfaceHostingProxyRootView` no longer has different behavior (whether it calls `start` on the provided *surface*) depending on which initializer is used. Call `start` yourself on the *surface* instead. ([13b93cfdda](https://github.com/facebook/react-native/commit/13b93cfddaa559697968ac1c19e55f7aaa053070) by Nolan O'Brien)
- Use `newArchEnabled` flag in RCTAppDelegate and RCTRootViewFactory ([7e1674fc59](https://github.com/facebook/react-native/commit/7e1674fc59abeeb70d946ee082a829fae4c671b7) by [@okwasniewski](https://github.com/okwasniewski))
- Do not move to the main queue synchronously when starting a new surface ([ab2c47be28](https://github.com/facebook/react-native/commit/ab2c47be285fde99a77d189fd04220ef8ad0933a) by [@cipolleschi](https://github.com/cipolleschi))
- Rename `RCTUIGraphicsImageRenderer` to `RCTMakeUIGraphicsImageRenderer` ([6a09fc09af](https://github.com/facebook/react-native/commit/6a09fc09af8eedbf409ab870d5714e44892b2a16) by [@Saadnajmi](https://github.com/Saadnajmi))
- Refactor RCTDevLoadingView to use constraints ([fbda60e657](https://github.com/facebook/react-native/commit/fbda60e65783d9a3f257cd427cbffc1c9b2cc01b) by [@okwasniewski](https://github.com/okwasniewski))
### Deprecated
#### Android specific
- Deprecated shadows for ReadableNative[Map|Array].[Readable|Writable] ([d424bb9d7c](https://github.com/facebook/react-native/commit/d424bb9d7cf101dc5609e8f787ba8af2a33d0262) by [@javache](https://github.com/javache))
- ReactContext.getFabricUIManager() method ([fb737ca7d3](https://github.com/facebook/react-native/commit/fb737ca7d34b636a3aa337a0935bf9a5a10c641d) by [@mdvacca](https://github.com/mdvacca))
#### iOS specific
- Deprecating RCTBridgeModule batchDidComplete and adding configuration to disable it ([731bd95c43](https://github.com/facebook/react-native/commit/731bd95c430c752126aaaa34e4911ba2b87b382f) by [@philIip](https://github.com/philIip))
### Removed
- Remove `BackHandler.removeEventListener` ([44d619414c](https://github.com/facebook/react-native/commit/44d619414c1de3dbf17a421afa8dbcec7cdab025) by [@retyui](https://github.com/retyui))
- Removed type for useConcurrentRoot from AppRegistry, as it was already ignored ([2ec547ad28](https://github.com/facebook/react-native/commit/2ec547ad28ca914c17e276abb91174dfa0dc87b2) by [@javache](https://github.com/javache))
- Remove "run on iOS" and "run on Android" from the dev server key commands ([19b971ff94](https://github.com/facebook/react-native/commit/19b971ff94a0fe353f82363e788c13f86815663b) by [@huntie](https://github.com/huntie))
- Removed `refs` property from `NativeMethods` TypeScript definition. ([223e98cc4b](https://github.com/facebook/react-native/commit/223e98cc4b656b94b48c88940114bfdc025f8ddf) by [@yungsters](https://github.com/yungsters))
#### Android specific
- Removed hasConstants constructor from ReactModuleInfo ([aec7a66ae8](https://github.com/facebook/react-native/commit/aec7a66ae84bd7689d902686711db8eabc21c1f1) by [@javache](https://github.com/javache))
- Removed TurboReactPackage, which was replaced by BaseReactPackage ([bf5c98cf5e](https://github.com/facebook/react-native/commit/bf5c98cf5e1ce5c041d3d9321a0ba2fd3c755b46) by [@javache](https://github.com/javache))
- DevToolsReactPerfLogger stats gathering now uses an internal API ([f503fe3f10](https://github.com/facebook/react-native/commit/f503fe3f100d96a31fc56451d7846d80ce5c342f) by [@javache](https://github.com/javache))
- BindingImpl is no longer part of the public interface ([18faf68b48](https://github.com/facebook/react-native/commit/18faf68b4825118253cf247572084c4da8f6366e) by [@javache](https://github.com/javache))
- FabricComponents is removed from public API ([300db67b27](https://github.com/facebook/react-native/commit/300db67b270a5d6fc85d27188d0d1089675f89c0) by [@javache](https://github.com/javache))
#### iOS specific
- Remove available for RCTKeyWindow check ([e98c221e5e](https://github.com/facebook/react-native/commit/e98c221e5e54e79c25acd06f14e7d01221823305) by [@okwasniewski](https://github.com/okwasniewski))
### Fixed
- Hermes: revert Intl removal ([4cffff35e0](https://github.com/facebook/react-native/commit/4cffff35e030f256c32bf69c5971dfee4e60723f) by [@robhogan](https://github.com/robhogan))
- Fix the nodes' owners not being updated when `display: contents` is used ([aa53bde21b](https://github.com/facebook/react-native/commit/aa53bde21b8952533cf17ffee234b273766f2133) by [@j-piasecki](https://github.com/j-piasecki))
- dev-middleware: Rewrite URLs in the inspector proxy to cover all configurations, not just Android emulators. ([74995bc90a](https://github.com/facebook/react-native/commit/74995bc90aa039b880e4875ad356d3bce324d902) by [@robhogan](https://github.com/robhogan))
- Fix C++ bridging template compatibility with MSVC ([e6848ba5ba](https://github.com/facebook/react-native/commit/e6848ba5ba997d102cbaf6181c7c8c73e25a0827) by [@acoates-ms](https://github.com/acoates-ms))
- Accessing KeyboardAvoidingEvent event in onLayout handler ([68db74205a](https://github.com/facebook/react-native/commit/68db74205afdd190304eb73ef71710781fa580b9) by [@mhoran](https://github.com/mhoran))
- dev-middleware: Fix URL rewriting where device and debugger reach the server on different ports/protocols. ([5da7ebf99a](https://github.com/facebook/react-native/commit/5da7ebf99ae317c104d8e4bfbf36d3d89f66b5c9) by [@robhogan](https://github.com/robhogan))
- dev-middleware: Regex-escape IP addresses in urlRegex replacements ([aae3e03e57](https://github.com/facebook/react-native/commit/aae3e03e57096c3dc51589a3de240d49a8b9fadf) by [@robhogan](https://github.com/robhogan))
- Fixed jest error from Appearance.js ([ce838a4bcf](https://github.com/facebook/react-native/commit/ce838a4bcfb1c08728b637a9addd24cc6e3477e0) by [@Kudo](https://github.com/Kudo))
- When using Babel with plain JavaScript files, support for additional user syntax plugins should be fixed (now uses Babel's parser instead of hermes-parser). There is no change for JS files annotated with `flow`, where extended JS syntax remains unsupported. ([3de9892353](https://github.com/facebook/react-native/commit/3de989235365504468d2b6c0bb194e944bf1ce8e) by [@huntie](https://github.com/huntie))
- Fix `Appearance.setColorScheme(null)` not resetting color scheme value ([7d63235086](https://github.com/facebook/react-native/commit/7d63235086352d8c424d634c7039551f0a5025dc) by [@sangonz193](https://github.com/sangonz193))
- Fix text not taking full width ([550b0c0ed1](https://github.com/facebook/react-native/commit/550b0c0ed16a64ce58102f15d4657abe92aac71c) by [@s77rt](https://github.com/s77rt))
- Linear gradient start and end point algorithm. ([221d1eceda](https://github.com/facebook/react-native/commit/221d1eceda0e5ab870e96dcdd26e22ab17a3870c) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
- Codegen: Support nested objects in arrays ([13780126d3](https://github.com/facebook/react-native/commit/13780126d3cb17ad00c2954f9830a3623812dc3e) by [@tvanlaerhoven](https://github.com/tvanlaerhoven))
- RN DevTools: Don't assume 10.0.2.2 is an alias for localhost unless it's used to establish a connection to the server ([69400be4fc](https://github.com/facebook/react-native/commit/69400be4fc0abd38072f6586f3e7d5b6c33e54be) by [@robhogan](https://github.com/robhogan))
- Do not discard props in the patch when they are not null while using `useNativeProps` ([4c3112c8d8](https://github.com/facebook/react-native/commit/4c3112c8d8685d6c34be9acf07b18871b3cee5b2) by [@cipolleschi](https://github.com/cipolleschi))
- : dev-middleware: Remove URL.canParse, restore compat with Node < 18.17 ([99767d43b0](https://github.com/facebook/react-native/commit/99767d43b04e41c83e3bcbfebe267d6fdc284549) by [@robhogan](https://github.com/robhogan))
- RN DevTools: Fix fetching sources and source maps when the dev-server is remote and not tunnelled via the same port+protocol. ([d1b0e9a30b](https://github.com/facebook/react-native/commit/d1b0e9a30b3afc56b9355453cf7f6e690bdd8aff) by [@robhogan](https://github.com/robhogan))
- Fix npm react-native start when cli-server-api isn't installed ([e0be2efe4e](https://github.com/facebook/react-native/commit/e0be2efe4e80edf99f96a2ae6a25856f6df5e0ca) by [@blakef](https://github.com/blakef))
- AnsiHighlight style in RTL layout ([9a3958a619](https://github.com/facebook/react-native/commit/9a3958a619fddb75ed3c6eddebd94f11c0d00e9f) by [@hexboy](https://github.com/hexboy))
- Fixes typo in ReactHostImpl ([e3f03269c5](https://github.com/facebook/react-native/commit/e3f03269c5cea28977e44ddf5c5125968336b0e6) by [@rozele](https://github.com/rozele))
- TextTransform: capitalize better reflects the web behaviour ([dc2000c875](https://github.com/facebook/react-native/commit/dc2000c8750f42b2f01bdad75455750814d567c6) by [@javache](https://github.com/javache))
- Fix for nodes with `display: contents` not being cleaned in some cases ([a88ddcecc9](https://github.com/facebook/react-native/commit/a88ddcecc93a9fa2d231907439d02b11bac8a944) by [@j-piasecki](https://github.com/j-piasecki))
- Microtasks are now correctly executed after the code evaluation in Console panel of DevTools. ([3dfe22bd27](https://github.com/facebook/react-native/commit/3dfe22bd27429a43b4648c597b71f7965f31ca65) by [@hoxyq](https://github.com/hoxyq))
- Passed height and width as native props to support cases where source is an array. ([45b177f50d](https://github.com/facebook/react-native/commit/45b177f50de624eefcb66bb2d8bc1ffb00855863) by [@shubhamguptadream11](https://github.com/shubhamguptadream11))
- `PerformanceEntryReporter::reportMark` and `PerformanceEntryReporter::reportMeasaure` now return created performance entries. ([32f7b3b4e0](https://github.com/facebook/react-native/commit/32f7b3b4e0b8be1d1138f43c46b3c86d9a64c29a) by [@robik](https://github.com/robik))
- Make Codegen work with local modules ([7b6e8e7765](https://github.com/facebook/react-native/commit/7b6e8e776574e683821133f0c814969d74c4de61) by [@cipolleschi](https://github.com/cipolleschi))
- Fix KeyboardAvoidingView not aware of the keyboard closing it is unmounted ([08bd8ac47d](https://github.com/facebook/react-native/commit/08bd8ac47da60121225e7b281bbf566e2c5a291e) by [@QichenZhu](https://github.com/QichenZhu))
- Fix onEndReached not being called when getItemLayout is present and we scroll past render window ([3485e9ed87](https://github.com/facebook/react-native/commit/3485e9ed871886b3e7408f90d623da5c018da493) by YunPeng Chong)
- Fix cast and control paths errors on windows ([0794fa909b](https://github.com/facebook/react-native/commit/0794fa909b2e06fad5c40dce402c5f14a24bb946) by [@TatianaKapos](https://github.com/TatianaKapos))
- Plumbing to get boxSizing prop to Yoga round 2 ([3ca796edc3](https://github.com/facebook/react-native/commit/3ca796edc327c5287533dcc8f4394033d5398c2d) by [@joevilches](https://github.com/joevilches))
- Fix onEndReached not being called when getItemLayout is present and we scroll past render window ([62b7396bf4](https://github.com/facebook/react-native/commit/62b7396bf45c04bd47e74fe4c1e5b5e59918244d) by [@NickGerleman](https://github.com/NickGerleman))
- TurboModule::get is now a final method, override `create` to customize property lookup ([5b5e150eaf](https://github.com/facebook/react-native/commit/5b5e150eaff015540720225b9e61acb306e1d107) by [@javache](https://github.com/javache))
- Improved types for AnimatedProps ([390925ea39](https://github.com/facebook/react-native/commit/390925ea39eb469768f21cf7069b8f75ccdec09d) by [@javache](https://github.com/javache))
- Upgrade Codegen dependency `jscodeshift@17.0.0` to resolve outdated dependencies ([39c98fb8f8](https://github.com/facebook/react-native/commit/39c98fb8f8af98aa40dc89a1580d6c1901fa86cf) by [@byCedric](https://github.com/byCedric))
- Fixed issues with W3C PointerEvents testsx ([1dcaf823f5](https://github.com/facebook/react-native/commit/1dcaf823f5e7d9b114dd803ce3181aa0b8f827ad) by [@rozele](https://github.com/rozele))
- Fixed issue with W3C PointerEvents tests ([68a6b69b27](https://github.com/facebook/react-native/commit/68a6b69b27275998b4083797942f3e26a92d3adb) by [@rozele](https://github.com/rozele))
- Fix setImmediate/clearTimeout mismatch in NativeAnimatedHelper that could clear an unrelated setTimeout. ([a5dd1be889](https://github.com/facebook/react-native/commit/a5dd1be889be21f8daefbc609702989ec7c156cf) by Benoit Girard)
- Improved error message when no view config is found. ([bca232ad90](https://github.com/facebook/react-native/commit/bca232ad90692da7a87be5e37ee2680380f94bef) by [@javache](https://github.com/javache))
- : Order of operations related to platformConfig propagation in NativeAnimated ([a64183b0c6](https://github.com/facebook/react-native/commit/a64183b0c6a56e9d482c7b8b0f80965493ed87af) by [@rozele](https://github.com/rozele))
- Rename overlayColor prop in Modal to backdropColor ([7aeff18970](https://github.com/facebook/react-native/commit/7aeff18970a2b47cbb3fffc1408e4bb21eec6fed) by [@alanleedev](https://github.com/alanleedev))
- Fix source mapping for codegenNativeCommands ([8fba154b66](https://github.com/facebook/react-native/commit/8fba154b6655b5d87609d7c9f136997141ea5e99) by [@vzaidman](https://github.com/vzaidman))
- Fixed accuracy of FlatList estimations to determine what elements are visible in the rendering window. ([40aaeb7181](https://github.com/facebook/react-native/commit/40aaeb71814a1987482d97fd3170af0add55bc6a) by [@rubennorte](https://github.com/rubennorte))
- Fix type conversion error in react native windows build. ([13db1cb88b](https://github.com/facebook/react-native/commit/13db1cb88bdd454cf19be358d6f0cd62f5a6d0cc) by [@marlenecota](https://github.com/marlenecota))
- Correctly pass down isLooping in parallel animation ([4014aa4528](https://github.com/facebook/react-native/commit/4014aa4528d43e905246850c83007a635938d7cb) by [@zeyap](https://github.com/zeyap))
#### Android specific
- Yoga: Fix YogaConfig getting garbage collected #1678 ([7dcb10b6e7](https://github.com/facebook/react-native/commit/7dcb10b6e7e226034a496eaed5351601ae0a1ae2) by [@michaeltroger](https://github.com/michaeltroger))
- Enable mix-blend-mode on ReactRootView so blending works with app background ([24b0ded3cf](https://github.com/facebook/react-native/commit/24b0ded3cf715bb0e849d9f7ca8cd2d4d42cbf90) by [@jorge-cab](https://github.com/jorge-cab))
- RN DevTools: Fix source loading when using an Android emulator connecting to a dev server on the host. ([ca9c56329f](https://github.com/facebook/react-native/commit/ca9c56329fe548b6631934afee0c9be63e1752a1) by [@robhogan](https://github.com/robhogan))
- Fixes some deadlocks when doing commits and state updates synchronously from the UI thread (e.g.: from reanimated). ([3986eefed1](https://github.com/facebook/react-native/commit/3986eefed1733f305db5410737a96b635f0159e7) by [@rubennorte](https://github.com/rubennorte))
- Ensure setSelection in onAttachedToWindow is within text range ([08759121cd](https://github.com/facebook/react-native/commit/08759121cda3785e4d7ee1f1c82011a3e3a955a9) by [@zeyap](https://github.com/zeyap))
- Fixed crash in legacy ReactFontManager ([3da23f7093](https://github.com/facebook/react-native/commit/3da23f7093730e10aeda6b58f4934a381e226dd2) by [@javache](https://github.com/javache))
- Dispatch onMomentumScrollEnd after programmatic scrolling ([c69e330324](https://github.com/facebook/react-native/commit/c69e330324724a1e363f4786b2b03ee7ff4b35c5) by [@Biki-das](https://github.com/Biki-das))
- RNGP - Do not attempt to substring to 1024 while logging ([e64513bf4e](https://github.com/facebook/react-native/commit/e64513bf4ecce60aff5c04e3bed91b203429d12f) by [@cortinico](https://github.com/cortinico))
- Missing isInvertColorsEnabled implementation for Android ([cc1d2853fb](https://github.com/facebook/react-native/commit/cc1d2853fb2b64adfb884cb30c8d22ce0260be15) by [@oddlyspaced](https://github.com/oddlyspaced))
- Addressed race condition in surface start. ([6ba7cb3102](https://github.com/facebook/react-native/commit/6ba7cb310273a0ecce6a168bf3aae45fb85bf955) by [@javache](https://github.com/javache))
- The definition of ts of resizeMethod attribute is none. ([758892a7d8](https://github.com/facebook/react-native/commit/758892a7d89cc1e316984f8f522738021410f530) by [@nianxiongdi](https://github.com/nianxiongdi))
- Reimplement Android lineHeight positioning/determination ([41265bac6b](https://github.com/facebook/react-native/commit/41265bac6b83ee0bb92d645ace81e314065bf5e0) by [@NickGerleman](https://github.com/NickGerleman))
- Fix legacy arch RTL horizontal ScrollView regression ([bfca7cfe7a](https://github.com/facebook/react-native/commit/bfca7cfe7a8e0da10fdb776100fbc706233c0d8d) by [@NickGerleman](https://github.com/NickGerleman))
- Fix RTL ScrollView position when content smaller than container ([0df59d4f03](https://github.com/facebook/react-native/commit/0df59d4f03f79c0fcb9ede2d21bf4d49c97c21ef) by [@NickGerleman](https://github.com/NickGerleman))
- Avoid null reference exception in bridgeless ReactDelegate ([0d664100bb](https://github.com/facebook/react-native/commit/0d664100bbf608550a5c42a4e9b02c6c5bd0f5b8) by [@rozele](https://github.com/rozele))
- Fix generating empty line at the end of multiline text view when `textAlign` is set to `justify` ([08e8f6adfd](https://github.com/facebook/react-native/commit/08e8f6adfdcdfec59002f34bb7acf35bb842b331) by [@coado](https://github.com/coado))
- Fix Frame Callback not being called after Host Resume ([e8f8ee3c0f](https://github.com/facebook/react-native/commit/e8f8ee3c0f28b8c5751ffaef495adea0b8daf1eb) by [@s77rt](https://github.com/s77rt))
- Fix crash in getViewState when using suspense fallbacks. ([bd133b5dd5](https://github.com/facebook/react-native/commit/bd133b5dd57b18140eae51c6d7aaab02874455c1) by [@javache](https://github.com/javache))
- Text without explicit font styles was potentially cut-off. ([95a5d1c628](https://github.com/facebook/react-native/commit/95a5d1c6287c7301265207d1962ba8b50d178b20) by [@javache](https://github.com/javache))
- Merge Android ViewNativeComponent ViewConfig into BaseViewConfig ([0ba00fc998](https://github.com/facebook/react-native/commit/0ba00fc99891a333d3625db15d9dd832ca7eac88) by [@NickGerleman](https://github.com/NickGerleman))
- Fixed styling on alert dialog titles to wrap two lines and retain bold appearance ([c54b23ff9e](https://github.com/facebook/react-native/commit/c54b23ff9ed7a6bfbb52c081c5afe4b3911d0dd2) by [@Abbondanzo](https://github.com/Abbondanzo))
- Prevent ArrayIndexOutOfBoundsException in permission check ([6aeca53b3e](https://github.com/facebook/react-native/commit/6aeca53b3ed4530e57a31d7a5593ae16b550b985) by [@antFrancon](https://github.com/antFrancon))
- Account for items dynamically scaling with the container when using `maintainVisibleContentPosition` in virtualized lists ([6c19996e10](https://github.com/facebook/react-native/commit/6c19996e10eda97a3501f53a68da246d1f122d01) by [@fabriziocucci](https://github.com/fabriziocucci))
- Apps will no longer fatally crash when trying to draw large images ([483b928224](https://github.com/facebook/react-native/commit/483b92822496fa2e6339f75049a33be1e9567f52) by [@Abbondanzo](https://github.com/Abbondanzo))
- Add missing BaseViewManager props to BaseViewManagerDelegate ([6741fd94ad](https://github.com/facebook/react-native/commit/6741fd94ad26012938caa65a5129f0eca6f2246e) by [@NickGerleman](https://github.com/NickGerleman))
- Fix TextInput caret moving to the beginning when attached to window ([ca0abd1b9e](https://github.com/facebook/react-native/commit/ca0abd1b9ea164a566b39cb9090eaa75647aad5a) by [@QichenZhu](https://github.com/QichenZhu))
- Fix issue where `onDropViewInstance` cleanup was not being handled after `ReactRootView.unmountReactApplication` ([0449630612](https://github.com/facebook/react-native/commit/04496306123c46730b46accb2cd6239531e51fef) by [@rozele](https://github.com/rozele))
- Fix issues with Modals and lifecycle events in multi-surface apps ([1ffef5669c](https://github.com/facebook/react-native/commit/1ffef5669c21f4b2c5fec6bc58a85f95518cf10e) by [@rozele](https://github.com/rozele))
- Fix mising `ANTI_ALIAS_FLAG` when resetting Text Paint ([276e3a7df7](https://github.com/facebook/react-native/commit/276e3a7df7de1b04dec0891fa7ed72917568ee7b) by [@NickGerleman](https://github.com/NickGerleman))
- Fix some cases where we override setBackgroundColor on View-level instead of VM level ([0b0ac81fbe](https://github.com/facebook/react-native/commit/0b0ac81fbeebf819e744b6ecc19d549aaab8406d) by [@NickGerleman](https://github.com/NickGerleman))
- Avoid blocking the main thread when decompressing drawable resources ([420229d669](https://github.com/facebook/react-native/commit/420229d66946320f06485c5a3d3c167eae1a407e) by [@Abbondanzo](https://github.com/Abbondanzo))
- Reenable `setAndroidLayoutDirection` by default ([6cf0cfb5a4](https://github.com/facebook/react-native/commit/6cf0cfb5a47a437b8a17b50b4c70460be15ee1cd) by [@NickGerleman](https://github.com/NickGerleman))
- Properly fix measurement of trailing newlines ([060c594457](https://github.com/facebook/react-native/commit/060c59445740f9b92188d2193623b36c3d859ba7) by [@NickGerleman](https://github.com/NickGerleman))
- Fix crash for Modal not attached to window manager ([eaa780de1c](https://github.com/facebook/react-native/commit/eaa780de1c799bf35fded2914d27b1953b093340) by [@cipolleschi](https://github.com/cipolleschi))
- Fix NPE on ReactTextInputManager.setTextDecorationLine ([41c6ad5597](https://github.com/facebook/react-native/commit/41c6ad55978184cad1a32ec63c2d1f07e8282d5e) by [@cortinico](https://github.com/cortinico))
- BoxShadow now supports platformColor. ([4ede9205a0](https://github.com/facebook/react-native/commit/4ede9205a0559fcaf7ac58a3d70bc902eb23fcb6) by [@javache](https://github.com/javache))
- MixBlendMode now properly does state updates ([fae572d815](https://github.com/facebook/react-native/commit/fae572d815c7fb9684fc6c3b7f001de35ea8fb69) by [@jorge-cab](https://github.com/jorge-cab))
- Fix interactions between removeClippedSubviews and RTL ([513e9669e7](https://github.com/facebook/react-native/commit/513e9669e78a4bfd9b0380335c61f581343c4009) by [@NickGerleman](https://github.com/NickGerleman))
- LayoutAnimations work on full new architecture ([43af902693](https://github.com/facebook/react-native/commit/43af902693f0befde802a7f684e26b19ec7126c8) by [@javache](https://github.com/javache))
- Fix: ReactDelegate/ReactFragment crashing on New Architecture apps ([12dda31bc1](https://github.com/facebook/react-native/commit/12dda31bc12f4a04ec9df70d30328b1001bb2cec) by [@cortinico](https://github.com/cortinico))
- ReactFragment should properly instantiate ReactDelegate on Bridgeless ([7176d11ce4](https://github.com/facebook/react-native/commit/7176d11ce468ca37e9cbe8afcc1f6344c250dd0c) by [@cortinico](https://github.com/cortinico))
- Fixed text being measured incorrectly when ending with an empty line on the new architecture ([bd323929dc](https://github.com/facebook/react-native/commit/bd323929dc5be5666ee36043babec7d981a095dc) by [@j-piasecki](https://github.com/j-piasecki))
- Linear gradient with platform colors ([6866968a79](https://github.com/facebook/react-native/commit/6866968a79d44518884965959760983acdadc17c) by [@intergalacticspacehighway](https://github.com/intergalacticspacehighway))
- ARG_DISABLE_HOST_LIFECYCLE_EVENTS in ReactFragment to allow unmounting a surface without destroying ReactHost. ([40c875deca](https://github.com/facebook/react-native/commit/40c875decabaa56d6dd45ce03b22e8b3931781ac) by [@vincenzovitale](https://github.com/vincenzovitale))
- Fixed incorrect scroll event/position for scroll views when doing a smooth scroll animation. ([b4c41ec768](https://github.com/facebook/react-native/commit/b4c41ec7685da6e8ef35c41c30aa402639bc42c1) by [@rubennorte](https://github.com/rubennorte))
- Use appropriate Nullable attribute for ReactRootView field in ReactDelegate ([cbddcfc691](https://github.com/facebook/react-native/commit/cbddcfc6911101608df36f2a8d047768296c63b2) by [@rozele](https://github.com/rozele))
- Hover events were dispatched incorrectly when multiple ReactRoots were layered. ([533ef2ca37](https://github.com/facebook/react-native/commit/533ef2ca37d3b19fc909315f183e3f30dbf4b93d) by [@javache](https://github.com/javache))
- Improve text line height calculation ([65d8f66b50](https://github.com/facebook/react-native/commit/65d8f66b50471d2fb4ddd5e63e17fcc808623110) by [@mellyeliu](https://github.com/mellyeliu))
#### iOS specific
- Fix possible NSRangeException when updating typing attributes in response to new text content ([6e06a810f0](https://github.com/facebook/react-native/commit/6e06a810f0ab1002f1d10351bc878babde36b1f1) by [@NickGerleman](https://github.com/NickGerleman))
- Ensure artifacts directory exists when building Hermes from local source ([c3091ccfed](https://github.com/facebook/react-native/commit/c3091ccfed4440d7f0b906a7eb954718656b71b2) by [@kraenhansen](https://github.com/kraenhansen))
- "Reconnect DevTools" button not working sometimes ([8507204b53](https://github.com/facebook/react-native/commit/8507204b533cf87d1e4345a9c062cd10cf0022c1) by [@EdmondChuiHW](https://github.com/EdmondChuiHW))
- Fixed use of view commands from layout effects ([6f1c2a512e](https://github.com/facebook/react-native/commit/6f1c2a512e44d25edefea53e864f688018745c07) by [@sammy-SC](https://github.com/sammy-SC))
- Fix `r` & `d` not working from Metro sometimes ([9a60038a40](https://github.com/facebook/react-native/commit/9a60038a40e16925ea1adeb3e3c937c22a615485) by [@EdmondChuiHW](https://github.com/EdmondChuiHW))
- Resolve deprecated function prototype warning in RCTAppearance.h ([594c9d9a46](https://github.com/facebook/react-native/commit/594c9d9a46623016abb6bbd0d8f2982bf68bdc34) by [@eli-front](https://github.com/eli-front))
- Fixes rn-tester bundled images examples ([8cbc7c3357](https://github.com/facebook/react-native/commit/8cbc7c3357ac4043e6c423261c090a1bf656f68e) by [@zhongwuzw](https://github.com/zhongwuzw))
- Fixed `onMomentumScrollBegin` event not firing on command-driven scroll events ([5b609cca09](https://github.com/facebook/react-native/commit/5b609cca099b3b0d4fc66d4cf50f69d3c5b7fc8e) by [@Abbondanzo](https://github.com/Abbondanzo))
- Typo in spm.rb ([5e18f7f788](https://github.com/facebook/react-native/commit/5e18f7f788ccbea60e96b8e7deab29d423ccf1a6) by [@okwasniewski](https://github.com/okwasniewski))
- Add png extension only if file exist when load local image ([44f2a08371](https://github.com/facebook/react-native/commit/44f2a083716205b7560bef2f09d25830e29cd0c5) by [@zhongwuzw](https://github.com/zhongwuzw))
- FIxes CornerRadiiAreEqualAndSymmetrical error when check topLeftHorizontal == topLeftVertical ([af384a914a](https://github.com/facebook/react-native/commit/af384a914a4e9ef6a5d25b00bc14b0483e5af879) by [@zhongwuzw](https://github.com/zhongwuzw))
- Fix numerous class interfaces having incorrect designated initializer patterns ([b98846c2e3](https://github.com/facebook/react-native/commit/b98846c2e37c3ec895536ab942978d7701f51a5e) by Nolan O'Brien)
- AutomaticallyAdjustKeyboardInsets not shifting scrollview content ([2d9933e616](https://github.com/facebook/react-native/commit/2d9933e616c3efe57ed0ca141277638182a69d9c) by [@zhongwuzw](https://github.com/zhongwuzw))
- Fix launching App Clips with nullish URLs. ([043e2fe14a](https://github.com/facebook/react-native/commit/043e2fe14a6f13885a552211f17d61292001fa76) by [@EvanBacon](https://github.com/EvanBacon))
- Fixes scrollIndicatorInsets not work in old arch ([c1178ac208](https://github.com/facebook/react-native/commit/c1178ac2085e073afb07453eefc9095a1f5d530f) by [@zhongwuzw](https://github.com/zhongwuzw))
- Silenced 'set but unused variable' warning. ([f7b28e86aa](https://github.com/facebook/react-native/commit/f7b28e86aaded58f76978179d8d83f11e913b026) by [@nlutsenko](https://github.com/nlutsenko))
- Fixed crash on promise rejection handler in iOS 18. ([26d8d490e4](https://github.com/facebook/react-native/commit/26d8d490e47bd3fa46dc4a3b8e66e9ec35c15cf7) by David Rickard)
- Fixed scroll view ([ab8f3ff3e9](https://github.com/facebook/react-native/commit/ab8f3ff3e9e6445fa9961467e965792908d4c2bd) by [@coado](https://github.com/coado))
- Fixes missing char mode of linebreakmode ([77889afa1c](https://github.com/facebook/react-native/commit/77889afa1c9d0bdb966102860a5d1d1d91187ae8) by [@zhongwuzw](https://github.com/zhongwuzw))
- Removed usage of set but unused variable. ([d386dfc804](https://github.com/facebook/react-native/commit/d386dfc804842ed36565966da5aed15d9df7960e) by [@nlutsenko](https://github.com/nlutsenko))
- Cast the UIScene to UIWindowScene only if the scene respond to the selector ([fdee0ebbcb](https://github.com/facebook/react-native/commit/fdee0ebbcb88f40c23b92b07792fbb9d1041c546) by [@cipolleschi](https://github.com/cipolleschi))
- Move RCTNotifyEventDispatcherObserversOfEvent_DEPRECATED to const ([a1ec345e2a](https://github.com/facebook/react-native/commit/a1ec345e2a2cdb4ccf255293616ed5e90f519e40) by [@okwasniewski](https://github.com/okwasniewski))
- Fixes the exported synchronous method not being called on the method queue when it's the main queue ([8bfd7e1039](https://github.com/facebook/react-native/commit/8bfd7e10393e649554c7246df430019c4f78d5e0) by [@zhongwuzw](https://github.com/zhongwuzw))
- Make sure that the Increment and Decrement accessibility actions works on iOS ([303e0ed764](https://github.com/facebook/react-native/commit/303e0ed7641409acf2d852c077f6be426afd7a0c) by [@cipolleschi](https://github.com/cipolleschi))
- Subscribe to orientation changes in RCTUIManager only on iOS ([2f5adc3874](https://github.com/facebook/react-native/commit/2f5adc3874bcdfc8d7d2c3cd5293eefec63a91f8) by [@okwasniewski](https://github.com/okwasniewski))
- Fix ActionSheetIOS crash `attempt to insert nil object from objects` ([bebd6531b5](https://github.com/facebook/react-native/commit/bebd6531b5f4ef0300aa5a4b6f9d23e60b57a25e) by [@RodolfoGS](https://github.com/RodolfoGS))
- Allow pods mixte type settings on post-install ([1e59f2e3f8](https://github.com/facebook/react-native/commit/1e59f2e3f8f0ab3ee4173bddaa089bbecf61d1eb) by [@MasGaNo](https://github.com/MasGaNo))
- Fallback to old resolve mechanism when node require fails to resolve react native path ([3cbaddbc16](https://github.com/facebook/react-native/commit/3cbaddbc164b9dc326b2a7ddc0b35ce885bc7d9d) by [@okwasniewski](https://github.com/okwasniewski))
- Fixed warnings when validating SVC ([de39a204c3](https://github.com/facebook/react-native/commit/de39a204c3588a3c02dc2e72464174c75b3a6749) by [@cipolleschi](https://github.com/cipolleschi))
- Solved SVC warnings for RNTester ([fad4a0783b](https://github.com/facebook/react-native/commit/fad4a0783b0a0478c147d9bde2ef9ab082a08297) by [@cipolleschi](https://github.com/cipolleschi))
- Don't reference PrivacyInfo.xcprivacy twice for new projects ([cadd41b1a2](https://github.com/facebook/react-native/commit/cadd41b1a2e16b1c77a8d3022f4ccbdbd5ea295f) by [@okwasniewski](https://github.com/okwasniewski))
## v0.76.3
### Fixed
#### Android specific
- Look for sdkmanager.bat ([6460d2b3e7](https://github.com/facebook/react-native/commit/6460d2b3e74c3a6e4075e9f12304c16427c3b1b2) by [@blakef](https://github.com/blakef))
- CMake Windows path normalization ([9946838bedd](https://github.com/facebook/react-native/commit/9946838beddac549053a3ba3eb3b1b49c22a3fd9) by [@blakef](https://github.com/blakef))
- Fix build failure on windows in android ([08b83005481](https://github.com/facebook/react-native/commit/08b830054812f4011becbbacdf1525701225df39) by [@FouadMagdy01](https://github.com/FouadMagdy01))
## v0.76.2
### Added
+1 -1
View File
@@ -87,7 +87,7 @@ The full documentation for React Native can be found on our [website][docs].
The React Native documentation discusses components, APIs, and topics that are specific to React Native. For further documentation on the React API that is shared between React Native and React DOM, refer to the [React documentation][r-docs].
The source for the React Native documentation and website is hosted on a separate repo, [**@facebook/react-native-website**][repo-website].
The source for the React Native documentation and website is hosted on a separate repository, [**@facebook/react-native-website**][repo-website].
[docs]: https://reactnative.dev/docs/getting-started
[r-docs]: https://react.dev/learn
+1
View File
@@ -18,6 +18,7 @@ module.exports = {
'<rootDir>/packages/react-native',
'<rootDir>/jest/integration/runtime',
],
moduleFileExtensions: [...baseConfig.moduleFileExtensions, 'cpp', 'h'],
// This allows running Meta-internal tests with the `-test.fb.js` suffix.
testRegex: '/__tests__/.*-itest(\\.fb)?\\.js$',
testPathIgnorePatterns: baseConfig.testPathIgnorePatterns,
+12 -8
View File
@@ -17,6 +17,10 @@ const rnTesterConfig = getDefaultConfig(
path.resolve('../../../packages/rn-tester'),
);
const JS_DIR = process.env.JS_DIR
? path.resolve(process.cwd(), process.env.JS_DIR)
: null;
const config = {
projectRoot: path.resolve(__dirname, '../../..'),
reporter: {
@@ -24,10 +28,10 @@ const config = {
},
resolver: {
blockList: /\/RendererProxy\.fb\.js$/, // Disable dependency injection for the renderer
disableHierarchicalLookup: !!process.env.JS_DIR,
disableHierarchicalLookup: !!JS_DIR,
sourceExts: ['fb.js', ...rnTesterConfig.resolver.sourceExts],
nodeModulesPaths: process.env.JS_DIR
? [path.join(process.env.JS_DIR, 'public', 'node_modules')]
nodeModulesPaths: JS_DIR
? [path.join(JS_DIR, 'public', 'node_modules')]
: [],
hasteImplModulePath: path.resolve(__dirname, 'hasteImpl.js'),
},
@@ -36,12 +40,12 @@ const config = {
// using babel-register.
babelTransformerPath: path.resolve(__dirname, 'metro-babel-transformer.js'),
},
watchFolders: process.env.JS_DIR
watchFolders: JS_DIR
? [
path.join(process.env.JS_DIR, 'RKJSModules', 'vendor', 'react'),
path.join(process.env.JS_DIR, 'tools', 'metro'),
path.join(process.env.JS_DIR, 'node_modules'),
path.join(process.env.JS_DIR, 'public', 'node_modules'),
path.join(JS_DIR, 'RKJSModules', 'vendor', 'react'),
path.join(JS_DIR, 'tools', 'metro'),
path.join(JS_DIR, 'node_modules'),
path.join(JS_DIR, 'public', 'node_modules'),
]
: [],
};
+89 -8
View File
@@ -24,6 +24,9 @@ import path from 'path';
const BUILD_OUTPUT_PATH = path.resolve(__dirname, '..', 'build');
const ENABLE_OPTIMIZED_MODE: false = false;
const PRINT_FANTOM_OUTPUT: false = false;
function parseRNTesterCommandResult(
commandArgs: $ReadOnlyArray<string>,
result: ReturnType<typeof spawnSync>,
@@ -58,15 +61,17 @@ function parseRNTesterCommandResult(
}
function getBuckModeForPlatform() {
const mode = ENABLE_OPTIMIZED_MODE ? 'opt' : 'dev';
switch (os.platform()) {
case 'linux':
return '@//arvr/mode/linux/dev';
return `@//arvr/mode/linux/${mode}`;
case 'darwin':
return os.arch() === 'arm64'
? '@//arvr/mode/mac-arm/dev'
: '@//arvr/mode/mac/dev';
? `@//arvr/mode/mac-arm/${mode}`
: `@//arvr/mode/mac/${mode}`;
case 'win32':
return '@//arvr/mode/win/dev';
return `@//arvr/mode/win/${mode}`;
default:
throw new Error(`Unsupported platform: ${os.platform()}`);
}
@@ -76,6 +81,55 @@ function getShortHash(contents: string): string {
return crypto.createHash('md5').update(contents).digest('hex').slice(0, 8);
}
function generateBytecodeBundle({
sourcePath,
bytecodePath,
}: {
sourcePath: string,
bytecodePath: string,
}): void {
const hermesCompilerCommandArgs = [
'run',
getBuckModeForPlatform(),
'//xplat/hermes/tools/hermesc:hermesc',
'--',
'-emit-binary',
'-O',
'-max-diagnostic-width',
'80',
'-out',
bytecodePath,
sourcePath,
];
const hermesCompilerCommandResult = spawnSync(
'buck2',
hermesCompilerCommandArgs,
{
encoding: 'utf8',
env: {
...process.env,
PATH: `/usr/local/bin:${process.env.PATH ?? ''}`,
},
},
);
if (hermesCompilerCommandResult.status !== 0) {
throw new Error(
[
'Failed to run Hermes compiler. Full output:',
'buck2 ' + hermesCompilerCommandArgs.join(' '),
'stdout:',
hermesCompilerCommandResult.stdout,
'stderr:',
hermesCompilerCommandResult.stderr,
'error:',
hermesCompilerCommandResult.error,
].join('\n'),
);
}
}
module.exports = async function runTest(
globalConfig: {...},
config: {...},
@@ -85,6 +139,8 @@ module.exports = async function runTest(
): mixed {
const startTime = Date.now();
const isOptimizedMode = ENABLE_OPTIMIZED_MODE;
const metroConfig = await Metro.loadConfig({
config: path.resolve(__dirname, '..', 'config', 'metro.config.js'),
});
@@ -101,24 +157,34 @@ module.exports = async function runTest(
`${getShortHash(entrypointContents)}-${path.basename(testPath)}`,
);
const testBundlePath = entrypointPath + '.bundle';
const testJSBundlePath = testBundlePath + '.js';
const testBytecodeBundlePath = testJSBundlePath + '.hbc';
fs.mkdirSync(path.dirname(entrypointPath), {recursive: true});
fs.writeFileSync(entrypointPath, entrypointContents, 'utf8');
await Metro.runBuild(metroConfig, {
entry: entrypointPath,
out: testBundlePath,
out: testJSBundlePath,
platform: 'android',
minify: false,
dev: true,
minify: isOptimizedMode,
dev: !isOptimizedMode,
});
if (isOptimizedMode) {
generateBytecodeBundle({
sourcePath: testJSBundlePath,
bytecodePath: testBytecodeBundlePath,
});
}
const rnTesterCommandArgs = [
'run',
getBuckModeForPlatform(),
'//xplat/ReactNative/react-native-cxx/samples/tester:tester',
'--',
`--bundlePath=${testBundlePath}`,
'--bundlePath',
testBundlePath,
];
const rnTesterCommandResult = spawnSync('buck2', rnTesterCommandArgs, {
encoding: 'utf8',
@@ -143,6 +209,21 @@ module.exports = async function runTest(
);
}
if (PRINT_FANTOM_OUTPUT) {
console.log(
[
'RN tester binary. Full output:',
'buck2 ' + rnTesterCommandArgs.join(' '),
'stdout:',
rnTesterCommandResult.stdout,
'stderr:',
rnTesterCommandResult.stderr,
'error:',
rnTesterCommandResult.error,
].join('\n'),
);
}
const rnTesterParsedOutput = parseRNTesterCommandResult(
rnTesterCommandArgs,
rnTesterCommandResult,
+57 -21
View File
@@ -175,6 +175,38 @@ function createMockFunction<TArgs: $ReadOnlyArray<mixed>, TReturn>(
// flowlint unsafe-getters-setters:off
class ErrorWithCustomBlame extends Error {
// Initially 5 to ignore all the frames from Babel helpers to instantiate this
// custom error class.
#ignoredFrameCount: number = 5;
#cachedProcessedStack: ?string;
blameToPreviousFrame(): this {
this.#ignoredFrameCount++;
return this;
}
get stack(): string {
if (this.#cachedProcessedStack == null) {
const originalStack = super.stack;
if (originalStack == null) {
this.#cachedProcessedStack = originalStack;
} else {
const lines = originalStack.split('\n');
lines.splice(1, this.#ignoredFrameCount);
this.#cachedProcessedStack = lines.join('\n');
}
}
return this.#cachedProcessedStack;
}
set stack(value: string) {
// no-op
}
}
class Expect {
#received: mixed;
#isNot: boolean = false;
@@ -191,27 +223,27 @@ class Expect {
toEqual(expected: mixed): void {
const pass = deepEqual(this.#received, expected, {strict: true});
if (!this.#isExpectedResult(pass)) {
throw new Error(
throw new ErrorWithCustomBlame(
`Expected${this.#maybeNotLabel()} to equal ${String(expected)} but received ${String(this.#received)}.`,
);
).blameToPreviousFrame();
}
}
toBe(expected: mixed): void {
const pass = this.#received === expected;
if (!this.#isExpectedResult(pass)) {
throw new Error(
throw new ErrorWithCustomBlame(
`Expected${this.#maybeNotLabel()} ${String(expected)} but received ${String(this.#received)}.`,
);
).blameToPreviousFrame();
}
}
toBeInstanceOf(expected: Class<mixed>): void {
const pass = this.#received instanceof expected;
if (!this.#isExpectedResult(pass)) {
throw new Error(
throw new ErrorWithCustomBlame(
`expected ${String(this.#received)}${this.#maybeNotLabel()} to be an instance of ${String(expected)}`,
);
).blameToPreviousFrame();
}
}
@@ -219,26 +251,26 @@ class Expect {
const pass =
Math.abs(expected - Number(this.#received)) < Math.pow(10, -precision);
if (!this.#isExpectedResult(pass)) {
throw new Error(
throw new ErrorWithCustomBlame(
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to be close to ${expected}`,
);
).blameToPreviousFrame();
}
}
toBeNull(): void {
const pass = this.#received == null;
if (!this.#isExpectedResult(pass)) {
throw new Error(
throw new ErrorWithCustomBlame(
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to be null`,
);
).blameToPreviousFrame();
}
}
toThrow(expected?: string): void {
if (expected != null && typeof expected !== 'string') {
throw new Error(
throw new ErrorWithCustomBlame(
'toThrow() implementation only accepts strings as arguments.',
);
).blameToPreviousFrame();
}
let pass = false;
@@ -249,9 +281,9 @@ class Expect {
pass = expected != null ? error.message === expected : true;
}
if (!this.#isExpectedResult(pass)) {
throw new Error(
throw new ErrorWithCustomBlame(
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to throw`,
);
).blameToPreviousFrame();
}
}
@@ -259,9 +291,9 @@ class Expect {
const mock = this.#requireMock();
const pass = mock.calls.length > 0;
if (!this.#isExpectedResult(pass)) {
throw new Error(
throw new ErrorWithCustomBlame(
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to have been called, but it was${this.#isNot ? '' : "n't"}`,
);
).blameToPreviousFrame();
}
}
@@ -269,9 +301,9 @@ class Expect {
const mock = this.#requireMock();
const pass = mock.calls.length === times;
if (!this.#isExpectedResult(pass)) {
throw new Error(
throw new ErrorWithCustomBlame(
`Expected ${String(this.#received)}${this.#maybeNotLabel()} to have been called ${times} times, but it was called ${mock.calls.length} times`,
);
).blameToPreviousFrame();
}
}
@@ -286,9 +318,11 @@ class Expect {
#requireMock(): JestMockFn<$ReadOnlyArray<mixed>, mixed>['mock'] {
// $FlowExpectedError[incompatible-use]
if (!this.#received?.[MOCK_FN_TAG]) {
throw new Error(
throw new ErrorWithCustomBlame(
`Expected ${String(this.#received)} to be a mock function, but it wasn't`,
);
)
.blameToPreviousFrame()
.blameToPreviousFrame();
}
// $FlowExpectedError[incompatible-use]
@@ -346,7 +380,9 @@ function executeTests() {
result.status = status;
result.duration = Date.now() - start;
result.failureMessages =
status === 'failed' && error ? [error.message] : [];
status === 'failed' && error
? [error.stack ?? error.message ?? String(error)]
: [];
}
}
+6 -6
View File
@@ -55,7 +55,7 @@
"@typescript-eslint/parser": "^7.1.1",
"ansi-styles": "^4.2.1",
"babel-plugin-minify-dead-code-elimination": "^0.5.2",
"babel-plugin-syntax-hermes-parser": "0.24.0",
"babel-plugin-syntax-hermes-parser": "0.25.1",
"babel-plugin-transform-define": "^2.1.4",
"babel-plugin-transform-flow-enums": "^0.0.2",
"chalk": "^4.0.0",
@@ -76,11 +76,11 @@
"eslint-plugin-react-native": "^4.0.0",
"eslint-plugin-redundant-undefined": "^0.4.0",
"eslint-plugin-relay": "^1.8.3",
"flow-api-translator": "0.24.0",
"flow-bin": "^0.253.0",
"flow-api-translator": "0.25.1",
"flow-bin": "^0.255.0",
"glob": "^7.1.1",
"hermes-eslint": "0.24.0",
"hermes-transform": "0.24.0",
"hermes-eslint": "0.25.1",
"hermes-transform": "0.25.1",
"inquirer": "^7.1.0",
"jest": "^29.6.3",
"jest-junit": "^10.0.0",
@@ -92,7 +92,7 @@
"node-fetch": "^2.2.0",
"nullthrows": "^1.1.1",
"prettier": "2.8.8",
"prettier-plugin-hermes-parser": "0.24.0",
"prettier-plugin-hermes-parser": "0.25.1",
"react": "18.3.1",
"react-test-renderer": "18.3.1",
"rimraf": "^3.0.2",
@@ -30,7 +30,6 @@
"metro": "^0.81.0",
"metro-config": "^0.81.0",
"metro-core": "^0.81.0",
"node-fetch": "^2.2.0",
"readline": "^1.3.0",
"semver": "^7.1.3"
},
@@ -12,7 +12,6 @@
import type TerminalReporter from 'metro/src/lib/TerminalReporter';
import chalk from 'chalk';
import fetch from 'node-fetch';
type PageDescription = $ReadOnly<{
id: string,
@@ -10,7 +10,6 @@
*/
import net from 'net';
import fetch from 'node-fetch';
/**
* Determine whether we can run the dev server.
@@ -14,8 +14,6 @@ import type {RequestOptions} from 'undici';
import {Agent, request} from 'undici';
declare var globalThis: $FlowFixMe;
/**
* A version of `fetch` that is usable with the HTTPS server created in
* ServerUtils (which uses a self-signed certificate).
@@ -66,27 +64,26 @@ export async function fetchJson<T: JSONSerializable>(url: string): Promise<T> {
* Change the global fetch dispatcher to allow self-signed certificates.
* This runs with Jest's `beforeAll` and `afterAll`, and restores the original dispatcher.
*/
export function withFetchSelfSignedCertsForAllTests() {
const fetchOriginal = globalThis.fetch;
export function withFetchSelfSignedCertsForAllTests(
fetchSpy: JestMockFn<Parameters<typeof fetch>, ReturnType<typeof fetch>>,
fetchOriginal: typeof fetch,
) {
const selfSignedCertDispatcher = new Agent({
connect: {
rejectUnauthorized: false,
},
});
let fetchSpy;
beforeAll(() => {
// For some reason, setting the `selfSignedCertDispatcher` with `setGlobalDispatcher` doesn't work.
// Instead of using `setGlobalDispatcher`, we'll use a spy to intercept the fetch calls and add the dispatcher.
fetchSpy = jest
.spyOn(globalThis, 'fetch')
.mockImplementation((url, options) =>
fetchOriginal(url, {
...options,
dispatcher: options?.dispatcher ?? selfSignedCertDispatcher,
}),
);
fetchSpy.mockImplementation((url, options) =>
fetchOriginal(url, {
...options,
// $FlowFixMe[prop-missing]: dispatcher
dispatcher: options?.dispatcher ?? selfSignedCertDispatcher,
}),
);
});
afterAll(() => {
@@ -23,10 +23,11 @@ export class DebuggerAgent {
#ws: ?WebSocket;
#readyPromise: Promise<void>;
constructor(url: string, signal?: AbortSignal) {
constructor(url: string, signal?: AbortSignal, hostHeader?: ?string) {
const ws = new WebSocket(url, {
// The mock server uses a self-signed certificate.
rejectUnauthorized: false,
...(hostHeader != null ? {headers: {Host: hostHeader}} : {}),
});
this.#ws = ws;
ws.on('message', data => {
@@ -115,8 +116,9 @@ export class DebuggerMock extends DebuggerAgent {
export async function createDebuggerMock(
url: string,
signal: AbortSignal,
hostHeader?: ?string,
): Promise<DebuggerMock> {
const debuggerMock = new DebuggerMock(url, signal);
const debuggerMock = new DebuggerMock(url, signal, hostHeader);
await debuggerMock.ready();
return debuggerMock;
}
@@ -27,10 +27,17 @@ export class DeviceAgent {
#ws: ?WebSocket;
#readyPromise: Promise<void>;
constructor(url: string, signal?: AbortSignal) {
constructor(url: string, signal?: AbortSignal, host?: ?string) {
const ws = new WebSocket(url, {
// The mock server uses a self-signed certificate.
rejectUnauthorized: false,
...(host != null
? {
headers: {
Host: host,
},
}
: {}),
});
this.#ws = ws;
ws.on('message', data => {
@@ -160,8 +167,9 @@ export class DeviceMock extends DeviceAgent {
export async function createDeviceMock(
url: string,
signal: AbortSignal,
host?: ?string,
): Promise<DeviceMock> {
const device = new DeviceMock(url, signal);
const device = new DeviceMock(url, signal, host);
await device.ready();
return device;
}
@@ -126,7 +126,15 @@ export async function createAndConnectTarget(
}>,
signal: AbortSignal,
page: PageFromDevice,
deviceId: ?string = null,
{
debuggerHostHeader = null,
deviceId = null,
deviceHostHeader = null,
}: $ReadOnly<{
debuggerHostHeader?: ?string,
deviceId?: ?string,
deviceHostHeader?: ?string,
}> = {},
): Promise<{device: DeviceMock, debugger_: DebuggerMock}> {
let device;
let debugger_;
@@ -136,6 +144,7 @@ export async function createAndConnectTarget(
deviceId ?? 'device' + Date.now()
}&name=foo&app=bar`,
signal,
deviceHostHeader,
);
device.getPages.mockImplementation(() => [page]);
@@ -150,7 +159,11 @@ export async function createAndConnectTarget(
const [{webSocketDebuggerUrl}] = pageList;
expect(webSocketDebuggerUrl).toBeDefined();
debugger_ = await createDebuggerMock(webSocketDebuggerUrl, signal);
debugger_ = await createDebuggerMock(
webSocketDebuggerUrl,
signal,
debuggerHostHeader,
);
await until(() => expect(device.connect).toBeCalled());
} catch (e) {
device?.close();
@@ -33,12 +33,18 @@ jest.useRealTimers();
jest.setTimeout(10000);
const fetchOriginal = fetch;
const fetchSpy: JestMockFn<
Parameters<typeof fetch>,
ReturnType<typeof fetch>,
> = jest.spyOn(globalThis, 'fetch');
describe.each(['HTTP', 'HTTPS'])(
'inspector proxy CDP rewriting hacks over %s',
protocol => {
// Inspector proxy tests are using a self-signed certificate for HTTPS tests.
if (protocol === 'HTTPS') {
withFetchSelfSignedCertsForAllTests();
withFetchSelfSignedCertsForAllTests(fetchSpy, fetchOriginal);
}
const serverRef = withServerForEachTest({
@@ -46,6 +52,7 @@ describe.each(['HTTP', 'HTTPS'])(
projectRoot: __dirname,
secure: protocol === 'HTTPS',
});
const autoCleanup = withAbortSignalForEachTest();
afterEach(() => {
jest.clearAllMocks();
@@ -188,7 +195,52 @@ describe.each(['HTTP', 'HTTPS'])(
}
});
describe.each(['10.0.2.2', '10.0.3.2', '127.0.0.1'])(
test("does not rewrite urls in Debugger.scriptParsed that don't match the device connection host", async () => {
serverRef.app.use('/source-map', serveStaticJson({version: 3}));
const {device, debugger_} = await createAndConnectTarget(
serverRef,
autoCleanup.signal,
{
app: 'bar-app',
id: 'page1',
title: 'bar-title',
vm: 'bar-vm',
},
{
deviceHostHeader: '192.168.0.123:' + serverRef.port,
},
);
try {
let fetchCalledWithURL;
fetchSpy.mockImplementationOnce(async url => {
fetchCalledWithURL = url instanceof URL ? url : null;
throw new Error('Unreachable');
});
const sourceMapURL = `${protocol.toLowerCase()}://127.0.0.1:${
serverRef.port
}/source-map`;
const scriptParsedMessage = await sendFromTargetToDebugger(
device,
debugger_,
'page1',
{
method: 'Debugger.scriptParsed',
params: {
sourceMapURL,
},
},
);
expect(fetchCalledWithURL?.href).toEqual(sourceMapURL);
expect(scriptParsedMessage.params.sourceMapURL).toEqual(
`${protocol.toLowerCase()}://127.0.0.1:${serverRef.port}/source-map`,
);
} finally {
device.close();
debugger_.close();
}
});
describe.each(['10.0.2.2:8080', '[::1]', 'example.com:2000'])(
'%s aliasing to and from localhost',
sourceHost => {
test('in source map fetching during Debugger.scriptParsed', async () => {
@@ -202,6 +254,9 @@ describe.each(['HTTP', 'HTTPS'])(
title: 'bar-title',
vm: 'bar-vm',
},
{
deviceHostHeader: sourceHost,
},
);
try {
const scriptParsedMessage = await sendFromTargetToDebugger(
@@ -211,9 +266,7 @@ describe.each(['HTTP', 'HTTPS'])(
{
method: 'Debugger.scriptParsed',
params: {
sourceMapURL: `${protocol.toLowerCase()}://${sourceHost}:${
serverRef.port
}/source-map`,
sourceMapURL: `${protocol.toLowerCase()}://${sourceHost}/source-map`,
},
},
);
@@ -236,6 +289,10 @@ describe.each(['HTTP', 'HTTPS'])(
title: 'bar-title',
vm: 'bar-vm',
},
{
debuggerHostHeader: 'localhost:' + serverRef.port,
deviceHostHeader: sourceHost,
},
);
try {
const scriptParsedMessage = await sendFromTargetToDebugger(
@@ -245,9 +302,7 @@ describe.each(['HTTP', 'HTTPS'])(
{
method: 'Debugger.scriptParsed',
params: {
url: `${protocol.toLowerCase()}://${sourceHost}:${
serverRef.port
}/some/file.js`,
url: `${protocol.toLowerCase()}://${sourceHost}/some/file.js`,
},
},
);
@@ -273,9 +328,7 @@ describe.each(['HTTP', 'HTTPS'])(
},
);
expect(setBreakpointByUrlMessage.params.url).toEqual(
`${protocol.toLowerCase()}://${sourceHost}:${
serverRef.port
}/some/file.js`,
`${protocol.toLowerCase()}://${sourceHost}/some/file.js`,
);
const setBreakpointByUrlRegexMessage =
@@ -284,12 +337,23 @@ describe.each(['HTTP', 'HTTPS'])(
method: 'Debugger.setBreakpointByUrl',
params: {
lineNumber: 1,
urlRegex: 'localhost:1000|localhost:2000',
urlRegex: `localhost:${serverRef.port}|example.com:2000`,
},
});
expect(setBreakpointByUrlRegexMessage.params.urlRegex).toEqual(
`${sourceHost}:1000|${sourceHost}:2000`,
);
// urlRegex rewriting is restricted to specific Android IPs that
// are well-known to route to the host. In this case we only
// replace hostname - longstanding behaviour.
if (sourceHost === '10.0.2.2:8080') {
expect(setBreakpointByUrlRegexMessage.params.urlRegex).toEqual(
`10\\.0\\.2\\.2:${serverRef.port}|example.com:2000`,
);
} else {
// Otherwise expect no change.
expect(setBreakpointByUrlRegexMessage.params.urlRegex).toEqual(
`localhost:${serverRef.port}|example.com:2000`,
);
}
} finally {
device.close();
debugger_.close();
@@ -307,6 +371,9 @@ describe.each(['HTTP', 'HTTPS'])(
title: 'bar-title',
vm: 'bar-vm',
},
{
deviceHostHeader: sourceHost,
},
);
try {
const response = await debugger_.sendAndGetResponse({
@@ -344,6 +411,9 @@ describe.each(['HTTP', 'HTTPS'])(
title: 'bar-title',
vm: 'bar-vm',
},
{
deviceHostHeader: '127.0.0.1:' + serverRef.port,
},
);
try {
const scriptParsedMessage = await sendFromTargetToDebugger(
@@ -11,7 +11,7 @@
import type {CreateCustomMessageHandlerFn} from './inspector-proxy/CustomMessageHandler';
import type {BrowserLauncher} from './types/BrowserLauncher';
import type {EventReporter} from './types/EventReporter';
import type {EventReporter, ReportableEvent} from './types/EventReporter';
import type {Experiments, ExperimentsConfig} from './types/Experiments';
import type {Logger} from './types/Logger';
import type {NextHandleFunction} from 'connect';
@@ -81,11 +81,15 @@ export default function createDevMiddleware({
unstable_customInspectorMessageHandler,
}: Options): DevMiddlewareAPI {
const experiments = getExperiments(experimentConfig);
const eventReporter = createWrappedEventReporter(
unstable_eventReporter,
logger,
);
const inspectorProxy = new InspectorProxy(
projectRoot,
serverBaseUrl,
unstable_eventReporter,
eventReporter,
experiments,
unstable_customInspectorMessageHandler,
);
@@ -97,7 +101,7 @@ export default function createDevMiddleware({
serverBaseUrl,
inspectorProxy,
browserLauncher: unstable_browserLauncher,
eventReporter: unstable_eventReporter,
eventReporter,
experiments,
logger,
}),
@@ -129,3 +133,26 @@ function getExperiments(config: ExperimentsConfig): Experiments {
enableNetworkInspector: config.enableNetworkInspector ?? false,
};
}
/**
* Creates a wrapped EventReporter that locally intercepts events to
* log to the terminal.
*/
function createWrappedEventReporter(
reporter: ?EventReporter,
logger: ?Logger,
): EventReporter {
return {
logEvent(event: ReportableEvent) {
switch (event.type) {
case 'profiling_target_registered':
logger?.info(
`Profiling build target "${event.appId}" registered for debugging`,
);
break;
}
reporter?.logEvent(event);
},
};
}
@@ -37,22 +37,6 @@ const debug = require('debug')('Metro:InspectorProxy');
const PAGES_POLLING_INTERVAL = 1000;
// Replace hosts appearing in the `url` and `sourceMapURL` fields of
// `Debugger.scriptParsed`, and back again in messages from the debugger,
// to account for device/debugger/proxy running on different networks.
const REWRITE_HOSTS_TO_LOCALHOST: Array<string> = [
// A device may retrieve a bundle through 127.0.0.1 via a (SSH) tunnel, but
// the (remote) Metro server may be on a host without an IPv4 loopback, so
// 127.0.0.1 may not be addressible locally for (e.g., for source map
// fetching). Replacing with the more general 'localhost' should always be
// safe while also more compatible with IPv6-only setups.
'127.0.0.1',
// Android's stock emulator and other emulators such as genymotion use a
// standard localhost alias.
'10.0.2.2',
'10.0.3.2',
];
// Prefix for script URLs that are alphanumeric IDs. See comment in #processMessageFromDeviceLegacy method for
// more details.
const FILE_PREFIX = 'file://';
@@ -60,13 +44,11 @@ const FILE_PREFIX = 'file://';
type DebuggerConnection = {
// Debugger web socket connection
socket: WS,
// If we replaced address (like '10.0.2.2') to localhost we need to store original
// address because Chrome uses URL or urlRegex params (instead of scriptId) to set breakpoints.
originalSourceURLAddress?: string,
prependedFilePrefix: boolean,
pageId: string,
userAgent: string | null,
customHandler: ?CustomMessageHandler,
debuggerRelativeBaseUrl: URL,
};
const REACT_NATIVE_RELOADABLE_PAGE_ID = '-1';
@@ -79,7 +61,9 @@ export type DeviceOptions = $ReadOnly<{
projectRoot: string,
eventReporter: ?EventReporter,
createMessageMiddleware: ?CreateCustomMessageHandlerFn,
deviceRelativeBaseUrl: URL,
serverRelativeBaseUrl: URL,
isProfilingBuild: boolean,
}>;
/**
@@ -136,6 +120,10 @@ export default class Device {
#connectedPageIds: Set<string> = new Set();
// A base HTTP(S) URL to this server, reachable from the device. Derived from
// the http request that created the connection.
#deviceRelativeBaseUrl: URL;
// A base HTTP(S) URL to the server, relative to this server.
#serverRelativeBaseUrl: URL;
@@ -152,6 +140,8 @@ export default class Device {
eventReporter,
createMessageMiddleware,
serverRelativeBaseUrl,
deviceRelativeBaseUrl,
isProfilingBuild,
}: DeviceOptions) {
this.#id = id;
this.#name = name;
@@ -159,6 +149,7 @@ export default class Device {
this.#deviceSocket = socket;
this.#projectRoot = projectRoot;
this.#serverRelativeBaseUrl = serverRelativeBaseUrl;
this.#deviceRelativeBaseUrl = deviceRelativeBaseUrl;
this.#deviceEventReporter = eventReporter
? new DeviceEventReporter(eventReporter, {
deviceId: id,
@@ -168,6 +159,10 @@ export default class Device {
: null;
this.#createCustomMessageHandler = createMessageMiddleware;
if (isProfilingBuild) {
this.#deviceEventReporter?.logProfilingTargetRegistered();
}
// $FlowFixMe[incompatible-call]
this.#deviceSocket.on('message', (message: string) => {
this.#messageFromDeviceQueue = this.#messageFromDeviceQueue
@@ -257,6 +252,7 @@ export default class Device {
oldDebugger.socket.removeAllListeners();
this.#deviceSocket.close();
this.handleDebuggerConnection(oldDebugger.socket, oldDebugger.pageId, {
debuggerRelativeBaseUrl: oldDebugger.debuggerRelativeBaseUrl,
userAgent: oldDebugger.userAgent,
});
}
@@ -287,7 +283,11 @@ export default class Device {
handleDebuggerConnection(
socket: WS,
pageId: string,
metadata: $ReadOnly<{
{
debuggerRelativeBaseUrl,
userAgent,
}: $ReadOnly<{
debuggerRelativeBaseUrl: URL,
userAgent: string | null,
}>,
) {
@@ -298,7 +298,8 @@ export default class Device {
if (!page) {
debug(
`Got new debugger connection for page ${pageId} of ${this.#name}, but no such page exists`,
`Got new debugger connection via ${debuggerRelativeBaseUrl.href} for ` +
`page ${pageId} of ${this.#name}, but no such page exists`,
);
socket.close();
return;
@@ -312,20 +313,24 @@ export default class Device {
this.#deviceEventReporter?.logConnection('debugger', {
pageId,
frontendUserAgent: metadata.userAgent,
frontendUserAgent: userAgent,
});
const debuggerInfo = {
socket,
prependedFilePrefix: false,
pageId,
userAgent: metadata.userAgent,
userAgent: userAgent,
customHandler: null,
debuggerRelativeBaseUrl,
};
this.#debuggerConnection = debuggerInfo;
debug(`Got new debugger connection for page ${pageId} of ${this.#name}`);
debug(
`Got new debugger connection via ${debuggerRelativeBaseUrl.href} for ` +
`page ${pageId} of ${this.#name}`,
);
if (this.#debuggerConnection && this.#createCustomMessageHandler) {
this.#debuggerConnection.customHandler = this.#createCustomMessageHandler(
@@ -379,7 +384,7 @@ export default class Device {
const debuggerRequest = JSON.parse(message);
this.#deviceEventReporter?.logRequest(debuggerRequest, 'debugger', {
pageId: this.#debuggerConnection?.pageId ?? null,
frontendUserAgent: metadata.userAgent,
frontendUserAgent: userAgent,
prefersFuseboxFrontend: this.#isPageFuseboxFrontend(
this.#debuggerConnection?.pageId,
),
@@ -656,6 +661,54 @@ export default class Device {
}
}
/**
* Given a URL from the debugger frontend, returns the equivalent URL
* reachable from the device.
*/
#debuggerRelativeToDeviceRelativeUrl(
debuggerRelativeUrl: URL,
{debuggerRelativeBaseUrl}: DebuggerConnection,
): URL {
const deviceRelativeUrl = new URL(debuggerRelativeUrl.href);
if (debuggerRelativeUrl.origin === debuggerRelativeBaseUrl.origin) {
deviceRelativeUrl.hostname = this.#deviceRelativeBaseUrl.hostname;
deviceRelativeUrl.port = this.#deviceRelativeBaseUrl.port;
deviceRelativeUrl.protocol = this.#deviceRelativeBaseUrl.protocol;
}
return deviceRelativeUrl;
}
/**
* Given a URL from the device, returns the equivalent URL reachable from
* the debugger frontend.
*/
#deviceRelativeUrlToDebuggerRelativeUrl(
deviceRelativeUrl: URL,
{debuggerRelativeBaseUrl}: DebuggerConnection,
): URL {
const debuggerRelativeUrl = new URL(deviceRelativeUrl.href);
if (deviceRelativeUrl.origin === this.#deviceRelativeBaseUrl.origin) {
debuggerRelativeUrl.hostname = debuggerRelativeBaseUrl.hostname;
debuggerRelativeUrl.port = debuggerRelativeBaseUrl.port;
debuggerRelativeUrl.protocol = debuggerRelativeUrl.protocol;
}
return debuggerRelativeUrl;
}
/**
* Given a URL from the device, returns the equivalent URL reachable from
* this proxy.
*/
#deviceRelativeUrlToServerRelativeUrl(deviceRelativeUrl: URL): URL {
const debuggerRelativeUrl = new URL(deviceRelativeUrl.href);
if (deviceRelativeUrl.origin === this.#deviceRelativeBaseUrl.origin) {
debuggerRelativeUrl.hostname = this.#serverRelativeBaseUrl.hostname;
debuggerRelativeUrl.port = this.#serverRelativeBaseUrl.port;
debuggerRelativeUrl.protocol = this.#serverRelativeBaseUrl.protocol;
}
return debuggerRelativeUrl;
}
// Allows to make changes in incoming message from device.
async #processMessageFromDeviceLegacy(
payload: CDPServerMessage,
@@ -677,19 +730,13 @@ export default class Device {
if ('sourceMapURL' in params) {
const sourceMapURL = this.#tryParseHTTPURL(params.sourceMapURL);
if (sourceMapURL) {
const serverRelativeUrl = new URL(sourceMapURL.href);
for (const hostToRewrite of REWRITE_HOSTS_TO_LOCALHOST) {
if (params.sourceMapURL.includes(hostToRewrite)) {
payload.params.sourceMapURL = params.sourceMapURL.replace(
hostToRewrite,
'localhost',
);
debuggerInfo.originalSourceURLAddress = hostToRewrite;
serverRelativeUrl.host = this.#serverRelativeBaseUrl.host;
serverRelativeUrl.protocol = this.#serverRelativeBaseUrl.protocol;
}
}
// Rewrite device-relative URLs to de debugger-relative URLs for the
// frontend.
payload.params.sourceMapURL =
this.#deviceRelativeUrlToDebuggerRelativeUrl(
sourceMapURL,
debuggerInfo,
).href;
// Some debug clients do not support fetching HTTP URLs. If the
// message headed to the debug client identifies the source map with
@@ -697,7 +744,9 @@ export default class Device {
// Data URL (which is more widely supported) before passing the
// message to the debug client.
try {
const sourceMap = await this.#fetchText(serverRelativeUrl);
const sourceMap = await this.#fetchText(
this.#deviceRelativeUrlToServerRelativeUrl(sourceMapURL),
);
payload.params.sourceMapURL =
'data:application/json;charset=utf-8;base64,' +
Buffer.from(sourceMap).toString('base64');
@@ -709,24 +758,19 @@ export default class Device {
}
}
if ('url' in params) {
const originalParamsUrl = params.url;
let serverRelativeUrl = originalParamsUrl;
const parsedUrl = this.#tryParseHTTPURL(originalParamsUrl);
let serverRelativeUrl = params.url;
const parsedUrl = this.#tryParseHTTPURL(params.url);
if (parsedUrl) {
for (const hostToRewrite of REWRITE_HOSTS_TO_LOCALHOST) {
if (parsedUrl.hostname === hostToRewrite) {
// URL is device-relative and points to the host - rewrite it to
// use localhost.
parsedUrl.hostname = 'localhost';
payload.params.url = parsedUrl.href;
debuggerInfo.originalSourceURLAddress = hostToRewrite;
// Rewrite device-relative URLs pointing to the server so that they're
// reachable from the frontend.
payload.params.url = this.#deviceRelativeUrlToDebuggerRelativeUrl(
parsedUrl,
debuggerInfo,
).href;
// Determine the server-relative URL.
parsedUrl.host = this.#serverRelativeBaseUrl.host;
parsedUrl.protocol = this.#serverRelativeBaseUrl.protocol;
serverRelativeUrl = parsedUrl.href;
}
}
// Determine the server-relative URL.
serverRelativeUrl =
this.#deviceRelativeUrlToServerRelativeUrl(parsedUrl).href;
}
// Chrome doesn't download source maps if URL param is not a valid
@@ -839,36 +883,52 @@ export default class Device {
debuggerInfo: DebuggerConnection,
): CDPRequest<'Debugger.setBreakpointByUrl'> {
// If we replaced Android emulator's address to localhost we need to change it back.
if (debuggerInfo.originalSourceURLAddress != null) {
const processedReq = {...req, params: {...req.params}};
if (processedReq.params.url != null) {
processedReq.params.url = processedReq.params.url.replace(
'localhost',
debuggerInfo.originalSourceURLAddress,
);
const {debuggerRelativeBaseUrl, prependedFilePrefix} = debuggerInfo;
if (
processedReq.params.url &&
processedReq.params.url.startsWith(FILE_PREFIX) &&
debuggerInfo.prependedFilePrefix
) {
// Remove fake URL prefix if we modified URL in #processMessageFromDeviceLegacy.
// $FlowFixMe[incompatible-use]
processedReq.params.url = processedReq.params.url.slice(
FILE_PREFIX.length,
);
}
const processedReq = {...req, params: {...req.params}};
if (processedReq.params.url != null) {
const originalUrlParam = processedReq.params.url;
const httpUrl = this.#tryParseHTTPURL(originalUrlParam);
if (httpUrl) {
processedReq.params.url = this.#debuggerRelativeToDeviceRelativeUrl(
httpUrl,
debuggerInfo,
).href;
} else if (
originalUrlParam.startsWith(FILE_PREFIX) &&
prependedFilePrefix
) {
// Remove fake URL prefix if we modified URL in #processMessageFromDeviceLegacy.
processedReq.params.url = originalUrlParam.slice(FILE_PREFIX.length);
}
if (processedReq.params.urlRegex != null) {
processedReq.params.urlRegex = processedReq.params.urlRegex.replace(
/localhost/g,
// $FlowFixMe[incompatible-call]
debuggerInfo.originalSourceURLAddress,
);
}
return processedReq;
}
return req;
// Retain special case rewriting of localhost to device-relative IPs
// within regex patterns. We don't rewrite the protocol here because
// these patterns typically come from CDT reinterpreting the source URL
// `file://host/path` into the regex `host/path|file://host/path`. See:
//
// https://github.com/ChromeDevTools/devtools-frontend/blob/f913cc6d76f2e2639c05b11ba673fc880b5490dd/front_end/core/sdk/DebuggerModel.ts#L505
//
// This has always been fragile and probably unnecessary - we don't set
// `file://` source URLs. It can be removed when we drop support for
// legacy targets, if not sooner.
if (
// Android's stock emulator and other emulators such as genymotion use a
// standard localhost alias.
new Set(['10.0.2.2', '10.0.3.2']).has(
this.#deviceRelativeBaseUrl.hostname,
) &&
debuggerRelativeBaseUrl.hostname === 'localhost' &&
processedReq.params.urlRegex != null
) {
processedReq.params.urlRegex = processedReq.params.urlRegex.replaceAll(
'localhost',
// regex-escape IPv4
this.#deviceRelativeBaseUrl.hostname.replaceAll('.', '\\.'),
);
}
return processedReq;
}
#processDebuggerGetScriptSource(
@@ -145,6 +145,17 @@ class DeviceEventReporter {
});
}
logProfilingTargetRegistered() {
this.#eventReporter.logEvent({
type: 'profiling_target_registered',
status: 'success',
appId: this.#metadata.appId,
deviceName: this.#metadata.deviceName,
deviceId: this.#metadata.deviceId,
pageId: null,
});
}
logConnection(
connectedEntity: 'debugger',
metadata: $ReadOnly<{
@@ -225,8 +225,13 @@ export default class InspectorProxy implements InspectorProxyQueries {
const deviceId = query.device || fallbackDeviceId;
const deviceName = query.name || 'Unknown';
const appName = query.app || 'Unknown';
const isProfilingBuild = query.profiling === 'true';
const deviceRelativeBaseUrl =
getBaseUrlFromRequest(req) ?? this.#serverBaseUrl;
const oldDevice = this.#devices.get(deviceId);
let newDevice;
const deviceOptions: DeviceOptions = {
id: deviceId,
@@ -236,7 +241,9 @@ export default class InspectorProxy implements InspectorProxyQueries {
projectRoot: this.#projectRoot,
eventReporter: this.#eventReporter,
createMessageMiddleware: this.#customMessageHandler,
deviceRelativeBaseUrl,
serverRelativeBaseUrl: this.#serverBaseUrl,
isProfilingBuild,
};
if (oldDevice) {
@@ -249,7 +256,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
this.#devices.set(deviceId, newDevice);
debug(
`Got new connection: name=${deviceName}, app=${appName}, device=${deviceId}`,
`Got new connection: name=${deviceName}, app=${appName}, device=${deviceId}, via=${deviceRelativeBaseUrl.origin}`,
);
socket.on('close', () => {
@@ -285,6 +292,8 @@ export default class InspectorProxy implements InspectorProxyQueries {
const query = url.parse(req.url || '', true).query || {};
const deviceId = query.device;
const pageId = query.page;
const debuggerRelativeBaseUrl =
getBaseUrlFromRequest(req) ?? this.#serverBaseUrl;
if (deviceId == null || pageId == null) {
throw new Error('Incorrect URL - must provide device and page IDs');
@@ -298,6 +307,7 @@ export default class InspectorProxy implements InspectorProxyQueries {
this.#startHeartbeat(socket, DEBUGGER_HEARTBEAT_INTERVAL_MS);
device.handleDebuggerConnection(socket, pageId, {
debuggerRelativeBaseUrl,
userAgent: req.headers['user-agent'] ?? query.userAgent ?? null,
});
} catch (e) {
@@ -77,6 +77,11 @@ export type ReportableEvent =
| 'PROTOCOL_ERROR',
>,
}
| {
type: 'profiling_target_registered',
status: 'success',
...DebuggerSessionIDs,
}
| {
type: 'proxy_error',
status: 'error',
@@ -18,8 +18,8 @@
"bugs": "https://github.com/facebook/react-native/issues",
"main": "index.js",
"devDependencies": {
"babel-plugin-syntax-hermes-parser": "0.24.0",
"hermes-eslint": "0.24.0"
"babel-plugin-syntax-hermes-parser": "0.25.1",
"hermes-eslint": "0.25.1"
},
"engines": {
"node": ">=18"
+2 -2
View File
@@ -32,8 +32,8 @@
"source-map-support": "0.5.0"
},
"devDependencies": {
"babel-plugin-syntax-hermes-parser": "0.24.0",
"hermes-eslint": "0.24.0"
"babel-plugin-syntax-hermes-parser": "0.25.1",
"hermes-eslint": "0.25.1"
},
"engines": {
"node": ">=18"
@@ -39,7 +39,7 @@ abstract class BuildCodegenCLITask : Exec() {
}
override fun exec() {
val logfile = "${project.layout.buildDirectory}/build-cli.log"
val logfile = "${project.layout.buildDirectory.getAsFile().get()}/build-cli.log"
File(logfile).apply {
parentFile.mkdirs()
if (exists()) {
+1 -1
View File
@@ -10,7 +10,7 @@ buildscript {
buildToolsVersion = "35.0.0"
minSdkVersion = 24
compileSdkVersion = 35
targetSdkVersion = 34
targetSdkVersion = 35
ndkVersion = "27.1.12297006"
kotlinVersion = "2.0.21"
}
@@ -8,7 +8,7 @@
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <ReactCodegen/RCTAppDependencyProvider.h>
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
@implementation AppDelegate
@@ -56,7 +56,7 @@
"@babel/plugin-transform-unicode-regex": "^7.24.7",
"@babel/template": "^7.25.0",
"@react-native/babel-plugin-codegen": "0.77.0-main",
"babel-plugin-syntax-hermes-parser": "0.24.0",
"babel-plugin-syntax-hermes-parser": "0.25.1",
"babel-plugin-transform-flow-enums": "^0.0.2",
"react-refresh": "^0.14.0"
},
+1 -1
View File
@@ -25,7 +25,7 @@ function isTSXSource(fileName) {
const loose = true;
const defaultPlugins = [
[require('babel-plugin-syntax-hermes-parser')],
[require('babel-plugin-syntax-hermes-parser'), {parseLangTypes: 'flow'}],
[require('babel-plugin-transform-flow-enums')],
[require('@babel/plugin-transform-block-scoping')],
[require('@babel/plugin-transform-class-properties'), {loose}],
@@ -17,7 +17,7 @@
"dependencies": {
"@babel/core": "^7.25.2",
"@react-native/babel-preset": "0.77.0-main",
"hermes-parser": "0.24.0",
"hermes-parser": "0.25.1",
"nullthrows": "^1.1.1"
},
"peerDependencies": {
@@ -23,6 +23,7 @@ type OnChangeEvent = $ReadOnly<{|
source: {url: string, ...},
x: Int32,
y: Int32,
arrayOfObjects: $ReadOnlyArray<{value: $ReadOnly<{str: string}>}>,
...
},
|}>;
@@ -161,6 +161,20 @@ void EventNestedObjectPropsNativeComponentViewEventEmitter::onChange(OnChange $e
}
location.setProperty(runtime, \\"x\\", $event.location.x);
location.setProperty(runtime, \\"y\\", $event.location.y);
auto arrayOfObjects = jsi::Array(runtime, $event.location.arrayOfObjects.size());
size_t arrayOfObjectsIndex = 0;
for (auto arrayOfObjectsValue : $event.location.arrayOfObjects) {
auto arrayOfObjectsObject = jsi::Object(runtime);
{
auto value = jsi::Object(runtime);
value.setProperty(runtime, \\"str\\", arrayOfObjectsValue.value.str);
arrayOfObjectsObject.setProperty(runtime, \\"value\\", value);
}
arrayOfObjects.setValueAtIndex(runtime, arrayOfObjectsIndex++, arrayOfObjectsObject);
}
location.setProperty(runtime, \\"arrayOfObjects\\", arrayOfObjects);
$payload.setProperty(runtime, \\"location\\", location);
}
return $payload;
@@ -199,10 +199,19 @@ class EventNestedObjectPropsNativeComponentViewEventEmitter : public ViewEventEm
std::string url;
};
struct OnChangeLocationArrayOfObjectsValue {
std::string str;
};
struct OnChangeLocationArrayOfObjects {
OnChangeLocationArrayOfObjectsValue value;
};
struct OnChangeLocation {
OnChangeLocationSource source;
int x;
int y;
std::vector<OnChangeLocationArrayOfObjects> arrayOfObjects;
};
struct OnChange {
+2 -2
View File
@@ -31,7 +31,7 @@
"dependencies": {
"@babel/parser": "^7.25.3",
"glob": "^7.1.1",
"hermes-parser": "0.24.0",
"hermes-parser": "0.25.1",
"invariant": "^2.2.4",
"jscodeshift": "^17.0.0",
"nullthrows": "^1.1.1",
@@ -49,7 +49,7 @@
"@babel/plugin-transform-flow-strip-types": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"chalk": "^4.0.0",
"hermes-estree": "0.24.0",
"hermes-estree": "0.25.1",
"micromatch": "^4.0.4",
"prettier": "2.8.8",
"rimraf": "^3.0.2"
@@ -104,7 +104,7 @@ function generateSetter(
) {
const eventChain = usingEvent
? `$event.${[...propertyParts, propertyName].join('.')}`
: [propertyParts, propertyName].join('.');
: [...propertyParts, propertyName].join('.');
return `${variableName}.setProperty(runtime, "${propertyName}", ${valueMapper(
eventChain,
)});`;
@@ -157,7 +157,7 @@ function generateArraySetter(
): string {
const eventChain = usingEvent
? `$event.${[...propertyParts, propertyName].join('.')}`
: [propertyParts, propertyName].join('.');
: [...propertyParts, propertyName].join('.');
const indexVar = `${propertyName}Index`;
const innerLoopVar = `${propertyName}Value`;
return `
@@ -2673,7 +2673,7 @@ const UNION_MODULE: SchemaType = {
},
};
const STRING_LITERALS = {
const STRING_LITERALS: SchemaType = {
modules: {
NativeSampleTurboModule: {
type: 'NativeModule',
@@ -73,8 +73,6 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
const useNativePropsInFabric =
ReactNativeFeatureFlags.shouldUseSetNativePropsInFabric();
const useSetNativePropsInNativeAnimationsInFabric =
ReactNativeFeatureFlags.shouldUseSetNativePropsInNativeAnimationsInFabric();
const useAnimatedPropsLifecycle =
ReactNativeFeatureFlags.useInsertionEffectsForAnimations()
@@ -119,12 +117,7 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
if (isFabricNode) {
// Call `scheduleUpdate` to synchronise Fiber and Shadow tree.
// Must not be called in Paper.
if (useSetNativePropsInNativeAnimationsInFabric) {
// $FlowFixMe[incompatible-use]
instance.setNativeProps(node.__getAnimatedValue());
} else {
scheduleUpdate();
}
scheduleUpdate();
}
return;
}
@@ -201,12 +194,7 @@ export default function useAnimatedProps<TProps: {...}, TInstance>(
}
};
},
[
node,
useNativePropsInFabric,
useSetNativePropsInNativeAnimationsInFabric,
props,
],
[node, useNativePropsInFabric, props],
);
const callbackRef = useRefEffect<TInstance>(refEffect);
@@ -116,6 +116,8 @@ class KeyboardAvoidingView extends React.Component<Props, State> {
};
_onLayout = async (event: ViewLayoutEvent) => {
event.persist();
const oldFrame = this._frame;
this._frame = event.nativeEvent.layout;
if (!this._initialFrameHeight) {
@@ -567,9 +567,6 @@ export type ViewProps = $ReadOnly<{|
* optimization. Set this property to `false` to disable this optimization and
* ensure that this `View` exists in the native view hierarchy.
*
* @platform android
* In Fabric, this prop is used in ios as well.
*
* See https://reactnative.dev/docs/view#collapsable
*/
collapsable?: ?boolean,
@@ -121,6 +121,12 @@ function reportException(
const NativeExceptionsManager =
require('./NativeExceptionsManager').default;
if (NativeExceptionsManager) {
if (isFatal) {
if (global.RN$hasHandledFatalException?.()) {
return;
}
global.RN$notifyOfFatalException?.();
}
NativeExceptionsManager.reportException(data);
}
}
@@ -121,7 +121,7 @@ const Presets = {
'opacity',
): LayoutAnimationConfig),
linear: (create(500, 'linear', 'opacity'): LayoutAnimationConfig),
spring: {
spring: ({
duration: 700,
create: {
type: 'linear',
@@ -135,7 +135,7 @@ const Presets = {
type: 'linear',
property: 'opacity',
},
},
}: LayoutAnimationConfig),
};
/**
@@ -40,8 +40,8 @@ const HermesBadge = (): Node => {
const styles = StyleSheet.create({
badge: {
position: 'absolute',
top: 8,
right: 12,
bottom: 8,
},
badgeText: {
fontSize: 14,
@@ -28,8 +28,7 @@ describe('processBackgroundImage', () => {
expect(result).toEqual([
{
type: 'linearGradient',
start: {x: 0, y: 0.5},
end: {x: 1, y: 0.5},
direction: {type: 'angle', value: 90},
colorStops: [
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
@@ -44,8 +43,7 @@ describe('processBackgroundImage', () => {
expect(result).toEqual([
{
type: 'linearGradient',
start: {x: 0, y: 0},
end: {x: 1, y: 1},
direction: {type: 'keyword', value: 'to bottom right'},
colorStops: [
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
@@ -68,14 +66,13 @@ describe('processBackgroundImage', () => {
expect(result).toEqual([]);
});
it('should process a linear gradient with whitespaces in direction', () => {
it('should process a linear gradient with whitespaces in direction keyword', () => {
const input = 'linear-gradient(to bottom right, red, blue)';
const result = processBackgroundImage(input);
expect(result).toEqual([
{
type: 'linearGradient',
start: {x: 0, y: 0},
end: {x: 1, y: 1},
direction: {type: 'keyword', value: 'to bottom right'},
colorStops: [
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
@@ -91,8 +88,7 @@ describe('processBackgroundImage', () => {
expect(result).toEqual([
{
type: 'linearGradient',
start: {x: 0, y: 0},
end: {x: 1, y: 1},
direction: {type: 'keyword', value: 'to bottom right'},
colorStops: [
{color: processColor('red'), position: 0.3},
{color: processColor('blue'), position: 0.8},
@@ -105,10 +101,7 @@ describe('processBackgroundImage', () => {
const input = 'linear-gradient(45deg, red, blue)';
const result = processBackgroundImage(input);
expect(result[0].type).toBe('linearGradient');
expect(result[0].start.x).toBeCloseTo(0.146447, 5);
expect(result[0].start.y).toBeCloseTo(0.853553, 5);
expect(result[0].end.x).toBeCloseTo(0.853553, 5);
expect(result[0].end.y).toBeCloseTo(0.146447, 5);
expect(result[0].direction).toEqual({type: 'angle', value: 45});
expect(result[0].colorStops).toEqual([
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
@@ -119,10 +112,41 @@ describe('processBackgroundImage', () => {
const input = 'linear-gradient(45Deg, red, blue)';
const result = processBackgroundImage(input);
expect(result[0].type).toBe('linearGradient');
expect(result[0].start.x).toBeCloseTo(0.146447, 5);
expect(result[0].start.y).toBeCloseTo(0.853553, 5);
expect(result[0].end.x).toBeCloseTo(0.853553, 5);
expect(result[0].end.y).toBeCloseTo(0.146447, 5);
expect(result[0].direction).toEqual({type: 'angle', value: 45});
expect(result[0].colorStops).toEqual([
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
]);
});
it('should process a linear gradient object style with case-insensitive direction keyword', () => {
const input = [
{
type: 'linearGradient',
direction: 'To Bottom',
colorStops: [{color: 'red'}, {color: 'blue'}],
},
];
const result = processBackgroundImage(input);
expect(result[0].type).toBe('linearGradient');
expect(result[0].direction).toEqual({type: 'angle', value: 180});
expect(result[0].colorStops).toEqual([
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
]);
});
it('should process a linear gradient object style with case-insensitive angle', () => {
const input = [
{
type: 'linearGradient',
direction: '45DEG',
colorStops: [{color: 'red'}, {color: 'blue'}],
},
];
const result = processBackgroundImage(input);
expect(result[0].type).toBe('linearGradient');
expect(result[0].direction).toEqual({type: 'angle', value: 45});
expect(result[0].colorStops).toEqual([
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
@@ -133,8 +157,10 @@ describe('processBackgroundImage', () => {
const input = 'LiNeAr-GradieNt(To Bottom, Red, Blue)';
const result = processBackgroundImage(input);
expect(result[0].type).toBe('linearGradient');
expect(result[0].start).toEqual({x: 0.5, y: 0});
expect(result[0].end).toEqual({x: 0.5, y: 1});
expect(result[0].direction).toEqual({
type: 'angle',
value: 180,
});
expect(result[0].colorStops).toEqual([
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
@@ -144,8 +170,10 @@ describe('processBackgroundImage', () => {
it('should process a linear gradient with case-insensitive direction enum', () => {
const input = 'linear-gradient(tO Right, red, blue)';
const result = processBackgroundImage(input);
expect(result[0].start).toEqual({x: 0, y: 0.5});
expect(result[0].end).toEqual({x: 1, y: 0.5});
expect(result[0].direction).toEqual({
type: 'angle',
value: 90,
});
expect(result[0].colorStops).toEqual([
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
@@ -154,10 +182,12 @@ describe('processBackgroundImage', () => {
it('should process a linear gradient with case-insensitive colors', () => {
const input =
'linear-gradient(to right, Rgba(0, 0, 0, 0.5), Blue, Hsla(0, 100%, 50%, 0.5))';
'linear-gradient(TO LEFT, Rgba(0, 0, 0, 0.5), Blue, Hsla(0, 100%, 50%, 0.5))';
const result = processBackgroundImage(input);
expect(result[0].start).toEqual({x: 0, y: 0.5});
expect(result[0].end).toEqual({x: 1, y: 0.5});
expect(result[0].direction).toEqual({
type: 'angle',
value: 270,
});
expect(result[0].colorStops).toEqual([
{color: processColor('rgba(0, 0, 0, 0.5)'), position: 0},
{color: processColor('blue'), position: 0.5},
@@ -167,20 +197,24 @@ describe('processBackgroundImage', () => {
it('should process multiple linear gradients', () => {
const input = `
linear-gradient(to right, red, blue),
linear-gradient(to top, red, blue),
linear-gradient(to bottom, green, yellow)`;
const result = processBackgroundImage(input);
expect(result).toHaveLength(2);
expect(result[0].type).toEqual('linearGradient');
expect(result[0].start).toEqual({x: 0, y: 0.5});
expect(result[0].end).toEqual({x: 1, y: 0.5});
expect(result[0].direction).toEqual({
type: 'angle',
value: 0,
});
expect(result[0].colorStops).toEqual([
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
]);
expect(result[1].type).toEqual('linearGradient');
expect(result[1].start).toEqual({x: 0.5, y: 0});
expect(result[1].end).toEqual({x: 0.5, y: 1});
expect(result[1].direction).toEqual({
type: 'angle',
value: 180,
});
expect(result[1].colorStops).toEqual([
{color: processColor('green'), position: 0},
@@ -190,20 +224,24 @@ describe('processBackgroundImage', () => {
it('should process multiple linear gradients with newlines', () => {
const input = `
linear-gradient(to right, red, blue),\n
linear-gradient(to left, red, blue),\n
linear-gradient(to bottom, green, yellow)`;
const result = processBackgroundImage(input);
expect(result).toHaveLength(2);
expect(result[0].type).toEqual('linearGradient');
expect(result[0].start).toEqual({x: 0, y: 0.5});
expect(result[0].end).toEqual({x: 1, y: 0.5});
expect(result[0].direction).toEqual({
type: 'angle',
value: 270,
});
expect(result[0].colorStops).toEqual([
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
]);
expect(result[1].type).toEqual('linearGradient');
expect(result[1].start).toEqual({x: 0.5, y: 0});
expect(result[1].end).toEqual({x: 0.5, y: 1});
expect(result[1].direction).toEqual({
type: 'angle',
value: 180,
});
expect(result[1].colorStops).toEqual([
{color: processColor('green'), position: 0},
@@ -212,7 +250,7 @@ describe('processBackgroundImage', () => {
});
it('should process a linear gradient with multiple color stops', () => {
const input = 'linear-gradient(to right, red 0%, green 50%, blue 100%)';
const input = 'linear-gradient(to bottom, red 0%, green 50%, blue 100%)';
const result = processBackgroundImage(input);
expect(result[0].colorStops).toEqual([
{color: processColor('red'), position: 0},
@@ -268,10 +306,14 @@ describe('processBackgroundImage', () => {
linear-gradient(to bottom , rgba(255,0,0,0.9) , rgba(0,0,255,0.2) )`;
const result = processBackgroundImage(input);
expect(result).toHaveLength(2);
expect(result[0].start).toEqual({x: 0, y: 0.5});
expect(result[0].end).toEqual({x: 1, y: 0.5});
expect(result[1].start).toEqual({x: 0.5, y: 0});
expect(result[1].end).toEqual({x: 0.5, y: 1});
expect(result[0].direction).toEqual({
type: 'angle',
value: 90,
});
expect(result[1].direction).toEqual({
type: 'angle',
value: 180,
});
expect(result[0].colorStops).toEqual([
{color: processColor('rgba(255,0,0,0.5)'), position: 0},
{color: processColor('rgba(0,0,255,0.8)'), position: 1},
@@ -321,8 +363,7 @@ describe('processBackgroundImage', () => {
expect(result).toEqual([
{
type: 'linearGradient',
start: {x: 0, y: 0},
end: {x: 1, y: 1},
direction: {type: 'keyword', value: 'to bottom right'},
colorStops: [
{color: processColor('red'), position: 0},
{color: processColor('blue'), position: 1},
@@ -339,8 +380,10 @@ describe('processBackgroundImage', () => {
},
];
const result = processBackgroundImage(input);
expect(result[0].start).toEqual({x: 0.5, y: 0});
expect(result[0].end).toEqual({x: 0.5, y: 1});
expect(result[0].direction).toEqual({
type: 'angle',
value: 180,
});
});
it('should process style object with direction enum', () => {
@@ -352,8 +395,10 @@ describe('processBackgroundImage', () => {
},
];
const result = processBackgroundImage(input);
expect(result[0].start).toEqual({x: 0, y: 0.5});
expect(result[0].end).toEqual({x: 1, y: 0.5});
expect(result[0].direction).toEqual({
type: 'angle',
value: 90,
});
});
it('should process style object with direction angle', () => {
@@ -365,10 +410,10 @@ describe('processBackgroundImage', () => {
},
];
const result = processBackgroundImage(input);
expect(result[0].start.x).toBeCloseTo(0.146447, 5);
expect(result[0].start.y).toBeCloseTo(0.853553, 5);
expect(result[0].end.x).toBeCloseTo(0.853553, 5);
expect(result[0].end.y).toBeCloseTo(0.146447, 5);
expect(result[0].direction).toEqual({
type: 'angle',
value: 45,
});
});
it('should fix up stop positions #1', () => {
@@ -14,25 +14,28 @@ import type {ProcessedColorValue} from './processColor';
import type {GradientValue} from './StyleSheetTypes';
const processColor = require('./processColor').default;
const DIRECTION_REGEX =
/^to\s+(?:top|bottom|left|right)(?:\s+(?:top|bottom|left|right))?/;
const DIRECTION_KEYWORD_REGEX =
/^to\s+(?:top|bottom|left|right)(?:\s+(?:top|bottom|left|right))?/i;
const ANGLE_UNIT_REGEX = /^([+-]?\d*\.?\d+)(deg|grad|rad|turn)$/i;
const TO_BOTTOM_START_END_POINTS = {
start: {x: 0.5, y: 0},
end: {x: 0.5, y: 1},
};
type LinearGradientDirection =
| {type: 'angle', value: number}
| {type: 'keyword', value: string};
type ParsedGradientValue = {
type: 'linearGradient',
start: {x: number, y: number},
end: {x: number, y: number},
direction: LinearGradientDirection,
colorStops: $ReadOnlyArray<{
color: ProcessedColorValue,
position: number,
}>,
};
const DEFAULT_DIRECTION: LinearGradientDirection = {
type: 'angle',
value: 180,
};
export default function processBackgroundImage(
backgroundImage: ?($ReadOnlyArray<GradientValue> | string),
): $ReadOnlyArray<ParsedGradientValue> {
@@ -76,37 +79,43 @@ export default function processBackgroundImage(
}
}
let points: {
start: ParsedGradientValue['start'],
end: ParsedGradientValue['end'],
} | null = null;
let direction: LinearGradientDirection = DEFAULT_DIRECTION;
const bgDirection =
bgImage.direction != null ? bgImage.direction.toLowerCase() : null;
if (typeof bgImage.direction === 'undefined') {
points = TO_BOTTOM_START_END_POINTS;
} else if (ANGLE_UNIT_REGEX.test(bgImage.direction)) {
const angle = parseAngle(bgImage.direction);
if (angle != null) {
points = calculateStartEndPointsFromAngle(angle);
}
} else if (DIRECTION_REGEX.test(bgImage.direction)) {
const processedPoints = calculateStartEndPointsFromDirection(
bgImage.direction,
);
if (processedPoints != null) {
points = processedPoints;
if (bgDirection != null) {
if (ANGLE_UNIT_REGEX.test(bgDirection)) {
const parsedAngle = getAngleInDegrees(bgDirection);
if (parsedAngle != null) {
direction = {
type: 'angle',
value: parsedAngle,
};
} else {
// If an angle is invalid, return an empty array and do not apply any gradient. Same as web.
return [];
}
} else if (DIRECTION_KEYWORD_REGEX.test(bgDirection)) {
const parsedDirection = getDirectionForKeyword(bgDirection);
if (parsedDirection != null) {
direction = parsedDirection;
} else {
// If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
return [];
}
} else {
// If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
return [];
}
}
const fixedColorStops = getFixedColorStops(processedColorStops);
if (points != null) {
result = result.concat({
type: 'linearGradient',
start: points.start,
end: points.end,
colorStops: fixedColorStops,
});
}
result = result.concat({
type: 'linearGradient',
direction,
colorStops: fixedColorStops,
});
}
}
@@ -118,30 +127,39 @@ function parseCSSLinearGradient(
): $ReadOnlyArray<ParsedGradientValue> {
const gradients = [];
let match;
// matches one or more linear-gradient functions in CSS
const linearGradientRegex = /linear-gradient\s*\(((?:\([^)]*\)|[^())])*)\)/gi;
while ((match = linearGradientRegex.exec(cssString))) {
const gradientContent = match[1];
const parts = gradientContent.split(',');
let points = TO_BOTTOM_START_END_POINTS;
let direction: LinearGradientDirection = DEFAULT_DIRECTION;
const trimmedDirection = parts[0].trim().toLowerCase();
// matches individual color stops in a gradient function
// supports various color formats: named colors, hex colors, rgb(a), and hsl(a)
// e.g. "red 20%", "blue 50%", "rgba(0, 0, 0, 0.5) 30% 50%"
// TODO: does not support color hint syntax yet. It is WIP.
const colorStopRegex =
/\s*((?:(?:rgba?|hsla?)\s*\([^)]+\))|#[0-9a-fA-F]+|[a-zA-Z]+)(?:\s+(-?[0-9.]+%?)(?:\s+(-?[0-9.]+%?))?)?\s*/gi;
if (ANGLE_UNIT_REGEX.test(trimmedDirection)) {
const angle = parseAngle(trimmedDirection);
if (angle != null) {
points = calculateStartEndPointsFromAngle(angle);
const parsedAngle = getAngleInDegrees(trimmedDirection);
if (parsedAngle != null) {
direction = {
type: 'angle',
value: parsedAngle,
};
parts.shift();
} else {
// If an angle is invalid, return an empty array and do not apply any gradient. Same as web.
return [];
}
} else if (DIRECTION_REGEX.test(trimmedDirection)) {
const parsedPoints =
calculateStartEndPointsFromDirection(trimmedDirection);
if (parsedPoints != null) {
points = parsedPoints;
} else if (DIRECTION_KEYWORD_REGEX.test(trimmedDirection)) {
const parsedDirection = getDirectionForKeyword(trimmedDirection);
if (parsedDirection != null) {
direction = parsedDirection;
parts.shift();
} else {
// If a direction is invalid, return an empty array and do not apply any gradient. Same as web.
@@ -198,8 +216,7 @@ function parseCSSLinearGradient(
gradients.push({
type: 'linearGradient',
start: points.start,
end: points.end,
direction,
colorStops: fixedColorStops,
});
}
@@ -207,83 +224,43 @@ function parseCSSLinearGradient(
return gradients;
}
function calculateStartEndPointsFromDirection(direction: string): ?{
start: {x: number, y: number},
end: {x: number, y: number},
} {
function getDirectionForKeyword(direction?: string): ?LinearGradientDirection {
if (direction == null) {
return null;
}
// Remove extra whitespace
const normalizedDirection = direction.replace(/\s+/g, ' ');
const normalized = direction.replace(/\s+/g, ' ').toLowerCase();
switch (normalizedDirection) {
case 'to right':
return {
start: {x: 0, y: 0.5},
end: {x: 1, y: 0.5},
};
case 'to left':
return {
start: {x: 1, y: 0.5},
end: {x: 0, y: 0.5},
};
case 'to bottom':
return TO_BOTTOM_START_END_POINTS;
switch (normalized) {
case 'to top':
return {
start: {x: 0.5, y: 1},
end: {x: 0.5, y: 0},
};
case 'to bottom right':
case 'to right bottom':
return {
start: {x: 0, y: 0},
end: {x: 1, y: 1},
};
case 'to top left':
case 'to left top':
return {
start: {x: 1, y: 1},
end: {x: 0, y: 0},
};
case 'to bottom left':
case 'to left bottom':
return {
start: {x: 1, y: 0},
end: {x: 0, y: 1},
};
return {type: 'angle', value: 0};
case 'to right':
return {type: 'angle', value: 90};
case 'to bottom':
return {type: 'angle', value: 180};
case 'to left':
return {type: 'angle', value: 270};
case 'to top right':
case 'to right top':
return {
start: {x: 0, y: 1},
end: {x: 1, y: 0},
};
return {type: 'keyword', value: 'to top right'};
case 'to bottom right':
case 'to right bottom':
return {type: 'keyword', value: 'to bottom right'};
case 'to top left':
case 'to left top':
return {type: 'keyword', value: 'to top left'};
case 'to bottom left':
case 'to left bottom':
return {type: 'keyword', value: 'to bottom left'};
default:
return null;
}
}
function calculateStartEndPointsFromAngle(angleRadians: number): {
start: {x: number, y: number},
end: {x: number, y: number},
} {
// Normalize angle to be between 0 and 2π
let angleRadiansNormalized = angleRadians % (2 * Math.PI);
if (angleRadiansNormalized < 0) {
angleRadiansNormalized += 2 * Math.PI;
function getAngleInDegrees(angle?: string): ?number {
if (angle == null) {
return null;
}
const endX = 0.5 + 0.5 * Math.sin(angleRadiansNormalized);
const endY = 0.5 - 0.5 * Math.cos(angleRadiansNormalized);
const startX = 1 - endX;
const startY = 1 - endY;
return {
start: {x: startX, y: startY},
end: {x: endX, y: endY},
};
}
function parseAngle(angle: string): ?number {
const match = angle.match(ANGLE_UNIT_REGEX);
if (!match) {
return null;
@@ -294,13 +271,13 @@ function parseAngle(angle: string): ?number {
const numericValue = parseFloat(value);
switch (unit) {
case 'deg':
return (numericValue * Math.PI) / 180;
case 'grad':
return (numericValue * Math.PI) / 200;
case 'rad':
return numericValue;
case 'grad':
return numericValue * 0.9; // 1 grad = 0.9 degrees
case 'rad':
return (numericValue * 180) / Math.PI;
case 'turn':
return numericValue * 2 * Math.PI;
return numericValue * 360; // 1 turn = 360 degrees
default:
return null;
}
+3 -1
View File
@@ -105,7 +105,9 @@ export function setColorScheme(colorScheme: ?ColorSchemeName): void {
const {NativeAppearance} = state;
if (NativeAppearance != null) {
NativeAppearance.setColorScheme(colorScheme ?? 'unspecified');
state.appearance = {colorScheme};
state.appearance = {
colorScheme: toColorScheme(NativeAppearance.getColorScheme()),
};
}
}
@@ -0,0 +1,39 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import useColorScheme from '../useColorScheme';
describe('useColorScheme', () => {
it('should return a mocked light theme by default', () => {
expect(jest.isMockFunction(useColorScheme)).toBe(true);
expect(useColorScheme()).toBe('light');
});
it('should have console.error when not using mock', () => {
const useColorSchemeActual = jest.requireActual<{
default: typeof useColorScheme,
}>('../useColorScheme').default;
const spy = jest.spyOn(console, 'error').mockImplementationOnce(() => {
// Simulate LogBox console.error() call to throw an error and stop the further execution
throw new Error('console.error() was called');
});
expect(() => {
useColorSchemeActual();
}).toThrow();
expect(spy).toHaveBeenCalledWith(
expect.stringMatching(
/Invalid hook call. Hooks can only be called inside of the body of a function component./,
),
);
});
});
@@ -5609,12 +5609,7 @@ declare function create(
declare const Presets: {
easeInEaseOut: LayoutAnimationConfig,
linear: LayoutAnimationConfig,
spring: {
duration: 700,
create: { type: \\"linear\\", property: \\"opacity\\" },
update: { type: \\"spring\\", springDamping: 0.4 },
delete: { type: \\"linear\\", property: \\"opacity\\" },
},
spring: LayoutAnimationConfig,
};
declare const LayoutAnimation: {
configureNext: configureNext,
@@ -6903,49 +6898,6 @@ exports[`public API should not change unintentionally Libraries/Network/fetch.js
"
`;
exports[`public API should not change unintentionally Libraries/NewAppScreen/components/Colors.js 1`] = `
"declare export default {
primary: \\"#1292B4\\",
white: \\"#FFF\\",
lighter: \\"#F3F3F3\\",
light: \\"#DAE1E7\\",
dark: \\"#444\\",
darker: \\"#222\\",
black: \\"#000\\",
};
"
`;
exports[`public API should not change unintentionally Libraries/NewAppScreen/components/DebugInstructions.js 1`] = `
"declare const DebugInstructions: () => Node;
declare export default typeof DebugInstructions;
"
`;
exports[`public API should not change unintentionally Libraries/NewAppScreen/components/Header.js 1`] = `
"declare const Header: () => Node;
declare export default typeof Header;
"
`;
exports[`public API should not change unintentionally Libraries/NewAppScreen/components/HermesBadge.js 1`] = `
"declare const HermesBadge: () => Node;
declare export default typeof HermesBadge;
"
`;
exports[`public API should not change unintentionally Libraries/NewAppScreen/components/LearnMoreLinks.js 1`] = `
"declare const LinkList: () => Node;
declare export default typeof LinkList;
"
`;
exports[`public API should not change unintentionally Libraries/NewAppScreen/components/ReloadInstructions.js 1`] = `
"declare const ReloadInstructions: () => Node;
declare export default typeof ReloadInstructions;
"
`;
exports[`public API should not change unintentionally Libraries/NewAppScreen/index.js 1`] = `
"export {
Colors,
@@ -8371,10 +8323,12 @@ declare module.exports: processAspectRatio;
`;
exports[`public API should not change unintentionally Libraries/StyleSheet/processBackgroundImage.js 1`] = `
"type ParsedGradientValue = {
"type LinearGradientDirection =
| { type: \\"angle\\", value: number }
| { type: \\"keyword\\", value: string };
type ParsedGradientValue = {
type: \\"linearGradient\\",
start: { x: number, y: number },
end: { x: number, y: number },
direction: LinearGradientDirection,
colorStops: $ReadOnlyArray<{
color: ProcessedColorValue,
position: number,
@@ -26,6 +26,7 @@ const IGNORE_PATTERNS = [
'**/*.fb.js',
'**/*.macos.js',
'**/*.windows.js',
'Libraries/NewAppScreen/components/**',
// Non source files
'Libraries/Renderer/implementations/**',
'Libraries/Renderer/shims/**',
@@ -67,28 +67,52 @@
* ScrollView, we force it to be centered, but when you zoom or the content otherwise
* becomes larger than the ScrollView, there is no padding around the content but it
* can still fill the whole view.
* This implementation is based on https://petersteinberger.com/blog/2013/how-to-center-uiscrollview/.
*/
- (void)centerContentIfNeeded
{
if (!_centerContent) {
return;
}
CGSize contentSize = self.contentSize;
CGSize boundsSize = self.bounds.size;
if (CGSizeEqualToSize(contentSize, CGSizeZero) || CGSizeEqualToSize(boundsSize, CGSizeZero)) {
return;
}
CGFloat top = 0, left = 0;
if (contentSize.width < boundsSize.width) {
left = (boundsSize.width - contentSize.width) * 0.5f;
}
if (contentSize.height < boundsSize.height) {
top = (boundsSize.height - contentSize.height) * 0.5f;
}
self.contentInset = UIEdgeInsetsMake(top, left, top, left);
}
- (void)setContentOffset:(CGPoint)contentOffset
{
if (_isSetContentOffsetDisabled) {
return;
}
if (_centerContent && !CGSizeEqualToSize(self.contentSize, CGSizeZero)) {
CGSize scrollViewSize = self.bounds.size;
if (self.contentSize.width <= scrollViewSize.width) {
contentOffset.x = -(scrollViewSize.width - self.contentSize.width) / 2.0;
}
if (self.contentSize.height <= scrollViewSize.height) {
contentOffset.y = -(scrollViewSize.height - self.contentSize.height) / 2.0;
}
}
super.contentOffset = CGPointMake(
RCTSanitizeNaNValue(contentOffset.x, @"scrollView.contentOffset.x"),
RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y"));
}
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
[self centerContentIfNeeded];
}
- (void)didAddSubview:(UIView *)subview
{
[super didAddSubview:subview];
[self centerContentIfNeeded];
}
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
{
if ([_overridingDelegate respondsToSelector:@selector(touchesShouldCancelInContentView:)]) {
@@ -258,6 +282,11 @@
}
}
- (void)scrollViewDidZoom:(__unused UIScrollView *)scrollView
{
[self centerContentIfNeeded];
}
#pragma mark -
- (BOOL)isHorizontal:(UIScrollView *)scrollView
@@ -450,10 +450,15 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
- (void)textInputDidChangeSelection
{
[self _updateTypingAttributes];
if (_comingFromJS) {
return;
}
// T207198334: Setting a new AttributedString (_comingFromJS) will trigger a selection change before the backing
// string is updated, so indicies won't point to what we want yet. Only respond to user selection change, and let
// `_setAttributedString` handle updating typing attributes if content changes.
[self _updateTypingAttributes];
const auto &props = static_cast<const TextInputProps &>(*_props);
if (props.multiline && ![_lastStringStateWasUpdatedWith isEqual:_backedTextInputView.attributedText]) {
[self textInputDidChange];
@@ -722,7 +727,7 @@ static NSSet<NSNumber *> *returnKeyTypesSet;
// https://github.com/facebook/react-native/blob/3102a58df38d96f3dacef0530e4dbb399037fcd2/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/SetSpanOperation.kt#L30
- (void)_updateTypingAttributes
{
if (_backedTextInputView.attributedText.length > 0) {
if (_backedTextInputView.attributedText.length > 0 && _backedTextInputView.selectedTextRange != nil) {
NSUInteger offsetStart = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
toPosition:_backedTextInputView.selectedTextRange.start];
@@ -10,11 +10,13 @@
#import <CoreGraphics/CoreGraphics.h>
#import <QuartzCore/QuartzCore.h>
#import <objc/runtime.h>
#import <ranges>
#import <React/RCTAssert.h>
#import <React/RCTBorderDrawing.h>
#import <React/RCTBoxShadow.h>
#import <React/RCTConversions.h>
#import <React/RCTLinearGradient.h>
#import <React/RCTLocalizedString.h>
#import <react/featureflags/ReactNativeFeatureFlags.h>
#import <react/renderer/components/view/ViewComponentDescriptor.h>
@@ -38,7 +40,7 @@ const CGFloat BACKGROUND_COLOR_ZPOSITION = -1024.0f;
CALayer *_outlineLayer;
CALayer *_boxShadowLayer;
CALayer *_filterLayer;
NSMutableArray<CAGradientLayer *> *_gradientLayers;
NSMutableArray<CALayer *> *_backgroundImageLayers;
BOOL _needsInvalidateLayer;
BOOL _isJSResponder;
BOOL _removeClippedSubviews;
@@ -1001,50 +1003,35 @@ static RCTBorderStyle RCTBorderStyleFromOutlineStyle(OutlineStyle outlineStyle)
}
// background image
[self clearExistingGradientLayers];
[self clearExistingBackgroundImageLayers];
if (!_props->backgroundImage.empty()) {
for (const auto &gradient : _props->backgroundImage) {
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
NSMutableArray *colors = [NSMutableArray array];
NSMutableArray *locations = [NSMutableArray array];
for (const auto &colorStop : gradient.colorStops) {
if (colorStop.position.has_value()) {
auto location = @(colorStop.position.value());
UIColor *color = RCTUIColorFromSharedColor(colorStop.color);
[colors addObject:(id)color.CGColor];
[locations addObject:location];
// iterate in reverse to match CSS specification
for (const auto &backgroundImage : std::ranges::reverse_view(_props->backgroundImage)) {
if (std::holds_alternative<LinearGradient>(backgroundImage)) {
const auto &linearGradient = std::get<LinearGradient>(backgroundImage);
CALayer *backgroundImageLayer = [RCTLinearGradient gradientLayerWithSize:self.layer.bounds.size
gradient:linearGradient];
backgroundImageLayer.frame = layer.bounds;
backgroundImageLayer.masksToBounds = YES;
// To make border radius work with gradient layers
if (borderMetrics.borderRadii.isUniform()) {
backgroundImageLayer.cornerRadius = layer.cornerRadius;
backgroundImageLayer.cornerCurve = layer.cornerCurve;
backgroundImageLayer.mask = nil;
} else {
CAShapeLayer *maskLayer =
[self createMaskLayer:self.bounds
cornerInsets:RCTGetCornerInsets(
RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), UIEdgeInsetsZero)];
backgroundImageLayer.mask = maskLayer;
backgroundImageLayer.cornerRadius = 0;
}
backgroundImageLayer.zPosition = BACKGROUND_COLOR_ZPOSITION;
[self.layer addSublayer:backgroundImageLayer];
[_backgroundImageLayers addObject:backgroundImageLayer];
}
gradientLayer.startPoint = CGPointMake(gradient.startX, gradient.startY);
gradientLayer.endPoint = CGPointMake(gradient.endX, gradient.endY);
if (locations.count > 0) {
gradientLayer.locations = locations;
}
gradientLayer.colors = colors;
gradientLayer.frame = layer.bounds;
// border styling to work with gradient layers
if (useCoreAnimationBorderRendering) {
gradientLayer.borderWidth = layer.borderWidth;
gradientLayer.borderColor = layer.borderColor;
gradientLayer.cornerRadius = layer.cornerRadius;
gradientLayer.cornerCurve = layer.cornerCurve;
} else {
CAShapeLayer *maskLayer = [CAShapeLayer layer];
CGPathRef path = RCTPathCreateWithRoundedRect(
self.bounds,
RCTGetCornerInsets(RCTCornerRadiiFromBorderRadii(borderMetrics.borderRadii), UIEdgeInsetsZero),
nil);
maskLayer.path = path;
CGPathRelease(path);
gradientLayer.mask = maskLayer;
}
gradientLayer.zPosition = BACKGROUND_COLOR_ZPOSITION;
[self.layer addSublayer:gradientLayer];
[_gradientLayers addObject:gradientLayer];
}
}
@@ -1115,16 +1102,16 @@ static RCTBorderStyle RCTBorderStyleFromOutlineStyle(OutlineStyle outlineStyle)
return maskLayer;
}
- (void)clearExistingGradientLayers
- (void)clearExistingBackgroundImageLayers
{
if (_gradientLayers == nil) {
_gradientLayers = [NSMutableArray new];
if (_backgroundImageLayers == nil) {
_backgroundImageLayers = [NSMutableArray new];
return;
}
for (CAGradientLayer *gradientLayer in _gradientLayers) {
[gradientLayer removeFromSuperlayer];
for (CALayer *backgroundImageLayer in _backgroundImageLayers) {
[backgroundImageLayer removeFromSuperlayer];
}
[_gradientLayers removeAllObjects];
[_backgroundImageLayers removeAllObjects];
}
#pragma mark - Accessibility
@@ -0,0 +1,19 @@
/*
* 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.
*/
#import <UIKit/UIKit.h>
#import <react/renderer/components/view/ViewProps.h>
NS_ASSUME_NONNULL_BEGIN
@interface RCTLinearGradient : NSObject
+ (CALayer *)gradientLayerWithSize:(CGSize)size gradient:(const facebook::react::LinearGradient &)gradient;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,134 @@
/*
* 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.
*/
#import "RCTLinearGradient.h"
#import <React/RCTConversions.h>
using namespace facebook::react;
@implementation RCTLinearGradient
+ (CALayer *)gradientLayerWithSize:(CGSize)size gradient:(const LinearGradient &)gradient
{
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size];
const auto &direction = gradient.direction;
const auto &colorStops = gradient.colorStops;
UIImage *gradientImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) {
CGContextRef context = rendererContext.CGContext;
NSMutableArray *colors = [NSMutableArray array];
CGFloat locations[colorStops.size()];
for (size_t i = 0; i < colorStops.size(); ++i) {
const auto &colorStop = colorStops[i];
CGColorRef cgColor = RCTCreateCGColorRefFromSharedColor(colorStop.color);
[colors addObject:(__bridge id)cgColor];
locations[i] = colorStop.position;
}
CGGradientRef cgGradient = CGGradientCreateWithColors(NULL, (__bridge CFArrayRef)colors, locations);
CGPoint startPoint;
CGPoint endPoint;
if (direction.type == GradientDirectionType::Angle) {
CGFloat angle = std::get<Float>(direction.value);
std::tie(startPoint, endPoint) = getPointsFromAngle(angle, size);
} else if (direction.type == GradientDirectionType::Keyword) {
auto keyword = std::get<GradientKeyword>(direction.value);
CGFloat angle = getAngleForKeyword(keyword, size);
std::tie(startPoint, endPoint) = getPointsFromAngle(angle, size);
} else {
// Default to top-to-bottom gradient
startPoint = CGPointMake(0.0, 0.0);
endPoint = CGPointMake(0.0, size.height);
}
CGContextDrawLinearGradient(context, cgGradient, startPoint, endPoint, 0);
for (id color in colors) {
CGColorRelease((__bridge CGColorRef)color);
}
CGGradientRelease(cgGradient);
}];
CALayer *gradientLayer = [CALayer layer];
gradientLayer.contents = (__bridge id)gradientImage.CGImage;
return gradientLayer;
}
// Spec: https://www.w3.org/TR/css-images-3/#linear-gradient-syntax
// Reference:
// https://github.com/chromium/chromium/blob/d32abbe13f5d52be7127fe25d5b778498165fab8/third_party/blink/renderer/core/css/css_gradient_value.cc#L1057
static std::pair<CGPoint, CGPoint> getPointsFromAngle(CGFloat angle, CGSize size)
{
angle = fmod(angle, 360.0);
if (angle < 0) {
angle += 360.0;
}
if (angle == 0.0) {
return {CGPointMake(0, size.height), CGPointMake(0, 0)};
}
if (angle == 90.0) {
return {CGPointMake(0, 0), CGPointMake(size.width, 0)};
}
if (angle == 180.0) {
return {CGPointMake(0, 0), CGPointMake(0, size.height)};
}
if (angle == 270.0) {
return {CGPointMake(size.width, 0), CGPointMake(0, 0)};
}
CGFloat radians = (90 - angle) * M_PI / 180.0;
CGFloat slope = tan(radians);
CGFloat perpendicularSlope = -1 / slope;
CGFloat halfHeight = size.height / 2;
CGFloat halfWidth = size.width / 2;
CGPoint endCorner;
if (angle < 90) {
endCorner = CGPointMake(halfWidth, halfHeight);
} else if (angle < 180) {
endCorner = CGPointMake(halfWidth, -halfHeight);
} else if (angle < 270) {
endCorner = CGPointMake(-halfWidth, -halfHeight);
} else {
endCorner = CGPointMake(-halfWidth, halfHeight);
}
CGFloat c = endCorner.y - perpendicularSlope * endCorner.x;
CGFloat endX = c / (slope - perpendicularSlope);
CGFloat endY = perpendicularSlope * endX + c;
return {CGPointMake(halfWidth - endX, halfHeight + endY), CGPointMake(halfWidth + endX, halfHeight - endY)};
}
// Spec: https://www.w3.org/TR/css-images-3/#linear-gradient-syntax
// Refer `using keywords` section
static CGFloat getAngleForKeyword(GradientKeyword keyword, CGSize size)
{
switch (keyword) {
case GradientKeyword::ToTopRight: {
CGFloat angleDeg = atan(size.width / size.height) * 180.0 / M_PI;
return 90.0 - angleDeg;
}
case GradientKeyword::ToBottomRight:
return atan(size.width / size.height) * 180.0 / M_PI + 90.0;
case GradientKeyword::ToTopLeft:
return atan(size.width / size.height) * 180.0 / M_PI + 270.0;
case GradientKeyword::ToBottomLeft:
return atan(size.height / size.width) * 180.0 / M_PI + 180.0;
default:
return 180.0;
}
}
@end
@@ -121,8 +121,8 @@ using namespace facebook::react;
auto &props = *sharedProps;
props.layoutConstraints = LayoutConstraints{{0, 0}, {500, 500}};
auto &yogaStyle = props.yogaStyle;
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(200));
return sharedProps;
})
.children({
@@ -136,8 +136,8 @@ using namespace facebook::react;
yogaStyle.setPositionType(yoga::PositionType::Absolute);
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(0));
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(0));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(200));
return sharedProps;
})
.children({
@@ -216,8 +216,8 @@ using namespace facebook::react;
yogaStyle.setPositionType(yoga::PositionType::Absolute);
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(0));
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(30));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(50));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(50));
return sharedProps;
})
.children({
@@ -260,8 +260,8 @@ using namespace facebook::react;
yogaStyle.setPositionType(yoga::PositionType::Absolute);
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(0));
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(90));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(50));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(50));
return sharedProps;
})
.children({
@@ -418,8 +418,8 @@ static ParagraphShadowNode::ConcreteState::Shared stateWithShadowNode(
auto &props = *sharedProps;
props.layoutConstraints = LayoutConstraints{{0, 0}, {500, 500}};
auto &yogaStyle = props.yogaStyle;
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(200));
return sharedProps;
})
.children({
@@ -434,8 +434,8 @@ static ParagraphShadowNode::ConcreteState::Shared stateWithShadowNode(
yogaStyle.setPositionType(yoga::PositionType::Absolute);
yogaStyle.setPosition(yoga::Edge::Left, yoga::StyleLength::points(0));
yogaStyle.setPosition(yoga::Edge::Top, yoga::StyleLength::points(90));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleSizeLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleSizeLength::points(20));
yogaStyle.setDimension(yoga::Dimension::Width, yoga::StyleLength::points(200));
yogaStyle.setDimension(yoga::Dimension::Height, yoga::StyleLength::points(20));
return sharedProps;
})
.children({
@@ -10,6 +10,7 @@
#import <React/RCTConvert.h>
typedef UIFont * (^RCTFontHandler)(CGFloat fontSize, NSString *fontWeightDescription);
typedef CGFloat RCTFontWeight;
/**
* React Native will use the System font for rendering by default. If you want to
@@ -19,6 +20,7 @@ typedef UIFont * (^RCTFontHandler)(CGFloat fontSize, NSString *fontWeightDescrip
*/
RCT_EXTERN void RCTSetDefaultFontHandler(RCTFontHandler handler);
RCT_EXTERN BOOL RCTHasFontHandlerSet(void);
RCT_EXTERN RCTFontWeight RCTGetFontWeight(UIFont *font);
@interface RCTFont : NSObject
+4 -5
View File
@@ -11,8 +11,7 @@
#import <CoreText/CoreText.h>
typedef CGFloat RCTFontWeight;
static RCTFontWeight weightOfFont(UIFont *font)
RCTFontWeight RCTGetFontWeight(UIFont *font)
{
static NSArray<NSString *> *weightSuffixes;
static NSArray<NSNumber *> *fontWeights;
@@ -405,7 +404,7 @@ RCT_ARRAY_CONVERTER(RCTFontVariantDescriptor)
if (font) {
familyName = font.familyName ?: defaultFontFamily;
fontSize = font.pointSize ?: defaultFontSize;
fontWeight = weightOfFont(font);
fontWeight = RCTGetFontWeight(font);
isItalic = isItalicFont(font);
isCondensed = isCondensedFont(font);
}
@@ -453,7 +452,7 @@ RCT_ARRAY_CONVERTER(RCTFontVariantDescriptor)
// It's actually a font name, not a font family name,
// but we'll do what was meant, not what was said.
familyName = font.familyName;
fontWeight = weight ? fontWeight : weightOfFont(font);
fontWeight = weight ? fontWeight : RCTGetFontWeight(font);
isItalic = style ? isItalic : isItalicFont(font);
isCondensed = isCondensedFont(font);
} else {
@@ -476,7 +475,7 @@ RCT_ARRAY_CONVERTER(RCTFontVariantDescriptor)
for (NSString *name in names) {
UIFont *match = [UIFont fontWithName:name size:fontSize];
if (isItalic == isItalicFont(match) && isCondensed == isCondensedFont(match)) {
CGFloat testWeight = weightOfFont(match);
CGFloat testWeight = RCTGetFontWeight(match);
if (ABS(testWeight - fontWeight) < ABS(closestWeight - fontWeight)) {
font = match;
closestWeight = testWeight;
@@ -87,9 +87,6 @@ CGFloat RCTCoreGraphicsFloatFromYogaValue(YGValue value, CGFloat baseFloatValue)
return RCTCoreGraphicsFloatFromYogaFloat(value.value) * baseFloatValue;
case YGUnitAuto:
case YGUnitUndefined:
case YGUnitMaxContent:
case YGUnitFitContent:
case YGUnitStretch:
return baseFloatValue;
}
}
@@ -63,9 +63,6 @@ typedef NS_ENUM(unsigned int, meta_prop_t) {
#define RCT_SET_YGVALUE(ygvalue, setter, ...) \
switch (ygvalue.unit) { \
case YGUnitAuto: \
case YGUnitMaxContent: \
case YGUnitFitContent: \
case YGUnitStretch: \
case YGUnitUndefined: \
setter(__VA_ARGS__, YGUndefined); \
break; \
@@ -91,35 +88,6 @@ typedef NS_ENUM(unsigned int, meta_prop_t) {
case YGUnitPercent: \
setter##Percent(__VA_ARGS__, ygvalue.value); \
break; \
case YGUnitMaxContent: \
case YGUnitFitContent: \
case YGUnitStretch: \
break; \
}
#define RCT_SET_YGVALUE_AUTO_INTRINSIC(ygvalue, setter, ...) \
switch (ygvalue.unit) { \
case YGUnitAuto: \
setter##Auto(__VA_ARGS__); \
break; \
case YGUnitMaxContent: \
setter##MaxContent(__VA_ARGS__); \
break; \
case YGUnitFitContent: \
setter##FitContent(__VA_ARGS__); \
break; \
case YGUnitStretch: \
setter##Stretch(__VA_ARGS__); \
break; \
case YGUnitUndefined: \
setter(__VA_ARGS__, YGUndefined); \
break; \
case YGUnitPoint: \
setter(__VA_ARGS__, ygvalue.value); \
break; \
case YGUnitPercent: \
setter##Percent(__VA_ARGS__, ygvalue.value); \
break; \
}
static void RCTProcessMetaPropsPadding(const YGValue metaProps[META_PROP_COUNT], YGNodeRef node)
@@ -515,14 +483,14 @@ RCT_BORDER_PROPERTY(Start, START)
RCT_BORDER_PROPERTY(End, END)
// Dimensions
#define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
-(void)set##setProp : (YGValue)value \
{ \
RCT_SET_YGVALUE_AUTO_INTRINSIC(value, YGNodeStyleSet##cssProp, _yogaNode); \
} \
-(YGValue)getProp \
{ \
return YGNodeStyleGet##cssProp(_yogaNode); \
#define RCT_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
-(void)set##setProp : (YGValue)value \
{ \
RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSet##cssProp, _yogaNode); \
} \
-(YGValue)getProp \
{ \
return YGNodeStyleGet##cssProp(_yogaNode); \
}
#define RCT_MIN_MAX_DIMENSION_PROPERTY(setProp, getProp, cssProp) \
@@ -666,7 +634,7 @@ RCTShadowViewMeasure(YGNodeConstRef node, float width, YGMeasureMode widthMode,
- (void)setFlexBasis:(YGValue)value
{
RCT_SET_YGVALUE_AUTO_INTRINSIC(value, YGNodeStyleSetFlexBasis, _yogaNode);
RCT_SET_YGVALUE_AUTO(value, YGNodeStyleSetFlexBasis, _yogaNode);
}
- (YGValue)flexBasis
@@ -159,26 +159,8 @@
return !shouldDisableScrollInteraction;
}
/*
* Automatically centers the content such that if the content is smaller than the
* ScrollView, we force it to be centered, but when you zoom or the content otherwise
* becomes larger than the ScrollView, there is no padding around the content but it
* can still fill the whole view.
*/
- (void)setContentOffset:(CGPoint)contentOffset
{
UIView *contentView = [self contentView];
if (contentView && _centerContent && !CGSizeEqualToSize(contentView.frame.size, CGSizeZero)) {
CGSize subviewSize = contentView.frame.size;
CGSize scrollViewSize = self.bounds.size;
if (subviewSize.width <= scrollViewSize.width) {
contentOffset.x = -(scrollViewSize.width - subviewSize.width) / 2.0;
}
if (subviewSize.height <= scrollViewSize.height) {
contentOffset.y = -(scrollViewSize.height - subviewSize.height) / 2.0;
}
}
super.contentOffset = CGPointMake(
RCTSanitizeNaNValue(contentOffset.x, @"scrollView.contentOffset.x"),
RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y"));
@@ -433,6 +415,12 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(
// Does nothing
}
- (void)setFrame:(CGRect)frame
{
[super setFrame:frame];
[self centerContentIfNeeded];
}
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
{
[super insertReactSubview:view atIndex:atIndex];
@@ -450,6 +438,8 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(
RCTApplyTransformationAccordingLayoutDirection(_contentView, self.reactLayoutDirection);
[_scrollView addSubview:view];
}
[self centerContentIfNeeded];
}
- (void)removeReactSubview:(UIView *)subview
@@ -658,9 +648,45 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(
}
RCT_SCROLL_EVENT_HANDLER(scrollViewWillBeginDecelerating, onMomentumScrollBegin)
RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, onScroll)
RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
[self centerContentIfNeeded];
RCT_SEND_SCROLL_EVENT(onScroll, nil);
RCT_FORWARD_SCROLL_EVENT(scrollViewDidZoom : scrollView);
}
/*
* Automatically centers the content such that if the content is smaller than the
* ScrollView, we force it to be centered, but when you zoom or the content otherwise
* becomes larger than the ScrollView, there is no padding around the content but it
* can still fill the whole view.
* This implementation is based on https://petersteinberger.com/blog/2013/how-to-center-uiscrollview/.
*/
- (void)centerContentIfNeeded
{
if (!_scrollView.centerContent) {
return;
}
CGSize contentSize = self.contentSize;
CGSize boundsSize = self.bounds.size;
if (CGSizeEqualToSize(contentSize, CGSizeZero) || CGSizeEqualToSize(boundsSize, CGSizeZero)) {
return;
}
CGFloat top = 0, left = 0;
if (contentSize.width < boundsSize.width) {
left = (boundsSize.width - contentSize.width) * 0.5f;
}
if (contentSize.height < boundsSize.height) {
top = (boundsSize.height - contentSize.height) * 0.5f;
}
_scrollView.contentInset = UIEdgeInsetsMake(top, left, top, left);
}
- (void)addScrollListener:(NSObject<UIScrollViewDelegate> *)scrollListener
{
[_scrollListeners addObject:scrollListener];
@@ -939,6 +965,7 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
CGSize contentSize = self.contentSize;
if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) {
_scrollView.contentSize = contentSize;
[self centerContentIfNeeded];
}
}
@@ -377,6 +377,7 @@ public class com/facebook/react/ReactRootView : android/widget/FrameLayout, com/
protected fun dispatchJSPointerEvent (Landroid/view/MotionEvent;Z)V
protected fun dispatchJSTouchEvent (Landroid/view/MotionEvent;)V
public fun dispatchKeyEvent (Landroid/view/KeyEvent;)Z
protected fun drawChild (Landroid/graphics/Canvas;Landroid/view/View;J)Z
protected fun finalize ()V
public fun getAppProperties ()Landroid/os/Bundle;
public fun getCurrentReactContext ()Lcom/facebook/react/bridge/ReactContext;
@@ -425,10 +426,6 @@ public abstract interface class com/facebook/react/ReactRootView$ReactRootViewEv
public abstract fun onAttachedToReactInstance (Lcom/facebook/react/ReactRootView;)V
}
public abstract class com/facebook/react/TurboReactPackage : com/facebook/react/BaseReactPackage {
public fun <init> ()V
}
public abstract interface class com/facebook/react/ViewManagerOnDemandReactPackage {
public abstract fun createViewManager (Lcom/facebook/react/bridge/ReactApplicationContext;Ljava/lang/String;)Lcom/facebook/react/uimanager/ViewManager;
public abstract fun getViewManagerNames (Lcom/facebook/react/bridge/ReactApplicationContext;)Ljava/util/Collection;
@@ -1482,7 +1479,7 @@ public class com/facebook/react/bridge/ReadableNativeArray : com/facebook/react/
public fun getDouble (I)D
public fun getDynamic (I)Lcom/facebook/react/bridge/Dynamic;
public fun getInt (I)I
public static fun getJNIPassCounter ()I
public static final fun getJNIPassCounter ()I
public fun getLong (I)J
public synthetic fun getMap (I)Lcom/facebook/react/bridge/ReadableMap;
public fun getMap (I)Lcom/facebook/react/bridge/ReadableNativeMap;
@@ -1622,7 +1619,7 @@ public abstract interface class com/facebook/react/bridge/WritableMap : com/face
public abstract fun putString (Ljava/lang/String;Ljava/lang/String;)V
}
public class com/facebook/react/bridge/WritableNativeArray : com/facebook/react/bridge/ReadableNativeArray, com/facebook/react/bridge/WritableArray {
public final class com/facebook/react/bridge/WritableNativeArray : com/facebook/react/bridge/ReadableNativeArray, com/facebook/react/bridge/WritableArray {
public fun <init> ()V
public fun pushArray (Lcom/facebook/react/bridge/ReadableArray;)V
public fun pushBoolean (Z)V
@@ -2039,9 +2036,9 @@ public final class com/facebook/react/defaults/DefaultReactHost {
public static final field INSTANCE Lcom/facebook/react/defaults/DefaultReactHost;
public static final fun getDefaultReactHost (Landroid/content/Context;Lcom/facebook/react/ReactNativeHost;)Lcom/facebook/react/ReactHost;
public static final fun getDefaultReactHost (Landroid/content/Context;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZLjava/util/List;)Lcom/facebook/react/ReactHost;
public static final fun getDefaultReactHost (Landroid/content/Context;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZLjava/util/List;Lkotlin/jvm/functions/Function1;)Lcom/facebook/react/ReactHost;
public static final fun getDefaultReactHost (Landroid/content/Context;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZLjava/util/List;Lkotlin/jvm/functions/Function1;Lcom/facebook/react/runtime/BindingsInstaller;)Lcom/facebook/react/ReactHost;
public static synthetic fun getDefaultReactHost$default (Landroid/content/Context;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZLjava/util/List;ILjava/lang/Object;)Lcom/facebook/react/ReactHost;
public static synthetic fun getDefaultReactHost$default (Landroid/content/Context;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZLjava/util/List;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/facebook/react/ReactHost;
public static synthetic fun getDefaultReactHost$default (Landroid/content/Context;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZLjava/util/List;Lkotlin/jvm/functions/Function1;Lcom/facebook/react/runtime/BindingsInstaller;ILjava/lang/Object;)Lcom/facebook/react/ReactHost;
}
public abstract class com/facebook/react/defaults/DefaultReactNativeHost : com/facebook/react/ReactNativeHost {
@@ -2062,6 +2059,7 @@ public final class com/facebook/react/defaults/DefaultTurboModuleManagerDelegate
public fun <init> ()V
public final fun addCxxReactPackage (Lkotlin/jvm/functions/Function0;)Lcom/facebook/react/defaults/DefaultTurboModuleManagerDelegate$Builder;
public final fun addCxxReactPackage (Lkotlin/jvm/functions/Function1;)Lcom/facebook/react/defaults/DefaultTurboModuleManagerDelegate$Builder;
public final fun addCxxReactPackages (Lkotlin/jvm/functions/Function1;)Lcom/facebook/react/defaults/DefaultTurboModuleManagerDelegate$Builder;
public synthetic fun build (Lcom/facebook/react/bridge/ReactApplicationContext;Ljava/util/List;)Lcom/facebook/react/ReactPackageTurboModuleManagerDelegate;
}
@@ -2221,6 +2219,7 @@ public abstract interface class com/facebook/react/devsupport/HMRClient : com/fa
public final class com/facebook/react/devsupport/InspectorFlags {
public static final field INSTANCE Lcom/facebook/react/devsupport/InspectorFlags;
public static final fun getFuseboxEnabled ()Z
public static final fun getIsProfilingBuild ()Z
}
public class com/facebook/react/devsupport/InspectorPackagerConnection : com/facebook/react/devsupport/IInspectorPackagerConnection {
@@ -2762,6 +2761,7 @@ public class com/facebook/react/fabric/mounting/MountingManager {
public fun attachRootView (ILandroid/view/View;Lcom/facebook/react/uimanager/ThemedReactContext;)V
public fun clearJSResponder ()V
public fun enqueuePendingEvent (IILjava/lang/String;ZLcom/facebook/react/bridge/WritableMap;I)V
public fun experimental_prefetchResource (Lcom/facebook/react/bridge/ReactContext;Ljava/lang/String;IILcom/facebook/react/common/mapbuffer/MapBuffer;)V
public fun getEventEmitter (II)Lcom/facebook/react/fabric/events/EventEmitterWrapper;
public fun getSurfaceManager (I)Lcom/facebook/react/fabric/mounting/SurfaceMountingManager;
public fun getSurfaceManagerEnforced (ILjava/lang/String;)Lcom/facebook/react/fabric/mounting/SurfaceMountingManager;
@@ -2961,11 +2961,9 @@ public abstract interface annotation class com/facebook/react/module/annotations
public final class com/facebook/react/module/model/ReactModuleInfo {
public static final field Companion Lcom/facebook/react/module/model/ReactModuleInfo$Companion;
public fun <init> (Ljava/lang/String;Ljava/lang/String;ZZZZ)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;ZZZZZ)V
public final fun canOverrideExistingModule ()Z
public static final fun classIsTurboModule (Ljava/lang/Class;)Z
public final fun className ()Ljava/lang/String;
public final fun hasConstants ()Z
public final fun isCxxModule ()Z
public final fun isTurboModule ()Z
public final fun name ()Ljava/lang/String;
@@ -3595,24 +3593,23 @@ public final class com/facebook/react/modules/statusbar/StatusBarModule : com/fa
public final class com/facebook/react/modules/statusbar/StatusBarModule$Companion {
}
public class com/facebook/react/modules/systeminfo/AndroidInfoHelpers {
public final class com/facebook/react/modules/systeminfo/AndroidInfoHelpers {
public static final field DEVICE_LOCALHOST Ljava/lang/String;
public static final field EMULATOR_LOCALHOST Ljava/lang/String;
public static final field GENYMOTION_LOCALHOST Ljava/lang/String;
public static final field INSTANCE Lcom/facebook/react/modules/systeminfo/AndroidInfoHelpers;
public static final field METRO_HOST_PROP_NAME Ljava/lang/String;
public fun <init> ()V
public static fun getAdbReverseTcpCommand (Landroid/content/Context;)Ljava/lang/String;
public static fun getAdbReverseTcpCommand (Ljava/lang/Integer;)Ljava/lang/String;
public static fun getFriendlyDeviceName ()Ljava/lang/String;
public static fun getInspectorHostMetadata (Landroid/content/Context;)Ljava/util/Map;
public static fun getServerHost (Landroid/content/Context;)Ljava/lang/String;
public static fun getServerHost (Ljava/lang/Integer;)Ljava/lang/String;
public static final fun getAdbReverseTcpCommand (I)Ljava/lang/String;
public static final fun getAdbReverseTcpCommand (Landroid/content/Context;)Ljava/lang/String;
public static final fun getFriendlyDeviceName ()Ljava/lang/String;
public static final fun getInspectorHostMetadata (Landroid/content/Context;)Ljava/util/Map;
public static final fun getServerHost (I)Ljava/lang/String;
public static final fun getServerHost (Landroid/content/Context;)Ljava/lang/String;
}
public class com/facebook/react/modules/systeminfo/AndroidInfoModule : com/facebook/fbreact/specs/NativePlatformConstantsAndroidSpec, com/facebook/react/turbomodule/core/interfaces/TurboModule {
public final class com/facebook/react/modules/systeminfo/AndroidInfoModule : com/facebook/fbreact/specs/NativePlatformConstantsAndroidSpec {
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;)V
public fun getAndroidID ()Ljava/lang/String;
public fun getTypedExportedConstants ()Ljava/util/Map;
public fun invalidate ()V
}
@@ -5286,6 +5283,8 @@ public abstract class com/facebook/react/uimanager/ViewManager : com/facebook/re
public fun createView (ILcom/facebook/react/uimanager/ThemedReactContext;Lcom/facebook/react/uimanager/ReactStylesDiffMap;Lcom/facebook/react/uimanager/StateWrapper;Lcom/facebook/react/touch/JSResponderHandler;)Landroid/view/View;
protected fun createViewInstance (ILcom/facebook/react/uimanager/ThemedReactContext;Lcom/facebook/react/uimanager/ReactStylesDiffMap;Lcom/facebook/react/uimanager/StateWrapper;)Landroid/view/View;
protected abstract fun createViewInstance (Lcom/facebook/react/uimanager/ThemedReactContext;)Landroid/view/View;
protected fun experimental_isPrefetchingEnabled ()Z
public fun experimental_prefetchResource (Lcom/facebook/react/bridge/ReactContext;IILcom/facebook/react/common/mapbuffer/MapBuffer;)V
public fun getCommandsMap ()Ljava/util/Map;
protected fun getDelegate ()Lcom/facebook/react/uimanager/ViewManagerDelegate;
public fun getExportedCustomBubblingEventTypeConstants ()Ljava/util/Map;
@@ -6023,11 +6022,6 @@ public final class com/facebook/react/uimanager/style/CornerRadii {
public fun toString ()Ljava/lang/String;
}
public final class com/facebook/react/uimanager/style/Gradient {
public fun <init> (Lcom/facebook/react/bridge/ReadableMap;Landroid/content/Context;)V
public final fun getShader (Landroid/graphics/Rect;)Landroid/graphics/Shader;
}
public abstract class com/facebook/react/uimanager/style/LogicalEdge : java/lang/Enum {
public static final field ALL Lcom/facebook/react/uimanager/style/LogicalEdge;
public static final field BLOCK Lcom/facebook/react/uimanager/style/LogicalEdge;
@@ -7835,8 +7829,6 @@ public class com/facebook/react/views/view/ReactDrawableHelper {
public class com/facebook/react/views/view/ReactViewGroup : android/view/ViewGroup, com/facebook/react/touch/ReactHitSlopView, com/facebook/react/touch/ReactInterceptingViewGroup, com/facebook/react/uimanager/ReactClippingViewGroup, com/facebook/react/uimanager/ReactOverflowViewWithInset, com/facebook/react/uimanager/ReactPointerEventsView, com/facebook/react/uimanager/ReactZIndexedViewGroup {
public fun <init> (Landroid/content/Context;)V
public fun addView (Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V
protected fun addViewInLayout (Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;Z)Z
protected fun dispatchDraw (Landroid/graphics/Canvas;)V
public fun dispatchGenericMotionEvent (Landroid/view/MotionEvent;)Z
public fun dispatchProvideStructure (Landroid/view/ViewStructure;)V
@@ -7844,7 +7836,6 @@ public class com/facebook/react/views/view/ReactViewGroup : android/view/ViewGro
public fun draw (Landroid/graphics/Canvas;)V
protected fun drawChild (Landroid/graphics/Canvas;Landroid/view/View;J)Z
protected fun getChildDrawingOrder (II)I
public fun getChildVisibleRect (Landroid/view/View;Landroid/graphics/Rect;Landroid/graphics/Point;)Z
public fun getClippingRect (Landroid/graphics/Rect;)V
public fun getHitSlopRect ()Landroid/graphics/Rect;
public fun getOverflow ()Ljava/lang/String;
@@ -7860,11 +7851,8 @@ public class com/facebook/react/views/view/ReactViewGroup : android/view/ViewGro
protected fun onMeasure (II)V
protected fun onSizeChanged (IIII)V
public fun onTouchEvent (Landroid/view/MotionEvent;)Z
public fun removeView (Landroid/view/View;)V
public fun removeViewAt (I)V
public fun removeViewInLayout (Landroid/view/View;)V
public fun removeViews (II)V
public fun removeViewsInLayout (II)V
public fun onViewAdded (Landroid/view/View;)V
public fun onViewRemoved (Landroid/view/View;)V
public fun requestLayout ()V
public fun setBackfaceVisibility (Ljava/lang/String;)V
public fun setBackfaceVisibilityDependantOpacity ()V
@@ -29,7 +29,12 @@
#include <DefaultComponentsRegistry.h>
#include <DefaultTurboModuleManagerDelegate.h>
#if __has_include("<autolinking.h>")
#define AUTOLINKING_AVAILABLE 1
#include <autolinking.h>
#else
#define AUTOLINKING_AVAILABLE 0
#endif
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <rncore.h>
@@ -56,8 +61,10 @@ void registerComponents(
REACT_NATIVE_APP_COMPONENT_REGISTRATION(registry);
#endif
#if AUTOLINKING_AVAILABLE
// And we fallback to the components autolinked
autolinking_registerProviders(registry);
#endif
}
std::shared_ptr<TurboModule> cxxModuleProvider(
@@ -71,8 +78,12 @@ std::shared_ptr<TurboModule> cxxModuleProvider(
// return std::make_shared<NativeCxxModuleExample>(jsInvoker);
// }
#if AUTOLINKING_AVAILABLE
// And we fallback to the CXX module providers autolinked
return autolinking_cxxModuleProvider(name, jsInvoker);
#endif
return nullptr;
}
std::shared_ptr<TurboModule> javaModuleProvider(
@@ -101,10 +112,12 @@ std::shared_ptr<TurboModule> javaModuleProvider(
return module;
}
#if AUTOLINKING_AVAILABLE
// And we fallback to the module providers autolinked
if (auto module = autolinking_ModuleProvider(name, params)) {
return module;
}
#endif
return nullptr;
}
@@ -37,9 +37,13 @@ fun getSDKPath(): String {
fun getSDKManagerPath(): String {
val metaSdkManagerPath = File("${getSDKPath()}/cmdline-tools/latest/bin/sdkmanager")
val ossSdkManagerPath = File("${getSDKPath()}/tools/bin/sdkmanager")
val windowsMetaSdkManagerPath = File("${getSDKPath()}/cmdline-tools/latest/bin/sdkmanager.bat")
val windowsOssSdkManagerPath = File("${getSDKPath()}/tools/bin/sdkmanager.bat")
return when {
metaSdkManagerPath.exists() -> metaSdkManagerPath.absolutePath
windowsMetaSdkManagerPath.exists() -> windowsMetaSdkManagerPath.absolutePath
ossSdkManagerPath.exists() -> ossSdkManagerPath.absolutePath
windowsOssSdkManagerPath.exists() -> windowsOssSdkManagerPath.absolutePath
else -> throw GradleException("Could not find sdkmanager executable.")
}
}
@@ -9,7 +9,7 @@
as the min SDK to lint the file.-->
<uses-sdk
android:minSdkVersion="24"
android:targetSdkVersion="34"
android:targetSdkVersion="35"
/>
</manifest>
@@ -8,7 +8,6 @@
package com.facebook.react;
import static com.facebook.react.ReactInstanceManager.initializeSoLoaderIfNecessary;
import static com.facebook.react.modules.systeminfo.AndroidInfoHelpers.getFriendlyDeviceName;
import android.app.Activity;
import android.app.Application;
@@ -37,6 +36,7 @@ import com.facebook.react.internal.ChoreographerProvider;
import com.facebook.react.jscexecutor.JSCExecutor;
import com.facebook.react.jscexecutor.JSCExecutorFactory;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.modules.systeminfo.AndroidInfoHelpers;
import com.facebook.react.packagerconnection.RequestHandler;
import java.util.ArrayList;
import java.util.List;
@@ -339,7 +339,7 @@ public class ReactInstanceManagerBuilder {
// We use the name of the device and the app for debugging & metrics
//noinspection ConstantConditions
String appName = mApplication.getPackageName();
String deviceName = getFriendlyDeviceName();
String deviceName = AndroidInfoHelpers.getFriendlyDeviceName();
return new ReactInstanceManager(
mApplication,
@@ -8,13 +8,16 @@
package com.facebook.react;
import static com.facebook.infer.annotation.ThreadConfined.UI;
import static com.facebook.react.uimanager.BlendModeHelper.needsIsolatedLayer;
import static com.facebook.react.uimanager.common.UIManagerType.DEFAULT;
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
import android.content.Context;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
@@ -65,6 +68,7 @@ import com.facebook.react.uimanager.RootView;
import com.facebook.react.uimanager.RootViewUtil;
import com.facebook.react.uimanager.UIManagerHelper;
import com.facebook.react.uimanager.common.UIManagerType;
import com.facebook.react.uimanager.common.ViewUtil;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.systrace.Systrace;
import java.util.concurrent.atomic.AtomicInteger;
@@ -290,6 +294,30 @@ public class ReactRootView extends FrameLayout implements RootView, ReactRoot {
}
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
BlendMode mixBlendMode = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& ViewUtil.getUIManagerType(this) == UIManagerType.FABRIC
&& needsIsolatedLayer(this)) {
mixBlendMode = (BlendMode) child.getTag(R.id.mix_blend_mode);
if (mixBlendMode != null) {
Paint p = new Paint();
p.setBlendMode(mixBlendMode);
canvas.saveLayer(0, 0, getWidth(), getHeight(), p);
}
}
boolean result = super.drawChild(canvas, child, drawingTime);
if (mixBlendMode != null) {
canvas.restore();
}
return result;
}
@Override
public boolean dispatchKeyEvent(KeyEvent ev) {
if (!hasActiveReactContext() || !isViewAttachedToReactInstance()) {
@@ -1,14 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react;
import com.facebook.react.common.annotations.DeprecatedInNewArchitecture;
/** This will eventually replace {@link LazyReactPackage} when TurboModules are finally done. */
@DeprecatedInNewArchitecture(message = "Use BaseReactPackage instead")
public abstract class TurboReactPackage extends BaseReactPackage {}
@@ -130,7 +130,7 @@ public class InterpolationAnimatedNode(config: ReadableMap) : ValueAnimatedNode(
val outputRange = arrayOfNulls<DoubleArray>(size)
// Match the first pattern into a List, since we don't know its length yet
var m = numericPattern.matcher(array.getString(0))
var m = numericPattern.matcher(array.getString(0) ?: "")
val firstOutputRange: MutableList<Double> = ArrayList()
while (m.find()) {
firstOutputRange.add(m.group().toDouble())
@@ -143,7 +143,7 @@ public class InterpolationAnimatedNode(config: ReadableMap) : ValueAnimatedNode(
for (i in 1 until size) {
val outputArr = DoubleArray(firstOutputRangeArr.size)
var j = 0
m = numericPattern.matcher(array.getString(i))
m = numericPattern.matcher(array.getString(i) ?: "")
while (m.find() && j < firstOutputRangeArr.size) {
outputArr[j++] = m.group().toDouble()
}
@@ -45,7 +45,9 @@ internal class ObjectAnimatedNode(
ReadableType.String -> result.pushString(source.getString(i))
ReadableType.Map -> {
val map = source.getMap(i)
if (map.hasKey(NODE_TAG_KEY) && map.getType(NODE_TAG_KEY) == ReadableType.Number) {
if (map != null &&
map.hasKey(NODE_TAG_KEY) &&
map.getType(NODE_TAG_KEY) == ReadableType.Number) {
val node = nativeAnimatedNodesManager.getNodeById(map.getInt(NODE_TAG_KEY))
requireNotNull(node) { "Mapped value node does not exist" }
if (node is ValueAnimatedNode) {
@@ -19,15 +19,15 @@ internal class TransformAnimatedNode(
config: ReadableMap,
private val nativeAnimatedNodesManager: NativeAnimatedNodesManager
) : AnimatedNode() {
private val transformConfigs: MutableList<TransformConfig>
private val transformConfigs: List<TransformConfig>
init {
val transforms = config.getArray("transforms")
transformConfigs =
if (transforms == null) mutableListOf()
if (transforms == null) emptyList()
else
MutableList<TransformConfig>(transforms.size()) { i ->
val transformConfigMap = transforms.getMap(i)
List<TransformConfig>(transforms.size()) { i ->
val transformConfigMap = checkNotNull(transforms.getMap(i))
val property = transformConfigMap.getString("property")
val type = transformConfigMap.getString("type")
if (type == "animated") {
@@ -46,7 +46,7 @@ internal class TransformAnimatedNode(
public fun collectViewUpdates(propsMap: JavaOnlyMap) {
val transforms =
MutableList<JavaOnlyMap>(transformConfigs.size) { i ->
List<JavaOnlyMap>(transformConfigs.size) { i ->
val transformConfig = transformConfigs[i]
val transform =
if (transformConfig is AnimatedTransformConfig) {
@@ -34,7 +34,7 @@ public class ColorPropConverter {
private static final String ATTR_SEGMENT = "attr/";
@Nullable
private static Integer getColorInteger(Object value, Context context) {
private static Integer getColorInteger(@Nullable Object value, Context context) {
if (value == null) {
return null;
}
@@ -84,7 +84,7 @@ public class ColorPropConverter {
}
@Nullable
public static Color getColorInstance(Object value, Context context) {
public static Color getColorInstance(@Nullable Object value, Context context) {
if (value == null) {
return null;
}
@@ -136,7 +136,7 @@ public class ColorPropConverter {
"ColorValue: the value must be a number or Object.");
}
public static Integer getColor(Object value, Context context) {
public static Integer getColor(@Nullable Object value, Context context) {
try {
if (supportWideGamut()) {
Color color = getColorInstance(value, context);
@@ -150,7 +150,7 @@ public class ColorPropConverter {
return getColorInteger(value, context);
}
public static Integer getColor(Object value, Context context, int defaultInt) {
public static Integer getColor(@Nullable Object value, Context context, int defaultInt) {
try {
return getColor(value, context);
} catch (JSApplicationCausedNativeException e) {
@@ -73,13 +73,13 @@ public class JavaOnlyArray : ReadableArray, WritableArray {
override fun getLong(index: Int): Long = (backingList[index] as Number).toLong()
override fun getString(index: Int): String = backingList[index] as String
override fun getString(index: Int): String? = backingList[index] as String?
override fun getArray(index: Int): ReadableArray = backingList[index] as ReadableArray
override fun getArray(index: Int): ReadableArray? = backingList[index] as ReadableArray?
override fun getBoolean(index: Int): Boolean = backingList[index] as Boolean
override fun getMap(index: Int): ReadableMap = backingList[index] as ReadableMap
override fun getMap(index: Int): ReadableMap? = backingList[index] as ReadableMap?
override fun getDynamic(index: Int): Dynamic = DynamicFromArray.create(this, index)
@@ -25,7 +25,6 @@ import com.facebook.react.bridge.interop.InteropModuleRegistry;
import com.facebook.react.bridge.queue.MessageQueueThread;
import com.facebook.react.bridge.queue.ReactQueueConfiguration;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.common.annotations.DeprecatedInNewArchitecture;
import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder;
import java.lang.ref.WeakReference;
import java.util.Collection;
@@ -503,8 +502,8 @@ public abstract class ReactContext extends ContextWrapper {
*/
public abstract @Nullable CallInvokerHolder getJSCallInvokerHolder();
@DeprecatedInNewArchitecture(
message =
@Deprecated(
since =
"This method will be deprecated later as part of Stable APIs with bridge removal and not"
+ " encouraged usage.")
/**
@@ -14,7 +14,7 @@ import java.util.ArrayList
* to Kotlin.
*/
public interface ReadableArray {
public fun getArray(index: Int): ReadableArray
public fun getArray(index: Int): ReadableArray?
public fun getBoolean(index: Int): Boolean
@@ -26,9 +26,9 @@ public interface ReadableArray {
public fun getLong(index: Int): Long
public fun getMap(index: Int): ReadableMap
public fun getMap(index: Int): ReadableMap?
public fun getString(index: Int): String
public fun getString(index: Int): String?
public fun getType(index: Int): ReadableType
@@ -1,171 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.bridge;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.infer.annotation.Assertions;
import com.facebook.proguard.annotations.DoNotStrip;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Implementation of a NativeArray that allows read-only access to its members. This will generally
* be constructed and filled in native code so you shouldn't construct one yourself.
*/
@DoNotStrip
public class ReadableNativeArray extends NativeArray implements ReadableArray {
static {
ReactBridge.staticInit();
}
protected ReadableNativeArray() {}
// WriteOnce but not in the constructor fields
private @Nullable Object[] mLocalArray;
private @Nullable ReadableType[] mLocalTypeArray;
private static int jniPassCounter = 0;
public static int getJNIPassCounter() {
return jniPassCounter;
}
private Object[] getLocalArray() {
if (mLocalArray != null) {
return mLocalArray;
}
synchronized (this) {
// Make sure no concurrent call already updated
if (mLocalArray == null) {
jniPassCounter++;
mLocalArray = Assertions.assertNotNull(importArray());
}
}
return mLocalArray;
}
private native Object[] importArray();
private ReadableType[] getLocalTypeArray() {
if (mLocalTypeArray != null) {
return mLocalTypeArray;
}
synchronized (this) {
// Make sure no concurrent call already updated
if (mLocalTypeArray == null) {
jniPassCounter++;
Object[] tempArray = Assertions.assertNotNull(importTypeArray());
mLocalTypeArray = Arrays.copyOf(tempArray, tempArray.length, ReadableType[].class);
}
}
return mLocalTypeArray;
}
private native Object[] importTypeArray();
@Override
public int size() {
return getLocalArray().length;
}
@Override
public boolean isNull(int index) {
return getLocalArray()[index] == null;
}
@Override
public boolean getBoolean(int index) {
return ((Boolean) getLocalArray()[index]).booleanValue();
}
@Override
public double getDouble(int index) {
return ((Double) getLocalArray()[index]).doubleValue();
}
@Override
public int getInt(int index) {
return ((Double) getLocalArray()[index]).intValue();
}
@Override
public long getLong(int index) {
return ((Long) getLocalArray()[index]).longValue();
}
@Override
public @NonNull String getString(int index) {
return (String) getLocalArray()[index];
}
@Override
public @NonNull ReadableNativeArray getArray(int index) {
return (ReadableNativeArray) getLocalArray()[index];
}
@Override
public @NonNull ReadableNativeMap getMap(int index) {
return (ReadableNativeMap) getLocalArray()[index];
}
@Override
public @NonNull ReadableType getType(int index) {
return getLocalTypeArray()[index];
}
@Override
public @NonNull Dynamic getDynamic(int index) {
return DynamicFromArray.create(this, index);
}
@Override
public int hashCode() {
return getLocalArray().hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ReadableNativeArray)) {
return false;
}
ReadableNativeArray other = (ReadableNativeArray) obj;
return Arrays.deepEquals(getLocalArray(), other.getLocalArray());
}
@Override
public @NonNull ArrayList<Object> toArrayList() {
ArrayList<Object> arrayList = new ArrayList<>();
for (int i = 0; i < this.size(); i++) {
switch (getType(i)) {
case Null:
arrayList.add(null);
break;
case Boolean:
arrayList.add(getBoolean(i));
break;
case Number:
arrayList.add(getDouble(i));
break;
case String:
arrayList.add(getString(i));
break;
case Map:
arrayList.add(getMap(i).toHashMap());
break;
case Array:
arrayList.add(getArray(i).toArrayList());
break;
default:
throw new IllegalArgumentException("Could not convert object at index: " + i + ".");
}
}
return arrayList;
}
}
@@ -0,0 +1,92 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.bridge
import com.facebook.proguard.annotations.DoNotStrip
import java.util.ArrayList
import java.util.Arrays
import kotlin.jvm.JvmStatic
/**
* Implementation of a NativeArray that allows read-only access to its members. This will generally
* be constructed and filled in native code so you shouldn't construct one yourself.
*/
@DoNotStrip
public open class ReadableNativeArray protected constructor() : NativeArray(), ReadableArray {
private val localArray: Array<Any?> by
lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
jniPassCounter++
importArray()
}
private external fun importArray(): Array<Any?>
private val localTypeArray: Array<ReadableType> by
lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
jniPassCounter++
val tempArray = importTypeArray()
Arrays.copyOf(tempArray, tempArray.size, Array<ReadableType>::class.java)
}
private external fun importTypeArray(): Array<Any>
override fun size(): Int = localArray.size
override fun isNull(index: Int): Boolean = localArray[index] == null
override fun getBoolean(index: Int): Boolean = localArray[index] as Boolean
override fun getDouble(index: Int): Double = localArray[index] as Double
override fun getInt(index: Int): Int = (localArray[index] as Double).toInt()
override fun getLong(index: Int): Long = localArray[index] as Long
override fun getString(index: Int): String? = localArray[index] as String?
override fun getArray(index: Int): ReadableNativeArray? =
localArray[index] as ReadableNativeArray?
override fun getMap(index: Int): ReadableNativeMap? = localArray[index] as ReadableNativeMap?
override fun getType(index: Int): ReadableType = localTypeArray[index]
override fun getDynamic(index: Int): Dynamic = DynamicFromArray.create(this, index)
override fun hashCode(): Int = localArray.hashCode()
override fun equals(other: Any?): Boolean {
if (other !is ReadableNativeArray) {
return false
}
return localArray.contentDeepEquals(other.localArray)
}
override fun toArrayList(): ArrayList<Any?> {
val arrayList = ArrayList<Any?>()
repeat(size()) { i ->
when (getType(i)) {
ReadableType.Null -> arrayList.add(null)
ReadableType.Boolean -> arrayList.add(getBoolean(i))
ReadableType.Number -> arrayList.add(getDouble(i))
ReadableType.String -> arrayList.add(getString(i))
ReadableType.Map -> arrayList.add(getMap(i)?.toHashMap())
ReadableType.Array -> arrayList.add(getArray(i)?.toArrayList())
}
}
return arrayList
}
private companion object {
@get:JvmStatic
@get:JvmName("getJNIPassCounter")
public var jniPassCounter: Int = 0
private set
}
}
@@ -177,12 +177,9 @@ public open class ReadableNativeMap protected constructor() : NativeMap(), Reada
}
private companion object {
init {
ReactBridge.staticInit()
}
private var jniPassCounter: Int = 0
@JvmStatic public fun getJNIPassCounter(): Int = jniPassCounter
@get:JvmStatic
@get:JvmName("getJNIPassCounter")
public var jniPassCounter: Int = 0
private set
}
}
@@ -1,67 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.bridge;
import androidx.annotation.Nullable;
import com.facebook.infer.annotation.Assertions;
import com.facebook.proguard.annotations.DoNotStrip;
/**
* Implementation of a write-only array stored in native memory. Use {@link Arguments#createArray()}
* if you need to stub out creating this class in a test. TODO(5815532): Check if consumed on read
*/
@DoNotStrip
public class WritableNativeArray extends ReadableNativeArray implements WritableArray {
static {
ReactBridge.staticInit();
}
public WritableNativeArray() {
initHybrid();
}
@Override
public native void pushNull();
@Override
public native void pushBoolean(boolean value);
@Override
public native void pushDouble(double value);
@Override
public native void pushInt(int value);
@Override
public native void pushLong(long value);
@Override
public native void pushString(@Nullable String value);
// Note: this consumes the map so do not reuse it.
@Override
public void pushArray(@Nullable ReadableArray array) {
Assertions.assertCondition(
array == null || array instanceof ReadableNativeArray, "Illegal type provided");
pushNativeArray((ReadableNativeArray) array);
}
// Note: this consumes the map so do not reuse it.
@Override
public void pushMap(@Nullable ReadableMap map) {
Assertions.assertCondition(
map == null || map instanceof ReadableNativeMap, "Illegal type provided");
pushNativeMap((ReadableNativeMap) map);
}
private native void initHybrid();
private native void pushNativeArray(ReadableNativeArray array);
private native void pushNativeMap(ReadableNativeMap map);
}
@@ -0,0 +1,52 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.bridge
import com.facebook.proguard.annotations.DoNotStrip
/**
* Implementation of a write-only array stored in native memory. Use [Arguments#createArray()] if
* you need to stub out creating this class in a test.
*/
@DoNotStrip
public class WritableNativeArray : ReadableNativeArray(), WritableArray {
init {
initHybrid()
}
external override fun pushNull()
external override fun pushBoolean(value: Boolean)
external override fun pushDouble(value: Double)
external override fun pushInt(value: Int)
external override fun pushLong(value: Long)
external override fun pushString(value: String?)
// Note: this consumes the map so do not reuse it.
override fun pushArray(array: ReadableArray?) {
check(array == null || array is ReadableNativeArray) { "Illegal type provided" }
pushNativeArray(array as ReadableNativeArray?)
}
// Note: this consumes the map so do not reuse it.
override fun pushMap(map: ReadableMap?) {
check(map == null || map is ReadableNativeMap) { "Illegal type provided" }
pushNativeMap(map as ReadableNativeMap?)
}
private external fun initHybrid()
private external fun pushNativeArray(array: ReadableNativeArray?)
private external fun pushNativeMap(map: ReadableNativeMap?)
}
@@ -63,10 +63,4 @@ public class WritableNativeMap : ReadableNativeMap(), WritableMap {
private external fun mergeNativeMap(source: ReadableNativeMap)
private external fun initHybrid()
private companion object {
init {
ReactBridge.staticInit()
}
}
}
@@ -5,42 +5,39 @@
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.common;
import com.facebook.infer.annotation.Nullsafe;
package com.facebook.react.common
/**
* Interface for handling a surface in React Native. In mobile platform a surface can be any
* container that holds some {@link View}. For example, a Dialog can be a surface to wrap content
* view object as needed. In VR platform, a surface is provided by Shell panel app sdk, which
* requires custom logic to show/hide. NativeModules requires a surface will delegate interactions
* with the surface to a SurfaceDelegate.
* container that holds some [View]. For example, a Dialog can be a surface to wrap content view
* object as needed. In VR platform, a surface is provided by Shell panel app sdk, which requires
* custom logic to show/hide. NativeModules requires a surface will delegate interactions with the
* surface to a SurfaceDelegate.
*/
@Nullsafe(Nullsafe.Mode.LOCAL)
public interface SurfaceDelegate {
/**
* Create the React content view that uses the appKey as the React application name
*
* @param appKey
*/
void createContentView(String appKey);
public fun createContentView(appKey: String): Unit
/**
* Check if the content view is created and ready to be shown
*
* @return true if the content view is ready to be shown
*/
boolean isContentViewReady();
public fun isContentViewReady(): Boolean
/** Destroy the React content view to avoid memory leak */
void destroyContentView();
public fun destroyContentView(): Unit
/** Show the surface containing the React content view */
void show();
public fun show(): Unit
/** Hide the surface containing the React content view */
void hide();
public fun hide(): Unit
/** Check if the surface is currently showing */
boolean isShowing();
public fun isShowing(): Boolean
}
@@ -16,6 +16,7 @@ import com.facebook.react.bridge.ReactContext
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.common.build.ReactBuildConfig
import com.facebook.react.fabric.ComponentFactory
import com.facebook.react.runtime.BindingsInstaller
import com.facebook.react.runtime.JSCInstance
import com.facebook.react.runtime.ReactHostImpl
import com.facebook.react.runtime.cxxreactpackage.CxxReactPackage
@@ -42,11 +43,12 @@ public object DefaultReactHost {
* `index.<platform>`
* @param jsBundleAssetPath the path to the JS bundle relative to the assets directory. Will be
* composed in a `asset://...` URL
* @param jsBundleFilePath the path to the JS bundle on the filesystem. Will be composed in a
* `file://...` URL
* @param isHermesEnabled whether to use Hermes as the JS engine, default to true.
* @param useDevSupport whether to enable dev support, default to ReactBuildConfig.DEBUG.
* @param cxxReactPackageProviders a list of cxxreactpackage providers (to register c++ turbo
* modules)
* @param jsBundleLoader a [JSBundleLoader] to use for creating the [ReactHost]
*
* TODO(T186951312): Should this be @UnstableReactNativeAPI?
*/
@@ -70,9 +72,9 @@ public object DefaultReactHost {
jsBundleFilePath,
isHermesEnabled,
useDevSupport,
cxxReactPackageProviders) {
throw it
}
cxxReactPackageProviders,
{ throw it },
null)
/**
* Util function to create a default [ReactHost] to be used in your application. This method is
@@ -84,13 +86,15 @@ public object DefaultReactHost {
* `index.<platform>`
* @param jsBundleAssetPath the path to the JS bundle relative to the assets directory. Will be
* composed in a `asset://...` URL
* @param jsBundleFilePath the path to the JS bundle on the filesystem. Will be composed in a
* `file://...` URL
* @param isHermesEnabled whether to use Hermes as the JS engine, default to true.
* @param useDevSupport whether to enable dev support, default to ReactBuildConfig.DEBUG.
* @param cxxReactPackageProviders a list of cxxreactpackage providers (to register c++ turbo
* modules)
* @param jsBundleLoader a [JSBundleLoader] to use for creating the [ReactHost]
* @param exceptionHandler Callback that can be used by React Native host applications to react to
* exceptions thrown by the internals of React Native.
* @param bindingsInstaller that can be used for installing bindings.
*
* TODO(T186951312): Should this be @UnstableReactNativeAPI?
*/
@@ -106,6 +110,7 @@ public object DefaultReactHost {
useDevSupport: Boolean = ReactBuildConfig.DEBUG,
cxxReactPackageProviders: List<(ReactContext) -> CxxReactPackage> = emptyList(),
exceptionHandler: (Exception) -> Unit = { throw it },
bindingsInstaller: BindingsInstaller? = null,
): ReactHost {
if (reactHost == null) {
@@ -128,6 +133,7 @@ public object DefaultReactHost {
jsBundleLoader = bundleLoader,
reactPackages = packageList,
jsRuntimeFactory = jsRuntimeFactory,
bindingsInstaller = bindingsInstaller,
turboModuleManagerDelegateBuilder = defaultTmmDelegateBuilder,
exceptionHandler = exceptionHandler)
val componentFactory = ComponentFactory()
@@ -40,33 +40,27 @@ private constructor(
}
public class Builder : ReactPackageTurboModuleManagerDelegate.Builder() {
private var cxxReactPackageProviders:
MutableList<((context: ReactApplicationContext) -> CxxReactPackage)> =
mutableListOf()
private val cxxReactPackageProviders =
mutableListOf<(context: ReactApplicationContext) -> List<CxxReactPackage>>()
public fun addCxxReactPackage(provider: () -> CxxReactPackage): Builder {
cxxReactPackageProviders.add { _ -> provider() }
return this
public fun addCxxReactPackage(provider: () -> CxxReactPackage): Builder = apply {
cxxReactPackageProviders.add { _ -> listOf(provider()) }
}
public fun addCxxReactPackage(
provider: (context: ReactApplicationContext) -> CxxReactPackage
): Builder {
cxxReactPackageProviders.add(provider)
return this
}
): Builder = apply { cxxReactPackageProviders.add { context -> listOf(provider(context)) } }
public fun addCxxReactPackages(
provider: (context: ReactApplicationContext) -> List<CxxReactPackage>
): Builder = apply { cxxReactPackageProviders.add(provider) }
override fun build(
context: ReactApplicationContext,
packages: List<ReactPackage>
): DefaultTurboModuleManagerDelegate {
val cxxReactPackages = mutableListOf<CxxReactPackage>()
for (cxxReactPackageProvider in cxxReactPackageProviders) {
cxxReactPackages.add(cxxReactPackageProvider(context))
}
return DefaultTurboModuleManagerDelegate(context, packages, cxxReactPackages)
}
): DefaultTurboModuleManagerDelegate =
DefaultTurboModuleManagerDelegate(
context, packages, cxxReactPackageProviders.flatMap { provider -> provider(context) })
}
private companion object {
@@ -9,6 +9,7 @@ package com.facebook.react.devsupport
import android.content.Context
import com.facebook.react.common.SurfaceDelegateFactory
import com.facebook.react.common.build.ReactBuildConfig
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener
import com.facebook.react.devsupport.interfaces.DevLoadingViewManager
import com.facebook.react.devsupport.interfaces.DevSupportManager
@@ -101,7 +102,11 @@ public class DefaultDevSupportManagerFactory : DevSupportManagerFactory {
useDevSupport: Boolean
): DevSupportManager =
if (!useDevSupport) {
ReleaseDevSupportManager()
if (ReactBuildConfig.UNSTABLE_ENABLE_FUSEBOX_RELEASE) {
PerftestDevSupportManager(applicationContext)
} else {
ReleaseDevSupportManager()
}
} else {
BridgelessDevSupportManager(
applicationContext,
@@ -325,11 +325,12 @@ public class DevServerHelper {
private String getInspectorDeviceUrl() {
return String.format(
Locale.US,
"http://%s/inspector/device?name=%s&app=%s&device=%s",
"http://%s/inspector/device?name=%s&app=%s&device=%s&profiling=%b",
mPackagerConnectionSettings.getDebugServerHost(),
Uri.encode(AndroidInfoHelpers.getFriendlyDeviceName()),
Uri.encode(mPackageName),
Uri.encode(getInspectorDeviceId()));
Uri.encode(getInspectorDeviceId()),
InspectorFlags.getIsProfilingBuild());
}
public void downloadBundleFromURL(
@@ -17,4 +17,6 @@ public object InspectorFlags {
}
@DoNotStrip @JvmStatic public external fun getFuseboxEnabled(): Boolean
@DoNotStrip @JvmStatic public external fun getIsProfilingBuild(): Boolean
}
@@ -43,7 +43,7 @@ internal class LogBoxDialogSurfaceDelegate(private val devSupportManager: DevSup
}
override fun show() {
if (isShowing || !isContentViewReady) {
if (isShowing() || !isContentViewReady()) {
return
}
val context = devSupportManager.currentActivity
@@ -61,7 +61,7 @@ internal class LogBoxDialogSurfaceDelegate(private val devSupportManager: DevSup
}
override fun hide() {
if (isShowing) {
if (isShowing()) {
dialog?.dismiss()
}
(reactRootView?.parent as ViewGroup?)?.removeView(reactRootView)
@@ -25,7 +25,7 @@ public class LogBoxModule(
override fun show() {
UiThreadUtil.runOnUiThread {
if (!surfaceDelegate.isContentViewReady) {
if (!surfaceDelegate.isContentViewReady()) {
/**
* LogBoxModule can be rendered in different surface. By default, it will use LogBoxDialog
* to wrap the content of logs. In other platform (for example VR), a surfaceDelegate can be
@@ -625,10 +625,10 @@ public class FabricUIManager
* @return if theme data is available in the output parameters.
*/
public boolean getThemeData(int surfaceId, float[] defaultTextInputPadding) {
Context context =
mMountingManager.getSurfaceManagerEnforced(surfaceId, "getThemeData").getContext();
SurfaceMountingManager surfaceMountingManager = mMountingManager.getSurfaceManager(surfaceId);
Context context = surfaceMountingManager != null ? surfaceMountingManager.getContext() : null;
if (context == null) {
FLog.w(TAG, "\"themedReactContext\" is null when call \"getThemeData\"");
FLog.w(TAG, "Couldn't get context for surfaceId %d in getThemeData", surfaceId);
return false;
}
@@ -427,6 +427,28 @@ public class MountingManager {
attachmentsPositions);
}
/**
* @deprecated THIS PREFETCH METHOD IS EXPERIMENTAL, DO NOT USE IT FOR PRODUCTION CODE. IT WILL
* MOST LIKELY CHANGE OR BE REMOVED IN THE FUTURE.
* @param reactContext
* @param componentName
* @param surfaceId {@link int} surface ID
* @param reactTag reactTag that should be set as ID of the view instance
* @param params {@link MapBuffer} prefetch request params defined in C++
*/
@AnyThread
@Deprecated
public void experimental_prefetchResource(
ReactContext reactContext,
String componentName,
int surfaceId,
int reactTag,
MapBuffer params) {
mViewManagerRegistry
.get(componentName)
.experimental_prefetchResource(reactContext, surfaceId, reactTag, params);
}
public void enqueuePendingEvent(
int surfaceId,
int reactTag,
@@ -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<<b1ad8179cf22c2e97f623435bf152aab>>
* @generated SignedSource<<6d8d8f4b81d7be882b315d0960499dcb>>
*/
/**
@@ -130,6 +130,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun enableIOSViewClipToPaddingBox(): Boolean = accessor.enableIOSViewClipToPaddingBox()
/**
* When enabled, Andoid will build and initiate image prefetch requests on ImageShadowNode::layout
*/
@JvmStatic
public fun enableImagePrefetchingAndroid(): Boolean = accessor.enableImagePrefetchingAndroid()
/**
* When enabled, LayoutAnimations API will animate state changes on Android.
*/
@@ -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<<7dd21b62dfe429aecdbd179cb482fb26>>
* @generated SignedSource<<031fce8e8b4c20a3e3d6dbecf94d138a>>
*/
/**
@@ -37,6 +37,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
private var enableFixForViewCommandRaceCache: Boolean? = null
private var enableGranularShadowTreeStateReconciliationCache: Boolean? = null
private var enableIOSViewClipToPaddingBoxCache: Boolean? = null
private var enableImagePrefetchingAndroidCache: Boolean? = null
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
private var enableLongTaskAPICache: Boolean? = null
@@ -219,6 +220,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
return cached
}
override fun enableImagePrefetchingAndroid(): Boolean {
var cached = enableImagePrefetchingAndroidCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.enableImagePrefetchingAndroid()
enableImagePrefetchingAndroidCache = cached
}
return cached
}
override fun enableLayoutAnimationsOnAndroid(): Boolean {
var cached = enableLayoutAnimationsOnAndroidCache
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<<fcfded14a5fe05501892993c1f58f3ed>>
* @generated SignedSource<<35811667ac2543e1f64e27bbdb483ec1>>
*/
/**
@@ -62,6 +62,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
@DoNotStrip @JvmStatic public external fun enableIOSViewClipToPaddingBox(): Boolean
@DoNotStrip @JvmStatic public external fun enableImagePrefetchingAndroid(): Boolean
@DoNotStrip @JvmStatic public external fun enableLayoutAnimationsOnAndroid(): Boolean
@DoNotStrip @JvmStatic public external fun enableLayoutAnimationsOnIOS(): 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<<86d8dd894e80a788af7f47172d30d33c>>
* @generated SignedSource<<9d829c58e49164a0b2b6b66bc0ce088a>>
*/
/**
@@ -57,6 +57,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
override fun enableIOSViewClipToPaddingBox(): Boolean = false
override fun enableImagePrefetchingAndroid(): Boolean = false
override fun enableLayoutAnimationsOnAndroid(): Boolean = false
override fun enableLayoutAnimationsOnIOS(): 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<<4bb5173b9ba1d3e620f3a7d613b27ac7>>
* @generated SignedSource<<0121e113410a5b0e14eaf74a3076df2f>>
*/
/**
@@ -41,6 +41,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
private var enableFixForViewCommandRaceCache: Boolean? = null
private var enableGranularShadowTreeStateReconciliationCache: Boolean? = null
private var enableIOSViewClipToPaddingBoxCache: Boolean? = null
private var enableImagePrefetchingAndroidCache: Boolean? = null
private var enableLayoutAnimationsOnAndroidCache: Boolean? = null
private var enableLayoutAnimationsOnIOSCache: Boolean? = null
private var enableLongTaskAPICache: Boolean? = null
@@ -240,6 +241,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
return cached
}
override fun enableImagePrefetchingAndroid(): Boolean {
var cached = enableImagePrefetchingAndroidCache
if (cached == null) {
cached = currentProvider.enableImagePrefetchingAndroid()
accessedFeatureFlags.add("enableImagePrefetchingAndroid")
enableImagePrefetchingAndroidCache = cached
}
return cached
}
override fun enableLayoutAnimationsOnAndroid(): Boolean {
var cached = enableLayoutAnimationsOnAndroidCache
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<<2217f2b9992c9424c3d1d221bdfa2236>>
* @generated SignedSource<<2787d9027695dd14ec6b917a32a1a6de>>
*/
/**
@@ -57,6 +57,8 @@ public interface ReactNativeFeatureFlagsProvider {
@DoNotStrip public fun enableIOSViewClipToPaddingBox(): Boolean
@DoNotStrip public fun enableImagePrefetchingAndroid(): Boolean
@DoNotStrip public fun enableLayoutAnimationsOnAndroid(): Boolean
@DoNotStrip public fun enableLayoutAnimationsOnIOS(): Boolean
@@ -14,36 +14,13 @@ import com.facebook.react.turbomodule.core.interfaces.TurboModule
* so Java modules don't have to be instantiated at React Native start up.
*/
public class ReactModuleInfo(
private val _name: String,
private val _className: String,
private val _canOverrideExistingModule: Boolean,
private val _needsEagerInit: Boolean,
@get:JvmName("name") public val name: String,
@get:JvmName("className") public val className: String,
@get:JvmName("canOverrideExistingModule") public val canOverrideExistingModule: Boolean,
@get:JvmName("needsEagerInit") public val needsEagerInit: Boolean,
public val isCxxModule: Boolean,
public val isTurboModule: Boolean
) {
@Deprecated("use ReactModuleInfo(String, String, boolean, boolean, boolean, boolean)]")
public constructor(
name: String,
className: String,
canOverrideExistingModule: Boolean,
needsEagerInit: Boolean,
@Suppress("UNUSED_PARAMETER") hasConstants: Boolean,
isCxxModule: Boolean,
isTurboModule: Boolean
) : this(name, className, canOverrideExistingModule, needsEagerInit, isCxxModule, isTurboModule)
public fun name(): String = _name
public fun className(): String = _className
public fun canOverrideExistingModule(): Boolean = _canOverrideExistingModule
public fun needsEagerInit(): Boolean = _needsEagerInit
@Deprecated("this is hardcoded to return true, regardless if the module has constants or not")
public fun hasConstants(): Boolean = true
public companion object {
/**
* Checks if the passed class is a TurboModule. Useful to populate the parameter [isTurboModule]
@@ -4,6 +4,8 @@
* 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") // Suppressing deprecation of NotThreadSafeViewHierarchyUpdateDebugListener
package com.facebook.react.modules.debug
@@ -60,9 +60,9 @@ internal class ReactOkHttpNetworkFetcher(private val okHttpClient: OkHttpClient)
val headers = OkHttpCompat.getHeadersFromMap(requestHeaders)
val request =
Request.Builder()
.headers(headers)
.cacheControl(cacheControlBuilder.build())
.url(uri.toString())
.headers(headers)
.get()
.build()
fetchWithRequest(fetchState, callback, request)
@@ -249,8 +249,8 @@ public class ImageLoaderModule : NativeImageLoaderAndroidSpec, LifecycleEventLis
val result: WritableMap = Arguments.createMap()
val imagePipeline: ImagePipeline = this@ImageLoaderModule.imagePipeline
for (i in 0 until uris.size()) {
val uriString: String = uris.getString(i)
if (uriString.isNotEmpty()) {
val uriString = uris.getString(i)
if (!uriString.isNullOrEmpty()) {
val uri = Uri.parse(uriString)
if (imagePipeline.isInBitmapMemoryCache(uri)) {
result.putString(uriString, "memory")

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