Created
March 31, 2018 06:39
-
-
Save wolverineks/a4716cd6ef1b86ef9b193b8d2fbfbaa4 to your computer and use it in GitHub Desktop.
Compound Components
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
import React, { Component } from 'react' | |
import type { Node } from 'react' | |
import { StyleSheet, Text, View } from 'react-native' | |
import { default as Modal } from 'react-native-modal' | |
import { styles } from './styles.js' | |
// CONTAINER ///////////////////////////////////////////////////////////////////////////// | |
export type ContainerProps = { | |
children: Node, | |
style?: StyleSheet.Styles | |
} | |
class Container extends Component<ContainerProps> { | |
render () { | |
return ( | |
<View {...this.props} style={[styles.container, this.props.style]}> | |
{this.props.children} | |
</View> | |
) | |
} | |
} | |
// HEADER ///////////////////////////////////////////////////////////////////////////// | |
export type HeaderProps = { | |
children: Node, | |
style?: StyleSheet.Styles | |
} | |
class Header extends Component<HeaderProps> { | |
render () { | |
return ( | |
<View {...this.props} style={[styles.header, this.props.style]}> | |
{this.props.children} | |
</View> | |
) | |
} | |
} | |
// ANDROID_HACK_SPACER ///////////////////////////////////////////////////////////////////////////// | |
/* | |
This spacer should be used with Icon to overcome the limitations on Android | |
React Native on Android does not support 'Overflow' | |
If/When React Native on Android supports 'Overflow', | |
* remove the hack component | |
* move the Icon component inside Modal.Container | |
https://github.com/facebook/react-native/issues/6802 | |
*/ | |
type AndroidHackSpacerProps = { | |
style?: StyleSheet.Styles | |
} | |
class AndroidHackSpacer extends Component<AndroidHackSpacerProps> { | |
render () { | |
return ( | |
<View style={styles.androidHackSpacer} /> | |
) | |
} | |
} | |
// ICON ///////////////////////////////////////////////////////////////////////////// | |
export type IconProps = { | |
children: Node, | |
style?: StyleSheet.Styles | |
} | |
class Icon extends Component<IconProps> { | |
static AndroidHackSpacer = AndroidHackSpacer | |
render () { | |
return ( | |
<View {...this.props} style={[styles.icon, this.props.style]}> | |
{this.props.children} | |
</View> | |
) | |
} | |
} | |
// TITLE ///////////////////////////////////////////////////////////////////////////// | |
type TitleProps = { | |
children: Node, | |
style?: StyleSheet.Styles | |
} | |
export class Title extends Component<TitleProps> { | |
render () { | |
return ( | |
<Text style={[styles.title, this.props.style]} {...this.props}> | |
{this.props.children} | |
</Text> | |
) | |
} | |
} | |
// BODY ///////////////////////////////////////////////////////////////////////////// | |
type BodyProps = { | |
children: Node, | |
style?: StyleSheet.Styles | |
} | |
export class Body extends Component<BodyProps> { | |
render () { | |
return ( | |
<View style={[styles.body, this.props.style]} {...this.props}> | |
{this.props.children} | |
</View> | |
) | |
} | |
} | |
// FOOTER ///////////////////////////////////////////////////////////////////////////// | |
type FooterProps = { | |
children: Node, | |
style?: StyleSheet.Styles | |
} | |
export class Footer extends Component<FooterProps> { | |
render () { | |
return ( | |
<View style={[styles.footer, this.props.style]} {...this.props}> | |
{this.props.children} | |
</View> | |
) | |
} | |
} | |
// INTERACTIVE_MODAL ///////////////////////////////////////////////////////////////////////////// | |
type Props = { | |
isVisible: boolean, | |
children: Node, | |
style?: StyleSheet.Styles | |
} | |
export class InteractiveModal extends Component<Props> { | |
static Icon = Icon | |
static Title = Title | |
static Description = Description | |
static Body = Body | |
static Footer = Footer | |
render () { | |
const { isVisible } = this.props | |
const children = React.Children.toArray(this.props.children) | |
const icon = children.find(child => child.type === InteractiveModal.Icon) | |
const title = children.find(child => child.type === InteractiveModal.Title) | |
const body = children.find(child => child.type === InteractiveModal.Body) | |
const footer = children.find(child => child.type === InteractiveModal.Footer) | |
return ( | |
<Modal useNativeDriver hideModalContentWhileAnimating isVisible={isVisible} | |
{...this.props} style={[styles.modal, this.props.style]}> | |
{icon} | |
<Container> | |
<Icon.AndroidHackSpacer /> | |
<Header style={styles.header}>{title}</Header> | |
<Body>{body}</Body> | |
<Footer>{footer}</Footer> | |
</Container> | |
</Modal> | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment