2015-07-28 17:31:26 +03:00
/ * *
2021-12-31 02:08:43 +03:00
* Copyright ( c ) Meta Platforms , Inc . and affiliates .
2015-07-28 17:31:26 +03:00
*
2018-02-17 05:24:55 +03:00
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree .
2015-07-28 17:31:26 +03:00
*
2018-05-11 05:06:46 +03:00
* @ format
2020-07-22 19:43:45 +03:00
* @ flow strict - local
2015-07-28 17:31:26 +03:00
* /
2018-05-11 05:06:46 +03:00
2019-05-08 18:44:25 +03:00
import type { ViewProps } from '../Components/View/ViewPropTypes' ;
2020-06-23 23:43:04 +03:00
import type { RootTag } from '../ReactNative/RootTag' ;
2019-07-10 15:37:03 +03:00
import type { DirectEventHandler } from '../Types/CodegenTypes' ;
2022-10-01 00:28:48 +03:00
import NativeEventEmitter from '../EventEmitter/NativeEventEmitter' ;
2020-06-23 23:43:04 +03:00
import { type EventSubscription } from '../vendor/emitter/EventEmitter' ;
2022-10-01 00:28:48 +03:00
import ModalInjection from './ModalInjection' ;
import NativeModalManager from './NativeModalManager' ;
2019-08-09 20:06:53 +03:00
import RCTModalHostView from './RCTModalHostViewNativeComponent' ;
2023-02-07 07:00:19 +03:00
import { VirtualizedListContextResetter } from '@react-native/virtualized-lists' ;
2020-05-04 10:57:01 +03:00
2022-10-01 00:28:48 +03:00
const ScrollView = require ( '../Components/ScrollView/ScrollView' ) ;
const View = require ( '../Components/View/View' ) ;
const AppContainer = require ( '../ReactNative/AppContainer' ) ;
const I18nManager = require ( '../ReactNative/I18nManager' ) ;
const { RootTagContext } = require ( '../ReactNative/RootTag' ) ;
const StyleSheet = require ( '../StyleSheet/StyleSheet' ) ;
const Platform = require ( '../Utilities/Platform' ) ;
const React = require ( 'react' ) ;
2021-01-07 14:16:31 +03:00
type ModalEventDefinitions = {
modalDismissed : [ { modalID : number } ] ,
} ;
2020-11-14 10:53:58 +03:00
const ModalEventEmitter =
Platform . OS === 'ios' && NativeModalManager != null
2021-04-12 16:23:53 +03:00
? new NativeEventEmitter < ModalEventDefinitions > (
// T88715063: NativeEventEmitter only used this parameter on iOS. Now it uses it on all platforms, so this code was modified automatically to preserve its behavior
// If you want to use the native module on other platforms, please remove this condition and test its behavior
Platform . OS !== 'ios' ? null : NativeModalManager ,
)
2020-11-14 10:53:58 +03:00
: null ;
2015-09-28 09:46:00 +03:00
/ * *
2016-06-24 04:32:21 +03:00
* The Modal component is a simple way to present content above an enclosing view .
2018-02-22 18:04:35 +03:00
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal
2015-09-28 09:46:00 +03:00
* /
2017-06-21 05:02:27 +03:00
2017-09-22 00:46:42 +03:00
// 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.
2018-05-11 01:44:52 +03:00
let uniqueModalIdentifier = 0 ;
2017-09-22 00:46:42 +03:00
2019-07-10 15:37:03 +03:00
type OrientationChangeEvent = $ReadOnly < { |
orientation : 'portrait' | 'landscape' ,
| } > ;
2018-09-25 01:14:04 +03:00
2019-07-10 12:10:06 +03:00
export type Props = $ReadOnly < { |
2018-09-25 01:14:04 +03:00
... ViewProps ,
/ * *
* The ` animationType ` prop controls how the modal animates .
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal#animationtype
2018-09-25 01:14:04 +03:00
* /
animationType ? : ? ( 'none' | 'slide' | 'fade' ) ,
/ * *
* The ` presentationStyle ` prop controls how the modal appears .
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal#presentationstyle
2018-09-25 01:14:04 +03:00
* /
presentationStyle ? : ? (
| 'fullScreen'
| 'pageSheet'
| 'formSheet'
| 'overFullScreen'
) ,
/ * *
* The ` transparent ` prop determines whether your modal will fill the
* entire view .
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal#transparent
2018-09-25 01:14:04 +03:00
* /
transparent ? : ? boolean ,
2019-10-11 08:12:32 +03:00
/ * *
* The ` statusBarTranslucent ` prop determines whether your modal should go under
* the system statusbar .
*
2022-12-09 13:30:09 +03:00
* See https : //reactnative.dev/docs/modal.html#statusbartranslucent-android
2019-10-11 08:12:32 +03:00
* /
statusBarTranslucent ? : ? boolean ,
2018-09-25 01:14:04 +03:00
/ * *
* The ` hardwareAccelerated ` prop controls whether to force hardware
* acceleration for the underlying window .
*
2020-03-11 19:56:32 +03:00
* This prop works only on Android .
2019-10-11 08:12:32 +03:00
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal#hardwareaccelerated
2018-09-25 01:14:04 +03:00
* /
hardwareAccelerated ? : ? boolean ,
/ * *
* The ` visible ` prop determines whether your modal is visible .
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal#visible
2018-09-25 01:14:04 +03:00
* /
visible ? : ? boolean ,
/ * *
* The ` onRequestClose ` callback is called when the user taps the hardware
2020-02-07 01:43:41 +03:00
* back button on Android or the menu button on Apple TV .
2018-09-25 01:14:04 +03:00
*
* This is required on Apple TV and Android .
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal#onrequestclose
2018-09-25 01:14:04 +03:00
* /
2019-07-10 15:37:03 +03:00
onRequestClose ? : ? DirectEventHandler < null > ,
2018-09-25 01:14:04 +03:00
/ * *
* The ` onShow ` prop allows passing a function that will be called once the
* modal has been shown .
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal#onshow
2018-09-25 01:14:04 +03:00
* /
2019-07-10 15:37:03 +03:00
onShow ? : ? DirectEventHandler < null > ,
2018-09-25 01:14:04 +03:00
/ * *
* The ` onDismiss ` prop allows passing a function that will be called once
* the modal has been dismissed .
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal#ondismiss
2018-09-25 01:14:04 +03:00
* /
onDismiss ? : ? ( ) => mixed ,
/ * *
* The ` supportedOrientations ` prop allows the modal to be rotated to any of the specified orientations .
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal#supportedorientations
2018-09-25 01:14:04 +03:00
* /
supportedOrientations ? : ? $ReadOnlyArray <
| 'portrait'
| 'portrait-upside-down'
| 'landscape'
| 'landscape-left'
| 'landscape-right' ,
> ,
/ * *
* The ` onOrientationChange ` callback is called when the orientation changes while the modal is being displayed .
*
2021-11-22 14:27:48 +03:00
* See https : //reactnative.dev/docs/modal#onorientationchange
2018-09-25 01:14:04 +03:00
* /
2019-07-10 15:37:03 +03:00
onOrientationChange ? : ? DirectEventHandler < OrientationChangeEvent > ,
2018-09-25 01:14:04 +03:00
| } > ;
2021-04-02 23:06:10 +03:00
function confirmProps ( props : Props ) {
if ( _ _DEV _ _ ) {
if (
props . presentationStyle &&
props . presentationStyle !== 'overFullScreen' &&
props . transparent === true
) {
console . warn (
` Modal with ' ${ props . presentationStyle } ' presentation style and 'transparent' value is not supported. ` ,
) ;
}
}
}
2018-09-25 01:14:04 +03:00
class Modal extends React . Component < Props > {
2019-08-21 19:56:31 +03:00
static defaultProps : { | hardwareAccelerated : boolean , visible : boolean | } = {
2016-04-22 05:46:36 +03:00
visible : true ,
2016-12-14 21:25:57 +03:00
hardwareAccelerated : false ,
2016-04-22 05:46:36 +03:00
} ;
2020-06-02 21:12:20 +03:00
static contextType : React . Context < RootTag > = RootTagContext ;
2020-03-06 02:55:10 +03:00
2017-09-22 00:46:42 +03:00
_identifier : number ;
2020-06-23 23:43:04 +03:00
_eventSubscription : ? EventSubscription ;
2017-09-22 00:46:42 +03:00
2018-09-25 01:14:04 +03:00
constructor ( props : Props ) {
2017-06-21 05:02:27 +03:00
super ( props ) ;
2021-04-02 23:06:10 +03:00
if ( _ _DEV _ _ ) {
confirmProps ( props ) ;
}
2017-09-22 00:46:42 +03:00
this . _identifier = uniqueModalIdentifier ++ ;
}
2020-11-14 10:53:58 +03:00
componentDidMount ( ) {
2021-05-03 01:41:22 +03:00
// 'modalDismissed' is for the old renderer in iOS only
2020-11-14 10:53:58 +03:00
if ( ModalEventEmitter ) {
this . _eventSubscription = ModalEventEmitter . addListener (
'modalDismissed' ,
event => {
if ( event . modalID === this . _identifier && this . props . onDismiss ) {
this . props . onDismiss ( ) ;
}
} ,
) ;
}
}
2017-09-22 00:46:42 +03:00
componentWillUnmount ( ) {
2020-11-14 10:53:58 +03:00
if ( this . _eventSubscription ) {
this . _eventSubscription . remove ( ) ;
2017-09-22 00:46:42 +03:00
}
2017-06-21 05:02:27 +03:00
}
2021-04-02 23:06:10 +03:00
componentDidUpdate ( ) {
if ( _ _DEV _ _ ) {
confirmProps ( this . props ) ;
2017-06-21 05:02:27 +03:00
}
}
2017-08-18 04:36:54 +03:00
render ( ) : React . Node {
2021-05-26 20:34:02 +03:00
if ( this . props . visible !== true ) {
2015-07-28 17:31:26 +03:00
return null ;
}
2016-05-09 17:07:39 +03:00
const containerStyles = {
2020-07-22 19:43:45 +03:00
backgroundColor :
this . props . transparent === true ? 'transparent' : 'white' ,
2016-04-21 18:56:46 +03:00
} ;
2015-08-13 19:09:10 +03:00
2020-02-06 23:43:03 +03:00
let animationType = this . props . animationType || 'none' ;
2016-04-29 01:59:11 +03:00
2017-06-21 05:02:27 +03:00
let presentationStyle = this . props . presentationStyle ;
if ( ! presentationStyle ) {
presentationStyle = 'fullScreen' ;
2020-07-22 19:43:45 +03:00
if ( this . props . transparent === true ) {
2017-06-21 05:02:27 +03:00
presentationStyle = 'overFullScreen' ;
}
}
2018-05-11 05:06:46 +03:00
const innerChildren = _ _DEV _ _ ? (
2020-06-02 21:12:20 +03:00
< AppContainer rootTag = { this . context } > { this . props . children } < / A p p C o n t a i n e r >
2018-05-11 05:06:46 +03:00
) : (
this . props . children
) ;
2016-09-29 14:46:17 +03:00
2015-07-28 17:31:26 +03:00
return (
2015-08-13 19:09:10 +03:00
< RCTModalHostView
2016-04-29 01:59:11 +03:00
animationType = { animationType }
2017-06-21 05:02:27 +03:00
presentationStyle = { presentationStyle }
2015-08-13 19:09:10 +03:00
transparent = { this . props . transparent }
2016-12-14 21:25:57 +03:00
hardwareAccelerated = { this . props . hardwareAccelerated }
2016-03-17 18:51:58 +03:00
onRequestClose = { this . props . onRequestClose }
2016-03-03 23:42:41 +03:00
onShow = { this . props . onShow }
2021-05-03 01:41:22 +03:00
onDismiss = { ( ) => {
if ( this . props . onDismiss ) {
this . props . onDismiss ( ) ;
}
} }
visible = { this . props . visible }
2019-10-11 08:12:32 +03:00
statusBarTranslucent = { this . props . statusBarTranslucent }
2017-09-22 00:46:42 +03:00
identifier = { this . _identifier }
2016-04-20 10:58:46 +03:00
style = { styles . modal }
2021-06-01 18:59:50 +03:00
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
2016-04-20 10:58:46 +03:00
onStartShouldSetResponder = { this . _shouldSetResponder }
2016-09-07 16:06:12 +03:00
supportedOrientations = { this . props . supportedOrientations }
2021-11-11 18:05:41 +03:00
onOrientationChange = { this . props . onOrientationChange }
testID = { this . props . testID } >
2020-05-04 10:57:01 +03:00
< VirtualizedListContextResetter >
< ScrollView . Context . Provider value = { null } >
< View
style = { [ styles . container , containerStyles ] }
collapsable = { false } >
{ innerChildren }
< / V i e w >
< / S c r o l l V i e w . C o n t e x t . P r o v i d e r >
< / V i r t u a l i z e d L i s t C o n t e x t R e s e t t e r >
2015-07-28 17:31:26 +03:00
< / R C T M o d a l H o s t V i e w >
) ;
}
2016-04-20 10:58:46 +03:00
// We don't want any responder events bubbling out of the modal.
_shouldSetResponder ( ) : boolean {
return true ;
}
2015-07-28 17:31:26 +03:00
}
2019-06-01 05:53:21 +03:00
const side = I18nManager . getConstants ( ) . isRTL ? 'right' : 'left' ;
2016-04-21 18:56:46 +03:00
const styles = StyleSheet . create ( {
2015-07-28 17:31:26 +03:00
modal : {
position : 'absolute' ,
} ,
container : {
2021-04-01 04:19:54 +03:00
/ * $ F l o w F i x M e [ i n v a l i d - c o m p u t e d - p r o p ] ( > = 0 . 1 1 1 . 0 s i t e = r e a c t _ n a t i v e _ f b ) T h i s
* comment suppresses an error found when Flow v0 . 111 was deployed . To see
* the error , delete this comment and run Flow . * /
2018-05-11 05:06:46 +03:00
[ side ] : 0 ,
2015-07-28 17:31:26 +03:00
top : 0 ,
2019-05-01 01:01:37 +03:00
flex : 1 ,
2018-05-11 05:06:46 +03:00
} ,
2015-07-28 17:31:26 +03:00
} ) ;
2021-04-12 22:44:52 +03:00
const ExportedModal : React . AbstractComponent <
React . ElementConfig < typeof Modal > ,
> = ModalInjection . unstable _Modal ? ? Modal ;
module . exports = ExportedModal ;