Skip to content

Instantly share code, notes, and snippets.

@KennyHammerlund
Last active May 11, 2019 20:16
Show Gist options
  • Save KennyHammerlund/00ad73394ccc6f514da5962a70d92997 to your computer and use it in GitHub Desktop.
Save KennyHammerlund/00ad73394ccc6f514da5962a70d92997 to your computer and use it in GitHub Desktop.
React Native Modal with a toggleable content display/peeker
import React from 'react';
import { Modal, TouchableHighlight, TouchableWithoutFeedback, View, TextStyle, Animated } from 'react-native';
import style from './Modal.style';
import Loading from '../LoadingDots/LoadingDots';
import Ripple from 'react-native-material-ripple';
import Text from '../Text';
import Glyphicon from '../Glyphicon';
import COLORS from '../../styles/constants/colors';
interface ModalProps {
onDeny?: () => void;
onConfirm?: () => void;
denyText?: string | null;
confirmText?: string | null;
loading?: boolean;
peekerComponent?: React.Component;
}
export const Title: React.FC<{ children: string, style: TextStyle }> = ({
children,
style: inputStyle,
}) => {
return (
<Text numberOfLines={3} style={[style.title, inputStyle]}>
{children}
</Text>
);
};
export const styles = style;
export const SubTitle: React.FC<{ children: string }> = ({ children }) => {
return (
<Text numberOfLines={3} style={style.subTitle}>
{children}
</Text>
);
};
export const Option: React.FC<{
selected: boolean,
onPress: () => void,
noIcon?: boolean,
disabled?: boolean,
}> = ({ children, selected, noIcon, disabled, ...rest }) => {
return (
<Ripple {...rest} style={style.option} disabled={disabled}>
{!noIcon && (
<Glyphicon
icon="ok"
style={{
fontSize: 20,
marginRight: 15,
color: selected ? COLORS.blue : COLORS.lightGrey,
}}
/>
)}
{typeof children === 'string' ? <Text style={style.optionText}>{children}</Text> : children}
</Ripple>
);
};
export class Main extends React.Component<ModalProps> {
state = { peeker: false };
togglePeeker = () => {
this.setState({ peeker: !this.state.peeker });
};
render() {
const { peeker } = this.state;
const { peekerComponent } = this.props;
const [peekerContentStyle, contentStyle] = (() => {
if (!peekerComponent) return [style.noPeeker, style.modal];
return peeker
? [style.expandedPeeker, style.shortModal]
: [style.shortPeeker, style.expandedModal];
})();
const content = (
<View style={contentStyle} key="content" onTouchEnd={peeker ? this.togglePeeker : () => {}}>
<View style={peekerComponent ? style.peekerContentWrapper : style.contentWrapper}>
{this.props.children}
</View>
{!peeker && (
<View style={style.buttonContainer}>
<Ripple
style={style.denyButton}
onPress={!this.props.loading ? this.props.onDeny : undefined}
>
{this.props.loading ? (
<Loading width="40%" size={12} />
) : (
<Text style={style.denyText}>{this.props.denyText || 'Cancel'}</Text>
)}
</Ripple>
{this.props.onConfirm && (
<Ripple
style={style.confirmButton}
onPress={!this.props.loading ? this.props.onConfirm : undefined}
>
{this.props.loading ? (
<Loading width="40%" color="muted" size={12} />
) : (
<Text style={style.confirmText}>{this.props.confirmText || `Yes`}</Text>
)}
</Ripple>
)}
</View>
)}
</View>
);
const peekerContent = (
<View
style={peekerContentStyle}
onTouchEnd={!peeker ? this.togglePeeker : () => {}}
key="peeker"
>
<View style={style.contentWrapper}>{peekerComponent}</View>
{peeker && (
<View style={style.buttonContainer}>
<Ripple style={style.denyButton} onPress={this.togglePeeker}>
{this.props.loading ? (
<Loading width="40%" size={12} />
) : (
<Text style={style.denyText}>{'Hide'}</Text>
)}
</Ripple>
</View>
)}
</View>
);
return (
<Modal
animationType="fade"
transparent={true}
visible={true}
onRequestClose={() => this.props.onDeny && this.props.onDeny()}
>
<TouchableHighlight onPress={this.props.onDeny} style={style.container}>
<TouchableWithoutFeedback>
{peekerComponent ? (
<View style={{ flex: 1, justifyContent: 'space-between' }}>
{peeker ? [peekerContent, content] : [content, peekerContent]}
</View>
) : (
content
)}
</TouchableWithoutFeedback>
</TouchableHighlight>
</Modal>
);
}
}
export default Main;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment