mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-16 14:06:49 +01:00
91 lines
2.4 KiB
TypeScript
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>
|
|
);
|
|
}
|