Browse Source
and make use of it in the SideBar component, to open the send and receive modals.master
meriadec
7 years ago
10 changed files with 244 additions and 9 deletions
@ -0,0 +1,13 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React, { PureComponent } from 'react' |
||||
|
|
||||
|
import Modal from 'components/base/Modal' |
||||
|
|
||||
|
class ReceiveModal extends PureComponent { |
||||
|
render() { |
||||
|
return <Modal name="receive">receive modal</Modal> |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default ReceiveModal |
@ -0,0 +1,13 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import React, { PureComponent } from 'react' |
||||
|
|
||||
|
import Modal from 'components/base/Modal' |
||||
|
|
||||
|
class SendModal extends PureComponent { |
||||
|
render() { |
||||
|
return <Modal name="send">send modal</Modal> |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default SendModal |
@ -0,0 +1,98 @@ |
|||||
|
// @flow
|
||||
|
/* eslint-disable jsx-a11y/click-events-have-key-events */ |
||||
|
/* eslint-disable jsx-a11y/no-static-element-interactions */ |
||||
|
|
||||
|
import React, { PureComponent } from 'react' |
||||
|
import { connect } from 'react-redux' |
||||
|
import Mortal from 'react-mortal' |
||||
|
import styled from 'styled-components' |
||||
|
|
||||
|
import { closeModal, isModalOpened } from 'reducers/modals' |
||||
|
|
||||
|
type Props = { |
||||
|
isOpened: boolean, |
||||
|
onClose: Function, |
||||
|
children: any, |
||||
|
} |
||||
|
|
||||
|
const springConfig = { |
||||
|
stiffness: 350, |
||||
|
} |
||||
|
|
||||
|
const mapStateToProps = (state, { name, isOpened }) => ({ |
||||
|
isOpened: isOpened || (name && isModalOpened(state, name)), |
||||
|
}) |
||||
|
|
||||
|
const mapDispatchToProps = (dispatch, { name }) => ({ |
||||
|
onClose: name ? () => dispatch(closeModal(name)) : undefined, |
||||
|
}) |
||||
|
|
||||
|
const Container = styled.div.attrs({ |
||||
|
style: p => ({ |
||||
|
pointerEvents: p.isVisible ? 'auto' : 'none', |
||||
|
}), |
||||
|
})` |
||||
|
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({ |
||||
|
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({ |
||||
|
style: p => ({ |
||||
|
opacity: p.op, |
||||
|
transform: `translate3d(0, ${p.offset}px, 0)`, |
||||
|
}), |
||||
|
})` |
||||
|
padding: 20px; |
||||
|
margin-top: 100px; |
||||
|
background: white; |
||||
|
width: 400px; |
||||
|
z-index: 2; |
||||
|
` |
||||
|
|
||||
|
class Modal extends PureComponent<Props> { |
||||
|
render() { |
||||
|
const { isOpened, onClose, children } = this.props |
||||
|
return ( |
||||
|
<Mortal |
||||
|
isOpened={isOpened} |
||||
|
onClose={onClose} |
||||
|
motionStyle={(spring, isVisible) => ({ |
||||
|
opacity: spring(isVisible ? 1 : 0, springConfig), |
||||
|
y: spring(isVisible ? 0 : 20, springConfig), |
||||
|
})} |
||||
|
> |
||||
|
{(m, isVisible) => ( |
||||
|
<Container isVisible={isVisible}> |
||||
|
<Backdrop op={m.opacity} onClick={onClose} /> |
||||
|
<Body op={m.opacity} offset={m.y}> |
||||
|
{children} |
||||
|
</Body> |
||||
|
</Container> |
||||
|
)} |
||||
|
</Mortal> |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps, mapDispatchToProps)(Modal) |
@ -0,0 +1,50 @@ |
|||||
|
// @flow
|
||||
|
|
||||
|
import { handleActions, createAction } from 'redux-actions' |
||||
|
|
||||
|
const state = {} |
||||
|
|
||||
|
type OpenPayload = { |
||||
|
name: string, |
||||
|
data?: Object | null, |
||||
|
} |
||||
|
|
||||
|
type ClosePayload = { |
||||
|
name: string, |
||||
|
} |
||||
|
|
||||
|
const handlers = { |
||||
|
MODAL_OPEN: (state, { payload }: { payload: OpenPayload }) => { |
||||
|
const { name, data } = payload |
||||
|
return { |
||||
|
...state, |
||||
|
[name]: { |
||||
|
isOpened: true, |
||||
|
data, |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
MODAL_CLOSE: (state, { payload }: { payload: ClosePayload }) => { |
||||
|
const { name } = payload |
||||
|
return { |
||||
|
...state, |
||||
|
[name]: { |
||||
|
isOpened: false, |
||||
|
data: null, |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
// Actions
|
||||
|
|
||||
|
export const openModal = createAction('MODAL_OPEN', (name, data = {}) => ({ name, data })) |
||||
|
export const closeModal = createAction('MODAL_CLOSE', name => ({ name })) |
||||
|
|
||||
|
// Selectors
|
||||
|
|
||||
|
export const isModalOpened = (state, name) => state.modals[name] && state.modals[name].isOpened |
||||
|
|
||||
|
// Exporting reducer
|
||||
|
|
||||
|
export default handleActions(handlers, state) |
Loading…
Reference in new issue