Skip to content

Instantly share code, notes, and snippets.

@wolverineks
Created March 31, 2018 06:39
Show Gist options
  • Save wolverineks/a4716cd6ef1b86ef9b193b8d2fbfbaa4 to your computer and use it in GitHub Desktop.
Save wolverineks/a4716cd6ef1b86ef9b193b8d2fbfbaa4 to your computer and use it in GitHub Desktop.
Compound Components
// @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