Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: software-mansion/react-native-screens
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4.22.0
Choose a base ref
...
head repository: software-mansion/react-native-screens
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4.23.0
Choose a head ref
  • 5 commits
  • 16 files changed
  • 4 contributors

Commits on Feb 3, 2026

  1. chore(Android): run :spotlessApply (#3614)

    For some reason `yarn lint-android` returns success locally, while
    the CI fails. Running `./gradlew :spotlessApply` fixes the issue.
    kkafar authored Feb 3, 2026
    Configuration menu
    Copy the full SHA
    5a6f842 View commit details
    Browse the repository at this point in the history

Commits on Feb 4, 2026

  1. feat(Android, Stack v5): allow for nested container pop via JS (#3612)

    ## Description
      
    Previously it has not been possible to pop nested container via JS.
    When there was only a single screen left in the JS stack state, the
    reducer would deny removing it and would just ignore the operation
    printing a warning that pop operation requires at least two screens.
    
    Currently, in such scenario the parent `StackContainer` (JS component)
    will be asked to pop whole screen that hosts the nested container.
    
    ## Changes
    
    This is achieved by changes in stack container state reducer.
    Previously it operated directly on stack, but now I need to somehow
    communicate that an action has not been performed directly on the
    container and must be forwarded to parent container. We can
    not use the `parentNavigation` directly in the reducer, because:
    
    1. reducer should be pure,
    2. we can not dispatch an action directly to the parent container during
    render (and this is when the state reducing takes place), React
    treats it as an error.
    
    Therefore, I see two possibilities here. Either we move all the
    `StackContainer` state to some centralized place (similarly to what
    react-navigation does with `NavigationContainer`) or we stay with
    current approach (each `StackContainer` owns its state) but we emit
    this intent as an side effect.
    
    Right now I went with second option. Reducer, when it find it makes
    sense, not only updates the stack state, but also produces side effects
    to be performed. Currently, there is only single side effect:
    `PopContainerStackNavigationEffect`, but I found it low cost to make it
    a bit more generic.
    
    Reducer produces the side effect, which is later consumed by the new
    `useParentNavigationEffect` hook.
    
    Important thing to note in this implementation is the referential
    stability of the effects array. The state object id changes every time
    `state.stack` or `state.effects` change. However, `state.effects` object
    id stays the same as long as there is no change to prevent excessive
    rendering.
    
    Given a nested stack, with only a single screen in the nested stack,
    the flow is as follows:
    
    1. `navigation.pop` is dispatched to the nested stack, this triggers
        render.
    2. Reducer detects that it has only a single screen & can not perform
        the action, therefore it produces new state with new effects array
        containing the `PopContainerStackNavigationEffect`.
    3. The `useParentNavigationEffect` schedules the `useEffect`, which is
    executed after this render.
    4. The `useEffect` is executed triggering render of the outer container
    and consuming the effect (trigger render of the inner container).
    5. New render starts from the outer container -> it performs the
        navigation action, detaching the screen that hosts nested container
    6. During the same render as in 5., nested container clears its
        `state.effects`.
    7. After the dismiss completes, `pop-completed` operation is dispatched
    by event listeners & hosting screen & nested container are cleared from
    the state (they no longer render).
    
    > [!note]
    > Thing to note here, is that the nested stack's only screen, when it's
    > being dismissed it sends `onDismissed(isNativeDismiss=true)` event,
    > because it is dismissed & it's activityMode has never been changed to
    > `detached`. I don't think this is causing any problems right now,
    > but it is definitely something to be aware of.
    
    What happens if there is only a single screen in outer stack & it
    hosts the nested stack? Nothing. Renders are triggered, but there is no
    one to handle that operation.
    
    ## Visual documentation
    
    | before | after | 
    | -- | -- | 
    | <video
    src=https://github.com/user-attachments/assets/836181fb-4f94-488f-93bd-27a58a3e2f20
    alt="before" /> | <video
    src=https://github.com/user-attachments/assets/84997062-07d6-4a48-878b-08d04e3891be
    alt="after" /> |
    
    
    
    
    ## Test plan
    
    I'm using `TestStackNesting`.
    Just as the video shows.
    
    ## Checklist
    
    - [x] Included code example that can be used to test this change.
    - [x] Updated / created local changelog entries in relevant test files.
    - [x] For visual changes, included screenshots / GIFs / recordings
    documenting the change.
    - [x] For API changes, updated relevant public types.
    - [x] Ensured that CI passes (all but Android lint - I'll fix it
    separately one day)
    kkafar authored Feb 4, 2026
    Configuration menu
    Copy the full SHA
    c72539d View commit details
    Browse the repository at this point in the history

Commits on Feb 5, 2026

  1. fix(android): default ScreenStackHeaderSubview type is LEFT (#3619)

    ## Description
    
    <!--
    Description and motivation for this PR. 
    This section should include "what & why".
    
    Please link all related issues that merging this PR should close,
    by using the `Closes #<issue-number>` syntax.
    
    For example: 
    Closes #12345.
    -->
    
    The default value for. the `ScreenStackHeaderSubview` type is `LEFT`.
    This can also be derived from the codegen spec:
    
    
    https://github.com/software-mansion/react-native-screens/blob/c72539d598d37ccbcd44a380ce017441fc8b3eed/src/fabric/ScreenStackHeaderSubviewNativeComponent.ts#L15
    
    Now, its important that the native side always matches the codegen side.
    I noticed this since i was turning on the new props 2.0 diffing
    mechanism. With that enabled, you won't receive props on the native view
    manager side that are equal to the default prop value.
    
    See here:
    
    <img width="2841" height="525" alt="Screenshot 2026-02-04 at 16 43 38"
    src="https://github.com/user-attachments/assets/3ae47738-7e75-4d8a-b24f-a04e80c096e3"
    />
    
    This is not a bug in react-native, that's how they intended it, see this
    issue:
    
    -
    facebook/react-native#55249 (comment)
    
    
    ## Changes
    
    <!--
    This is "how" of the PR description.
    
    Please describe things you've changed here, make a **high level**
    overview,
    if change is simple you can omit this section.
    
    For example:
    
    - Updated `about.md` docs
    -->
    
    Change default type from right to left to match codegen spec.
    
    ## Before & after - visual documentation
    
    <!--
    This section is MANDATORY for any PR that introduces any visual changes.
    
    If your PR does not introduce such changes, please omit this section.
    
    Consider using a table here to position the recordings / screenshots 
    next to each other.
    
    | Before | After |
    | --- | --- |
    | ![Before](before.png) | ![After](after.png) |
    
    Alternatively add two sections - Before & After
    
    ### Before
    
    ### After
    -->
    
    ## Test plan
    
    <!--
    Please name all newly added and existing test files that you tested the
    changes with.
    This section should also contain short description of steps to reproduce
    the issue.
    
    The reproduction code should be minimal & complete. Don't exclude
    exports or remove "not important" parts of reproduction example.
    -->
    
    ## Checklist
    
    - [ ] Included code example that can be used to test this change.
    - [ ] Updated / created local changelog entries in relevant test files.
    - [ ] For visual changes, included screenshots / GIFs / recordings
    documenting the change.
    - [ ] For API changes, updated relevant public types.
    - [ ] Ensured that CI passes
    hannojg authored Feb 5, 2026
    Configuration menu
    Copy the full SHA
    2711117 View commit details
    Browse the repository at this point in the history

Commits on Feb 6, 2026

  1. fix(Android, FormSheet): Add logic for dismissing keyboard when the B…

    …ottomSheet is presented (#3617)
    
    ## Description
    
    Add logic to handle keyboard visibility and focus restoration on sheet
    enter/exit
    
    > [!IMPORTANT]  
    > It doesn't work well in some edge cases, especially when we have a
    Screen with a TextInput and a FormSheet with another TextInput. When
    using an HW keyboard in such a case, if we submit the Input inside the
    FormSheet (losing focus) and then want to reopen it, the focus search
    might select the TextInput on the Screen, as we do not block focus on
    the Screen behind the FormSheet.
    > Creating ticket for that:
    software-mansion/react-native-screens-labs#929
    
    Implementation details:
    - I'm checking the IME inset on the DecorView, there's 1 soft keyboard
    for the whole application - it's easier to detect whether it was open on
    the previous Screen
    - I'm restoring the focus, only if the keyboard was visible on the
    previous screen - that might be bad for applications that are designed
    for keyboard/D-Pad navigation
    - I don't want the Screen to be the subject of focus - there is no good
    reason for that imo, therefore, I've added FOCUS_AFTER_DESCENDANTS to
    focus on the 1st focusable descendant inside the FormSheet
    - I'm using onCreate/Destroy callbacks, instead of onStart/Stop
    callbacks, because of the timing for autoFocus inside the FormSheet
    
    Closes:
    software-mansion/react-native-screens-labs#928
    
    ## Changes
    
    - added lifecycle callbacks for sheet creation/destruction that will
    show/hide keyboard from Screen and save the latest focus
    
    ## Before & after - visual documentation
    
    | Before | After |
    | --- | --- |
    | <video
    src="https://github.com/user-attachments/assets/bd07bc9d-ee8e-4c92-bea8-75117446bb96"
    /> | <video
    src="https://github.com/user-attachments/assets/5e8cd8e6-6da9-47d0-b138-48332087cc59"
    /> |
    
    ## Test plan
    
    Test3617
    
    ## Checklist
    
    - [x] Included code example that can be used to test this change.
    - [ ] Updated / created local changelog entries in relevant test files.
    - [x] For visual changes, included screenshots / GIFs / recordings
    documenting the change.
    - [ ] For API changes, updated relevant public types.
    - [ ] Ensured that CI passes
    
    ---------
    
    Co-authored-by: Kacper Kafara <kacperkafara@gmail.com>
    t0maboro and kkafar authored Feb 6, 2026
    Configuration menu
    Copy the full SHA
    9b387ce View commit details
    Browse the repository at this point in the history
  2. release: 4.23.0 (#3623)

    Another minor release. It's minor, because it ships with improvements
    with
    experimental APIs, however its purpose is mostly to publish fix for
    FormSheet
    on Android.
    
    Changelog:
    
    * fix(Android, FormSheet): Add logic for dismissing keyboard when the
    BottomSheet is presented (#3617) (9b387ce)
    * fix(android): default ScreenStackHeaderSubview type is LEFT (#3619)
    (2711117)
    * feat(Android, Stack v5): allow for nested container pop via JS (#3612)
    (c72539d)
    * chore(Android): run :spotlessApply (#3614) (5a6f842)
    kkafar authored Feb 6, 2026
    Configuration menu
    Copy the full SHA
    61a7d8e View commit details
    Browse the repository at this point in the history
Loading