fix(ui): close the alert dialog when AlertDialogAction is clicked

The base-vega registry template renders AlertDialogAction as a plain
Button with no Close binding, so confirm buttons fired their onClick
but left the dialog open; both consumers (conversation delete,
MCP credential revoke) were written against the Radix semantics where
Action dismisses on click. Binds Action to AlertDialogPrimitive.Close
via the render prop, mirroring AlertDialogCancel, and pins the
behavior with a test so a future shadcn add --overwrite cannot
silently reintroduce the template's non-closing Action.
This commit is contained in:
ryan-crabbe-berri 2026-07-06 13:00:38 -07:00
parent 0820c6cf06
commit be56b43dcb
2 changed files with 75 additions and 2 deletions

View file

@ -0,0 +1,61 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "./alert-dialog";
import { Button } from "./button";
function ConfirmDialog({ onConfirm }: { onConfirm: () => void }) {
return (
<AlertDialog>
<AlertDialogTrigger render={<Button>Open</Button>} />
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete this?</AlertDialogTitle>
<AlertDialogDescription>Cannot be undone</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={onConfirm}>Confirm</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
);
}
describe("AlertDialog", () => {
it("fires the action handler and closes the dialog on confirm", async () => {
const user = userEvent.setup();
const onConfirm = vi.fn();
render(<ConfirmDialog onConfirm={onConfirm} />);
await user.click(screen.getByRole("button", { name: "Open" }));
expect(screen.getByText("Delete this?")).toBeInTheDocument();
await user.click(screen.getByRole("button", { name: "Confirm" }));
expect(onConfirm).toHaveBeenCalledOnce();
expect(screen.queryByText("Delete this?")).not.toBeInTheDocument();
});
it("closes without firing the action on cancel", async () => {
const user = userEvent.setup();
const onConfirm = vi.fn();
render(<ConfirmDialog onConfirm={onConfirm} />);
await user.click(screen.getByRole("button", { name: "Open" }));
await user.click(screen.getByRole("button", { name: "Cancel" }));
expect(onConfirm).not.toHaveBeenCalled();
expect(screen.queryByText("Delete this?")).not.toBeInTheDocument();
});
});

View file

@ -122,8 +122,20 @@ function AlertDialogDescription({
);
}
function AlertDialogAction({ className, ...props }: React.ComponentProps<typeof Button>) {
return <Button data-slot="alert-dialog-action" className={cn(className)} {...props} />;
function AlertDialogAction({
className,
variant = "default",
size = "default",
...props
}: AlertDialogPrimitive.Close.Props & Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
return (
<AlertDialogPrimitive.Close
data-slot="alert-dialog-action"
className={cn(className)}
render={<Button variant={variant} size={size} />}
{...props}
/>
);
}
function AlertDialogCancel({