feat(drill): PeekModal — centered Radix Dialog with eyebrow + title
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
// @vitest-environment happy-dom
|
||||||
|
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
|
||||||
|
|
||||||
|
import { afterEach, describe, it, expect, vi } from "vitest";
|
||||||
|
import { cleanup, render, screen, fireEvent } from "@testing-library/react";
|
||||||
|
import { PeekModal } from "@/components/drill/PeekModal";
|
||||||
|
|
||||||
|
// happy-dom keeps `document.body` between tests; without cleanup,
|
||||||
|
// `screen.getByRole(...)` finds buttons from earlier renders.
|
||||||
|
afterEach(() => cleanup());
|
||||||
|
|
||||||
|
describe("PeekModal", () => {
|
||||||
|
it("renders title and body when open; close button fires onClose", () => {
|
||||||
|
const onClose = vi.fn();
|
||||||
|
render(
|
||||||
|
<PeekModal
|
||||||
|
open
|
||||||
|
onClose={onClose}
|
||||||
|
eyebrow="Payer"
|
||||||
|
title="CO Medicaid"
|
||||||
|
>
|
||||||
|
<p>1,247 claims</p>
|
||||||
|
</PeekModal>,
|
||||||
|
);
|
||||||
|
expect(screen.getByText("Payer")).toBeTruthy();
|
||||||
|
expect(screen.getByText("CO Medicaid")).toBeTruthy();
|
||||||
|
expect(screen.getByText("1,247 claims")).toBeTruthy();
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: /close/i }));
|
||||||
|
expect(onClose).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders nothing when closed", () => {
|
||||||
|
const { container } = render(
|
||||||
|
<PeekModal open={false} onClose={() => {}} title="hidden">
|
||||||
|
<p>should not appear</p>
|
||||||
|
</PeekModal>,
|
||||||
|
);
|
||||||
|
// jest-dom's toBeEmptyDOMElement is not installed; assert via raw DOM.
|
||||||
|
expect(container.firstChild).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("esc key closes", () => {
|
||||||
|
const onClose = vi.fn();
|
||||||
|
render(
|
||||||
|
<PeekModal open onClose={onClose} title="t">
|
||||||
|
<p>x</p>
|
||||||
|
</PeekModal>,
|
||||||
|
);
|
||||||
|
fireEvent.keyDown(document.body, { key: "Escape" });
|
||||||
|
expect(onClose).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Dialog, DialogContent } from "@/components/ui/dialog";
|
||||||
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
eyebrow?: string;
|
||||||
|
title: string;
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centered peek modal — used for cross-reference drills (payer,
|
||||||
|
* validation rule, etc.). Smaller than the right-side Drawer
|
||||||
|
* (max-width: 480px); closes on Esc, backdrop click, and the X button.
|
||||||
|
* No keyboard j/k nav — single record.
|
||||||
|
*/
|
||||||
|
export function PeekModal({ open, onClose, eyebrow, title, children }: Props) {
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={(o) => { if (!o) onClose(); }}>
|
||||||
|
<DialogContent
|
||||||
|
className="max-w-[480px] w-[90vw]"
|
||||||
|
aria-describedby={undefined}
|
||||||
|
>
|
||||||
|
{eyebrow ? (
|
||||||
|
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
||||||
|
{eyebrow}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<h2 className="text-[18px] font-semibold tracking-tight">{title}</h2>
|
||||||
|
<div className="mt-2">{children}</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user