| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 | 
							- // @flow
 - 
 - import React, { Component } from 'react';
 - import {
 -     Modal,
 -     Text,
 -     TouchableHighlight,
 -     TouchableWithoutFeedback,
 -     View
 - } from 'react-native';
 - import { connect } from 'react-redux';
 - 
 - import { Icon } from '../../font-icons';
 - 
 - import { simpleBottomSheet as styles } from './styles';
 - 
 - /**
 -  * Underlay color for the buttons on the sheet.
 -  *
 -  * @type {string}
 -  */
 - const BUTTON_UNDERLAY_COLOR = '#eee';
 - 
 - type Option = {
 - 
 -     /**
 -      * Name of the icon which will be rendered on the right.
 -      */
 -     iconName: string,
 - 
 -     /**
 -      * True if the element is selected (will be highlighted in blue),
 -      * false otherwise.
 -      */
 -     selected: boolean,
 - 
 -     /**
 -      * Text which will be rendered in the row.
 -      */
 -     text: string
 - };
 - 
 - 
 - /**
 -  * The type of {@code SimpleBottomSheet}'s React {@code Component} prop types.
 -  */
 - type Props = {
 - 
 -     /**
 -      * Handler for the cancel event, which happens when the user dismisses
 -      * the sheet.
 -      */
 -     onCancel: Function,
 - 
 -     /**
 -      * Handler for the event when an option has been selected in the sheet.
 -      */
 -     onSubmit: Function,
 - 
 -     /**
 -      * Array of options which will be rendered as rows.
 -      */
 -     options: Array<Option>
 - };
 - 
 - /**
 -  * A component emulating Android's BottomSheet, in a simplified form.
 -  * It supports text options with an icon, which the user can tap. The style has
 -  * been implemented following the Material Design guidelines for bottom
 -  * sheets: https://material.io/guidelines/components/bottom-sheets.html
 -  *
 -  * For all intents and purposes, this component has been designed to work and
 -  * behave as a {@code Dialog}.
 -  */
 - class SimpleBottomSheet extends Component<Props> {
 -     /**
 -      * Initializes a new {@code SimpleBottomSheet} instance.
 -      *
 -      * @param {Object} props - The read-only React {@code Component} props with
 -      * which the new instance is to be initialized.
 -      */
 -     constructor(props) {
 -         super(props);
 - 
 -         this._onButtonPress = this._onButtonPress.bind(this);
 -         this._onCancel = this._onCancel.bind(this);
 -     }
 - 
 -     /**
 -      * Implements React's {@link Component#render()}.
 -      *
 -      * @inheritdoc
 -      * @returns {ReactElement}
 -      */
 -     render() {
 -         return (
 -             <Modal
 -                 animationType = { 'slide' }
 -                 onRequestClose = { this._onCancel }
 -                 transparent = { true }
 -                 visible = { true }>
 -                 <View style = { styles.container }>
 -                     <TouchableWithoutFeedback
 -                         onPress = { this._onCancel } >
 -                         <View style = { styles.overlay } />
 -                     </TouchableWithoutFeedback>
 -                     <View style = { styles.sheet }>
 -                         <View style = { styles.rowsWrapper }>
 -                             { this._renderOptions() }
 -                         </View>
 -                     </View>
 -                 </View>
 -             </Modal>
 -         );
 -     }
 - 
 -     _onButtonPress: (?Object) => void;
 - 
 -     /**
 -      * Handle pressing of one of the options. The sheet will be hidden and the
 -      * onSubmit prop will be called with the selected option.
 -      *
 -      * @param {Object} option - The option which the user selected.
 -      * @private
 -      * @returns {void}
 -      */
 -     _onButtonPress(option) {
 -         const { onSubmit } = this.props;
 - 
 -         onSubmit && onSubmit(option);
 -     }
 - 
 -     _onCancel: () => void;
 - 
 -     /**
 -      * Cancels the dialog by calling the onCancel prop callback.
 -      *
 -      * @private
 -      * @returns {void}
 -      */
 -     _onCancel() {
 -         const { onCancel } = this.props;
 - 
 -         onCancel && onCancel();
 -     }
 - 
 -     /**
 -      * Renders sheet rows based on the options prop.
 -      *
 -      * @private
 -      * @returns {Array} - Array of rows to be rendered in the sheet.
 -      */
 -     _renderOptions() {
 -         return this.props.options.map(
 -             (option, index) => this._renderRow(option, index));
 -     }
 - 
 -     /**
 -      * Renders a single row of the sheet.
 -      *
 -      * @param {Object} option - Single option which needs to be rendered.
 -      * @param {int} index - Option index, used as a key for React.
 -      * @private
 -      * @returns {ReactElement} - A row element with an icon and text.
 -      */
 -     _renderRow(option, index) {
 -         const { iconName, selected, text } = option;
 -         const selectedStyle = selected ? styles.rowSelectedText : {};
 - 
 -         return (
 -             <TouchableHighlight
 -                 key = { index }
 - 
 -                 // TODO The following disables an eslint error alerting about a
 -                 // known potential/theoretical performance pernalty:
 -                 //
 -                 // A bind call or arrow function in a JSX prop will create a
 -                 // brand new function on every single render. This is bad for
 -                 // performance, as it will result in the garbage collector being
 -                 // invoked way more than is necessary. It may also cause
 -                 // unnecessary re-renders if a brand new function is passed as a
 -                 // prop to a component that uses reference equality check on the
 -                 // prop to determine if it should update.
 -                 //
 -                 // I'm not addressing the potential/theoretical performance
 -                 // penalty at the time of this writing because it doesn't seem
 -                 // to me that it's a practical performance penalty in the case.
 -                 //
 -                 // eslint-disable-next-line react/jsx-no-bind
 -                 onPress = { this._onButtonPress.bind(this, option) }
 -                 underlayColor = { BUTTON_UNDERLAY_COLOR } >
 -                 <View style = { styles.row } >
 -                     <Icon
 -                         name = { iconName }
 -                         style = { [ styles.rowIcon, selectedStyle ] } />
 -                     <View style = { styles.rowPadding } />
 -                     <Text style = { [ styles.rowText, selectedStyle ] } >
 -                         { text }
 -                     </Text>
 -                 </View>
 -             </TouchableHighlight>
 -         );
 -     }
 - }
 - 
 - export default connect()(SimpleBottomSheet);
 
 
  |