Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions Example/ios/ScreensExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,7 @@
"-lc++",
);
PRODUCT_NAME = ScreensExample;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
Expand All @@ -999,6 +1000,7 @@
"-lc++",
);
PRODUCT_NAME = ScreensExample;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
Expand Down
31 changes: 29 additions & 2 deletions Example/nativeStack.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Image,
Text,
ToolbarAndroid,
Platform,
} from 'react-native';
import {
Screen,
Expand Down Expand Up @@ -57,13 +58,35 @@ export class Stack extends Component {
const active =
index === stack.length - 1 ||
(transitioning !== 0 && index === stack.length - 2);
let stackPresentation = 'transparentModal';
let popoverConfig = {};
if (key === 'cyan' && Platform.isPad) {
stackPresentation = 'popover';
popoverConfig = {
popoverSourceViewNativeID: 'push:pink',
popoverSourceRect: {
x: 10,
y: 10,
width: 44,
height: 44,
},
popoverPermittedArrowDirections: ['up', 'down'],
preferredContentSize: {
width: 600,
height: 600,
},
};
style = popoverConfig.preferredContentSize;
}
return (
<Screen
style={style}
key={key}
stackAnimation="fade"
active={1}
onDismissed={() => this.removeByKey(key)}>
stackPresentation={stackPresentation}
onDismissed={() => this.removeByKey(key)}
{...popoverConfig}>
<ScreenStackHeaderConfig title={key}>
{/* {index === 0 && (
<ScreenStackHeaderLeftView>
Expand Down Expand Up @@ -130,7 +153,11 @@ class App extends Component {
}}
/>
{pop && <Button title="Pop" onPress={pop} />}
{push && <Button title="Push" onPress={push} />}
{push && (
<View nativeID={`push:${key}`}>
<Button title="Push" onPress={push} />
</View>
)}
{remove && <Button title="Remove middle screen" onPress={remove} />}
<TextInput placeholder="Hello" style={styles.textInput} />
<View style={{ height: 100, backgroundColor: 'red', width: '70%' }} />
Expand Down
19 changes: 17 additions & 2 deletions createNativeStackNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,23 @@ class StackView extends React.Component {

_renderScene = (scene, scenes) => {
const { navigation, getComponent } = scene.descriptor;
const { mode, transparentCard } = this.props.navigationConfig;
const {
mode,
transparentCard,
popoverSourceViewNativeID,
popoverSourceRect,
popoverPermittedArrowDirections,
preferredContentSize,
} = this.props.navigationConfig;
const SceneComponent = getComponent();

let stackPresentation = 'push';
let stackPresentation;
if (mode === 'modal') {
stackPresentation = transparentCard ? 'transparentModal' : 'modal';
} else if (mode === 'popover') {
stackPresentation = mode;
} else {
stackPresentation = 'push';
}

const { screenProps } = this.props;
Expand All @@ -144,6 +155,10 @@ class StackView extends React.Component {
key={`screen_${scene.key}`}
style={StyleSheet.absoluteFill}
stackPresentation={stackPresentation}
popoverSourceViewNativeID={popoverSourceViewNativeID}
popoverSourceRect={popoverSourceRect}
popoverPermittedArrowDirections={popoverPermittedArrowDirections}
preferredContentSize={preferredContentSize}
onDismissed={() => this._removeScene(scene)}>
{this._renderHeaderConfig(scene, scenes)}
<SceneView
Expand Down
40 changes: 40 additions & 0 deletions ios/RNSScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ typedef NS_ENUM(NSInteger, RNSScreenStackPresentation) {
RNSScreenStackPresentationPush,
RNSScreenStackPresentationModal,
RNSScreenStackPresentationTransparentModal,
RNSScreenStackPresentationPopover,
};

typedef NS_ENUM(NSInteger, RNSScreenStackAnimation) {
Expand Down Expand Up @@ -36,6 +37,45 @@ typedef NS_ENUM(NSInteger, RNSScreenStackAnimation) {
@property (nonatomic) RNSScreenStackAnimation stackAnimation;
@property (nonatomic) RNSScreenStackPresentation stackPresentation;

/**
nativeID for the native view containing the anchor rectangle for the popover.

@see https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller/1622313-sourceview
@see https://facebook.github.io/react-native/docs/view.html#nativeid
*/
@property (nullable, nonatomic, strong) NSString *popoverSourceViewNativeID;

/**
The rectangle in the specified view in which to anchor the popover.

@example: {x: 0, y: 0, width: 44, height: 44}
@see https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller/1622324-sourcerect
*/
@property (nonatomic, assign) CGRect popoverSourceRect;

/**
The arrow directions that you prefer for the popover.

up: UIPopoverArrowDirectionUp = 1UL << 0,
down: UIPopoverArrowDirectionDown = 1UL << 1,
left: UIPopoverArrowDirectionLeft = 1UL << 2,
right: UIPopoverArrowDirectionRight = 1UL << 3,

@default: [up, down, left, right]
@see https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller/1622319-permittedarrowdirections
*/
@property (nullable, nonatomic, strong) NSArray *popoverPermittedArrowDirections;

/**
The preferred size for the view controller’s view.

@example: {width: 300, height: 500}
@see https://developer.apple.com/documentation/uikit/uiviewcontroller/1621476-preferredcontentsize
*/
@property (nonatomic, assign) CGSize preferredContentSize;

@property (nonatomic, assign, readonly) UIPopoverArrowDirection realPopoverPermittedArrowDirections;

- (void)notifyFinishTransitioning;

@end
Expand Down
68 changes: 64 additions & 4 deletions ios/RNSScreen.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#import <React/RCTUIManager.h>
#import <React/RCTShadowView.h>
#import <React/RCTTouchHandler.h>

@interface RNSScreenFrameData : NSObject
@property (nonatomic, readonly) CGFloat rightInset;
Expand Down Expand Up @@ -40,10 +41,17 @@ - (void)notifyFinishTransitioning;

@end

@interface RNSScreenView()

@property (nonatomic, assign) UIPopoverArrowDirection realPopoverPermittedArrowDirections;

@end

@implementation RNSScreenView {
__weak RCTBridge *_bridge;
RNSScreen *_controller;
BOOL _invalidated;
NSMapTable *_touchHandlers;
}

@synthesize controller = _controller;
Expand All @@ -56,11 +64,32 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
_controller.modalPresentationStyle = UIModalPresentationOverCurrentContext;
_stackPresentation = RNSScreenStackPresentationPush;
_stackAnimation = RNSScreenStackAnimationDefault;
_touchHandlers = [NSMapTable weakToStrongObjectsMapTable];
_realPopoverPermittedArrowDirections = UIPopoverArrowDirectionAny;
}

return self;
}

- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex {
[super insertReactSubview:subview atIndex:atIndex];

RCTTouchHandler *touchHandler = [_touchHandlers objectForKey:subview];
if (touchHandler == nil) {
touchHandler = [[RCTTouchHandler alloc] initWithBridge:_bridge];
[touchHandler attachToView:subview];
[_touchHandlers setObject:touchHandler forKey:subview];
}
}

- (void)removeReactSubview:(UIView *)subview {
[super removeReactSubview:subview];
RCTTouchHandler *touchHandler = [_touchHandlers objectForKey:subview];
if (touchHandler != nil) {
[touchHandler detachFromView:subview];
[_touchHandlers removeObjectForKey:subview];
}
}

- (void)updateBounds
{
CGFloat navbarOffset = 0;
Expand All @@ -77,6 +106,8 @@ - (void)updateBounds
forView:self];
}

#pragma mark - Setter

- (void)setActive:(BOOL)active
{
if (active != _active) {
Expand All @@ -101,7 +132,32 @@ - (void)setStackPresentation:(RNSScreenStackPresentation)stackPresentation
case RNSScreenStackPresentationTransparentModal:
_controller.modalPresentationStyle = UIModalPresentationOverCurrentContext;
break;
case RNSScreenStackPresentationPopover:
_controller.modalPresentationStyle = UIModalPresentationPopover;
break;
}
}

- (void)setPopoverPermittedArrowDirections:(NSArray *)popoverPermittedArrowDirections
{
if (popoverPermittedArrowDirections.count == 0 || [_popoverPermittedArrowDirections isEqualToArray:popoverPermittedArrowDirections]) {
return;
}
_popoverPermittedArrowDirections = popoverPermittedArrowDirections;

UIPopoverArrowDirection permittedArrowDirections = 0;
for (NSString *direction in popoverPermittedArrowDirections) {
if ([direction isEqualToString:@"up"]) {
permittedArrowDirections |= UIPopoverArrowDirectionUp;
} else if ([direction isEqualToString:@"down"]) {
permittedArrowDirections |= UIPopoverArrowDirectionDown;
} else if ([direction isEqualToString:@"left"]) {
permittedArrowDirections |= UIPopoverArrowDirectionLeft;
} else if ([direction isEqualToString:@"right"]) {
permittedArrowDirections |= UIPopoverArrowDirectionRight;
}
}
_realPopoverPermittedArrowDirections = permittedArrowDirections;
}

- (UIView *)reactSuperview
Expand Down Expand Up @@ -218,7 +274,11 @@ @implementation RNSScreenManager
RCT_EXPORT_VIEW_PROPERTY(active, BOOL)
RCT_EXPORT_VIEW_PROPERTY(stackPresentation, RNSScreenStackPresentation)
RCT_EXPORT_VIEW_PROPERTY(stackAnimation, RNSScreenStackAnimation)
RCT_EXPORT_VIEW_PROPERTY(onDismissed, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(popoverSourceViewNativeID, NSString)
RCT_EXPORT_VIEW_PROPERTY(popoverSourceRect, CGRect)
RCT_EXPORT_VIEW_PROPERTY(popoverPermittedArrowDirections, NSArray)
RCT_EXPORT_VIEW_PROPERTY(preferredContentSize, CGSize)
RCT_EXPORT_VIEW_PROPERTY(onDismissed, RCTDirectEventBlock)

- (UIView *)view
{
Expand All @@ -237,7 +297,8 @@ @implementation RCTConvert (RNSScreen)
RCT_ENUM_CONVERTER(RNSScreenStackPresentation, (@{
@"push": @(RNSScreenStackPresentationPush),
@"modal": @(RNSScreenStackPresentationModal),
@"transparentModal": @(RNSScreenStackPresentationTransparentModal)
@"transparentModal": @(RNSScreenStackPresentationTransparentModal),
@"popover": @(RNSScreenStackPresentationPopover)
}), RNSScreenStackPresentationPush, integerValue)

RCT_ENUM_CONVERTER(RNSScreenStackAnimation, (@{
Expand All @@ -246,5 +307,4 @@ @implementation RCTConvert (RNSScreen)
@"fade": @(RNSScreenStackAnimationFade)
}), RNSScreenStackAnimationDefault, integerValue)


@end
4 changes: 2 additions & 2 deletions ios/RNSScreenStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
#import <React/RCTUIManagerObserverCoordinator.h>
#import "RNSScreenContainer.h"

@interface RNSScreenStackView : UIView <RNSScreenContainerDelegate>
@interface RNSScreenStackView : UIView <RNSScreenContainerDelegate, RCTInvalidating>

- (void)markChildUpdated;
- (void)didUpdateChildren;

@end

@interface RNSScreenStackManager : RCTViewManager
@interface RNSScreenStackManager : RCTViewManager <RCTInvalidating>

@end
Loading