diff --git a/packages/rn-tester/js/examples/Modal/ModalCustomizable.js b/packages/rn-tester/js/examples/Modal/ModalCustomizable.js new file mode 100644 index 00000000000..2b9c72d37d3 --- /dev/null +++ b/packages/rn-tester/js/examples/Modal/ModalCustomizable.js @@ -0,0 +1,343 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import * as React from 'react'; +import { + Modal, + Picker, + Platform, + StyleSheet, + Switch, + Text, + TouchableHighlight, + View, + ScrollView, +} from 'react-native'; +import type {RNTesterExampleModuleItem} from '../../types/RNTesterTypes'; + +const Item = Picker.Item; + +class Button extends React.Component<$FlowFixMeProps, $FlowFixMeState> { + state = { + active: false, + }; + + _onHighlight = () => { + this.setState({active: true}); + }; + + _onUnhighlight = () => { + this.setState({active: false}); + }; + + render() { + const colorStyle = { + color: this.state.active ? '#fff' : '#000', + }; + return ( + + + {this.props.children} + + + ); + } +} + +const supportedOrientationsPickerValues = [ + ['portrait'], + ['landscape'], + ['landscape-left'], + ['portrait', 'landscape-right'], + ['portrait', 'landscape'], + [], +]; + +class ModalExample extends React.Component<{...}, $FlowFixMe> { + state: $FlowFixMe = { + animationType: 'none', + modalVisible: false, + transparent: false, + hardwareAccelerated: false, + statusBarTranslucent: false, + presentationStyle: 'fullScreen', + selectedSupportedOrientation: '0', + currentOrientation: 'unknown', + action: '', + }; + + _setModalVisible = visible => { + this.setState({modalVisible: visible}); + }; + + _setAnimationType = type => { + this.setState({animationType: type}); + }; + + _toggleTransparent = () => { + this.setState({transparent: !this.state.transparent}); + }; + + _toggleHardwareAccelerated = () => { + this.setState({hardwareAccelerated: !this.state.hardwareAccelerated}); + }; + + _toggleStatusBarTranslucent = () => { + this.setState({statusBarTranslucent: !this.state.statusBarTranslucent}); + }; + + renderSwitch(): React.Node { + if (Platform.isTV) { + return null; + } + if (Platform.OS === 'android') { + return ( + <> + Hardware Accelerated + + Status Bar Translucent + + Transparent + + + ); + } + return ( + + ); + } + + render(): React.Node { + const modalBackgroundStyle = { + backgroundColor: this.state.transparent + ? 'rgba(0, 0, 0, 0.5)' + : '#f5fcff', + }; + const innerContainerTransparentStyle = this.state.transparent + ? {backgroundColor: '#fff', padding: 20} + : null; + const activeButtonStyle = { + backgroundColor: '#ddd', + }; + + return ( + + this._setModalVisible(false)} + supportedOrientations={ + supportedOrientationsPickerValues[ + Number(this.state.selectedSupportedOrientation) + ] + } + onOrientationChange={evt => + this.setState({currentOrientation: evt.nativeEvent.orientation}) + } + onDismiss={() => { + if (this.state.action === 'onDismiss') { + alert(this.state.action); + } + }} + onShow={() => { + if (this.state.action === 'onShow') { + alert(this.state.action); + } + }}> + + + + This modal was presented{' '} + {this.state.animationType === 'none' ? 'without' : 'with'}{' '} + animation. + + + It is currently displayed in {this.state.currentOrientation}{' '} + mode. + + + + + + + Animation Type + + + + + + {this.renderSwitch()} + {this.renderPickers()} + + + ); + } + renderPickers(): React.Node { + if (Platform.isTV) { + return null; + } + return ( + + + Presentation style + + this.setState({presentationStyle}) + } + itemStyle={styles.pickerItem}> + + + + + + + + + + Supported orientations + + this.setState({selectedSupportedOrientation: i.toString()}) + } + itemStyle={styles.pickerItem}> + + + + + + + + + + + Actions + {Platform.OS === 'ios' ? ( + this.setState({action})} + itemStyle={styles.pickerItem}> + + + + + ) : ( + this.setState({action})} + itemStyle={styles.pickerItem}> + + + + )} + + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + padding: 20, + }, + innerContainer: { + borderRadius: 10, + alignItems: 'center', + }, + row: { + alignItems: 'center', + flex: 1, + flexDirection: 'row', + marginBottom: 20, + }, + rowTitle: { + flex: 1, + fontWeight: 'bold', + }, + button: { + borderRadius: 5, + flexGrow: 1, + height: 44, + alignSelf: 'stretch', + justifyContent: 'center', + overflow: 'hidden', + }, + buttonText: { + fontSize: 18, + margin: 5, + textAlign: 'center', + }, + modalButton: { + marginTop: 10, + }, + pickerItem: { + fontSize: 16, + }, + ScrollView: { + paddingTop: 10, + paddingBottom: 100, + }, +}); + +export default ({ + title: 'Modal Presentation', + name: 'basic', + description: 'Modals can be presented with or without animation', + render: (): React.Node => , +}: RNTesterExampleModuleItem); diff --git a/packages/rn-tester/js/examples/Modal/ModalExample.js b/packages/rn-tester/js/examples/Modal/ModalExample.js index 1cfae6d4d93..1c0405029ff 100644 --- a/packages/rn-tester/js/examples/Modal/ModalExample.js +++ b/packages/rn-tester/js/examples/Modal/ModalExample.js @@ -4,347 +4,21 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format * @flow strict-local + * @format */ -'use strict'; +import ModalCustomizable from './ModalCustomizable'; +import ModalOnShow from './ModalOnShow'; +import type {RNTesterExampleModuleItem} from '../../types/RNTesterTypes'; -const React = require('react'); - -const { - Modal, - Picker, - Platform, - StyleSheet, - Switch, - Text, - TouchableHighlight, - View, - ScrollView, -} = require('react-native'); - -const Item = Picker.Item; - -exports.displayName = (undefined: ?string); -exports.framework = 'React'; -exports.title = 'Modal'; -exports.category = 'UI'; -exports.documentationURL = 'https://reactnative.dev/docs/modal'; -exports.description = 'Component for presenting modal views.'; - -class Button extends React.Component<$FlowFixMeProps, $FlowFixMeState> { - state = { - active: false, - }; - - _onHighlight = () => { - this.setState({active: true}); - }; - - _onUnhighlight = () => { - this.setState({active: false}); - }; - - render() { - const colorStyle = { - color: this.state.active ? '#fff' : '#000', - }; - return ( - - - {this.props.children} - - - ); - } -} - -const supportedOrientationsPickerValues = [ - ['portrait'], - ['landscape'], - ['landscape-left'], - ['portrait', 'landscape-right'], - ['portrait', 'landscape'], - [], -]; - -class ModalExample extends React.Component<{...}, $FlowFixMeState> { - state = { - animationType: 'none', - modalVisible: false, - transparent: false, - hardwareAccelerated: false, - statusBarTranslucent: false, - presentationStyle: 'fullScreen', - selectedSupportedOrientation: '0', - currentOrientation: 'unknown', - action: '', - }; - - _setModalVisible = visible => { - this.setState({modalVisible: visible}); - }; - - _setAnimationType = type => { - this.setState({animationType: type}); - }; - - _toggleTransparent = () => { - this.setState({transparent: !this.state.transparent}); - }; - - _toggleHardwareAccelerated = () => { - this.setState({hardwareAccelerated: !this.state.hardwareAccelerated}); - }; - - _toggleStatusBarTranslucent = () => { - this.setState({statusBarTranslucent: !this.state.statusBarTranslucent}); - }; - - renderSwitch() { - if (Platform.isTV) { - return null; - } - if (Platform.OS === 'android') { - return ( - <> - Hardware Accelerated - - Status Bar Translucent - - Transparent - - - ); - } - return ( - - ); - } - - render() { - const modalBackgroundStyle = { - backgroundColor: this.state.transparent - ? 'rgba(0, 0, 0, 0.5)' - : '#f5fcff', - }; - const innerContainerTransparentStyle = this.state.transparent - ? {backgroundColor: '#fff', padding: 20} - : null; - const activeButtonStyle = { - backgroundColor: '#ddd', - }; - - return ( - - this._setModalVisible(false)} - supportedOrientations={ - supportedOrientationsPickerValues[ - Number(this.state.selectedSupportedOrientation) - ] - } - onOrientationChange={evt => - this.setState({currentOrientation: evt.nativeEvent.orientation}) - } - onDismiss={() => { - if (this.state.action === 'onDismiss') alert(this.state.action); - }} - onShow={() => { - if (this.state.action === 'onShow') alert(this.state.action); - }}> - - - - This modal was presented{' '} - {this.state.animationType === 'none' ? 'without' : 'with'}{' '} - animation. - - - It is currently displayed in {this.state.currentOrientation}{' '} - mode. - - - - - - - Animation Type - - - - - - {this.renderSwitch()} - {this.renderPickers()} - - - ); - } - renderPickers() { - if (Platform.isTV) { - return null; - } - return ( - - - Presentation style - - this.setState({presentationStyle}) - } - itemStyle={styles.pickerItem}> - - - - - - - - - - Supported orientations - - this.setState({selectedSupportedOrientation: i.toString()}) - } - itemStyle={styles.pickerItem}> - - - - - - - - - - - Actions - {Platform.OS === 'ios' ? ( - this.setState({action})} - itemStyle={styles.pickerItem}> - - - - - ) : ( - this.setState({action})} - itemStyle={styles.pickerItem}> - - - - )} - - - ); - } -} - -exports.examples = [ - { - title: 'Modal Presentation', - name: 'basic', - description: 'Modals can be presented with or without animation', - render: (): React.Node => , - }, -]; - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - padding: 20, - }, - innerContainer: { - borderRadius: 10, - alignItems: 'center', - }, - row: { - alignItems: 'center', - flex: 1, - flexDirection: 'row', - marginBottom: 20, - }, - rowTitle: { - flex: 1, - fontWeight: 'bold', - }, - button: { - borderRadius: 5, - flexGrow: 1, - height: 44, - alignSelf: 'stretch', - justifyContent: 'center', - overflow: 'hidden', - }, - buttonText: { - fontSize: 18, - margin: 5, - textAlign: 'center', - }, - modalButton: { - marginTop: 10, - }, - pickerItem: { - fontSize: 16, - }, - ScrollView: { - paddingTop: 10, - paddingBottom: 100, - }, -}); +export const displayName = (undefined: ?string); +export const framework = 'React'; +export const title = 'Modal'; +export const category = 'UI'; +export const documentationURL = 'https://reactnative.dev/docs/modal'; +export const description = 'Component for presenting modal views.'; +export const examples = ([ + ModalCustomizable, + ModalOnShow, +]: Array); diff --git a/packages/rn-tester/js/examples/Modal/ModalOnShow.js b/packages/rn-tester/js/examples/Modal/ModalOnShow.js new file mode 100644 index 00000000000..dc24ace791a --- /dev/null +++ b/packages/rn-tester/js/examples/Modal/ModalOnShow.js @@ -0,0 +1,122 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import * as React from 'react'; +import {Modal, Pressable, StyleSheet, Text, View} from 'react-native'; +import type {RNTesterExampleModuleItem} from '../../types/RNTesterTypes'; + +function ModalOnShowOnDismiss(): React.Node { + const [modalVisible, setModalVisible] = React.useState(false); + const [onShowCount, setOnShowCount] = React.useState(0); + const [onDismissCount, setOnDismissCount] = React.useState(0); + + return ( + + { + setOnShowCount(onShowCount + 1); + }} + onDismiss={() => { + setOnDismissCount(onDismissCount + 1); + }} + onRequestClose={() => { + setModalVisible(false); + }}> + + + + onShow is called {onShowCount} times + + + onDismiss is called {onDismissCount} times + + setModalVisible(false)}> + + Hide Modal + + + + + + onShow is called {onShowCount} times + + onDismiss is called {onDismissCount} times + + setModalVisible(true)}> + + Show Modal + + + + ); +} + +const styles = StyleSheet.create({ + container: { + display: 'flex', + alignItems: 'center', + paddingVertical: 30, + }, + centeredView: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + modalBackdrop: { + backgroundColor: 'rgba(0, 0, 0, 0.5)', + }, + modalView: { + margin: 20, + backgroundColor: 'white', + borderRadius: 20, + padding: 35, + alignItems: 'center', + shadowColor: '#000', + shadowOffset: { + width: 0, + height: 2, + }, + shadowOpacity: 0.25, + shadowRadius: 4, + elevation: 5, + }, + button: { + borderRadius: 20, + padding: 10, + marginVertical: 20, + elevation: 2, + }, + buttonOpen: { + backgroundColor: '#F194FF', + }, + buttonClose: { + backgroundColor: '#2196F3', + }, + textStyle: { + color: 'white', + fontWeight: 'bold', + textAlign: 'center', + }, +}); + +export default ({ + title: "Modal's onShow/onDismiss", + name: 'onShow', + description: + 'onShow and onDismiss (iOS only) callbacks are called when modals is shown/dissmissed', + render: (): React.Node => , +}: RNTesterExampleModuleItem);