StackedRouter: new router simulates app behaviour #45
1 changed files with 25 additions and 10 deletions
|
@ -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(() => {
|
||||||
|
|
Loading…
Reference in a new issue