Last active
April 28, 2022 00:46
-
-
Save sinclairnick/81e7a316b6a68c45ca7bbe539b19e333 to your computer and use it in GitHub Desktop.
Await-able custom confirmation dialog in React, i.e. a custom window.confirm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
Button, | |
Dialog, | |
DialogActions, | |
DialogContent, | |
DialogContentText, | |
DialogTitle, | |
} from "@mui/material"; | |
import { createContext, FC, useContext, useRef, useState } from "react"; | |
import { defaultConfirmArgs } from "./confirmation.constants"; | |
import { | |
ConfirmationContextType, | |
ConfirmationProps, | |
ConfirmFn, | |
} from "./confirmation.types"; | |
const ConfirmationContext = createContext<ConfirmationContextType>({} as any); | |
export const ConfirmationProvider: FC<ConfirmationProps> = (props) => { | |
const [isDialogOpen, setIsDialogOpen] = useState(false); | |
const confirmArgsRef = useRef(defaultConfirmArgs); | |
const handleYesRef = useRef(() => {}); | |
const handleNoRef = useRef(() => {}); | |
const handleClose = () => { | |
handleNoRef.current(); | |
setIsDialogOpen(false); | |
}; | |
const handleConfirm = () => { | |
handleYesRef.current(); | |
setIsDialogOpen(false); | |
}; | |
const confirm: ConfirmFn = async (args = defaultConfirmArgs) => { | |
confirmArgsRef.current = args; | |
setIsDialogOpen(true); | |
return new Promise((res, rej) => { | |
handleYesRef.current = () => res(true); | |
handleNoRef.current = () => res(false); | |
}); | |
}; | |
return ( | |
<> | |
<ConfirmationContext.Provider value={{ confirm }}> | |
{props.children} | |
</ConfirmationContext.Provider> | |
<Dialog open={isDialogOpen} onClose={handleClose}> | |
<DialogTitle>{confirmArgsRef.current.title}</DialogTitle> | |
<DialogContent> | |
<DialogContentText> | |
{confirmArgsRef.current.description} | |
</DialogContentText> | |
</DialogContent> | |
<DialogActions> | |
<Button color="inherit" onClick={handleClose}> | |
Cancel | |
</Button> | |
<Button color="primary" variant="contained" onClick={handleConfirm}> | |
Confirm | |
</Button> | |
</DialogActions> | |
</Dialog> | |
</> | |
); | |
}; | |
export const useConfirm = () => { | |
const ctx = useContext(ConfirmationContext); | |
if (ctx == null) { | |
throw new Error("Cannot use confirmation context outside provider"); | |
} | |
return ctx.confirm; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ConfirmArgs } from "./confirmation.types"; | |
export const defaultConfirmArgs: ConfirmArgs = { | |
title: "Are you sure?", | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ReactNode } from "react"; | |
export type ConfirmationProps = {}; | |
export type ConfirmArgs = { | |
title?: ReactNode; | |
description?: ReactNode; | |
}; | |
export type ConfirmFn = (args?: ConfirmArgs) => Promise<boolean>; | |
export type ConfirmationContextType = { | |
confirm: ConfirmFn; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment