nextjs-router-events
Version:
A router events alternative for Next.js 13+ with app directory with the ability to prevent user navigation.
87 lines (86 loc) • 3.74 kB
JavaScript
'use client';
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
import { jsx as _jsx } from "react/jsx-runtime";
import { FreezeRequestsContext } from './context';
import { triggerBeforeRouteChangeEvent, triggerRouteChangeEndEvent, triggerRouteChangeStartEvent, } from './events';
import React, { useEffect, useState } from 'react';
var createForceClickEvent = function (event) {
var res = new MouseEvent('click', event);
res.isForceAnchorClickEvent = true;
return res;
};
export var RouteChangesProvider = function (_a) {
var children = _a.children;
var _b = __read(useState([]), 2), freezeRequests = _b[0], setFreezeRequests = _b[1];
useEffect(function () {
var abortController = new AbortController();
var handleAnchorClick = function (event) {
var target = event.currentTarget;
var isFrozen = freezeRequests.length !== 0;
if (isFrozen && !event.isForceAnchorClickEvent) {
event.preventDefault();
event.stopPropagation();
window.addEventListener('routeChangeConfirmationEvent', function (ev) {
if (ev.detail.targetUrl === target.href) {
var forceClickEvent = createForceClickEvent(event);
target.dispatchEvent(forceClickEvent); // NOTE: may want to use a timeout here
}
}, { signal: abortController.signal });
triggerBeforeRouteChangeEvent(target.href);
return;
}
triggerRouteChangeStartEvent(target.href);
};
var handleAnchors = function (anchors) {
anchors.forEach(function (a) {
a.addEventListener('click', handleAnchorClick, {
signal: abortController.signal,
capture: true,
});
});
};
var handleMutation = function (mutationList) {
mutationList.forEach(function (record) {
if (record.type === 'childList' && record.target instanceof HTMLElement) {
var anchors_1 = record.target.querySelectorAll('a[href]');
handleAnchors(anchors_1);
}
});
};
var anchors = document.querySelectorAll('a[href]');
handleAnchors(anchors);
var mutationObserver = new MutationObserver(handleMutation);
mutationObserver.observe(document, { childList: true, subtree: true });
var pushStateProxy = new Proxy(window.history.pushState, {
apply: function (target, thisArg, argArray) {
triggerRouteChangeEndEvent(argArray[2]);
return target.apply(thisArg, argArray);
},
getPrototypeOf: function (target) {
return target;
},
});
window.history.pushState = pushStateProxy;
return function () {
mutationObserver.disconnect();
abortController.abort();
window.history.pushState = Object.getPrototypeOf(pushStateProxy);
};
}, [freezeRequests]);
return (_jsx(FreezeRequestsContext.Provider, { value: { freezeRequests: freezeRequests, setFreezeRequests: setFreezeRequests }, children: children }));
};