Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#import <Foundation/Foundation.h>
#import "RNSFormSheetProviders.h"

@class RNSFormSheetAppearanceCoordinator;
@class RNSFormSheetContentController;
Expand All @@ -10,9 +11,10 @@ NS_ASSUME_NONNULL_BEGIN

@interface RNSFormSheetAppearanceApplicator : NSObject

- (void)updateAppearanceIfNeededForHost:(RNSFormSheetHostComponentView *)host
controller:(RNSFormSheetContentController *)controller
coordinator:(RNSFormSheetAppearanceCoordinator *)coordinator;
- (void)updateAppearanceIfNeededForAppearanceProvider:(id<RNSFormSheetAppearanceProvider>)appearanceProvider

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have one remark regarding naming.

Suggested change
- (void)updateAppearanceIfNeededForAppearanceProvider:(id<RNSFormSheetAppearanceProvider>)appearanceProvider
- (void)updateAppearanceIfNeededWithAppearanceProvider:(id<RNSFormSheetAppearanceProvider>)appearanceProvider

The For part does sound inappropriate and misleading in this context.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

behaviorProvider:(id<RNSFormSheetBehaviorProvider>)behaviorProvider

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: behavior will have a dedicated path, but I'm extracting it to a separate PR in which I'm going to introduce a dedicated class for that

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

associated followup PR: #4084

controller:(RNSFormSheetContentController *)controller
coordinator:(RNSFormSheetAppearanceCoordinator *)coordinator;

- (void)resetInitialDetent;

Expand Down
36 changes: 20 additions & 16 deletions ios/gamma/modals/form-sheet/RNSFormSheetAppearanceApplicator.mm
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#import "RNSFormSheetAppearanceUpdateFlags.h"
#import "RNSFormSheetContentController.h"
#import "RNSFormSheetDetentResolver.h"
#import "RNSFormSheetHostComponentView.h"

@implementation RNSFormSheetAppearanceApplicator {
BOOL _initialDetentApplied;
Expand All @@ -25,20 +24,24 @@ - (void)resetInitialDetent
_initialDetentApplied = NO;
}

- (void)updateAppearanceIfNeededForHost:(RNSFormSheetHostComponentView *)host
controller:(RNSFormSheetContentController *)controller
coordinator:(RNSFormSheetAppearanceCoordinator *)coordinator
- (void)updateAppearanceIfNeededForAppearanceProvider:(id<RNSFormSheetAppearanceProvider>)appearanceProvider
behaviorProvider:(id<RNSFormSheetBehaviorProvider>)behaviorProvider
controller:(RNSFormSheetContentController *)controller
coordinator:(RNSFormSheetAppearanceCoordinator *)coordinator
{
[coordinator updateIfNeeds:RNSFormSheetAppearanceUpdateFlagsConfiguration
performOperations:^{
[self updateSheetConfigurationForHost:host controller:controller];
[self updateSheetConfigurationForAppearanceProvider:appearanceProvider
behaviorProvider:behaviorProvider
controller:controller];
}];
}

#pragma mark - Updaters

- (void)updateSheetConfigurationForHost:(RNSFormSheetHostComponentView *)host
controller:(RNSFormSheetContentController *)controller
- (void)updateSheetConfigurationForAppearanceProvider:(id<RNSFormSheetAppearanceProvider>)appearanceProvider
behaviorProvider:(id<RNSFormSheetBehaviorProvider>)behaviorProvider
controller:(RNSFormSheetContentController *)controller
{
#if !TARGET_OS_TV
UISheetPresentationController *sheet = controller.sheetPresentationController;
Expand All @@ -47,22 +50,23 @@ - (void)updateSheetConfigurationForHost:(RNSFormSheetHostComponentView *)host
@"[RNScreens] sheetPresentationController is nil. Ensure modalPresentationStyle is set to UIModalPresentationFormSheet.");

NSArray<UISheetPresentationControllerDetent *> *nativeDetents =
[RNSFormSheetDetentResolver buildSheetDetentsForFractions:host.detents];
[RNSFormSheetDetentResolver buildSheetDetentsForFractions:behaviorProvider.detents];

Comment thread
t0maboro marked this conversation as resolved.
UISheetPresentationControllerDetentIdentifier initialDetentIdentifier = nil;
if (!_initialDetentApplied) {
initialDetentIdentifier = [RNSFormSheetDetentResolver initialDetentIdentifierForDetents:nativeDetents
atRequestedIndex:host.initialDetentIndex];
initialDetentIdentifier =
[RNSFormSheetDetentResolver initialDetentIdentifierForDetents:nativeDetents
atRequestedIndex:behaviorProvider.initialDetentIndex];
_initialDetentApplied = YES;
}

UISheetPresentationControllerDetentIdentifier largestUndimmedDetentIdentifier =
[RNSFormSheetDetentResolver largestUndimmedDetentIdentifierForDetents:nativeDetents
atRequestedIndex:host.largestUndimmedDetentIndex];
UISheetPresentationControllerDetentIdentifier largestUndimmedDetentIdentifier = [RNSFormSheetDetentResolver
largestUndimmedDetentIdentifierForDetents:nativeDetents
atRequestedIndex:appearanceProvider.largestUndimmedDetentIndex];

BOOL prefersGrabberVisible = host.prefersGrabberVisible;
CGFloat preferredCornerRadius = host.preferredCornerRadius;
BOOL prefersScrollingExpandsWhenScrolledToEdge = host.prefersScrollingExpandsWhenScrolledToEdge;
BOOL prefersGrabberVisible = appearanceProvider.prefersGrabberVisible;
CGFloat preferredCornerRadius = appearanceProvider.preferredCornerRadius;
BOOL prefersScrollingExpandsWhenScrolledToEdge = behaviorProvider.prefersScrollingExpandsWhenScrolledToEdge;

[sheet animateChanges:^{
sheet.detents = nativeDetents;
Expand Down
16 changes: 14 additions & 2 deletions ios/gamma/modals/form-sheet/RNSFormSheetContentController.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#import <UIKit/UIKit.h>
#import "RNSFormSheetProviders.h"

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -20,10 +21,21 @@ NS_ASSUME_NONNULL_BEGIN

@property (nonatomic, weak, nullable) id<RNSFormSheetContentControllerDelegate> delegate;

@property (nonatomic, weak, nullable) id<RNSFormSheetPresentationProvider> presentationProvider;
@property (nonatomic, weak, nullable) id<RNSFormSheetAppearanceProvider> appearanceProvider;
@property (nonatomic, weak, nullable) id<RNSFormSheetBehaviorProvider> behaviorProvider;
Comment thread
t0maboro marked this conversation as resolved.

@property (nonatomic, readonly, nonnull) RNSFormSheetContentView *contentView;

- (void)presentFromWindowIfNeeded:(nonnull UIWindow *)window;
- (void)dismissIfNeeded;
#pragma mark - Signals

- (void)setNeedsPresentationUpdate;
- (void)setNeedsAppearanceUpdate;
- (void)setNeedsInitialDetentReset;

#pragma mark - Updating

- (void)flushPendingUpdates;

@end

Expand Down
93 changes: 92 additions & 1 deletion ios/gamma/modals/form-sheet/RNSFormSheetContentController.mm
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#import "RNSFormSheetContentController.h"
#import "RNSFormSheetAppearanceApplicator.h"
#import "RNSFormSheetAppearanceCoordinator.h"
#import "RNSFormSheetAppearanceUpdateFlags.h"
#import "RNSFormSheetContentView.h"
#import "RNSFormSheetHostComponentView.h"
Comment thread
t0maboro marked this conversation as resolved.
Outdated
#import "RNSPresentationSourceProvider.h"

#import <React/RCTAssert.h>
Expand All @@ -13,12 +17,22 @@ @interface RNSFormSheetContentController () <UIAdaptivePresentationControllerDel
>
@end

@implementation RNSFormSheetContentController
@implementation RNSFormSheetContentController {
RNSFormSheetAppearanceCoordinator *_Nonnull _appearanceCoordinator;
RNSFormSheetAppearanceApplicator *_Nonnull _appearanceApplicator;

BOOL _needsInitialDetentReset;
}

- (instancetype)init
{
if (self = [super init]) {
self.modalPresentationStyle = UIModalPresentationFormSheet;

_appearanceCoordinator = [RNSFormSheetAppearanceCoordinator new];
_appearanceApplicator = [RNSFormSheetAppearanceApplicator new];

_needsInitialDetentReset = NO;
}
return self;
}
Expand Down Expand Up @@ -46,6 +60,27 @@ - (void)viewDidLayoutSubviews

#pragma mark - Presentation

- (void)updatePresentationState
{
id<RNSFormSheetPresentationProvider> presentationProvider = self.presentationProvider;

RCTAssert(presentationProvider != nil,
@"[RNScreens] Presentation provider must be set before updating presentation state.");

if (presentationProvider == nil) {
return;
}

if (presentationProvider.isOpen) {
UIWindow *window = presentationProvider.hostWindow;
if (window != nil) {
[self presentFromWindowIfNeeded:window];
}
} else {
[self dismissIfNeeded];
}
}

- (void)prepareForPresentation
{
// The presentation controller is recreated by UIKit on every present/dismiss cycle.
Expand Down Expand Up @@ -88,6 +123,62 @@ - (void)dismissIfNeeded
[self dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark - Appearance

- (void)updateAppearanceIfNeeded
{
id<RNSFormSheetAppearanceProvider> appearanceProvider = self.appearanceProvider;
id<RNSFormSheetBehaviorProvider> behaviorProvider = self.behaviorProvider;

RCTAssert(appearanceProvider != nil, @"[RNScreens] Appearance provider must be set before updating appearance.");

RCTAssert(behaviorProvider != nil, @"[RNScreens] Behavior provider must be set before updating appearance.");

if (appearanceProvider == nil || behaviorProvider == nil) {
return;
}

if (_needsInitialDetentReset) {
_needsInitialDetentReset = NO;
[_appearanceApplicator resetInitialDetent];
}
Comment on lines +140 to +143

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do my first reading & don't understand the code fully yet, but detent update in appearance method doesn't fit for me. Aren't detents rather a behaviour?

Thinking now. Maybe call it configuration or something and then have both detents and appearance here.

@t0maboro t0maboro May 22, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right, there are a few things I don't like here:

  • appearance & behavior separation
  • that AppearanceApplicator is not stateless

my current plan is to:

  • separate appearance and behavior on Providers level for this PR
  • refactor AppearanceApplicator to extract Behavior configuration (next PR)
  • make AppearanceApplcator stateless (next PR)

let me know if you're okay with that


[_appearanceApplicator updateAppearanceIfNeededForAppearanceProvider:appearanceProvider
behaviorProvider:behaviorProvider
controller:self
coordinator:_appearanceCoordinator];

// TODO: @t0maboro - decouple presentation logic from AppearanceCoordinator
[_appearanceCoordinator updateIfNeeds:RNSFormSheetAppearanceUpdateFlagsPresentation
performOperations:^{
[self updatePresentationState];
}];
}

#pragma mark - Signals

- (void)setNeedsPresentationUpdate
{
[_appearanceCoordinator setNeeds:RNSFormSheetAppearanceUpdateFlagsPresentation];
}

- (void)setNeedsAppearanceUpdate
{
[_appearanceCoordinator setNeeds:RNSFormSheetAppearanceUpdateFlagsConfiguration];
}

- (void)setNeedsInitialDetentReset
{
_needsInitialDetentReset = YES;
}

#pragma mark - Updating

- (void)flushPendingUpdates
{
[self updateAppearanceIfNeeded];
}

#pragma mark - UIAdaptivePresentationControllerDelegate

- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
- (const std::vector<double> &)detents;
#endif

@property (nonatomic, readonly) BOOL isOpen;
@property (nonatomic, readonly) BOOL prefersGrabberVisible;
@property (nonatomic, readonly) CGFloat preferredCornerRadius;
@property (nonatomic, readonly) NSInteger largestUndimmedDetentIndex;
Expand Down
Loading
Loading