@rocketsofawesome/mirage
Version:
[Live Demo of the Pattern Library](https://rocketsofawesome.github.io/mirage/)
195 lines (180 loc) • 4.49 kB
JavaScript
import React from 'react'
import PropTypes from 'prop-types'
import styled, { keyframes } from 'styled-components'
import classNames from 'classnames'
import {
FlexCol,
FlexRow,
InlineImage,
MegaMenuSection,
NavyLink,
} from 'SRC'
const FadeIn = keyframes`
0% {
opacity: 0;
}
10% {
opacity: 0;
}
100% {
opacity: 1;
}
`
const FadeOut = keyframes`
0% {
opacity: 1;
}
10% {
opacity: 1;
}
99% {
opacity: 0;
height: auto;
}
100% {
opacity: 0;
height: 0;
}
`
export class BaseMegaMenu extends React.Component {
constructor (props) {
super(props)
this.state = {
closed: props.closed,
closing: props.closing,
menuImage: undefined
}
this.menu = undefined
}
componentDidUpdate (prevProps) {
const { visible: currentlyVisible, animationLength } = this.props
if (!currentlyVisible && currentlyVisible !== prevProps.visible) {
this.setState({closing: true})
setTimeout(() => { this.setState({closed: true})}, animationLength)
} else if (currentlyVisible && currentlyVisible !== prevProps.visible) {
this.setState({closed: false, closing: false})
}
}
setRef = (elem) => {
this.menu = elem
}
setMenuImage = (src) => () => {
this.setState({menuImage: src})
}
clearMenuImage = () => {
this.setState({menuImage: undefined})
}
render () {
const { className, regions, visible, renderLink } = this.props
const { menuImage: src, closing, closed } = this.state
const classes = classNames(className, {
'opened': visible,
'closed': closed,
'closing': closing
})
return (
<div ref={this.setRef} className={classes}>
<FlexRow element='menu' constrained>
<FlexCol desktop={{width: 3, span: 2}}>
{regions.left.map((section, id) => {
return (
<MegaMenuSection
key={`left-${id}`}
section={section}
renderLink={renderLink}
setMenuImage={this.setMenuImage}
clearMenuImage={this.clearMenuImage} />
)
})}
</FlexCol>
<FlexCol desktop={{width: 3}}>
{regions.right.map((section, id) => {
return (
<MegaMenuSection
key={`right-${id}`}
section={section}
renderLink={renderLink}
setMenuImage={this.setMenuImage}
clearMenuImage={this.clearMenuImage} />
)
})}
</FlexCol>
<FlexCol desktop={{width: 4}}>
<div className='imageContainer'>
{src && <InlineImage aria-hidden className='menuImage' src={src} />}
</div>
</FlexCol>
</FlexRow>
</div>
)
}
}
const MegaMenu = styled(BaseMegaMenu)`
overflow: hidden;
padding-top: 4rem;
padding-bottom: 4rem;
background-color: ${props => props.theme.colors.white};
box-shadow: 0 2px 1px 0 rgba(0,0,0,.16);
border-top: 0.2rem solid ${props => props.theme.colors.rocketBlue};
border-bottom: 0.2rem solid ${props => props.theme.colors.rocketBlue};
z-index: 100;
&.closed {
opacity: 0;
height: 0;
padding: 0;
}
&.closing {
opacity: 0;
animation: ${FadeOut} ${props => (props.animationLength / 1000)}s ease-in;
}
&.opened {
opacity: 1;
animation: ${FadeIn} ${props => (props.animationLength / 1000)}s ease-in;
}
${NavyLink} {
margin-bottom: 1rem;
display: inline-block;
}
li {
list-style: none;
}
}
.imageContainer {
position: relative;
width: 100%;
height: 100%;
display: flex;
}
.menuImage {
position: absolute;
left: 0;
top: 0;
width: auto;
max-width: 100%;
max-height: 30rem;
margin-top: 2rem;
border: 0.1rem solid ${props => props.theme.colors.rocketBlue};
border-radius: 0.2rem;
animation: ${FadeIn} ${props => (props.animationLength / 1000)}s ease-in;
}
`
MegaMenu.propTypes = {
animationLength: PropTypes.number,
className: PropTypes.string,
closed: PropTypes.bool,
closing: PropTypes.bool,
regions: PropTypes.shape({
left: PropTypes.array,
right: PropTypes.array
}),
visible: PropTypes.bool,
renderLink: PropTypes.func
}
MegaMenu.defaultProps = {
closed: true,
closing: false,
animationLength: 300,
visible: false
}
/** @component */
export default MegaMenu