import "./dialog.scss" ; import * as React from "react" ; import { createPortal , findDOMNode } from "react-dom" ; import { Animate } from "../animate" ; import { cssNames , noop , stopPropagation } from "../../utils" ; export interface DialogProps { className ? : string ; contentClassName ? : string ; isOpen ? : boolean ; open ? : ( ) => void ; close ? : ( ) => void ; onOpen ? : ( ) => void ; onClose ? : ( ) => void ; modal ? : boolean ; pinned ? : boolean ; animated ? : boolean ; } interface DialogState { isOpen : boolean ; } export class Dialog extends React . Component < DialogProps , DialogState > { private contentElem : HTMLElement ; static defaultProps : DialogProps = { isOpen : false , open : noop , close : noop , onOpen : noop , onClose : noop , modal : true , animated : true , pinned : false , } ; public state : DialogState = { isOpen : this . props . isOpen , } ; get elem ( ) { return findDOMNode ( this ) as HTMLElement ; } get isOpen ( ) { return this . state . isOpen ; } componentDidMount ( ) { if ( this . isOpen ) this . onOpen ( ) ; } componentDidUpdate ( prevProps ) { var { isOpen } = this . props ; if ( isOpen !== prevProps . isOpen ) { isOpen ? this . open ( ) : this . close ( ) ; } } componentWillUnmount ( ) { if ( this . isOpen ) this . onClose ( ) ; } open ( ) { setTimeout ( this . onOpen ) ; this . setState ( { isOpen : true } ) ; this . props . open ( ) ; } close ( ) { this . onClose ( ) ; this . setState ( { isOpen : false } ) ; this . props . close ( ) ; } onOpen = ( ) => { this . props . onOpen ( ) ; if ( ! this . props . pinned ) { if ( this . elem ) this . elem . addEventListener ( 'click' , this . onClickOutside ) ; window . addEventListener ( 'keydown' , this . onEscapeKey ) ; } } ; onClose = ( ) => { this . props . onClose ( ) ; if ( ! this . props . pinned ) { if ( this . elem ) this . elem . removeEventListener ( 'click' , this . onClickOutside ) ; window . removeEventListener ( 'keydown' , this . onEscapeKey ) ; } } ; onEscapeKey = ( evt ) => { var escapeKey = evt . code === "Escape" ; if ( escapeKey ) { this . close ( ) ; evt . stopPropagation ( ) ; } } ; onClickOutside = ( evt ) => { var target = evt . target as HTMLElement ; if ( ! this . contentElem . contains ( target ) ) { this . close ( ) ; evt . stopPropagation ( ) ; } } ; render ( ) { if ( ! this . isOpen ) return null ; var { className , modal , animated , pinned , contentClassName } = this . props ; className = cssNames ( "Dialog flex center" , className , { modal , pinned } ) ; contentClassName = cssNames ( "box" , contentClassName ) ; var dialog = ( < div className = { className } onClick = { stopPropagation } > < div className = { contentClassName } ref = { e => this . contentElem = e } > { this . props . children } < /div> < /div>); if ( animated ) { dialog = < Animate name = "opacity-scale" > { dialog } < /Animate>; } return createPortal ( dialog , document . body ) ; } }