vite-plugin-vanjs
Version:
An async first mini meta-framework for VanJS powered by Vite
114 lines (100 loc) • 2.76 kB
JavaScript
// router/state.js
import van from "vanjs-core";
import isServer from "../setup/isServer.mjs";
/**
* Fix the URL of a route
* @param {string=} url
* @returns
*/
export const fixRouteUrl = (url) => {
if (!url) return "/";
if (url.startsWith("/")) {
return url;
}
return `/${url}`;
};
const initialPath = !isServer ? globalThis.location.pathname : "/";
const initialSearch = !isServer ? globalThis.location.search : "";
/**
* Normalize a search string to a plain string (strip leading "?")
* @param {string} search
* @returns {string}
*/
const normalizeSearch = (search) => {
if (!search) return "";
return search.startsWith("?") ? search.slice(1) : search;
};
const STATE_PROXY = "_proxy";
const proxyProps = {
value: 1,
enumerable: false,
configurable: false,
writable: false,
};
/**
* @param {number | Omit<keyof T, "symbol">} key
* @param {T[keyof T]} value
* @param {Record<string, string | number>} target
* @returns {T}
*/
const defineProxy = (key, value, target) => {
const stateObj = van.state(value);
const getter = () => stateObj.val;
const setter = (newVal) => {
stateObj.val = newVal;
};
stateObj.val = value;
Object.defineProperties(target, {
[STATE_PROXY]: proxyProps,
[key]: {
get: getter,
set: setter,
enumerable: true,
},
});
return stateObj;
};
/** @typedef */
/**
* @template {Record<string, unknown>} T
* @param {T} init
* @returns {T}
*/
export function microStore(init) {
/** @type {T} */
const target = {};
for (const [prop, value] of Object.entries(init)) {
const isPlainObject = value && typeof value === "object" &&
!Array.isArray(value) && Object.getPrototypeOf(value) === Object;
if (isPlainObject && Object.keys(value).length > 0) {
for (const [sp, sv] of Object.entries(value)) {
target[prop] = defineProxy(sp, sv, {});
}
} else if (isPlainObject) {
defineProxy(prop, value, target);
} else if (!Array.isArray(value) && value != null) {
defineProxy(prop, value, target);
} else {
console.warn(typeof value + " is not supported.");
}
}
return target;
}
export const routerState = microStore({
pathname: initialPath,
searchParams: normalizeSearch(initialSearch),
params: {},
loading: false,
});
/**
* @type {typeof import("./types.d.ts").setRouterState}
*/
export const setRouterState = (path, search = undefined, params = {}) => {
const [pathname, searchPart] = fixRouteUrl(path).split("?");
routerState.pathname = pathname;
routerState.searchParams = normalizeSearch(search || searchPart || "");
Object.keys(routerState.params).forEach((key) =>
delete routerState.params[key]
);
Object.assign(routerState.params, params);
};