5a43894875
Four fixes: 1. Mobile edit fullscreen scroll: the Sheet primitive's data-[side=bottom]:h-auto was overriding our h-[100dvh] on SheetForm, preventing scroll. Added data-[side=bottom]:h-[100dvh] to the SheetForm className to win the specificity battle. 2. Direct-edit close showed list view: when opened via editWidgetId (the hover edit button), saving or canceling called reset() which showed the widget list instead of closing the dialog. Now derives directEdit from editWidgetId — when true, reset() calls onClose() to close entirely. 3. Copy button missing on mobile: MobileWidgetSections didn't pass onCopy to its WidgetInstanceCard instances. Now accepts and wires onCopyWidget, so referenced widgets show the copy/detach button on mobile too. 4. Service enabled badge stale: ServiceConfigEditor showed instance.enabled (the initial prop) instead of the local enabled state. Now reads the local enabled variable so the badge updates when the user toggles the switch. 128 tests pass; 0 lint errors; build clean.
163 lines
3.9 KiB
TypeScript
163 lines
3.9 KiB
TypeScript
import * as React from "react";
|
|
import { Dialog as DialogPrimitive } from "radix-ui";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
import { Button } from "@/components/ui/button";
|
|
import { XIcon } from "lucide-react";
|
|
|
|
function Dialog({
|
|
...props
|
|
}: React.ComponentProps<typeof DialogPrimitive.Root>) {
|
|
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
|
}
|
|
|
|
function DialogTrigger({
|
|
...props
|
|
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
|
}
|
|
|
|
function DialogPortal({
|
|
...props
|
|
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
|
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
|
}
|
|
|
|
function DialogClose({
|
|
...props
|
|
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
|
|
}
|
|
|
|
function DialogOverlay({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
return (
|
|
<DialogPrimitive.Overlay
|
|
data-slot="dialog-overlay"
|
|
className={cn(
|
|
"fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
className,
|
|
)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function DialogContent({
|
|
className,
|
|
children,
|
|
showCloseButton = true,
|
|
...props
|
|
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
|
showCloseButton?: boolean;
|
|
}) {
|
|
return (
|
|
<DialogPortal>
|
|
<DialogOverlay />
|
|
<DialogPrimitive.Content
|
|
data-slot="dialog-content"
|
|
className={cn(
|
|
"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] max-h-[calc(100dvh-2rem)] overflow-y-auto -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
{showCloseButton && (
|
|
<DialogPrimitive.Close data-slot="dialog-close" asChild>
|
|
<Button
|
|
variant="ghost"
|
|
className="absolute top-2 right-2"
|
|
size="icon-sm"
|
|
>
|
|
<XIcon />
|
|
<span className="sr-only">Close</span>
|
|
</Button>
|
|
</DialogPrimitive.Close>
|
|
)}
|
|
</DialogPrimitive.Content>
|
|
</DialogPortal>
|
|
);
|
|
}
|
|
|
|
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
return (
|
|
<div
|
|
data-slot="dialog-header"
|
|
className={cn("flex flex-col gap-2", className)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function DialogFooter({
|
|
className,
|
|
showCloseButton = false,
|
|
children,
|
|
...props
|
|
}: React.ComponentProps<"div"> & {
|
|
showCloseButton?: boolean;
|
|
}) {
|
|
return (
|
|
<div
|
|
data-slot="dialog-footer"
|
|
className={cn(
|
|
"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end",
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
{showCloseButton && (
|
|
<DialogPrimitive.Close asChild>
|
|
<Button variant="outline">Close</Button>
|
|
</DialogPrimitive.Close>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function DialogTitle({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<typeof DialogPrimitive.Title>) {
|
|
return (
|
|
<DialogPrimitive.Title
|
|
data-slot="dialog-title"
|
|
className={cn("text-base leading-none font-medium", className)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
function DialogDescription({
|
|
className,
|
|
...props
|
|
}: React.ComponentProps<typeof DialogPrimitive.Description>) {
|
|
return (
|
|
<DialogPrimitive.Description
|
|
data-slot="dialog-description"
|
|
className={cn(
|
|
"text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
className,
|
|
)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export {
|
|
Dialog,
|
|
DialogClose,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogOverlay,
|
|
DialogPortal,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
};
|