refactor(web): shared DetailDrawer; objects-page uses it (#58)
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
import { expect, test, vi } from "vitest";
|
||||
import { within } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import { renderApp } from "../test/render";
|
||||
import { DetailDrawer } from "./detail-drawer";
|
||||
|
||||
test("renders children in a named drawer and closes via the close button", async () => {
|
||||
const onClose = vi.fn();
|
||||
renderApp(
|
||||
<DetailDrawer open onClose={onClose} ariaLabel="Object detail">
|
||||
<p>detail body</p>
|
||||
</DetailDrawer>,
|
||||
);
|
||||
|
||||
const body = within(document.body);
|
||||
expect(await body.findByText("detail body")).toBeInTheDocument();
|
||||
await userEvent.click(body.getByRole("button", { name: /close detail/i }));
|
||||
expect(onClose).toHaveBeenCalled();
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { X } from "lucide-react";
|
||||
|
||||
import { Drawer, DrawerClose, DrawerContent } from "@/components/ui/drawer";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
/** A right-sliding Base UI Drawer for a master/detail "detail" on narrow viewports.
|
||||
* Provides the close affordance + an accessible dialog name; the caller supplies the content. */
|
||||
export function DetailDrawer({
|
||||
open,
|
||||
onClose,
|
||||
ariaLabel,
|
||||
children,
|
||||
}: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
ariaLabel: string;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
open={open}
|
||||
onOpenChange={(next) => {
|
||||
if (!next) onClose();
|
||||
}}
|
||||
swipeDirection="right"
|
||||
>
|
||||
<DrawerContent aria-label={ariaLabel}>
|
||||
<div className="flex justify-end border-b p-2">
|
||||
<DrawerClose
|
||||
aria-label={t("actions.closeDetail")}
|
||||
render={<Button variant="ghost" size="icon-sm" />}
|
||||
>
|
||||
<X className="size-4" aria-hidden="true" />
|
||||
</DrawerClose>
|
||||
</div>
|
||||
<div className="flex-1 overflow-auto">{children}</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user