48
loading...
This website collects cookies to deliver better user experience
LoginFormModal
component that's abstracted the modal for the login and registration forms. The component itself isn't all that complicated and only accepts a handful of props, but it's pretty inflexible and we'll need to create more modals throughout the application so we want something that's a lot more flexible.<LoginFormModal
onSubmit={handleSubmit}
modalTitle="Modal title"
modalLabelText="Modal label (for screen readers)"
submitButton={<button>Submit form</button>}
openButton={<button>Open Modal</button>}
/>
<Modal>
<ModalOpenButton>
<button>Open Modal</button>
</ModalOpenButton>
<ModalContents aria-label="Modal label (for screen readers)">
<ModalDismissButton>
<button>Close Modal</button>
</ModalDismissButton>
<h3>Modal title</h3>
<div>Some great contents of the modal</div>
</ModalContents>
</Modal>
LoginFormModal
, but it is simpler and more flexible and will suit our future use cases without getting any more complex.Modal
supports this, but theLoginFormModal
would need to accept a new prop. Or what if we want the closerenderCloseBelow
. But with our Modal
, it's obvious. You just move theModalCloseButton
component to where you want it to go.<select>
and <option>
in HTML.modal
.import * as React from 'react'
import VisuallyHidden from '@reach/visually-hidden'
/* Here the Dialog and CircleButton is a custom component
Dialog is nothing button some styles applied on reach-dialog
component provided by @reach-ui */
import {Dialog, CircleButton} from './lib'
const ModalContext = React.createContext()
//this helps in identifying the context while visualizing the component tree
ModalContext.displayName = 'ModalContext'
function Modal(props) {
const [isOpen, setIsOpen] = React.useState(false)
return <ModalContext.Provider value={[isOpen, setIsOpen]} {...props} />
}
function ModalDismissButton({children: child}) {
const [, setIsOpen] = React.useContext(ModalContext)
return React.cloneElement(child, {
onClick: () => setIsOpen(false),
})
}
function ModalOpenButton({children: child}) {
const [, setIsOpen] = React.useContext(ModalContext)
return React.cloneElement(child, {
onClick: () => setIsOpen(true),
})
}
function ModalContentsBase(props) {
const [isOpen, setIsOpen] = React.useContext(ModalContext)
return (
<Dialog isOpen={isOpen} onDismiss={() => setIsOpen(false)} {...props} />
)
}
function ModalContents({title, children, ...props}) {
return (
//we are making generic reusable component thus we allowed user custom styles
//or any prop they want to override
<ModalContentsBase {...props}>
<div>
<ModalDismissButton>
<CircleButton>
<VisuallyHidden>Close</VisuallyHidden>
<span aria-hidden>×</span>
</CircleButton>
</ModalDismissButton>
</div>
<h3>{title}</h3>
{children}
</ModalContentsBase>
)
}
export {Modal, ModalDismissButton, ModalOpenButton, ModalContents}
<Modal>
<ModalOpenButton>
<Button>Login</Button>
</ModalOpenButton>
<ModalContents aria-label="Login form" title="Login">
<LoginForm
onSubmit={register}
submitButton={<Button>Login</Button>}
/>
</ModalContents>
</Modal>
ModalOpenButton
and ModalCloseButton
set the onClick
callAll(() => setIsOpen(false), ()=>console.log("I ran"))
const callAll = (...fns) => (...args) => fns.forEach(fn => fn && fn(...args))
function ModalDismissButton({children: child}) {
const [, setIsOpen] = React.useContext(ModalContext)
return React.cloneElement(child, {
onClick: callAll(() => setIsOpen(false), child.props.onClick),
})
}
function ModalOpenButton({children: child}) {
const [, setIsOpen] = React.useContext(ModalContext)
return React.cloneElement(child, {
onClick: callAll(() => setIsOpen(true), child.props.onClick),
})
}
onClickHandler
to our custom button like this:<ModalOpenButton>
<button onClick={() => console.log('sending data to facebook ;)')}>Open Modal</button>
</ModalOpenButton>