138 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			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,
 | |
|   };
 | |
| }
 | 
