StackedRouter: new router simulates app behaviour #45

Merged
Rubicon merged 18 commits from stacky into master 2024-11-18 10:35:30 +00:00
Showing only changes of commit 32dffaaa3d - Show all commits

View file

@ -6,17 +6,18 @@ import {
createRenderEffect, createRenderEffect,
createUniqueId, createUniqueId,
Index, Index,
onMount,
Show, Show,
untrack, untrack,
useContext, useContext,
type Accessor, type Accessor,
} from "solid-js"; } from "solid-js";
import { createStore, unwrap } from "solid-js/store"; import { createStore, unwrap } from "solid-js/store";
import { insert, render } from "solid-js/web";
import "./StackedRouter.css"; import "./StackedRouter.css";
import { animateSlideInFromRight, animateSlideOutToRight } from "./anim"; import { animateSlideInFromRight, animateSlideOutToRight } from "./anim";
import { ANIM_CURVE_DECELERATION, ANIM_CURVE_STD } from "../material/theme"; import { ANIM_CURVE_DECELERATION, ANIM_CURVE_STD } from "../material/theme";
import {
makeEventListener,
} from "@solid-primitives/event-listener";
export type StackedRouterProps = Omit<RouterProps, "url">; export type StackedRouterProps = Omit<RouterProps, "url">;
@ -24,7 +25,6 @@ export type StackFrame = {
path: string; path: string;
rootId: string; rootId: string;
state: unknown; state: unknown;
beforeShow?: (element: HTMLElement) => void;
}; };
export type NewFrameOptions<T> = (T extends undefined export type NewFrameOptions<T> = (T extends undefined
@ -141,10 +141,21 @@ const StackedRouter: Component<StackedRouterProps> = (oprops) => {
state: opts?.state, state: opts?.state,
rootId: createUniqueId(), rootId: createUniqueId(),
}; };
mutStack(opts?.replace ? stack.length - 1 : stack.length, frame); mutStack(opts?.replace ? stack.length - 1 : stack.length, frame);
if (opts?.replace) {
window.history.replaceState(unwrap(stack), "", path);
} else {
window.history.pushState(unwrap(stack), "", path);
}
return frame; return frame;
}); });
const onlyPopFrame = (depth: number) => {
mutStack((o) => o.toSpliced(o.length - depth, depth));
window.history.go(-depth);
};
const popFrame = (depth: number = 1) => const popFrame = (depth: number = 1) =>
untrack(() => { untrack(() => {
if (import.meta.env.DEV) { if (import.meta.env.DEV) {
@ -157,14 +168,10 @@ const StackedRouter: Component<StackedRouterProps> = (oprops) => {
const element = document.getElementById(lastFrame.rootId)!; const element = document.getElementById(lastFrame.rootId)!;
requestAnimationFrame(() => { requestAnimationFrame(() => {
const animation = animateClose(element); const animation = animateClose(element);
animation.addEventListener("finish", () => animation.addEventListener("finish", () => onlyPopFrame(depth));
mutStack((o) => o.toSpliced(o.length - depth, depth)),
);
}); });
} else { } else {
mutStack((o) => { onlyPopFrame(depth);
return o.toSpliced(o.length - depth, depth);
});
} }
}); });
@ -175,10 +182,18 @@ const StackedRouter: Component<StackedRouterProps> = (oprops) => {
createRenderEffect(() => { createRenderEffect(() => {
if (stack.length === 0) { if (stack.length === 0) {
pushFrame("/", undefined); pushFrame(window.location.pathname);
} }
}); });
createRenderEffect(() => {
makeEventListener(window, "popstate", (event) => {
if (event.state && stack.length !== event.state.length) {
mutStack(event.state);
}
});
});
const onBeforeDialogMount = (element: HTMLDialogElement) => { const onBeforeDialogMount = (element: HTMLDialogElement) => {
createEffect(() => { createEffect(() => {
requestAnimationFrame(() => { requestAnimationFrame(() => {