UNPKG

react-sprucebot

Version:

React components for your Sprucebot Skill 💪🏼

209 lines (190 loc) 4.63 kB
import React, { Component } from 'react' import styled from 'styled-components' import classnames from 'classnames' import PropTypes from 'prop-types' import ReactDOM from 'react-dom' import skill from '../../skillskit/index' import Measure from 'react-measure' import Button from '../Button/Button' import IconButton from '../IconButton/IconButton' import { H2 } from '../Typography/Typography' import SK from '../../skillskit' const DialogUnderlay = styled.div.attrs({ className: ({ show }) => classnames('dialog_underlay', show ? 'on' : 'off') })` min-height: 100%; ` const DialogContainer = styled.div.attrs({ className: ({ show, className }) => classnames('dialog', className, show ? 'on' : 'off') })` opacity: ${props => props.opacity}; ` const DialogCloseButton = styled(Button).attrs({ className: 'btn__close_dialog', remove: true })`` export default class Dialog extends Component { constructor(props) { super(props) //for callbacks this.iframeMessageHandler = this.iframeMessageHandler.bind(this) this.state = { width: -1, height: 500, scrollTop: 0, firstShow: true, opacity: 0, inIframe: true } } setSize({ width, height }) { this.setState({ width, height }) this.postHeight() } postHeight() { const underlay = document.querySelector('.dialog_underlay') const underlayHeight = underlay ? underlay.offsetHeight : 0 //min height on body document.body.style.minHeight = `${underlayHeight}px` } componentDidMount() { window.addEventListener('message', this.iframeMessageHandler) if (this.props.show && this.state.firstShow) { this.requestScroll() } } componentDidUpdate() { // in case our starting state is not showing if (this.props.show && this.state.firstShow) { this.requestScroll() } } componentWillReceiveProps(nextProps) { // if we are being show, set opacity and request scroll if (!this.props.show && nextProps.show) { this.setState({ firstShow: true, opacity: 0 }) this.requestScroll() } if (this.props.show && !nextProps.show) { document.body.style.minHeight = `auto` } } componentWillUnmount() { document.body.style.minHeight = `auto` window.removeEventListener('message', this.iframeMessageHandler) } requestScroll() { SK.requestScroll() setTimeout(() => { // we are not in the sb iframe if (this.state.opacity === 0) { this.setState({ opacity: 1, scrollTop: window.document.body.scrollTop, firstShow: false, inIframe: false }) } }, 250) } iframeMessageHandler(e) { try { const results = JSON.parse(e.data) if (this.state.firstShow && results.name === 'SkillContainer:ScrollTop') { const top = results.skillScrollTop < 0 ? Math.abs(results.skillScrollTop) : 0 this.setState({ scrollTop: top, firstShow: false, opacity: 1 }) } } catch (err) {} } onTapClose() { this.postHeight() if (this.props.onTapClose) { this.props.onTapClose() } } render() { const { tag, children, className, title, onTapClose, show, ...props } = this.props const { opacity, height, inIframe } = this.state const Tag = tag const dialogStyle = { marginTop: this.state.scrollTop } if (!show) { return null } const hasHeader = onTapClose || title return ( <Measure scroll onResize={contentRect => { this.setSize({ width: contentRect.scroll.width, height: contentRect.scroll.height }) }} > {({ measureRef }) => ( <DialogUnderlay className={`${inIframe ? '' : 'not_in_iframe'} `} ref={ref => (this.underlay = ref)} show={show} height={height} onClick={e => { if (e.target.className.search('dialog_underlay') > -1) { this.onTapClose() } }} > <DialogContainer innerRef={measureRef} className={`${className} ${hasHeader ? 'has_header' : ''}`} show={show} opacity={opacity} style={dialogStyle} {...props} > {hasHeader && ( <div className="dialog__header"> {title && <H2>{title}</H2>} {onTapClose && ( <IconButton className="btn__close_dialog" onClick={this.onTapClose.bind(this)} > close </IconButton> )} </div> )} {children} </DialogContainer> </DialogUnderlay> )} </Measure> ) } } Dialog.propTypes = { tag: PropTypes.string, show: PropTypes.bool, onTapClose: PropTypes.func, title: PropTypes.string } Dialog.defaultProps = { tag: 'div', show: true }