Actualizar sigpro.ts

This commit is contained in:
2026-04-07 13:23:12 +02:00
parent b3a8bcfa52
commit e6ab0a2052

110
sigpro.ts
View File

@@ -497,107 +497,71 @@ export const Transition = (
type Route = { type Route = {
path: string; path: string;
component: Component | (() => Promise<Component>); component: Component;
}; };
export const Router = (routes: Route[]) => { type RouterInstance = {
const getPath = () => window.location.hash.replace(/^#/, "") || "/"; view: Node;
const currentPath = $(getPath()); to: (path: string) => void;
back: () => void;
params: Signal<Record<string, string>>;
};
export const Router = (routes: Route[]): RouterInstance => {
const getPath = () => window.location.hash.slice(1) || "/";
const path = $(getPath());
const params = $<Record<string, string>>({}); const params = $<Record<string, string>>({});
const update = () => { const matchRoute = (path: string): { component: Component; params: Record<string, string> } | null => {
currentPath(getPath());
};
window.addEventListener("hashchange", update);
const outlet = h("div", { class: "router-outlet" });
let currentView: Node | null = null;
let currentCleanup: CleanupFn | null = null;
const loadComponent = async (route: Route) => {
let comp = route.component;
if (typeof comp === "function" && comp.toString().includes("import")) {
const mod = await (comp as () => Promise<any>)();
comp = mod.default || mod;
}
return comp as Component;
};
const matchRoute = (path: string): { route: Route; params: Record<string, string> } | null => {
for (const route of routes) { for (const route of routes) {
const routeParts = route.path.split("/").filter(Boolean); const routeParts = route.path.split("/").filter(Boolean);
const pathParts = path.split("/").filter(Boolean); const pathParts = path.split("/").filter(Boolean);
if (routeParts.length !== pathParts.length) continue; if (routeParts.length !== pathParts.length) continue;
const matchedParams: Record<string, string> = {}; const matchedParams: Record<string, string> = {};
let match = true; let ok = true;
for (let i = 0; i < routeParts.length; i++) { for (let i = 0; i < routeParts.length; i++) {
if (routeParts[i].startsWith(":")) { if (routeParts[i].startsWith(":")) {
matchedParams[routeParts[i].slice(1)] = pathParts[i]; matchedParams[routeParts[i].slice(1)] = pathParts[i];
} else if (routeParts[i] !== pathParts[i]) { } else if (routeParts[i] !== pathParts[i]) {
match = false; ok = false;
break; break;
} }
} }
if (match) return { route, params: matchedParams };
if (ok) return { component: route.component, params: matchedParams };
} }
const wildcard = routes.find(r => r.path === "*");
if (wildcard) return { component: wildcard.component, params: {} };
return null; return null;
}; };
window.addEventListener("hashchange", () => path(getPath()));
const outlet = h("div");
effect(() => { effect(() => {
const path = currentPath(); const matched = matchRoute(path());
const matched = matchRoute(path);
if (!matched) return; if (!matched) return;
const { route, params: routeParams } = matched; params(matched.params);
params(routeParams);
const load = async () => { while (outlet.firstChild) outlet.removeChild(outlet.firstChild);
if (currentCleanup) { outlet.appendChild(h(matched.component));
currentCleanup();
currentCleanup = null;
}
if (currentView && currentView.parentNode) {
remove(currentView);
currentView = null;
}
const Comp = await loadComponent(route);
const instance = h(Comp, routeParams);
if (isNode(instance)) {
currentView = instance;
outlet.appendChild(instance);
if ((instance as ElementWithLifecycle).$c) {
currentCleanup = () => {
(instance as ElementWithLifecycle).$s?.();
if (instance.parentNode) remove(instance);
};
} else {
currentCleanup = () => {
if (instance.parentNode) remove(instance);
};
}
}
};
load();
}); });
return outlet; return {
view: outlet,
to: (p: string) => { window.location.hash = p; },
back: () => window.history.back(),
params: () => params,
};
}; };
Router.to = (path: string) => {
window.location.hash = path.replace(/^#?\/?/, "#/");
};
Router.back = () => {
window.history.back();
};
Router.params = (() => {
const p = $<Record<string, string>>({});
return p;
})();
export const mount = ( export const mount = (
component: Component, component: Component,
target: string | HTMLElement, target: string | HTMLElement,