diff --git a/src/components/overlays/OverlayRouter.tsx b/src/components/overlays/OverlayRouter.tsx
new file mode 100644
index 00000000..f9272dcf
--- /dev/null
+++ b/src/components/overlays/OverlayRouter.tsx
@@ -0,0 +1,18 @@
+import { ReactNode } from "react";
+
+import { OverlayAnchorPosition } from "@/components/overlays/positions/OverlayAnchorPosition";
+import { OverlayMobilePosition } from "@/components/overlays/positions/OverlayMobilePosition";
+import { useIsMobile } from "@/hooks/useIsMobile";
+
+interface OverlayRouterProps {
+ children?: ReactNode;
+ id: string;
+}
+
+export function OverlayRouter(props: OverlayRouterProps) {
+ const { isMobile } = useIsMobile();
+ const content = props.children;
+
+ if (isMobile) return {content};
+ return {content};
+}
diff --git a/src/components/overlays/positions/OverlayAnchorPosition.tsx b/src/components/overlays/positions/OverlayAnchorPosition.tsx
new file mode 100644
index 00000000..80f98391
--- /dev/null
+++ b/src/components/overlays/positions/OverlayAnchorPosition.tsx
@@ -0,0 +1,82 @@
+import classNames from "classnames";
+import { ReactNode, useCallback, useEffect, useRef, useState } from "react";
+
+import { createOverlayAnchorEvent } from "@/components/overlays/OverlayAnchor";
+
+interface AnchorPositionProps {
+ children?: ReactNode;
+ id: string;
+ className?: string;
+}
+
+export function OverlayAnchorPosition(props: AnchorPositionProps) {
+ const ref = useRef(null);
+ const [left, setLeft] = useState(0);
+ const [top, setTop] = useState(0);
+ const [cardRect, setCardRect] = useState(null);
+ const [anchorRect, setAnchorRect] = useState(null);
+
+ const calculateAndSetCoords = useCallback(
+ (anchor: DOMRect, card: DOMRect) => {
+ const buttonCenter = anchor.left + anchor.width / 2;
+ const bottomReal = window.innerHeight - anchor.bottom;
+
+ setTop(
+ window.innerHeight - bottomReal - anchor.height - card.height - 30
+ );
+ setLeft(
+ Math.min(
+ buttonCenter - card.width / 2,
+ window.innerWidth - card.width - 30
+ )
+ );
+ },
+ []
+ );
+
+ useEffect(() => {
+ if (!anchorRect || !cardRect) return;
+ calculateAndSetCoords(anchorRect, cardRect);
+ }, [anchorRect, calculateAndSetCoords, cardRect]);
+
+ useEffect(() => {
+ if (!ref.current) return;
+ function checkBox() {
+ const divRect = ref.current?.getBoundingClientRect();
+ setCardRect(divRect ?? null);
+ }
+ checkBox();
+ const observer = new ResizeObserver(checkBox);
+ observer.observe(ref.current);
+ return () => {
+ observer.disconnect();
+ };
+ }, []);
+
+ useEffect(() => {
+ const evtStr = createOverlayAnchorEvent(props.id);
+ if ((window as any)[evtStr]) setAnchorRect((window as any)[evtStr]);
+ function listen(ev: CustomEvent) {
+ setAnchorRect(ev.detail);
+ }
+ document.addEventListener(evtStr, listen as any);
+ return () => {
+ document.removeEventListener(evtStr, listen as any);
+ };
+ }, [props.id]);
+
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/src/components/overlays/positions/OverlayMobilePosition.tsx b/src/components/overlays/positions/OverlayMobilePosition.tsx
new file mode 100644
index 00000000..68534714
--- /dev/null
+++ b/src/components/overlays/positions/OverlayMobilePosition.tsx
@@ -0,0 +1,20 @@
+import classNames from "classnames";
+import { ReactNode } from "react";
+
+interface MobilePositionProps {
+ children?: ReactNode;
+ className?: string;
+}
+
+export function OverlayMobilePosition(props: MobilePositionProps) {
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/src/hooks/useOverlayRouter.ts b/src/hooks/useOverlayRouter.ts
index c4791168..10bbdde7 100644
--- a/src/hooks/useOverlayRouter.ts
+++ b/src/hooks/useOverlayRouter.ts
@@ -73,6 +73,7 @@ export function useInternalOverlayRouter(id: string) {
export function useOverlayRouter(id: string) {
const router = useInternalOverlayRouter(id);
return {
+ id,
open: router.open,
close: router.close,
navigate: router.navigate,
diff --git a/src/pages/developer/TestView.tsx b/src/pages/developer/TestView.tsx
index 4c64406f..6ce44c41 100644
--- a/src/pages/developer/TestView.tsx
+++ b/src/pages/developer/TestView.tsx
@@ -1,6 +1,7 @@
import { OverlayAnchor } from "@/components/overlays/OverlayAnchor";
import { Overlay, OverlayDisplay } from "@/components/overlays/OverlayDisplay";
import { OverlayPage } from "@/components/overlays/OverlayPage";
+import { OverlayRouter } from "@/components/overlays/OverlayRouter";
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
// simple empty view, perfect for putting in tests
@@ -18,57 +19,59 @@ export default function TestView() {
>
Open
-
-
+
+
-
-
-
-
HOME
-
-
-
-
-
-
-
ONE
-
-
-
-
-
-
TWO
-
-
-
+
+
+
+
+
HOME
+
+
+
+
+
+
+
ONE
+
+
+
+
+
+
TWO
+
+
+
+