Last active
February 20, 2019 18:37
-
-
Save alobato/9f8e867a9fb1de4185c3baeab5c79faa to your computer and use it in GitHub Desktop.
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
| import React, { useEffect } from 'react' | |
| import Modal from '../components/StyledModalAlert' | |
| const Alert = ({autoHideDuration = 3000, open, message, onClose}) => { | |
| return ( | |
| <> | |
| {open && ( | |
| <Modal | |
| hasBackdrop={false} | |
| onCloseCompleted={() => onClose()} | |
| render={({onRequestClose}) => { | |
| let timeout | |
| useEffect(() => { | |
| if (open) { | |
| timeout = setTimeout(() => { | |
| onRequestClose() | |
| }, autoHideDuration) | |
| return () => clearTimeout(timeout) | |
| } | |
| }, [open]) | |
| return ( | |
| <div onClick={() => onRequestClose()}>{message}</div> | |
| ) | |
| }} | |
| /> | |
| )} | |
| </> | |
| ) | |
| } | |
| export default Alert |
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
| import React, { forwardRef, useRef, useEffect } from 'react' | |
| import { createPortal } from 'react-dom' | |
| import useKeyPress from '../hooks/useKeypress' | |
| import useLockBodyScroll from '../hooks/useLockBodyScroll' | |
| const Portal = ({children}) => createPortal(children, document.getElementById('modal-root')) | |
| const Backdrop = forwardRef(({onClick, zIndex = 1000, style}, ref) => ( | |
| <div ref={ref} style={{position: 'fixed', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: 'black', opacity: 0, zIndex: zIndex, outline: 'none', tabIndex: -1, ...style}} onClick={onClick} /> | |
| )) | |
| const Modal = ({render, className, onCloseCompleted = () => {}, zIndex = 1001, hasBackdrop = true, clickOutsideDisabled = false, backdropOpacity = 0.6, exitAnimation, enterAnimation, backdropStyle}) => { | |
| if (hasBackdrop) useLockBodyScroll() | |
| const modal = useRef() | |
| const backdrop = useRef() | |
| let initialOpacity = 0 | |
| const handleExit = () => { | |
| if (exitAnimation) { | |
| exitAnimation(modal, backdrop, backdropOpacity, onCloseCompleted) | |
| } else { | |
| onCloseCompleted() | |
| } | |
| } | |
| useEffect(() => { | |
| if (enterAnimation) { | |
| enterAnimation(modal, backdrop, backdropOpacity) | |
| } else { | |
| modal.current.style.opacity = 1 | |
| modal.current.style.transform = 'translateY(0)' | |
| backdrop.current.style.opacity = backdropOpacity | |
| } | |
| }, []) | |
| const escPress = useKeyPress('Escape') | |
| if (escPress) handleExit() | |
| return ( | |
| <Portal> | |
| <div className={className} ref={modal} tabIndex='-1' style={{opacity: initialOpacity, position: 'fixed', top: 0, right: 0, bottom: 0, left: 0, zIndex: zIndex, overflow: 'hidden', pointerEvents: 'none', outline: 'none', display: 'flex', alignItems: 'center', justifyContent: 'center'}}> | |
| <div> | |
| {render({onRequestClose: handleExit})} | |
| </div> | |
| </div> | |
| {hasBackdrop && | |
| <Backdrop | |
| style={backdropStyle} | |
| ref={backdrop} | |
| onClick={() => { | |
| if (clickOutsideDisabled) return false | |
| handleExit() | |
| }} /> | |
| } | |
| </Portal> | |
| ) | |
| } | |
| export default Modal |
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
| import { Component } from 'react' | |
| import PropTypes from 'prop-types' | |
| import { createPortal } from 'react-dom' | |
| const portalRoot = document.getElementById('portal-root') | |
| export default class Portal extends Component { | |
| static propTypes = { | |
| children: PropTypes.node.isRequired | |
| } | |
| render() { | |
| return createPortal(this.props.children, portalRoot) | |
| } | |
| } |
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
| import React from 'react' | |
| import Modal from './Modal' | |
| import styled from 'styled-components' | |
| const enterAnimation = (modal, backdrop, backdropOpacity) => { | |
| if (!modal.current) return | |
| if ('animate' in modal.current) { | |
| backdrop.current.animate([{opacity: 0}, {opacity: backdropOpacity}], {duration: 300, easing: 'ease'}) | |
| modal.current.animate([{opacity: 0, transform: 'translateY(-100px)'}, {opacity: 1, transform: 'translateY(0)'}], {duration: 300, easing: 'ease'}) | |
| .onfinish = () => { | |
| if (modal.current) { modal.current.style.opacity = 1 } | |
| if (backdrop.current) { backdrop.current.style.opacity = backdropOpacity } | |
| } | |
| } else { | |
| modal.current.style.opacity = 1 | |
| modal.current.style.transform = 'translateY(0)' | |
| backdrop.current.style.opacity = backdropOpacity | |
| } | |
| } | |
| const exitAnimation = (modal, backdrop, backdropOpacity, callback) => { | |
| if (!modal.current) return | |
| if ('animate' in modal.current) { | |
| backdrop.current.animate([{opacity: backdropOpacity}, {opacity: 0}], {duration: 300, easing: 'ease'}) | |
| modal.current.animate([{opacity: 1, transform: 'translateY(0)'}, {opacity: 0, transform: 'translateY(-100px)'}], {duration: 300, easing: 'ease'}) | |
| .onfinish = () => { callback() } | |
| } else { | |
| callback() | |
| } | |
| } | |
| const StyledModal = styled(Modal)` | |
| & > div { | |
| position: relative; | |
| background-color: white; | |
| box-shadow: 0 7px 8px -4px rgba(0,0,0,0.2), 0 13px 19px 2px rgba(0,0,0,0.14), 0 5px 24px 4px rgba(0,0,0,0.12); | |
| pointer-events: auto; | |
| height: calc(100vh); | |
| max-height: 295px; | |
| margin: 0; | |
| overflow: scroll; | |
| width: 100%; | |
| border-radius: 8px; | |
| @media (min-width: 40em) { | |
| margin: 32px auto; | |
| width: auto; | |
| /* height: min-content; */ | |
| height: calc(100vh - 64px); | |
| max-height: 800px; | |
| min-width: 36em; | |
| } | |
| } | |
| ` | |
| const StyledModalWithAnimations = props => ( | |
| <StyledModal enterAnimation={enterAnimation} exitAnimation={exitAnimation} {...props} /> | |
| ) | |
| export default StyledModalWithAnimations |
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
| import React from 'react' | |
| import Modal from './Modal' | |
| import styled from 'styled-components' | |
| const enterAnimation = (modal, backdrop, backdropOpacity) => { | |
| if (!modal.current) return | |
| if ('animate' in modal.current) { | |
| modal.current.animate([{opacity: 0, transform: 'translateY(-100px)'}, {opacity: 1, transform: 'translateY(0)'}], {duration: 300, easing: 'ease'}) | |
| .onfinish = () => { | |
| if (modal.current) { modal.current.style.opacity = 1 } | |
| } | |
| } else { | |
| modal.current.style.opacity = 1 | |
| modal.current.style.transform = 'translateY(0)' | |
| } | |
| } | |
| const exitAnimation = (modal, backdrop, backdropOpacity, callback) => { | |
| if (!modal.current) return | |
| if ('animate' in modal.current) { | |
| modal.current.animate([{opacity: 1, transform: 'translateY(0)'}, {opacity: 0, transform: 'translateY(-100px)'}], {duration: 300, easing: 'ease'}) | |
| .onfinish = () => { callback() } | |
| } else { | |
| callback() | |
| } | |
| } | |
| const StyledModal = styled(Modal)` | |
| align-items: stretch !important; | |
| & > div { | |
| cursor: pointer; | |
| margin-top: 8px; | |
| pointer-events: auto !important; | |
| height: 40px; | |
| border-radius: 4px; | |
| padding: 0 40px; | |
| background-color: hsla(0, 0%, 0%, 0.8); | |
| color: hsla(0, 0%, 90%, 1); | |
| min-width: 100px; | |
| text-align: center; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| ` | |
| const StyledModalWithAnimations = props => ( | |
| <StyledModal enterAnimation={enterAnimation} exitAnimation={exitAnimation} {...props} /> | |
| ) | |
| export default StyledModalWithAnimations |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment