UNPKG

@websolutespa/payload-plugin-bowl

Version:

Bowl PayloadCms plugin of the BOM Repository

119 lines (118 loc) 4.46 kB
'use client'; import { useRouteTransition } from '@payloadcms/ui'; import { useRouter } from 'next/navigation'; import { useCallback, useEffect, useRef } from 'react'; function on(obj, ...args) { if (obj && obj.addEventListener) { obj.addEventListener(...args); } } function off(obj, ...args) { if (obj && obj.removeEventListener) { obj.removeEventListener(...args); } } export const useBeforeUnload = (enabled = true, message)=>{ const handler = useCallback((event)=>{ const finalEnabled = typeof enabled === 'function' ? enabled() : true; if (!finalEnabled) { return; } event.preventDefault(); if (message) { event.returnValue = message; } return message; }, [ enabled, message ]); useEffect(()=>{ if (!enabled) { return; } on(window, 'beforeunload', handler); return ()=>off(window, 'beforeunload', handler); }, [ enabled, handler ]); }; export const usePreventLeave = ({ hasAccepted = false, message = 'Are you sure want to leave this page?', onAccept, onPrevent, prevent = true })=>{ // check when page is about to be reloaded useBeforeUnload(prevent, message); const { startRouteTransition } = useRouteTransition(); const router = useRouter(); const cancelledURL = useRef(''); // check when page is about to be changed useEffect(()=>{ function isAnchorOfCurrentUrl(currentUrl, newUrl) { const currentUrlObj = new URL(currentUrl); const newUrlObj = new URL(newUrl); // Compare hostname, pathname, and search parameters if (currentUrlObj.hostname === newUrlObj.hostname && currentUrlObj.pathname === newUrlObj.pathname && currentUrlObj.search === newUrlObj.search) { // Check if the new URL is just an anchor of the current URL page const currentHash = currentUrlObj.hash; const newHash = newUrlObj.hash; return currentHash !== newHash && currentUrlObj.href.replace(currentHash, '') === newUrlObj.href.replace(newHash, ''); } return false; } function findClosestAnchor(element) { while(element && element.tagName.toLowerCase() !== 'a'){ element = element.parentElement; } return element; } function handleClick(event) { try { const target = event.target; const anchor = findClosestAnchor(target); if (anchor) { const currentUrl = window.location.href; const newUrl = anchor.href; const isAnchor = isAnchorOfCurrentUrl(currentUrl, newUrl); const isDownloadLink = anchor.download !== ''; const isNewTab = anchor.target === '_blank' || event.metaKey || event.ctrlKey; const isPageLeaving = !(newUrl === currentUrl || isAnchor || isDownloadLink || isNewTab); if (isPageLeaving && prevent && (!onPrevent ? !window.confirm(message) : true)) { // Keep a reference of the href cancelledURL.current = newUrl; // Cancel the route change event.preventDefault(); event.stopPropagation(); if (typeof onPrevent === 'function') { onPrevent(); } } } } catch (err) { alert(err); } } // Add the global click event listener document.addEventListener('click', handleClick, true); // Clean up the global click event listener when the component is unmounted return ()=>{ document.removeEventListener('click', handleClick, true); }; }, [ onPrevent, prevent, message ]); useEffect(()=>{ if (hasAccepted && cancelledURL.current) { if (onAccept) { onAccept(); } startRouteTransition(()=>router.push(cancelledURL.current)); } }, [ hasAccepted, onAccept, router, startRouteTransition ]); }; //# sourceMappingURL=usePreventLeave.js.map