Skip to content

Instantly share code, notes, and snippets.

@brendancarney
Created May 4, 2020 13:47
Show Gist options
  • Save brendancarney/28fef2a00c79c6c387af93c744f70f36 to your computer and use it in GitHub Desktop.
Save brendancarney/28fef2a00c79c6c387af93c744f70f36 to your computer and use it in GitHub Desktop.
import { useEffect } from "react"
import { confirm } from "../modals"
const hrefBlank = element => {
const href = element.getAttribute("href")
return !href || href === "#"
}
function useBeforeLeave({
message = "",
title = "Unsaved Changes",
enabled = true,
confirm: confirmText = "Leave without saving",
cancel = "Cancel",
} = {}) {
useEffect(() => {
const handleClick = async event => {
if (!enabled) return
const element = event.target
if (element.matches("a") && !element.dataset.confirmed) {
// don't trigger for empty href
if (hrefBlank(element)) return
// don't trigger if the link would open in a new window
if (element.target === "_blank") return
if (element.isContentEditable) return
// We always prevent the default action because the event listener is
// synchronous, and determining if the user wants to navigate away is
// asynchronous.
event.preventDefault()
const confirmation = await confirm(title, {
message,
confirm: confirmText,
cancel,
})
if (confirmation) {
// Once confirmed, set data-confirm so we can retrigger the click,
// but not prompt for confirmation next time.
element.dataset.confirmed = true
element.click()
}
}
}
document.addEventListener("click", handleClick)
return () => document.removeEventListener("click", handleClick)
}, [message, title, enabled, confirmText, cancel])
}
export default useBeforeLeave
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment