Files
yaak-mountain-loop/src-web/components/Overlay.tsx
Gregory Schier b4a1c418bb Run oxfmt across repo, add format script and docs
Add .oxfmtignore to skip generated bindings and wasm-pack output.
Add npm format script, update DEVELOPMENT.md for Vite+ toolchain,
and format all non-generated files with oxfmt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 10:15:49 -07:00

91 lines
2.4 KiB
TypeScript

import classNames from "classnames";
import { FocusTrap } from "focus-trap-react";
import * as m from "motion/react-m";
import type { ReactNode } from "react";
import { useRef } from "react";
import { Portal } from "./Portal";
interface Props {
children: ReactNode;
portalName: string;
open: boolean;
onClose?: () => void;
zIndex?: keyof typeof zIndexes;
variant?: "default" | "transparent";
noBackdrop?: boolean;
}
const zIndexes: Record<number, string> = {
10: "z-10",
20: "z-20",
30: "z-30",
40: "z-40",
50: "z-50",
};
export function Overlay({
variant = "default",
zIndex = 30,
open,
onClose,
portalName,
noBackdrop,
children,
}: Props) {
const containerRef = useRef<HTMLDivElement>(null);
if (noBackdrop) {
return (
<Portal name={portalName}>
{open && (
<FocusTrap focusTrapOptions={{ clickOutsideDeactivates: true }}>
{/* NOTE: <div> wrapper is required for some reason, or FocusTrap complains */}
<div>{children}</div>
</FocusTrap>
)}
</Portal>
);
}
return (
<Portal name={portalName}>
{open && (
<FocusTrap
focusTrapOptions={{
// Allow outside click so we can click things like toasts
allowOutsideClick: true,
delayInitialFocus: true,
checkCanFocusTrap: async () => {
// Not sure why delayInitialFocus: true doesn't help, but having this no-op promise
// seems to be required to make things work.
},
}}
>
<m.div
ref={containerRef}
className={classNames("fixed inset-0", zIndexes[zIndex])}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>
<div
aria-hidden
onClick={onClose}
className={classNames(
"absolute inset-0",
variant === "default" && "bg-backdrop backdrop-blur-sm",
)}
/>
{/* Show the draggable region at the top */}
{/* TODO: Figure out tauri drag region and also make clickable still */}
{variant === "default" && (
<div data-tauri-drag-region className="absolute top-0 left-0 h-md right-0" />
)}
{children}
</m.div>
</FocusTrap>
)}
</Portal>
);
}