@muryp/router-dom
Version:
spa in astro or native/vanilla js
107 lines (106 loc) • 3.22 kB
JavaScript
function convertRoutes(t) {
let n = {};
for (let r in t) {
if (!Object.prototype.hasOwnProperty.call(t, r)) continue;
let i = t[r];
if (r.startsWith("@")) {
n[r] = typeof i == "object" && i ? convertRoutes(i) : i;
continue;
}
let a = r.replace(/^\//, "").split("/").filter(Boolean);
if (a.length <= 1) {
let t = a[0] || r;
typeof i == "object" && i ? n[t] = {
...n[t],
...convertRoutes(i)
} : n[t] = i;
continue;
}
let o = n;
a.forEach((t, n) => {
if (o[t] || (o[t] = {}), n === a.length - 1) {
let n = typeof i == "object" && i ? convertRoutes(i) : { component: i };
o[t] = {
...o[t],
...n
};
}
o = o[t];
});
}
return n;
}
function matchRouteLogic(e, t) {
let n = t, r = {}, i = [];
if ((n.middleware || n.layout) && i.push({
middleware: n.middleware,
layout: n.layout
}), e.length === 0) return t["@home"] && i.push(t["@home"]), {
configs: i,
params: r
};
for (let t of e) {
if (!n || typeof n != "object") break;
let e = n[t];
if (!e) {
let i = Object.keys(n).find((e) => e.startsWith(":"));
if (i) r[i.slice(1)] = t, e = n[i];
else return {
configs: [],
params: {}
};
}
n = e, (n.layout || n.component || n.middleware) && i.push(n);
}
return {
configs: i,
params: r
};
}
function parseUrlLogic(e, t, n = "/") {
let r = n.replace(/\/$/, "") + "/", i = new URL(e).pathname.replace(r, ""), [a, o] = t.replace(/^#/, "").split("#"), [s, c] = a.split("?"), l = `${i}/${s}`.split("/").filter(Boolean), u = {};
return c && new URLSearchParams(c).forEach((e, t) => {
u[t] = e;
}), {
segments: l,
query: u,
anchor: o
};
}
async function executeComponent(e, t, n) {
return typeof e == "string" ? e : await e(t, n) || "";
}
async function render({ routes: e, settings: i }) {
let s = window.location.href, c = window.location.hash, { segments: l, query: u, anchor: d } = parseUrlLogic(s, c, i.rootUrl), { configs: f, params: p } = matchRouteLogic(l, e), m = {
params: p,
query: u,
url: s,
id: i.id
}, h = f.length === 0 || !f.some((e) => e.component) ? [e["@404"]] : f;
if (i.middleware && i.middleware(m) === !1) return redirectToHome();
for (let e of h) if (e.middleware && await e.middleware(m) === !1) return redirectToHome();
let g = "", _ = [...h].reverse(), v = _.find((e) => e.component);
v?.component && (g = await executeComponent(v.component, m));
for (let e of _) e.layout && (g = await executeComponent(e.layout, m, g));
let y = document.getElementById(i.id);
y && (y.innerHTML = g), updateTitle(_, m), h.forEach((e) => e.script?.(m)), i.script?.(m), d && document.getElementById(d)?.scrollIntoView();
}
function redirectToHome() {
window.location.hash = "#/";
}
async function updateTitle(e, t) {
let n = e.find((e) => e.title);
if (n?.title) {
let e = typeof n.title == "function" ? await n.title(t) : n.title;
e && (document.title = e);
}
}
function onChange(e) {
window.onpopstate = async () => {
render(e);
};
}
function MurypRoutesDom(t) {
t.routes = convertRoutes(t.routes), t.routes["@home"] = t.routes["/"], delete t.routes["/"], t.settings.isFirstRender !== !1 && render(t), onChange(t);
}
export { MurypRoutesDom as default };