UNPKG

react-fantastic

Version:

Fantastic react component library

140 lines 6.44 kB
import React, { Component } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; const objectWithoutProperties = function(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }; const propTypes = { className: PropTypes.string, bg: PropTypes.string, show: PropTypes.bool, width: PropTypes.number, top: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), setCloseDrawer: PropTypes.func, onCloseDrawer: PropTypes.func, onOpenDrawer: PropTypes.func, hideOnClickOutside: PropTypes.bool, toggleDrawerOnDekstop: PropTypes.bool, children: PropTypes.node }; const defaultProps = { bg: 'light', show: true, width: 240, top: 0, hideOnClickOutside: true, toggleDrawerOnDekstop: true }; class Drawer extends Component { constructor(props){ super(props); this.state = { viewport: { width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || window.screen.width, initialClientX: null }, show: props.show, container: null, appbarHeight: props.top }; this.resizeWindow = this.resizeWindow.bind(this); this.onClickOutside = this.onClickOutside.bind(this); this.toggleDrawerOnDekstop = this.toggleDrawerOnDekstop.bind(this); }; componentDidMount(){ let containers = document.body.querySelectorAll('div[class*=container]'), container, drawer = this.drawer; for (const key in containers) { if (containers.hasOwnProperty(key)) { const element = containers[key]; container = drawer.previousSibling === element || drawer.nextSibling === element ? element : null; } } if(container && drawer) { this.setState({ container }); this.state.viewport.width > 768 ? Object.assign(container.style, { position: 'relative', width: Number(container.clientWidth)-(Number(drawer.clientWidth) === 0 ? this.props.width : Number(drawer.clientWidth))+'px' }) : Object.assign(container.style, {width: 100+'%', position: 'initial'}); } window.addEventListener('resize', this.resizeWindow, true); document.body.addEventListener('click', this.onClickOutside, false); }; componentDidUpdate(prevProps) { const { show, toggleDrawerOnDekstop } = this.props; prevProps.show !== show && this.setState({show}); toggleDrawerOnDekstop && this.toggleDrawerOnDekstop(show); }; componentWillUnmount() { window.removeEventListener('resize',this.resizeWindow, false); document.body.removeEventListener('click', this.onClickOutside, false); }; resizeWindow(e) { e && e.preventDefault(); const drawer = this.drawer, browserWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || window.screen.width, { container } = this.state; this.setState({ viewport: { width: browserWidth } }); const appbar = document.querySelector('nav.appbar'); if(browserWidth > 768) { this.setState({ appbarHeight: appbar.clientHeight }); } this.state.viewport.width > 768 ? Object.assign(container.style, { position: 'relative', width: (Number(this.state.viewport.width)-Number(drawer.clientWidth))+'px', left: Number(drawer.clientWidth)+'px' }) : Object.assign(container.style, {width: 100+'%', left: 0, position: 'initial'}); }; onClickOutside(e) { const { viewport, show } = this.state, { setCloseDrawer, hideOnClickOutside, onCloseDrawer } = this.props, drawer = this.drawer; if(show){ e.preventDefault(); if(e.target && !drawer.contains(e.target) && setCloseDrawer && hideOnClickOutside) { e.stopPropagation(); if(viewport.width < 768) { if(onCloseDrawer) { this.props.onCloseDrawer(e); this.props.setCloseDrawer(e); } else { this.props.setCloseDrawer(e); } } } } }; toggleDrawerOnDekstop(show) { let container = this.state.container, drawer = this.drawer; if(this.state.viewport.width > 768) { if(container && drawer) { if(!show) { drawer.className = drawer.className.replace(/drawer-mini/gm, '').trim() + ' drawer-mini'; Object.assign(container.style, { width: (Number(this.state.viewport.width)-Number(this.props.width))+'px', left: Number(drawer.clientWidth)+'px' }); } else { drawer.className = drawer.className.replace(/drawer-mini/gm, '').trim(); Object.assign(container.style, { width: (Number(this.state.viewport.width)-Number(this.props.width))+'px', left: Number(drawer.clientWidth)+'px' }); } } } }; render() { const { className, bg, top, style, children } = this.props, { viewport, show, appbarHeight } = this.state; const classes = classNames('drawer', className, viewport.width < 768 ? show ? 'show' : 'hide' : 'show', {['bg-'+bg]: bg}); return React.createElement( 'div', Object.assign({}, objectWithoutProperties(this.props, Object.keys(propTypes).filter(e => e !== 'children')), { className: classes, ref: el => this.drawer = el, style: Object.assign({}, style, { top: viewport.width < 768 ? String(top)+'px' : String(appbarHeight)+'px', zIndex: top > 0 && 1001 }) } ), children ) } }; Drawer.propTypes = propTypes; Drawer.defaultProps = defaultProps; export default Drawer;