Add onDismiss to Modal.js

Summary: Adds an onDismiss so that navigation events can be chained to the dismissing of a modal.

Reviewed By: sahrens

Differential Revision: D5852953

fbshipit-source-id: a86e36fdd5b0b206c2dd9fa248e2a88da22efa31
This commit is contained in:
Mehdi Mulani 2017-09-21 14:46:42 -07:00 committed by Facebook Github Bot
parent dd87db392d
commit a389ffbd84
7 changed files with 109 additions and 2 deletions

View File

@ -13,6 +13,8 @@
const AppContainer = require('AppContainer');
const I18nManager = require('I18nManager');
const NativeEventEmitter = require('NativeEventEmitter');
const NativeModules = require('NativeModules');
const Platform = require('Platform');
const React = require('React');
const PropTypes = require('prop-types');
@ -22,6 +24,10 @@ const View = require('View');
const deprecatedPropType = require('deprecatedPropType');
const requireNativeComponent = require('requireNativeComponent');
const RCTModalHostView = requireNativeComponent('RCTModalHostView', null);
const ModalEventEmitter = Platform.OS === 'ios' && NativeModules.ModalManager ?
new NativeEventEmitter(NativeModules.ModalManager) : null;
import type EmitterSubscription from 'EmitterSubscription';
/**
* The Modal component is a simple way to present content above an enclosing view.
@ -79,6 +85,12 @@ const RCTModalHostView = requireNativeComponent('RCTModalHostView', null);
* ```
*/
// In order to route onDismiss callbacks, we need to uniquely identifier each
// <Modal> on screen. There can be different ones, either nested or as siblings.
// We cannot pass the onDismiss callback to native as the view will be
// destroyed before the callback is fired.
var uniqueModalIdentifier = 0;
class Modal extends React.Component<Object> {
static propTypes = {
/**
@ -125,6 +137,11 @@ class Modal extends React.Component<Object> {
* The `onShow` prop allows passing a function that will be called once the modal has been shown.
*/
onShow: PropTypes.func,
/**
* The `onDismiss` prop allows passing a function that will be called once the modal has been dismissed.
* @platform ios
*/
onDismiss: PropTypes.func,
animated: deprecatedPropType(
PropTypes.bool,
'Use the `animationType` prop instead.'
@ -153,9 +170,32 @@ class Modal extends React.Component<Object> {
rootTag: PropTypes.number,
};
_identifier: number;
_eventSubscription: ?EmitterSubscription;
constructor(props: Object) {
super(props);
Modal._confirmProps(props);
this._identifier = uniqueModalIdentifier++;
}
componentDidMount() {
if (ModalEventEmitter) {
this._eventSubscription = ModalEventEmitter.addListener(
'modalDismissed',
event => {
if (event.modalID === this._identifier && this.props.onDismiss) {
this.props.onDismiss();
}
},
);
}
}
componentWillUnmount() {
if (this._eventSubscription) {
this._eventSubscription.remove();
}
}
componentWillReceiveProps(nextProps: Object) {
@ -208,6 +248,7 @@ class Modal extends React.Component<Object> {
hardwareAccelerated={this.props.hardwareAccelerated}
onRequestClose={this.props.onRequestClose}
onShow={this.props.onShow}
identifier={this._identifier}
style={styles.modal}
onStartShouldSetResponder={this._shouldSetResponder}
supportedOrientations={this.props.supportedOrientations}

View File

@ -1071,6 +1071,7 @@
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */; };
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */; };
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBACB1A6023D300E9B192 /* RCTConvert.m */; };
916F9C2D1F743F57002E5920 /* RCTModalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 91076A871F743AB00081B4FA /* RCTModalManager.m */; };
9936F3371F5F2F480010BF04 /* PrivateDataBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9936F3351F5F2F480010BF04 /* PrivateDataBase.cpp */; };
9936F3381F5F2F480010BF04 /* PrivateDataBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9936F3361F5F2F480010BF04 /* PrivateDataBase.h */; };
9936F3391F5F2F5C0010BF04 /* PrivateDataBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 9936F3361F5F2F480010BF04 /* PrivateDataBase.h */; };
@ -2084,6 +2085,8 @@
83CBBACA1A6023D300E9B192 /* RCTConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTConvert.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
83CBBACB1A6023D300E9B192 /* RCTConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert.m; sourceTree = "<group>"; };
83F15A171B7CC46900F10295 /* UIView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+Private.h"; sourceTree = "<group>"; };
91076A871F743AB00081B4FA /* RCTModalManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTModalManager.m; sourceTree = "<group>"; };
91076A881F743AB00081B4FA /* RCTModalManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTModalManager.h; sourceTree = "<group>"; };
9936F3131F5F2E4B0010BF04 /* libprivatedata.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libprivatedata.a; sourceTree = BUILT_PRODUCTS_DIR; };
9936F32F1F5F2E5B0010BF04 /* libprivatedata-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libprivatedata-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; };
9936F3351F5F2F480010BF04 /* PrivateDataBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PrivateDataBase.cpp; path = privatedata/PrivateDataBase.cpp; sourceTree = "<group>"; };
@ -2373,6 +2376,8 @@
83392EB21B6634E10013B15F /* RCTModalHostViewController.m */,
83A1FE8D1B62643A00BE0E65 /* RCTModalHostViewManager.h */,
83A1FE8E1B62643A00BE0E65 /* RCTModalHostViewManager.m */,
91076A881F743AB00081B4FA /* RCTModalManager.h */,
91076A871F743AB00081B4FA /* RCTModalManager.m */,
13B0800C1A69489C00A75B9A /* RCTNavigator.h */,
13B0800D1A69489C00A75B9A /* RCTNavigator.m */,
13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */,
@ -4144,6 +4149,7 @@
1450FF861BCFF28A00208362 /* RCTProfile.m in Sources */,
13AB90C11B6FA36700713B4F /* RCTComponentData.m in Sources */,
13B0801B1A69489C00A75B9A /* RCTNavigatorManager.m in Sources */,
916F9C2D1F743F57002E5920 /* RCTModalManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -725,6 +725,7 @@
83CBBA691A601EF300E9B192 /* RCTEventDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA661A601EF300E9B192 /* RCTEventDispatcher.m */; };
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */; };
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBACB1A6023D300E9B192 /* RCTConvert.m */; };
916F9C2E1F743F7E002E5920 /* RCTModalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 91076A891F743AD70081B4FA /* RCTModalManager.m */; };
945929C41DD62ADD00653A7D /* RCTConvert+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 945929C31DD62ADD00653A7D /* RCTConvert+Transform.m */; };
945929C51DD62ADD00653A7D /* RCTConvert+Transform.m in Sources */ = {isa = PBXBuildFile; fileRef = 945929C31DD62ADD00653A7D /* RCTConvert+Transform.m */; };
A12E9E1B1E5DEA350029001B /* RCTPackagerClient.h in Headers */ = {isa = PBXBuildFile; fileRef = A12E9E171E5DEA350029001B /* RCTPackagerClient.h */; };
@ -1412,6 +1413,8 @@
83CBBACA1A6023D300E9B192 /* RCTConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = RCTConvert.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
83CBBACB1A6023D300E9B192 /* RCTConvert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert.m; sourceTree = "<group>"; };
83F15A171B7CC46900F10295 /* UIView+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+Private.h"; sourceTree = "<group>"; };
91076A891F743AD70081B4FA /* RCTModalManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTModalManager.m; sourceTree = "<group>"; };
91076A8A1F743AD70081B4FA /* RCTModalManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTModalManager.h; sourceTree = "<group>"; };
945929C21DD62ADD00653A7D /* RCTConvert+Transform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+Transform.h"; sourceTree = "<group>"; };
945929C31DD62ADD00653A7D /* RCTConvert+Transform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+Transform.m"; sourceTree = "<group>"; };
A12E9E171E5DEA350029001B /* RCTPackagerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTPackagerClient.h; sourceTree = "<group>"; };
@ -1587,6 +1590,8 @@
83392EB21B6634E10013B15F /* RCTModalHostViewController.m */,
83A1FE8D1B62643A00BE0E65 /* RCTModalHostViewManager.h */,
83A1FE8E1B62643A00BE0E65 /* RCTModalHostViewManager.m */,
91076A8A1F743AD70081B4FA /* RCTModalManager.h */,
91076A891F743AD70081B4FA /* RCTModalManager.m */,
13B0800C1A69489C00A75B9A /* RCTNavigator.h */,
13B0800D1A69489C00A75B9A /* RCTNavigator.m */,
13B0800E1A69489C00A75B9A /* RCTNavigatorManager.h */,
@ -2700,6 +2705,7 @@
597AD1BF1E577D7800152581 /* RCTRootContentView.m in Sources */,
13723B501A82FD3C00F88898 /* RCTStatusBarManager.m in Sources */,
000E6CEB1AB0E980000CDF4D /* RCTSourceCode.m in Sources */,
916F9C2E1F743F7E002E5920 /* RCTModalManager.m in Sources */,
001BFCD01D8381DE008E587E /* RCTMultipartStreamReader.m in Sources */,
133CAE8E1B8E5CFD00F6AD92 /* RCTDatePicker.m in Sources */,
14C2CA761B3AC64F00E6CBB2 /* RCTFrameUpdate.m in Sources */,

View File

@ -26,6 +26,8 @@
@property (nonatomic, copy) RCTDirectEventBlock onShow;
@property (nonatomic, copy) NSNumber *identifier;
@property (nonatomic, weak) id<RCTModalHostViewInteractor> delegate;
@property (nonatomic, copy) NSArray<NSString *> *supportedOrientations;

View File

@ -12,6 +12,7 @@
#import "RCTBridge.h"
#import "RCTModalHostView.h"
#import "RCTModalHostViewController.h"
#import "RCTModalManager.h"
#import "RCTShadowView.h"
#import "RCTUtils.h"
@ -82,10 +83,15 @@ RCT_EXPORT_MODULE()
- (void)dismissModalHostView:(RCTModalHostView *)modalHostView withViewController:(RCTModalHostViewController *)viewController animated:(BOOL)animated
{
dispatch_block_t completionBlock = ^{
if (modalHostView.identifier) {
[[self.bridge moduleForClass:[RCTModalManager class]] modalDismissed:modalHostView.identifier];
}
};
if (_dismissalBlock) {
_dismissalBlock([modalHostView reactViewController], viewController, animated, nil);
_dismissalBlock([modalHostView reactViewController], viewController, animated, completionBlock);
} else {
[viewController dismissViewControllerAnimated:animated completion:nil];
[viewController dismissViewControllerAnimated:animated completion:completionBlock];
}
}
@ -107,6 +113,7 @@ RCT_EXPORT_VIEW_PROPERTY(animationType, NSString)
RCT_EXPORT_VIEW_PROPERTY(presentationStyle, UIModalPresentationStyle)
RCT_EXPORT_VIEW_PROPERTY(transparent, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onShow, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(identifier, NSNumber)
RCT_EXPORT_VIEW_PROPERTY(supportedOrientations, NSArray)
RCT_EXPORT_VIEW_PROPERTY(onOrientationChange, RCTDirectEventBlock)

View File

@ -0,0 +1,19 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <UIKit/UIKit.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface RCTModalManager : RCTEventEmitter <RCTBridgeModule>
- (void)modalDismissed:(NSNumber *)modalID;
@end

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTModalManager.h"
@implementation RCTModalManager
RCT_EXPORT_MODULE();
- (NSArray<NSString *> *)supportedEvents
{
return @[ @"modalDismissed" ];
}
- (void)modalDismissed:(NSNumber *)modalID
{
[self sendEventWithName:@"modalDismissed" body:@{ @"modalID": modalID }];
}
@end