one
Version:
One is a new React Framework that makes Vite serve both native and web.
228 lines • 7.35 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all) __defProp(target, name, {
get: all[name],
enumerable: true
});
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: () => from[key],
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
value: true
}), mod);
var useBlocker_exports = {};
__export(useBlocker_exports, {
checkBlocker: () => checkBlocker,
useBlocker: () => useBlocker
});
module.exports = __toCommonJS(useBlocker_exports);
var React = __toESM(require("react"), 1);
var import_react_native = require("react-native-web");
let currentLocation = typeof window !== "undefined" ? window.location.pathname + window.location.search : "";
let isBlocking = false;
let isProceeding = false;
let pendingNavigation = null;
const blockerCallbacks = /* @__PURE__ */new Map();
let listenersSetup = false;
function setupListeners() {
if (listenersSetup || typeof window === "undefined") return;
listenersSetup = true;
currentLocation = window.location.pathname + window.location.search;
window.addEventListener("popstate", () => {
if (isProceeding) return;
const nextLocation = window.location.pathname + window.location.search;
for (const [, callbacks] of blockerCallbacks) {
if (callbacks.shouldBlock()) {
isBlocking = true;
pendingNavigation = {
previousLocation: currentLocation,
nextLocation,
historyAction: "pop"
};
window.history.go(1);
callbacks.onBlock(pendingNavigation);
return;
}
}
currentLocation = nextLocation;
});
const originalPushState = window.history.pushState.bind(window.history);
const originalReplaceState = window.history.replaceState.bind(window.history);
window.history.pushState = function (state, title, url) {
if (isProceeding || !url) {
return originalPushState(state, title, url);
}
const nextLocation = typeof url === "string" ? url : url.toString();
for (const [, callbacks] of blockerCallbacks) {
if (callbacks.shouldBlock()) {
isBlocking = true;
pendingNavigation = {
previousLocation: currentLocation,
nextLocation,
historyAction: "push"
};
callbacks.onBlock(pendingNavigation);
return;
}
}
currentLocation = nextLocation;
return originalPushState(state, title, url);
};
window.history.replaceState = function (state, title, url) {
if (isProceeding || !url) {
return originalReplaceState(state, title, url);
}
const nextLocation = typeof url === "string" ? url : url.toString();
for (const [, callbacks] of blockerCallbacks) {
if (callbacks.shouldBlock()) {
isBlocking = true;
pendingNavigation = {
previousLocation: currentLocation,
nextLocation,
historyAction: "replace"
};
callbacks.onBlock(pendingNavigation);
return;
}
}
currentLocation = nextLocation;
return originalReplaceState(state, title, url);
};
window.addEventListener("beforeunload", event => {
for (const [, callbacks] of blockerCallbacks) {
if (callbacks.shouldBlock()) {
event.preventDefault();
event.returnValue = "";
return;
}
}
});
}
function useBlocker(shouldBlock) {
const [state, setState] = React.useState("unblocked");
const [blockedLocation, setBlockedLocation] = React.useState(null);
const idRef = React.useRef(null);
const shouldBlockRef = React.useRef(shouldBlock);
shouldBlockRef.current = shouldBlock;
React.useEffect(() => {
if (import_react_native.Platform.OS !== "web" || typeof window === "undefined") return;
setupListeners();
const id = Symbol("blocker");
idRef.current = id;
blockerCallbacks.set(id, {
shouldBlock: () => {
const block = shouldBlockRef.current;
if (typeof block === "function") {
return block({
currentLocation,
nextLocation: pendingNavigation?.nextLocation || "",
historyAction: pendingNavigation?.historyAction || "push"
});
}
return block;
},
onBlock: pending => {
setBlockedLocation(pending.nextLocation);
setState("blocked");
},
onProceed: () => {
setState("proceeding");
},
onReset: () => {
setState("unblocked");
setBlockedLocation(null);
}
});
return () => {
blockerCallbacks.delete(id);
};
}, []);
const reset = React.useCallback(() => {
isBlocking = false;
pendingNavigation = null;
setBlockedLocation(null);
setState("unblocked");
}, []);
const proceed = React.useCallback(() => {
if (!pendingNavigation) return;
setState("proceeding");
isProceeding = true;
const pending = pendingNavigation;
pendingNavigation = null;
isBlocking = false;
requestAnimationFrame(() => {
if (pending.historyAction === "pop") {
window.history.back();
} else if (pending.historyAction === "push") {
window.history.pushState(null, "", pending.nextLocation);
} else {
window.history.replaceState(null, "", pending.nextLocation);
}
currentLocation = pending.nextLocation;
requestAnimationFrame(() => {
isProceeding = false;
setBlockedLocation(null);
setState("unblocked");
});
});
}, []);
if (state === "unblocked") {
return {
state: "unblocked"
};
}
if (state === "proceeding") {
return {
state: "proceeding",
location: blockedLocation
};
}
return {
state: "blocked",
reset,
proceed,
location: blockedLocation
};
}
function checkBlocker(nextLocation, historyAction = "push") {
if (import_react_native.Platform.OS !== "web" || typeof window === "undefined") {
return false;
}
if (isProceeding) {
return false;
}
for (const [, callbacks] of blockerCallbacks) {
if (callbacks.shouldBlock()) {
isBlocking = true;
pendingNavigation = {
previousLocation: currentLocation,
nextLocation,
historyAction
};
callbacks.onBlock(pendingNavigation);
return true;
}
}
return false;
}