mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-11-08 12:24:45 +00:00
64 lines
2.0 KiB
TypeScript
64 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import { type ComponentProps, useRef } from "react";
|
|
|
|
import { Modal } from "@/components/shadcn/modal";
|
|
import { useMountEffect } from "@/hooks/use-mount-effect";
|
|
import { useSidePanelPushWidth } from "@/hooks/use-side-panel-push-width";
|
|
import { SIDE_PANEL_ELEMENT_ID } from "@/lib/ui-layout";
|
|
import { useSidePanelStore } from "@/store/side-panel";
|
|
|
|
type SidePanelHostModalProps = Omit<
|
|
ComponentProps<typeof Modal>,
|
|
"modal" | "insetRight" | "isInsetResizing" | "ref"
|
|
>;
|
|
|
|
function isInsideSidePanel(target: EventTarget | null): boolean {
|
|
return (
|
|
target instanceof Element &&
|
|
target.closest(`#${SIDE_PANEL_ELEMENT_ID}`) !== null
|
|
);
|
|
}
|
|
|
|
// A dialog that shares the screen with the global side panel: it centers in
|
|
// the space the panel leaves and nothing done in the panel can dismiss it.
|
|
export function SidePanelHostModal({
|
|
onEscapeKeyDown,
|
|
children,
|
|
...props
|
|
}: SidePanelHostModalProps) {
|
|
const insetRight = useSidePanelPushWidth();
|
|
const isResizing = useSidePanelStore((state) => state.isResizing);
|
|
const contentRef = useRef<HTMLDivElement>(null);
|
|
|
|
const handleEscapeKeyDown = (event: KeyboardEvent) => {
|
|
onEscapeKeyDown?.(event);
|
|
if (event.defaultPrevented || !isInsideSidePanel(event.target)) return;
|
|
// Radix handles Escape first (document capture), so the panel's own
|
|
// listener sees it prevented: close the panel here instead of the dialog.
|
|
event.preventDefault();
|
|
useSidePanelStore.getState().closePanel();
|
|
contentRef.current?.focus();
|
|
};
|
|
|
|
return (
|
|
<Modal
|
|
{...props}
|
|
ref={contentRef}
|
|
modal={false}
|
|
insetRight={insetRight}
|
|
isInsetResizing={isResizing}
|
|
onEscapeKeyDown={handleEscapeKeyDown}
|
|
>
|
|
<ModalHostRegistration />
|
|
{children}
|
|
</Modal>
|
|
);
|
|
}
|
|
|
|
// Mounted with the dialog content, so it is registered exactly while open.
|
|
function ModalHostRegistration() {
|
|
useMountEffect(() => useSidePanelStore.getState().registerModalHost());
|
|
return null;
|
|
}
|