UNPKG

@coreui/react

Version:

CoreUI React 17 Bootstrap 4 components

167 lines (146 loc) 4.15 kB
import React, { useState, useEffect, useRef } from 'react' import PropTypes from 'prop-types' import classNames from 'classnames' import { Transition } from 'react-transition-group' export const Context = React.createContext({}) const getTransitionClass = s => { return s === 'entering' ? 'd-block' : s === 'entered' ? 'show d-block' : s === 'exiting' ? 'd-block' : '' } //animation fixes introduced thanks to Sirlordt //component - CoreUI / CModal const CModal = props => { const { innerRef, show, centered, size, color, borderColor, fade, backdrop, closeOnBackdrop, onOpened, onClosed, addContentClass, onClose, className, scrollable, ...attributes } = props const [isOpen, setIsOpen] = useState(false) const [modalTrigger, setModalTrigger] = useState(false) const modalClick = e => e.target.dataset.modal && closeOnBackdrop && close() useEffect(() => { setIsOpen(show) }, [show]) const onKeypress = e => e.keyCode == '27' && close() useEffect(() => { isOpen && document.addEventListener('keydown', onKeypress) return () => document.removeEventListener('keydown', onKeypress) }, [isOpen]) const close = () => { onClose && onClose() setIsOpen(false) } const onEntered = () => { setModalTrigger(document.querySelector(':focus')) nodeRef.current.focus() onOpened && onOpened() } const onExited = () => { modalTrigger && modalTrigger.focus() onClosed && onClosed() } const modalClasses = classNames( 'modal overflow-auto fade', { [`modal-${color}`]: color }, className ) const dialogClasses = classNames( 'modal-dialog', { 'modal-dialog-scrollable': scrollable, 'modal-dialog-centered': centered, [`modal-${size}`]: size } ) const contentClasses = classNames( 'modal-content', { [`border-${borderColor}`]: borderColor, }, addContentClass ) const backdropClasses = classNames({ 'modal-backdrop': true, 'fade': fade, 'show': isOpen || fade }) const nodeRef = useRef(null) return ( <div onClick={modalClick}> <Transition in={Boolean(isOpen)} onEntered={onEntered} onExited={onExited} timeout={fade ? 150 : 0} nodeRef={nodeRef} > {(status) => { let transitionClass = getTransitionClass(status) const classes = classNames( modalClasses, transitionClass ) return ( <div tabIndex="-1" role="dialog" className={classes} data-modal={true} ref={nodeRef} > <div className={dialogClasses} role="document"> <div {...attributes} className={contentClasses} ref={innerRef} > <Context.Provider value={{close}}> {props.children} </Context.Provider> </div> </div> </div> ) }} </Transition> { backdrop && isOpen && <div className={backdropClasses}></div> } </div> ) } CModal.propTypes = { children: PropTypes.node, className: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.object]), innerRef: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), show: PropTypes.bool, centered: PropTypes.bool, size: PropTypes.oneOf(['', 'sm', 'lg', 'xl']), backdrop: PropTypes.bool, color: PropTypes.string, borderColor: PropTypes.string, onOpened: PropTypes.func, onClosed: PropTypes.func, fade: PropTypes.bool, closeOnBackdrop: PropTypes.bool, onClose: PropTypes.func, addContentClass: PropTypes.string, scrollable: PropTypes.bool, } CModal.defaultProps = { backdrop: true, fade: true, closeOnBackdrop: true } export default CModal