movie-web/src/hooks/useOverlayRouter.ts
2023-12-23 18:24:43 +13:00

138 lines
3.4 KiB
TypeScript

import { useCallback, useEffect, useMemo } from "react";
import { useQueryParam } from "@/hooks/useQueryParams";
import { useOverlayStore } from "@/stores/overlay/store";
function splitPath(path: string, prefix?: string): string[] {
const parts = [prefix ?? "", ...path.split("/")];
return parts.filter((v) => v.length > 0);
}
function joinPath(path: string[]): string {
return `/${path.join("/")}`;
}
export function useRouterAnchorUpdate(id: string) {
const [route] = useQueryParam("r");
const setAnchorPoint = useOverlayStore((s) => s.setAnchorPoint);
const routerActive = useMemo(
() => !!route && route.startsWith(`/${id}`),
[route, id],
);
const update = useCallback(() => {
if (!routerActive) return;
const anchor = document.getElementById(`__overlayRouter::${id}`);
if (anchor) {
const rect = anchor.getBoundingClientRect();
setAnchorPoint({
h: rect.height,
w: rect.width,
x: rect.x,
y: rect.y,
});
}
}, [routerActive, setAnchorPoint, id]);
useEffect(() => {
update();
}, [routerActive, update]);
useEffect(() => {
function resizeEvent() {
update();
}
window.addEventListener("resize", resizeEvent);
return () => {
window.removeEventListener("resize", resizeEvent);
};
}, [update]);
}
export function useInternalOverlayRouter(id: string) {
const [route, setRoute] = useQueryParam("r");
const transition = useOverlayStore((s) => s.transition);
const setTransition = useOverlayStore((s) => s.setTransition);
const routerActive = !!route && route.startsWith(`/${id}`);
function makePath(path: string) {
return joinPath(splitPath(path, id));
}
function navigate(path: string) {
const oldRoute = route;
const newRoute = joinPath(splitPath(path, id));
setTransition({
from: oldRoute ?? "/",
to: newRoute,
});
setRoute(newRoute);
}
function showBackwardsTransition(path: string) {
if (!transition) return "none";
const current = joinPath(splitPath(path, id));
if (current === transition.to && transition.from.startsWith(transition.to))
return "yes";
if (
current === transition.from &&
transition.to.startsWith(transition.from)
)
return "yes";
return "no";
}
function isCurrentPage(path: string) {
return routerActive && route === joinPath(splitPath(path, id));
}
function isOverlayActive() {
return routerActive;
}
const close = useCallback(
(preventRouteClear?: boolean) => {
if (route && !preventRouteClear) setRoute(null);
setTransition(null);
},
[setRoute, route, setTransition],
);
const open = useCallback(
(defaultRoute = "/") => {
setTransition(null);
setRoute(joinPath(splitPath(defaultRoute, id)));
},
[id, setRoute, setTransition],
);
const activeRoute = routerActive
? joinPath(splitPath(route.slice(`/${id}`.length)))
: "/";
return {
activeRoute,
showBackwardsTransition,
isCurrentPage,
isOverlayActive,
navigate,
close,
open,
makePath,
currentRoute: route,
};
}
export function useOverlayRouter(id: string) {
const router = useInternalOverlayRouter(id);
return {
id,
route: router.activeRoute,
isRouterActive: router.isOverlayActive(),
open: router.open,
close: router.close,
navigate: router.navigate,
};
}