diff --git a/packages/surveys/src/components/general/render-survey.tsx b/packages/surveys/src/components/general/render-survey.tsx index 9e167a875d..5b09f0a229 100644 --- a/packages/surveys/src/components/general/render-survey.tsx +++ b/packages/surveys/src/components/general/render-survey.tsx @@ -64,7 +64,6 @@ export function RenderSurvey(props: SurveyContainerProps) { onClose={close} isOpen={isOpen} dir={dir}> - {/* @ts-expect-error -- TODO: fix this */} { + afterEach(() => { + cleanup(); + }); + + test("marks modal surveys as labelled modal dialogs", () => { + render( + + + + ); + + const dialog = screen.getByRole("dialog", { name: "Dialog" }); + + expect(dialog.getAttribute("aria-modal")).toBe("true"); + }); + + test("does not add dialog semantics to inline surveys", () => { + render( + + + + ); + + expect(screen.queryByRole("dialog")).toBeNull(); + }); + + test("wires the modal dialog to the survey content", () => { + render( + + + + ); + + const dialog = screen.getByRole("dialog", { name: "Dialog" }); + + expect(dialog.contains(screen.getByRole("button", { name: "Start" }))).toBe(true); + }); +}); diff --git a/packages/surveys/src/components/wrappers/survey-container.tsx b/packages/surveys/src/components/wrappers/survey-container.tsx index 137fdd2ee4..d11388dde7 100644 --- a/packages/surveys/src/components/wrappers/survey-container.tsx +++ b/packages/surveys/src/components/wrappers/survey-container.tsx @@ -1,12 +1,14 @@ -import { useEffect, useRef } from "preact/hooks"; +import { type ComponentChildren } from "preact"; +import { useEffect } from "preact/hooks"; import { type TOverlay, type TPlacement } from "@formbricks/types/common"; +import { useFocusTrap } from "@/lib/use-focus-trap"; import { cn } from "@/lib/utils"; interface SurveyContainerProps { mode: "modal" | "inline"; placement?: TPlacement; overlay?: TOverlay; - children: React.ReactNode; + children: ComponentChildren; onClose?: () => void; clickOutside?: boolean; isOpen?: boolean; @@ -23,8 +25,8 @@ export function SurveyContainer({ isOpen = true, dir = "auto", }: Readonly) { - const modalRef = useRef(null); const isModal = mode === "modal"; + const modalRef = useFocusTrap({ enabled: isModal && isOpen, onEscapeKeyDown: onClose }); const hasOverlay = overlay !== "none"; useEffect(() => { @@ -47,7 +49,7 @@ export function SurveyContainer({ return () => { document.removeEventListener("mousedown", handleClickOutside); }; - }, [clickOutside, onClose, isModal, isOpen]); + }, [clickOutside, hasOverlay, modalRef, onClose, isModal, isOpen]); const getPlacementStyle = (placement: TPlacement): string => { switch (placement) { @@ -92,6 +94,10 @@ export function SurveyContainer({ )}>