more overlay system testing

Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>
This commit is contained in:
mrjvs 2023-10-08 20:12:31 +02:00
parent a05191e1c4
commit d9855cb244
6 changed files with 67 additions and 29 deletions

View File

@ -3,11 +3,11 @@ import { ReactNode, useCallback, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { Transition } from "@/components/Transition";
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
export interface OverlayProps {
id: string;
children?: ReactNode;
onClose?: () => void;
show?: boolean;
darken?: boolean;
}
@ -16,6 +16,7 @@ export function OverlayDisplay(props: { children: ReactNode }) {
}
export function Overlay(props: OverlayProps) {
const router = useOverlayRouter(props.id);
const [portalElement, setPortalElement] = useState<Element | null>(null);
const ref = useRef<HTMLDivElement>(null);
const target = useRef<Element | null>(null);
@ -37,9 +38,9 @@ export function Overlay(props: OverlayProps) {
if (e.currentTarget !== e.target) return;
if (!startedTarget) return;
if (!startedTarget.isEqualNode(e.currentTarget as Element)) return;
if (props.onClose) props.onClose();
router.close();
},
[props]
[router]
);
useEffect(() => {
@ -47,25 +48,21 @@ export function Overlay(props: OverlayProps) {
setPortalElement(element ?? document.body);
}, []);
const backdrop = (
<Transition animation="fade" isChild>
<div
onClick={click}
className={classNames({
"absolute inset-0": true,
"bg-black opacity-90": props.darken,
})}
/>
</Transition>
);
return (
<div ref={ref}>
{portalElement
? createPortal(
<Transition show={props.show} animation="none">
<Transition show={router.isOverlayActive()} animation="none">
<div className="popout-wrapper pointer-events-auto fixed inset-0 z-[999] select-none">
{backdrop}
<Transition animation="fade" isChild>
<div
onClick={click}
className={classNames({
"absolute inset-0": true,
"bg-black opacity-90": props.darken,
})}
/>
</Transition>
<Transition animation="slide-up" className="h-0" isChild>
{props.children}
</Transition>

View File

@ -13,7 +13,7 @@ interface Props {
active?: boolean; // true if a child view is loaded
}
export function FloatingView(props: Props) {
export function OverlayPage(props: Props) {
const { isMobile } = useIsMobile();
const width = !isMobile ? `${props.width}px` : "100%";
return (

View File

@ -1,3 +0,0 @@
export function LeftSideControls(props: {children: React.ReactNode}) {
}

View File

@ -4,7 +4,6 @@ export function useOverlayRouter(id: string) {
const [route, setRoute] = useQueryParam("r");
const routeParts = (route ?? "").split("/").filter((v) => v.length > 0);
const routerActive = routeParts.length > 0 && routeParts[0] === id;
const currentPage = routeParts[routeParts.length - 1] ?? "/";
function navigate(path: string) {
const newRoute = [id, ...path.split("/").filter((v) => v.length > 0)];
@ -20,7 +19,7 @@ export function useOverlayRouter(id: string) {
}
function isCurrentPage(page: string) {
return routerActive && page === currentPage;
return routerActive && route === `/${id}${page}`;
}
function isLoaded(page: string) {
@ -40,7 +39,11 @@ export function useOverlayRouter(id: string) {
}
function close() {
navigate("/");
setRoute(null);
}
function open() {
setRoute(`/${id}`);
}
return {
@ -51,5 +54,6 @@ export function useOverlayRouter(id: string) {
isCurrentPage,
pageProps,
isActive,
open,
};
}

View File

@ -1,5 +1,5 @@
import { useCallback, useMemo } from "react";
import { useLocation } from "react-router-dom";
import { useHistory, useLocation } from "react-router-dom";
export function useQueryParams() {
const loc = useLocation();
@ -19,6 +19,7 @@ export function useQueryParams() {
export function useQueryParam(param: string) {
const params = useQueryParams();
const location = useLocation();
const router = useHistory();
const currentValue = params[param];
const set = useCallback(
@ -26,9 +27,11 @@ export function useQueryParam(param: string) {
const parsed = new URLSearchParams(location.search);
if (value) parsed.set(param, value);
else parsed.delete(param);
location.search = parsed.toString();
router.push({
search: parsed.toString(),
});
},
[param, location]
[param, location, router]
);
return [currentValue, set] as const;

View File

@ -1,4 +1,41 @@
import { OverlayAnchor } from "@/components/overlays/OverlayAnchor";
import { Overlay, OverlayDisplay } from "@/components/overlays/OverlayDisplay";
import { OverlayPage } from "@/components/overlays/OverlayPage";
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
// simple empty view, perfect for putting in tests
export default function TestView() {
return <div />;
const router = useOverlayRouter("test");
const pages = ["", "/one", "/two"];
return (
<OverlayDisplay>
<div className="h-[400px] w-[800px] flex justify-center items-center">
<button
type="button"
onClick={() => {
router.open();
}}
>
Open
</button>
<button
type="button"
onClick={() => {
router.navigate(pages[Math.floor(pages.length * Math.random())]);
}}
>
random page
</button>
<OverlayAnchor id="test">
<div className="h-20 w-20 bg-white" />
</OverlayAnchor>
<Overlay id="test">
<OverlayPage {...router.pageProps("")}>Home</OverlayPage>
<OverlayPage {...router.pageProps("/one")}>Page one</OverlayPage>
<OverlayPage {...router.pageProps("/two")}>Page two</OverlayPage>
</Overlay>
</div>
</OverlayDisplay>
);
}