Skip to content

Instantly share code, notes, and snippets.

@pucinsk
Created February 11, 2021 22:20
Show Gist options
  • Save pucinsk/7b74c86098a8f35b2be9117ca9d5a244 to your computer and use it in GitHub Desktop.
Save pucinsk/7b74c86098a8f35b2be9117ca9d5a244 to your computer and use it in GitHub Desktop.
React Material UI 'drawer-like' component which can be rendered from container.
import React, { useMemo, forwardRef, useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { makeStyles, Paper, Slide, ClickAwayListener } from '@material-ui/core'
const useStyles = makeStyles(function (theme) {
return (
{
root: {
backgroundColor: theme.palette.background.paper,
flexGrow: 1,
display: 'flex',
}
}
)
})
const AwesomeDrawer = function ({ direction, open, setOpen, ariaLabel, children }) {
const classes = useStyles()
const Slider = function (sliderProps, ref) {
return (
<ClickAwayListener onClickAway={() => setOpen(false)}>
<Slide ref={ref} {...sliderProps} />
</ClickAwayListener>
)
}
const AwesomeSlider = useMemo(function () {
return (
forwardRef(Slider)
)
})
useEffect(function() {
if (open) {
document.body.classList.add('overlay-visible')
document.documentElement.classList.add('overlay-visible')
} else {
document.body.classList.remove('overlay-visible')
document.documentElement.classList.remove('overlay-visible')
}
}, [open])
return (
<AwesomeSlider direction={direction} in={open} mountOnEnter unmountOnExit>
<Paper className={classes.root} id={ariaLabel}>
{children}
</Paper>
</AwesomeSlider>
)
}
AwesomeDrawer.propTypes = {
direction: PropTypes.oneOf(['left', 'right']),
open: PropTypes.bool,
ariaLabel: PropTypes.string.isRequired,
children: PropTypes.node,
}
AwesomeDrawer.defaultProps = {
direction: 'left',
open: false,
}
export const SliderProvider = (sliderTarget) => {
let open = false
const isOpen = function () {
return !!document.getElementById(sliderTarget)
}
const setOpen = function (newValue) {
open = newValue
notify()
}
let observers = []
const subscribe = function (observer) {
observers.push(observer)
}
const unsubscribe = function (observer) {
observers = observers.filter(_observer => _observer !== observer)
}
const notify = function () {
observers.forEach(observer => observer(open))
}
return (
{
setOpen,
isOpen,
subscribe,
unsubscribe,
}
)
}
export const useSlider = function (provider) {
const [isOpen, setIsOpen] = useState(provider.isOpen())
useEffect(function () {
const listener = function (newIsOpen) {
setIsOpen(newIsOpen)
}
provider.subscribe(listener)
return function () {
provider.unsubscribe(listener)
}
}, [])
return [isOpen, setIsOpen]
}
export default AwesomeDrawer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment