-
-
Notifications
You must be signed in to change notification settings - Fork 650
feat(iOS, FormSheet v5): Introduce PresentationManager for FormSheet component #4086
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
t0maboro
wants to merge
8
commits into
@t0maboro/separate-behavior-from-appearance
Choose a base branch
from
@t0maboro/formsheet-presentation-state
base: @t0maboro/separate-behavior-from-appearance
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
76b7292
Add SFT for testing presentation state
t0maboro 6fe7d86
Add PresentationManager
t0maboro 8879cee
Match other tests convention
t0maboro 822198d
Refresh configuration before presentation
t0maboro d0da2db
Rename
t0maboro 93e35ac
Rename
t0maboro 9fd5f90
Cleanup
t0maboro d130afe
Potential fix for pull request finding
t0maboro File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
...rc/tests/single-feature-tests/form-sheet/test-form-sheet-presentation-state-ios/index.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| import React, { useState } from 'react'; | ||
| import { Button, StyleSheet, Text, View } from 'react-native'; | ||
| import { FormSheet } from 'react-native-screens/experimental'; | ||
| import { scenarioDescription } from './scenario-description'; | ||
| import { createScenario } from '@apps/tests/shared/helpers'; | ||
| import { Colors } from '@apps/shared/styling'; | ||
|
|
||
| export function App() { | ||
| const [isOpen, setIsOpen] = useState(false); | ||
|
|
||
| return ( | ||
| <View style={styles.container}> | ||
| <Text style={styles.title}>FormSheet Test</Text> | ||
| <Button | ||
| title="Open FormSheet" | ||
| color={Colors.primary} | ||
| onPress={() => setIsOpen(true)} | ||
| /> | ||
| <FormSheet | ||
| isOpen={isOpen} | ||
| onNativeDismiss={() => { | ||
| setIsOpen(false); | ||
| }} | ||
| detents={[0.6, 1.0]}> | ||
| <View style={styles.sheetContent}> | ||
| <Text style={styles.sheetTitle}>FormSheet content</Text> | ||
| <View style={styles.spacing} /> | ||
| <Button | ||
| title="Quickly dismiss & present" | ||
| color={Colors.primary} | ||
| onPress={() => { | ||
| setIsOpen(false); | ||
| setTimeout(() => { | ||
| setIsOpen(true); | ||
| }, 32); | ||
| }} | ||
| /> | ||
| </View> | ||
| </FormSheet> | ||
| </View> | ||
| ); | ||
| } | ||
|
|
||
| const styles = StyleSheet.create({ | ||
| container: { | ||
| flex: 1, | ||
| justifyContent: 'center', | ||
| alignItems: 'center', | ||
| backgroundColor: Colors.offBackground, | ||
| }, | ||
| title: { | ||
| fontSize: 20, | ||
| fontWeight: 'bold', | ||
| marginBottom: 20, | ||
| color: Colors.text, | ||
| }, | ||
| sheetContent: { | ||
| flex: 1, | ||
| backgroundColor: Colors.background, | ||
| padding: 24, | ||
| justifyContent: 'center', | ||
| alignItems: 'center', | ||
| }, | ||
| sheetTitle: { | ||
| fontSize: 22, | ||
| fontWeight: '600', | ||
| marginBottom: 12, | ||
| color: Colors.text, | ||
| }, | ||
| spacing: { | ||
| height: 32, | ||
| }, | ||
| }); | ||
|
|
||
| export default createScenario(App, scenarioDescription); |
11 changes: 11 additions & 0 deletions
11
...e-feature-tests/form-sheet/test-form-sheet-presentation-state-ios/scenario-description.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import type { ScenarioDescription } from '@apps/tests/shared/helpers'; | ||
|
|
||
| export const scenarioDescription: ScenarioDescription = { | ||
| name: 'Presentation state', | ||
| key: 'test-form-sheet-presentation-state-ios', | ||
| details: | ||
| 'Verifies the presentation state machine when subjected to rapid consecutive open/close state changes from JS.', | ||
| platforms: ['ios'], | ||
| e2eCoverage: 'tbd', | ||
| smokeTest: false, | ||
| }; |
47 changes: 47 additions & 0 deletions
47
...gle-feature-tests/form-sheet/test-form-sheet-presentation-state-ios/scenario.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # Test Scenario: Presentation state | ||
|
|
||
| ## Details | ||
|
|
||
| **Description:** Verify the presentation state machine. This test ensures that when the React Native state rapidly toggles between `false` and `true` the native layer correctly queues the presentation changes and prevents state desynchronization. | ||
|
|
||
| **OS test creation version:** iOS: 18.6 and 26.4 | ||
|
|
||
| ## E2E test | ||
|
|
||
| Other: Planned, but will be implemented separately. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - iOS device or simulator: iPhone | ||
|
|
||
| ## Steps - iPhone | ||
|
|
||
| ### Baseline | ||
|
|
||
| 1. Launch the app and navigate to the **Presentation state** screen. | ||
|
|
||
| - [ ] Expected: Content with the button "Open FormSheet" is shown. | ||
|
|
||
| --- | ||
|
|
||
| ### Initialization | ||
|
|
||
| 2. Tap the "Open FormSheet" button. | ||
|
|
||
| - [ ] Expected: The FormSheet opens smoothly and displays its content. | ||
|
|
||
| --- | ||
|
|
||
| ### Rapid State Toggling (Stress Test) | ||
|
|
||
| 3. Tap the "Quickly dismiss & present" button. | ||
|
|
||
| - [ ] Expected: The FormSheet should begin the dismissal animation. As soon as the dismissal animation finishes, the FormSheet should immediately automatically re-present itself. The final state should be opened FormSheet. | ||
|
|
||
| --- | ||
|
|
||
| ### Final Dismissal Verification | ||
|
|
||
| 4. Grab the top edge of the FormSheet and swipe down completely to natively dismiss it. | ||
|
|
||
| - [ ] Expected: The FormSheet dismisses and returns the user to the underlying main screen. The native state is synchronized, and tapping "Open FormSheet" again works correctly. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
ios/gamma/modals/form-sheet/RNSFormSheetPresentationManager.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| #pragma once | ||
|
|
||
| #import <Foundation/Foundation.h> | ||
| #import "RNSFormSheetProviders.h" | ||
|
|
||
| @class RNSFormSheetContentController; | ||
|
|
||
| NS_ASSUME_NONNULL_BEGIN | ||
|
|
||
| @interface RNSFormSheetPresentationManager : NSObject | ||
|
|
||
| - (void)updatePresentationIfNeededWithProvider:(id<RNSFormSheetPresentationProvider>)provider | ||
| controller:(RNSFormSheetContentController *)controller; | ||
|
|
||
| - (void)handleNativeDismiss; | ||
|
|
||
| @end | ||
|
|
||
| NS_ASSUME_NONNULL_END |
102 changes: 102 additions & 0 deletions
102
ios/gamma/modals/form-sheet/RNSFormSheetPresentationManager.mm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| #import "RNSFormSheetPresentationManager.h" | ||
| #import "RNSFormSheetContentController.h" | ||
| #import "RNSFormSheetPresentationState.h" | ||
| #import "RNSPresentationSourceProvider.h" | ||
|
|
||
| #import <React/RCTLog.h> | ||
|
|
||
| @implementation RNSFormSheetPresentationManager { | ||
| RNSFormSheetPresentationState _state; | ||
| } | ||
|
|
||
| - (instancetype)init | ||
| { | ||
| if (self = [super init]) { | ||
| _state = RNSFormSheetPresentationStateDismissed; | ||
| } | ||
| return self; | ||
| } | ||
|
|
||
| - (void)updatePresentationIfNeededWithProvider:(id<RNSFormSheetPresentationProvider>)provider | ||
| controller:(RNSFormSheetContentController *)controller | ||
| { | ||
| BOOL shouldBeOpen = provider.isOpen; | ||
|
|
||
| if (shouldBeOpen) { | ||
| [self presentIfNeededWithProvider:provider controller:controller]; | ||
| } else { | ||
| [self dismissIfNeededWithProvider:provider controller:controller]; | ||
| } | ||
| } | ||
|
|
||
| - (void)presentIfNeededWithProvider:(id<RNSFormSheetPresentationProvider>)provider | ||
| controller:(RNSFormSheetContentController *)controller | ||
| { | ||
| if (_state != RNSFormSheetPresentationStateDismissed) { | ||
| return; | ||
| } | ||
|
|
||
| UIWindow *window = provider.hostWindow; | ||
| if (window == nil) { | ||
| return; | ||
| } | ||
|
|
||
| UIViewController *presentationSourceViewController = | ||
| [RNSPresentationSourceProvider findViewControllerForPresentationInWindow:window]; | ||
| if (presentationSourceViewController == nil) { | ||
| RCTLogError( | ||
| @"[RNScreens] Failed to present form sheet: The source view controller cannot be found for target window."); | ||
| return; | ||
| } | ||
|
|
||
| _state = RNSFormSheetPresentationStatePresenting; | ||
| [controller prepareForPresentation]; | ||
|
|
||
| __weak auto weakSelf = self; | ||
| [presentationSourceViewController presentViewController:controller | ||
| animated:YES | ||
| completion:^{ | ||
| auto strongSelf = weakSelf; | ||
| if (!strongSelf) { | ||
| return; | ||
| } | ||
|
|
||
| strongSelf->_state = RNSFormSheetPresentationStatePresented; | ||
| [strongSelf updatePresentationIfNeededWithProvider:provider | ||
| controller:controller]; | ||
| }]; | ||
| } | ||
|
|
||
| - (void)dismissIfNeededWithProvider:(id<RNSFormSheetPresentationProvider>)provider | ||
| controller:(RNSFormSheetContentController *)controller | ||
| { | ||
| if (_state != RNSFormSheetPresentationStatePresented) { | ||
| return; | ||
| } | ||
|
|
||
| if (controller.presentingViewController == nil) { | ||
| _state = RNSFormSheetPresentationStateDismissed; | ||
| return; | ||
| } | ||
|
|
||
| _state = RNSFormSheetPresentationStateDismissing; | ||
|
|
||
| __weak auto weakSelf = self; | ||
| [controller dismissViewControllerAnimated:YES | ||
| completion:^{ | ||
| auto strongSelf = weakSelf; | ||
| if (!strongSelf) { | ||
| return; | ||
| } | ||
|
|
||
| strongSelf->_state = RNSFormSheetPresentationStateDismissed; | ||
| [strongSelf updatePresentationIfNeededWithProvider:provider controller:controller]; | ||
| }]; | ||
| } | ||
|
|
||
| - (void)handleNativeDismiss | ||
| { | ||
| _state = RNSFormSheetPresentationStateDismissed; | ||
| } | ||
|
|
||
| @end |
10 changes: 10 additions & 0 deletions
10
ios/gamma/modals/form-sheet/RNSFormSheetPresentationState.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| #pragma once | ||
|
|
||
| #import <Foundation/Foundation.h> | ||
|
|
||
| typedef NS_ENUM(NSInteger, RNSFormSheetPresentationState) { | ||
| RNSFormSheetPresentationStateDismissed, | ||
| RNSFormSheetPresentationStateDismissing, | ||
| RNSFormSheetPresentationStatePresented, | ||
| RNSFormSheetPresentationStatePresenting | ||
| }; | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.