@sgpinkus/my-vue-router
Version:
A very simple Vue router
237 lines (236 loc) • 7.47 kB
JavaScript
import { defineComponent as h, ref as u, watch as b, h as i, createBlock as l, createCommentVNode as _, openBlock as m, unref as p, withCtx as f, renderSlot as d, shallowRef as $ } from "vue";
import { compile as g, match as C } from "path-to-regexp";
const v = h({
name: "RoutePath",
props: {
path: {
type: String,
required: !0
}
},
setup(e, { slots: t }) {
const { route: a } = r.matchPath(e.path);
let o = u({});
return b([r == null ? void 0 : r.currentRoute, r == null ? void 0 : r.currentPath], () => {
o.value = {
route: !0,
"route-active": a ? r.isActiveRoute(a) : !1,
"route-hyper-active": r.isCurrentPath(e.path)
};
}, { immediate: !0 }), () => i(
"a",
{
onClick: (n) => {
r.dispatch({ path: e.path }), n.preventDefault();
},
class: o.value,
href: e.path
},
t.default && t.default()
);
}
}), y = h({
name: "RouteName",
props: {
name: {
type: String,
required: !0
},
params: {
type: Object,
required: !1
}
},
setup(e, { slots: t }) {
const { route: a, path: o } = r.matchName(e.name, e.params);
let n = u({});
return b([r == null ? void 0 : r.currentRoute, r == null ? void 0 : r.currentPath], () => {
n.value = {
route: !0,
"route-active": a ? r.isActiveRoute(a) : !1,
"route-hyper-active": r.isCurrentPath(o)
};
}, { immediate: !0 }), () => i(
"a",
{
onClick: (s) => {
r.dispatch({ name: e.name, params: e.params }), s.preventDefault();
},
href: o,
class: n.value
},
t.default && t.default()
);
}
}), N = h({
name: "RouteView",
setup() {
return () => {
var o;
const e = (o = r.currentRoute) == null ? void 0 : o.value;
let t = {};
typeof (e == null ? void 0 : e.props) == "function" ? t = e == null ? void 0 : e.props(e) : e != null && e.props && (t = e == null ? void 0 : e.props), P("routeProp", e, r) && (t.route = r == null ? void 0 : r.currentRouteProp()), P("paramsToProps", e, r) && (t = { ...t, ...r.currentRouteParams.value });
const a = e != null && e.component ? i(e.component, t) : [];
return k("View render", e.__file), i(a);
};
}
});
function P(e, t, a) {
return t[e] || a.options[e] || !1;
}
function k(...e) {
}
const S = /* @__PURE__ */ h({
__name: "route-link",
props: {
name: {},
params: {},
path: {}
},
setup(e) {
const t = e;
return (a, o) => t.path ? (m(), l(p(v), {
key: 0,
path: t.path
}, {
default: f(() => [
d(a.$slots, "default")
]),
_: 3
}, 8, ["path"])) : t.name ? (m(), l(p(y), {
key: 1,
name: t.name,
params: t.params
}, {
default: f(() => [
d(a.$slots, "default")
]),
_: 3
}, 8, ["name", "params"])) : _("", !0);
}
}), A = Symbol(), O = {
installGlobalRef: "$router",
routeProp: !1,
paramsToProps: !1,
basePath: void 0
}, j = () => i("div"), q = {
name: "null",
path: "*",
component: j,
_match: () => !1,
_compile: () => "",
_id: -1
};
let r = null;
function U(e, t = {}) {
return r = new L(e, t), r;
}
function x() {
if (!r)
throw new Error("Router not initialized. Call createRouter() first.");
return r;
}
function R(e) {
return "component" in e;
}
function w(e) {
return "redirect" in e;
}
function B(e, t) {
return Object.entries(e).length !== Object.entries(t).length ? !1 : Object.entries(e).every(([a, o]) => t[a] === o);
}
function c(e) {
return new URL(e, "http://dummy-base.local");
}
function V(e) {
const t = c(e).hash.replace(/^#/, "");
if (t) {
const a = document.querySelector(`a[name="${t}"`) || document.querySelector(`a[id="${t}"`);
a && a.scrollIntoView({});
}
}
function E(e) {
if (e && (e = `/${e}`.replaceAll(/\/+/g, "/"), e !== "/"))
return e.replace(/\/$/, "");
}
class L {
constructor(t, a = {}) {
this.currentRoute = $(q), this.currentPath = u(""), this.currentRouteParams = u({}), this.routes = [], this.options = {}, this.options = { ...O, ...a, basePath: E(a.basePath) }, this.routes = t.map((n, s) => ({ ...n, _match: C(n.path), _compile: g(n.path), _id: s }));
const o = new URL(window.location.href).pathname;
this.setPath(this.unBasePath(o)), window.addEventListener("popstate", (n) => this.historyPopState(n));
}
matchPath(t) {
const a = c(t);
for (const o of this.routes) {
const n = o._match(a.pathname);
if (n)
return { route: o, ...n };
}
return { route: void 0, params: {} };
}
matchName(t, a = {}) {
for (const o of this.routes)
if (o.name === t)
try {
const n = o._compile(a);
if (n) return { route: o, path: n };
} catch (n) {
console.error(n);
continue;
}
return { route: void 0, path: "" };
}
setPath(t, a = !0) {
const { route: o, params: n } = this.matchPath(t);
return o ? (R(o) ? (this.currentRoute.value = o, this.currentPath.value = t, this.currentRouteParams.value = n, a && window.history.pushState({ path: t }, "", this.rebasePath(t)), V(t)) : w(o) && (window.location.href = this.rebasePath(o.redirect)), !0) : !1;
}
setName(t, a = {}, o = !0) {
const { route: n, path: s } = this.matchName(t, a);
return n ? (R(n) ? (this.currentRoute.value = n, this.currentPath.value = s, this.currentRouteParams.value = a, o && window.history.pushState({ name: t, params: a }, "", this.rebasePath(s))) : w(n) && (window.location.href = this.rebasePath(n.redirect)), !0) : !1;
}
currentRouteProp() {
const t = ["name", "path", "meta"];
return { ...Object.fromEntries(
Object.entries(this.currentRoute.value).filter(([o]) => t.includes(o))
), params: this.currentRouteParams.value };
}
isActiveRoute(t) {
return t._id === this.currentRoute.value._id;
}
isCurrentPath(t) {
return window.location.href.replace(window.location.origin, "") === this.rebasePath(t);
}
rebasePath(t) {
if (!this.options.basePath || c(t).origin !== "http://dummy-base.local") return t;
const a = `${this.options.basePath}/${t}`.replaceAll(/\/+/g, "/").trim();
return console.debug(`rebasePath path=${t} to ${a}`), a;
}
unBasePath(t) {
if (!this.options.basePath) return t;
const a = t.trim().replace(RegExp(`^${this.options.basePath}`), "/").replaceAll(/\/+/g, "/");
return console.debug(`unbasePath path=${t}, basePath=${this.options.basePath} gives ${a}`), a;
}
install(t) {
t.component("RoutePath", v), t.component("RouteName", y), t.component("RouteView", N), t.component("RouteLink", S), t.provide(A, this), this.options.installGlobalRef && (t.config.globalProperties[this.options.installGlobalRef] = this);
}
historyPopState(t) {
!t || !t.state || ("name" in t.state ? this.setName(t.state.name, t.state.params, !1) : "path" in t.state && this.setPath(t.state.path, !1));
}
dispatch(t) {
let a = !1;
if (!(window.history.state && B(window.history.state, t)))
return "name" in t ? a = this.setName(t.name, t.params) : "path" in t && (a = this.setPath(t.path)), a;
}
}
export {
S as RouteLink,
y as RouteName,
v as RoutePath,
N as RouteView,
L as Router,
A as RouterInjectionKey,
U as createRouter,
x as getRouter,
r as router
};
//# sourceMappingURL=index.js.map