one
Version:
One is a React framework for web, iOS, and Android apps.
178 lines (175 loc) • 4.46 kB
JavaScript
import { nanoid } from "nanoid/non-secure";
function createMemoryHistory() {
let index = 0;
let items = [];
const pending = [];
const interrupt = () => {
pending.forEach((it) => {
const cb = it.cb;
it.cb = () => cb(true);
});
};
const history = {
get index() {
const id = window.history.state?.id;
if (id) {
const index2 = items.findIndex((item) => item.id === id);
return index2 > -1 ? index2 : 0;
}
return 0;
},
get(index2) {
return items[index2];
},
backIndex({ path }) {
for (let i = index - 1; i >= 0; i--) {
const item = items[i];
if (item.path === path) {
return i;
}
}
return -1;
},
push({ path, state, displayPath, unmaskOnReload }) {
interrupt();
const id = nanoid();
items = items.slice(0, index + 1);
items.push({
path,
state,
id,
displayPath
});
index = items.length - 1;
const urlPath = displayPath ?? path;
if (process.env.ONE_DEBUG_ROUTER) {
console.info(`[one] \u{1F4DC} history.push path=${path}${displayPath ? ` displayPath=${displayPath}` : ""}`);
}
const historyState = { id };
if (displayPath && displayPath !== path) {
historyState.__tempLocation = {
pathname: path,
search: "",
hash: ""
};
if (unmaskOnReload) {
historyState.__tempKey = id;
}
}
window.history.pushState(historyState, "", urlPath);
},
replace({ path, state, displayPath, unmaskOnReload }) {
interrupt();
const id = window.history.state?.id ?? nanoid();
let pathWithHash = path;
const hash = pathWithHash.includes("#") ? "" : location.hash;
if (!items.length || items.findIndex((item) => item.id === id) < 0) {
pathWithHash = pathWithHash + hash;
items = [{
path: pathWithHash,
state,
id,
displayPath
}];
index = 0;
} else {
if (items[index].path === path) {
pathWithHash = pathWithHash + hash;
}
items[index] = {
path,
state,
id,
displayPath
};
}
const urlPath = displayPath ? displayPath + hash : pathWithHash;
if (process.env.ONE_DEBUG_ROUTER) {
console.info(`[one] \u{1F4DC} history.replace path=${pathWithHash}${displayPath ? ` displayPath=${displayPath}` : ""}`);
}
const historyState = { id };
if (displayPath && displayPath !== path) {
historyState.__tempLocation = {
pathname: path,
search: "",
hash: ""
};
if (unmaskOnReload) {
historyState.__tempKey = id;
}
}
window.history.replaceState(historyState, "", urlPath);
},
go(n) {
interrupt();
const nextIndex = index + n;
const lastItemIndex = items.length - 1;
if (n < 0 && !items[nextIndex]) {
n = -index;
index = 0;
} else if (n > 0 && nextIndex > lastItemIndex) {
n = lastItemIndex - index;
index = lastItemIndex;
} else {
index = nextIndex;
}
if (n === 0) {
return;
}
return new Promise((resolve, reject) => {
const done = (interrupted) => {
clearTimeout(timer);
if (interrupted) {
reject(new Error("History was changed during navigation."));
return;
}
const { title } = window.document;
window.document.title = "";
window.document.title = title;
resolve();
};
pending.push({
ref: done,
cb: done
});
const timer = setTimeout(() => {
const index2 = pending.findIndex((it) => it.ref === done);
if (index2 > -1) {
pending[index2].cb();
pending.splice(index2, 1);
}
}, 100);
const onPopState = () => {
const id = window.history.state?.id;
const currentIndex = items.findIndex((item) => item.id === id);
index = Math.max(currentIndex, 0);
const last = pending.pop();
window.removeEventListener("popstate", onPopState);
last?.cb();
};
window.addEventListener("popstate", onPopState);
window.history.go(n);
});
},
listen(listener) {
const onPopState = () => {
if (pending.length) {
return;
}
const popId = window.history.state?.id;
if (popId) {
const foundIndex = items.findIndex((item) => item.id === popId);
if (foundIndex > -1) {
index = foundIndex;
}
}
listener();
};
window.addEventListener("popstate", onPopState);
return () => window.removeEventListener("popstate", onPopState);
}
};
return history;
}
export { createMemoryHistory };
//# sourceMappingURL=createMemoryHistory.mjs.map