From 82a5226e7a8b90b37923fb6574d3b356a1d81743 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Aug 2024 10:19:14 +0200 Subject: [PATCH 01/38] chore(deps): bump rexml from 3.2.9 to 3.3.6 in /Example (#2314) Bumps [rexml](https://github.com/ruby/rexml) from 3.2.9 to 3.3.6.
Release notes

Sourced from rexml's releases.

REXML 3.3.6 - 2024-08-22

Improvements

Fixes

Thanks

REXML 3.3.5 - 2024-08-12

Fixes

... (truncated)

Changelog

Sourced from rexml's changelog.

3.3.6 - 2024-08-22 {#version-3-3-6}

Improvements

Fixes

Thanks

3.3.5 - 2024-08-12 {#version-3-3-5}

Fixes

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=rexml&package-manager=bundler&previous-version=3.2.9&new-version=3.3.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/software-mansion/react-native-screens/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Example/Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Example/Gemfile.lock b/Example/Gemfile.lock index 87401e9531..8da5212e64 100644 --- a/Example/Gemfile.lock +++ b/Example/Gemfile.lock @@ -84,7 +84,7 @@ GEM netrc (0.11.0) nkf (0.2.0) public_suffix (4.0.7) - rexml (3.2.9) + rexml (3.3.6) strscan ruby-macho (2.5.1) strscan (3.1.0) @@ -92,13 +92,13 @@ GEM ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - xcodeproj (1.24.0) + xcodeproj (1.25.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.2, < 4.0) PLATFORMS ruby From b7a51fc6703565a789eb647b0a8cca3ded660819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrycja=20Kali=C5=84ska?= <59940332+patrycjakalinska@users.noreply.github.com> Date: Thu, 29 Aug 2024 11:52:09 +0200 Subject: [PATCH 02/38] docs: Fix placement of Hero on big screens (#2305) Before: ![image](https://github.com/user-attachments/assets/2cfbec89-ddd2-46b0-ac1f-aadd7a8271d9) After: image --- .../Hero/ScreenSequence/styles.module.css | 20 +++++++++++++++++++ .../Hero/StartScreen/styles.module.css | 16 +-------------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/docs/src/components/Hero/ScreenSequence/styles.module.css b/docs/src/components/Hero/ScreenSequence/styles.module.css index 2651a9ebfd..271678ed76 100644 --- a/docs/src/components/Hero/ScreenSequence/styles.module.css +++ b/docs/src/components/Hero/ScreenSequence/styles.module.css @@ -8,6 +8,26 @@ align-items: center; } +@media (min-width: 2920px) { + .screens { + top: 3rem; + min-height: 70%; + } +} +@media (min-width: 3000px) and (min-height: 1500px) { + .screens { + top: -3vh; + min-height: 50%; + } +} + +@media (min-width: 3000px) and (min-height: 2000px) { + .screens { + top: -3vh; + min-height: 50%; + } +} + @media (max-width: 2000px) { .screens { top: 4rem; diff --git a/docs/src/components/Hero/StartScreen/styles.module.css b/docs/src/components/Hero/StartScreen/styles.module.css index 6804223a85..b5c1c1e8e0 100644 --- a/docs/src/components/Hero/StartScreen/styles.module.css +++ b/docs/src/components/Hero/StartScreen/styles.module.css @@ -25,7 +25,7 @@ color: var(--swm-blue-light-80); } -[data-theme='dark'] .headingLabel :nth-child(2) { +[data-theme="dark"] .headingLabel :nth-child(2) { color: var(--swm-blue-dark-80); } @@ -55,20 +55,6 @@ justify-content: flex-start; } -@media (min-width: 2920px) { - .hero { - flex-direction: row-reverse; - margin-bottom: 0; - align-items: center; - } - .subheadingLabel { - width: 100%; - } - .heading { - margin: 0; - } -} - @media (max-width: 996px) { .hero { margin-bottom: 1rem; From fcee5e15f871a0054018119ad2e2bf9425d85c5e Mon Sep 17 00:00:00 2001 From: Ilia Kurganskii Date: Mon, 2 Sep 2024 10:22:31 +0200 Subject: [PATCH 03/38] docs(readme): update FullWindowOverlay example path (#2326) ## Description Update path for FullWindowOverlay example ## Changes - Updated `README.md` docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 47c9fb4300..b75cb3c413 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ To take advantage of the native stack navigator primitive for React Navigation t ## `FullWindowOverlay` -Native `iOS` component for rendering views straight under the `Window`. Based on `RCTPerfMonitor`. You should treat it as a wrapper, providing full-screen, transparent view which receives no props and should ideally render one child `View`, being the root of its view hierarchy. For the example usage, see https://github.com/software-mansion/react-native-screens/blob/main/TestsExample/src/Test1096.tsx +Native `iOS` component for rendering views straight under the `Window`. Based on `RCTPerfMonitor`. You should treat it as a wrapper, providing full-screen, transparent view which receives no props and should ideally render one child `View`, being the root of its view hierarchy. For the example usage, see https://github.com/software-mansion/react-native-screens/blob/main/apps/src/tests/Test1096.tsx ## Interop with [react-native-navigation](https://github.com/wix/react-native-navigation) From ee7915f2c92157368029187c16fc313a6f6ab28b Mon Sep 17 00:00:00 2001 From: Kirill Zyusko Date: Mon, 2 Sep 2024 10:28:12 +0200 Subject: [PATCH 04/38] fix: do not force set `translucent` nav bar (until it's explicitly specified) (#2301) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description I have next navigator structure: - JS - native-stack `native-stack` navigator customizes options as: ```ts { headerShown: false, statusBarTranslucent: true, navigationBarColor: "#FFFFFF", navigationBarTranslucent: true, }, ``` When I go to `native-stack` - everything works well: the nav bar changes color. However, when I go back, then I'm getting a gray space in the bottom of my screen. It happens because we disable mode `edge-to-edge` by calling `WindowCompat.setDecorFitsSystemWindows(window, true)` (the gray space appears because before we were already in edge-to-edge mode, because I had `KeyboardProvider` mounted in `App.tsx`). So to fix this problem I decided explicitly check for boolean value for `navigationBarTranslucent` and set `decorFitsSystemWindows` only when we have an actual boolean value. If you think that it's a problem in my project, then, please, let me know the way to fix it 😊 ## Changes - call `WindowCompat.setDecorFitsSystemWindows(window, true)` only if `isNavigationBarTranslucent` has a boolean value; ## Screenshots / GIFs ### Before ![telegram-cloud-photo-size-2-5321328488650760881-y](https://github.com/user-attachments/assets/4c1ef654-3146-44bd-aa00-6a810c2aa0aa) ### After ![telegram-cloud-photo-size-2-5321328488650760882-y](https://github.com/user-attachments/assets/7920cf2c-e5b7-46e9-bb75-a581ce2dab2a) ## Test code and steps to reproduce I tested in `react-native-keyboard-controller` example app, but if you need to test it in your code - let me know, and I'll try to prepare a reproduction code. ## Checklist - [x] Included code example that can be used to test this change - [x] Updated TS types - [x] Updated documentation: - [x] https://github.com/software-mansion/react-native-screens/blob/main/guides/GUIDE_FOR_LIBRARY_AUTHORS.md - [x] https://github.com/software-mansion/react-native-screens/blob/main/native-stack/README.md - [x] https://github.com/software-mansion/react-native-screens/blob/main/src/types.tsx - [x] https://github.com/software-mansion/react-native-screens/blob/main/src/native-stack/types.tsx - [x] Ensured that CI passes --- .../src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt index cbdb5478df..37aefe87b5 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenWindowTraits.kt @@ -225,7 +225,7 @@ object ScreenWindowTraits { val window = activity.window val screenForNavBarTranslucent = findScreenForTrait(screen, WindowTraits.NAVIGATION_BAR_TRANSLUCENT) - val translucent = screenForNavBarTranslucent?.isNavigationBarTranslucent ?: false + val translucent = screenForNavBarTranslucent?.isNavigationBarTranslucent ?: return // Following method controls whether to display edge-to-edge content that draws behind the navigation bar WindowCompat.setDecorFitsSystemWindows(window, !translucent) From d424e1a20fe55688ec9b15ec74d21b2a93dc8bb6 Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 3 Sep 2024 11:21:32 +0100 Subject: [PATCH 05/38] fix(Android): getChildDrawingOrder when using refreshcontrol (#2330) ## Description Fixes #2329 ## Changes - Changes how we check if the child is a CircleImageView to be minification safe ## Test code and steps to reproduce Build `[this](https://github.com/BenIrving/refreshcontrolrepro/tree/main)` repro using this changeset, observe no crash when navigating between screens. You can also check `Test640.tsx` test by going into the second screen (by button), then try to manually refresh list by swiping down (until the refresh control will show). During the refresh, try to go back to the first screen - application shouldn't crash. ## Checklist - [x] Ensured that CI passes Co-authored-by: Ben Irving --- android/src/main/java/com/swmansion/rnscreens/Screen.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/swmansion/rnscreens/Screen.kt b/android/src/main/java/com/swmansion/rnscreens/Screen.kt index 6bbfda09cc..4ae30f5538 100644 --- a/android/src/main/java/com/swmansion/rnscreens/Screen.kt +++ b/android/src/main/java/com/swmansion/rnscreens/Screen.kt @@ -9,9 +9,11 @@ import android.view.View import android.view.ViewGroup import android.view.WindowManager import android.webkit.WebView +import android.widget.ImageView import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.children import androidx.fragment.app.Fragment +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.facebook.react.bridge.GuardedRunnable import com.facebook.react.bridge.ReactContext import com.facebook.react.uimanager.UIManagerHelper @@ -363,7 +365,7 @@ class Screen( parent?.let { for (i in 0 until it.childCount) { val child = it.getChildAt(i) - if (child.javaClass.simpleName.equals("CircleImageView")) { + if (parent is SwipeRefreshLayout && child is ImageView) { // SwipeRefreshLayout class which has CircleImageView as a child, // does not handle `startViewTransition` properly. // It has a custom `getChildDrawingOrder` method which returns From ef475388882abd74f545b91a8d3bddffc87481f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrycja=20Kali=C5=84ska?= <59940332+patrycjakalinska@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:22:57 +0200 Subject: [PATCH 06/38] docs: add Testimonials (#2333) This PR adds gathered Testimonials to Screens landing page image --- .../Testimonials/TestimonialList/index.tsx | 75 +++++++++++++------ docs/src/pages/index.js | 4 +- 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/docs/src/components/Testimonials/TestimonialList/index.tsx b/docs/src/components/Testimonials/TestimonialList/index.tsx index 2a008f021c..c8ffa85156 100644 --- a/docs/src/components/Testimonials/TestimonialList/index.tsx +++ b/docs/src/components/Testimonials/TestimonialList/index.tsx @@ -5,33 +5,62 @@ import TestimonialItem from '@site/src/components/Testimonials/TestimonialItem'; const items = [ { - author: 'Test author', - company: 'Test', - body: 'Screens are the best ever and ever - I love using it!', - link: 'https://test.com/', + author: 'Satyajit Sahoo', + company: 'Callstack', + body: "React Navigation wouldn't be the same today without React Native Screens. Gotta give kudos to the Screens team for bringing native navigation with a nice API. And they are always hard at work to bring more native features as well!", + link: 'https://x.com/satya164/status/1826694902660694028', image: { - alt: 'test', - src: '/img/logo.svg', + alt: 'satya', + src: 'https://pbs.twimg.com/profile_images/1426585051379159040/RG8CUmff_400x400.jpg', }, }, { - author: 'Test author', - company: 'Test', - body: 'Screens are the best ever and ever - I love using it!', - link: 'https://test.com/', + author: 'Ferran Negre Pizzaro', + company: 'FitHero', + body: 'I would never build a serious React Native app without it.', + link: 'https://x.com/ferrannp/status/1826734343571796317', image: { - alt: 'test', - src: '/img/logo.svg', + alt: 'ferran', + src: 'https://pbs.twimg.com/profile_images/1225546442917515264/OBZyRYWO_400x400.jpg', }, }, { - author: 'Test author', - company: 'Test', - body: 'Screens are the best ever and ever - I love using it!', - link: 'https://test.com/', + author: 'Sébastien Lorber', + company: 'This Week In React', + body: 'React Native Screens is what makes React Native navigation truly competitive against native apps', + link: 'https://x.com/sebastienlorber/status/1828760445106466959', image: { - alt: 'test', - src: '/img/logo.svg', + alt: 'seb', + src: 'https://pbs.twimg.com/profile_images/573206276819140608/gKAusMeX_400x400.jpeg', + }, + }, + { + author: 'Jamon Holmgren', + company: 'Infinite Red', + body: 'React Native Screens is one of the most underrated React Native libraries!', + link: 'https://x.com/jamonholmgren/status/1826713786797228166', + image: { + alt: 'jamon', + src: 'https://pbs.twimg.com/profile_images/1712505856905170944/LDFMYGSQ_400x400.jpg', + }, + }, + { + author: 'Kwesi Kay', + body: "React Native Screens has been a game-changer for me! It optimizes performance by reducing memory usage and makes navigation smoother, especially in large apps. Couldn't imagine building without it now! 😍", + link: 'https://x.com/EiiKwesiKay/status/1826282042965000267', + image: { + alt: 'kwesikay', + src: 'https://pbs.twimg.com/profile_images/1823345356794449920/UVMh-ABt_400x400.jpg', + }, + }, + { + author: 'Brent Vatne', + company: 'Expo', + body: "react-native-screens is one of the most essential libraries in the ecosystem. it's a crucial building block for react-navigation and expo-router, and therefore nearly all react-native apps! native stack in particular does tons of heavy lifting to make your apps feel fantastic.", + link: 'https://x.com/notbrent/status/1826699409738137796', + image: { + alt: 'brent', + src: 'https://pbs.twimg.com/profile_images/1509282922498428929/gV2uTCff_400x400.jpg', }, }, ]; @@ -42,7 +71,7 @@ const TestimonialList = () => { useEffect(() => { const updateHeight = () => { const testimonialContainer = document.querySelector( - `.testimonialContainer-${activeIndex}` + `.testimonialContainer-${activeIndex}`, ); const testimonialSlides = document.querySelector('.testimonialSlides'); @@ -73,7 +102,7 @@ const TestimonialList = () => {
{ {items[i + 1].body} )} -
+ , ); } @@ -104,7 +133,7 @@ const TestimonialList = () => { key={idx} className={clsx( styles.testimonialSlide, - activeIndex === idx ? styles.activeTestimonialSlide : '' + activeIndex === idx ? styles.activeTestimonialSlide : '', )}> {item} @@ -116,7 +145,7 @@ const TestimonialList = () => { key={idx} className={clsx( styles.dot, - idx === activeIndex && styles.activeDot + idx === activeIndex && styles.activeDot, )} onClick={() => handleDotClick(idx)} /> diff --git a/docs/src/pages/index.js b/docs/src/pages/index.js index eb707d0be0..185bee1e18 100644 --- a/docs/src/pages/index.js +++ b/docs/src/pages/index.js @@ -24,9 +24,9 @@ export default function Home() {
- {/*
+ -
*/} +
Date: Thu, 12 Sep 2024 09:27:52 +0200 Subject: [PATCH 07/38] fix(Android): Request layout manually for CustomToolbar below Android API 29 (#2332) ## Description On Android API 29, while using `windowSoftInputMode` with `adjustPan` option, requestLayout is not being called while subviews are being added. That's because while ScreenStackHeaderConfig adds view to the toolbar, onMeasure is being called and even if we're calling `requestLayout` on parent, Android is returning from requesting the layout, as there's somehow ongoing layout. This is not the case for Android API 30 and higher. The solution is to request another layout via ReactChoreographer (same as in ScreenContainer) to call our own layout callback on the next frame. ## Changes - Request layout via ReactChoreographer on `requestLayout` call in CustomToolbar class ## Screenshots / GIFs
BEFORE ![CleanShot 2024-09-03 at 17 59 13](https://github.com/user-attachments/assets/3f7952a5-6430-4b25-b587-4690fac236d3)
AFTER ![CleanShot 2024-09-03 at 17 51 14](https://github.com/user-attachments/assets/f2551b98-5de1-4021-8c72-0e4718aaaf45)
## Test code and steps to reproduce Use `Test2332.tsx` test case to check whether this PR works properly. ## Checklist - [x] Included code example that can be used to test this change - [ ] Ensured that CI passes --------- Co-authored-by: Kacper Kafara --- .../com/swmansion/rnscreens/CustomToolbar.kt | 41 ++++++++- apps/src/tests/Test2332.tsx | 86 +++++++++++++++++++ apps/src/tests/index.ts | 2 +- 3 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 apps/src/tests/Test2332.tsx diff --git a/android/src/main/java/com/swmansion/rnscreens/CustomToolbar.kt b/android/src/main/java/com/swmansion/rnscreens/CustomToolbar.kt index 7168a4c6fd..0682ebc063 100644 --- a/android/src/main/java/com/swmansion/rnscreens/CustomToolbar.kt +++ b/android/src/main/java/com/swmansion/rnscreens/CustomToolbar.kt @@ -2,11 +2,50 @@ package com.swmansion.rnscreens import android.annotation.SuppressLint import android.content.Context +import android.os.Build import androidx.appcompat.widget.Toolbar +import com.facebook.react.modules.core.ChoreographerCompat +import com.facebook.react.modules.core.ReactChoreographer // This class is used to store config closer to search bar @SuppressLint("ViewConstructor") // Only we construct this view, it is never inflated. open class CustomToolbar( context: Context, val config: ScreenStackHeaderConfig, -) : Toolbar(context) +) : Toolbar(context) { + private var isLayoutEnqueued = false + private val layoutCallback: ChoreographerCompat.FrameCallback = + object : ChoreographerCompat.FrameCallback() { + override fun doFrame(frameTimeNanos: Long) { + isLayoutEnqueued = false + measure( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY), + ) + layout(left, top, right, bottom) + } + } + + override fun requestLayout() { + super.requestLayout() + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { + // Below Android API 29, layout is not being requested when subviews are being added to the layout, + // leading to having their subviews in position 0,0 of the toolbar (as Android don't calculate + // the position of each subview, even if Yoga has correctly set their width and height). + // This is mostly the issue, when windowSoftInputMode is set to adjustPan in AndroidManifest. + // Thus, we're manually calling the layout **after** the current layout. + @Suppress("SENSELESS_COMPARISON") // mLayoutCallback can be null here since this method can be called in init + if (!isLayoutEnqueued && layoutCallback != null) { + isLayoutEnqueued = true + // we use NATIVE_ANIMATED_MODULE choreographer queue because it allows us to catch the current + // looper loop instead of enqueueing the update in the next loop causing a one frame delay. + ReactChoreographer + .getInstance() + .postFrameCallback( + ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, + layoutCallback, + ) + } + } + } +} diff --git a/apps/src/tests/Test2332.tsx b/apps/src/tests/Test2332.tsx new file mode 100644 index 0000000000..9728439194 --- /dev/null +++ b/apps/src/tests/Test2332.tsx @@ -0,0 +1,86 @@ +/** + * + * IMPORTANT! READ BEFORE TESTING! + * Remember to switch windowSoftInputMode to `adjustPan` in AndroidManifest.xml file. + * + */ + +import React, { useLayoutEffect } from 'react'; +import { NavigationContainer } from '@react-navigation/native'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; +import { Button, Text, TextInput, View } from 'react-native'; +import { NativeStackNavigationProp } from '@react-navigation/native-stack'; +import { HeaderButton } from '@react-navigation/elements'; +type RootStackNavigatorParamsList = { + Home: undefined; + Details: undefined; +}; +const Stack = createNativeStackNavigator(); +const HomeScreen = () => { + const navigation = + useNavigation>(); + const onHandlePress = () => { + navigation.navigate('Details'); + }; + return ( + + HomeScreen + +