|
|
@ -1,4 +1,5 @@ |
|
|
|
// @flow
|
|
|
|
|
|
|
|
/* eslint-disable jsx-a11y/click-events-have-key-events */ |
|
|
|
/* eslint-disable jsx-a11y/no-static-element-interactions */ |
|
|
|
|
|
|
@ -8,12 +9,19 @@ import Mortal from 'react-mortal' |
|
|
|
import styled from 'styled-components' |
|
|
|
import noop from 'lodash/noop' |
|
|
|
|
|
|
|
import type { Element } from 'react' |
|
|
|
|
|
|
|
import { rgba } from 'styles/helpers' |
|
|
|
|
|
|
|
import { closeModal, isModalOpened } from 'reducers/modals' |
|
|
|
|
|
|
|
import Box from 'components/base/Box' |
|
|
|
|
|
|
|
type Props = { |
|
|
|
isOpened?: boolean, |
|
|
|
onClose: Function, |
|
|
|
children: any, |
|
|
|
preventBackdropClick: boolean, |
|
|
|
render: Function, |
|
|
|
} |
|
|
|
|
|
|
|
const springConfig = { |
|
|
@ -33,56 +41,58 @@ const mapDispatchToProps = (dispatch, { name, onClose = noop }) => ({ |
|
|
|
: onClose, |
|
|
|
}) |
|
|
|
|
|
|
|
const Container = styled.div.attrs({ |
|
|
|
const Container = styled(Box).attrs({ |
|
|
|
align: 'center', |
|
|
|
justify: 'flex-start', |
|
|
|
sticky: true, |
|
|
|
style: p => ({ |
|
|
|
pointerEvents: p.isVisible ? 'auto' : 'none', |
|
|
|
}), |
|
|
|
})` |
|
|
|
overflow: hidden; |
|
|
|
position: fixed; |
|
|
|
z-index: 1; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
right: 0; |
|
|
|
bottom: 0; |
|
|
|
overflow: hidden; |
|
|
|
display: flex; |
|
|
|
align-items: flex-start; |
|
|
|
justify-content: center; |
|
|
|
` |
|
|
|
|
|
|
|
const Backdrop = styled.div.attrs({ |
|
|
|
const Backdrop = styled(Box).attrs({ |
|
|
|
bg: p => rgba(p.theme.colors.black, 0.4), |
|
|
|
sticky: true, |
|
|
|
style: p => ({ |
|
|
|
opacity: p.op, |
|
|
|
}), |
|
|
|
})` |
|
|
|
position: fixed; |
|
|
|
top: 0; |
|
|
|
left: 0; |
|
|
|
right: 0; |
|
|
|
bottom: 0; |
|
|
|
background: rgba(0, 0, 0, 0.4); |
|
|
|
` |
|
|
|
|
|
|
|
const Body = styled.div.attrs({ |
|
|
|
const Wrapper = styled(Box).attrs({ |
|
|
|
bg: 'transparent', |
|
|
|
flow: 20, |
|
|
|
mt: 100, |
|
|
|
style: p => ({ |
|
|
|
opacity: p.op, |
|
|
|
transform: `translate3d(0, ${p.offset}px, 0)`, |
|
|
|
}), |
|
|
|
})` |
|
|
|
padding: 20px; |
|
|
|
margin-top: 100px; |
|
|
|
background: white; |
|
|
|
width: 400px; |
|
|
|
width: 430px; |
|
|
|
z-index: 2; |
|
|
|
` |
|
|
|
|
|
|
|
class Modal extends PureComponent<Props> { |
|
|
|
const Body = styled(Box).attrs({ |
|
|
|
bg: p => p.theme.colors.white, |
|
|
|
p: 20, |
|
|
|
})` |
|
|
|
border-radius: 5px; |
|
|
|
` |
|
|
|
|
|
|
|
export class Modal extends PureComponent<Props> { |
|
|
|
static defaultProps = { |
|
|
|
onClose: noop, |
|
|
|
preventBackdropClick: true, |
|
|
|
isOpened: false, |
|
|
|
} |
|
|
|
|
|
|
|
render() { |
|
|
|
const { isOpened, onClose, children } = this.props |
|
|
|
const { preventBackdropClick, isOpened, onClose, render } = this.props |
|
|
|
return ( |
|
|
|
<Mortal |
|
|
|
isOpened={isOpened} |
|
|
@ -94,10 +104,10 @@ class Modal extends PureComponent<Props> { |
|
|
|
> |
|
|
|
{(m, isVisible) => ( |
|
|
|
<Container isVisible={isVisible}> |
|
|
|
<Backdrop op={m.opacity} onClick={onClose} /> |
|
|
|
<Body op={m.opacity} offset={m.y}> |
|
|
|
{children} |
|
|
|
</Body> |
|
|
|
<Backdrop op={m.opacity} onClick={preventBackdropClick ? undefined : onClose} /> |
|
|
|
<Wrapper op={m.opacity} offset={m.y}> |
|
|
|
{render({ onClose })} |
|
|
|
</Wrapper> |
|
|
|
</Container> |
|
|
|
)} |
|
|
|
</Mortal> |
|
|
@ -105,4 +115,25 @@ class Modal extends PureComponent<Props> { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
export const ModalBody = ({ |
|
|
|
children, |
|
|
|
onClose, |
|
|
|
}: { |
|
|
|
children: Element<any> | string, |
|
|
|
onClose?: Function, |
|
|
|
}) => ( |
|
|
|
<Body> |
|
|
|
{onClose && ( |
|
|
|
<Box align="flex-end"> |
|
|
|
<Box onClick={onClose}>[x]</Box> |
|
|
|
</Box> |
|
|
|
)} |
|
|
|
{children} |
|
|
|
</Body> |
|
|
|
) |
|
|
|
|
|
|
|
ModalBody.defaultProps = { |
|
|
|
onClose: undefined, |
|
|
|
} |
|
|
|
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(Modal) |