Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
5.6 kB ยท 237 lines
TSX
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238"use client";
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle,} from "@openstatus/ui/components/ui/alert-dialog";import { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger,} from "@openstatus/ui/components/ui/sheet";import { cn } from "@openstatus/ui/lib/utils";import React, { createContext, useContext, useEffect, useRef, useState,} from "react";
export function FormSheetContent({ children, className, ...props}: React.ComponentProps<typeof SheetContent>) { return ( <SheetContent className={cn("max-h-screen gap-0", className)} {...props}> {children} </SheetContent> );}
export function FormSheetHeader({ children, className, ...props}: React.ComponentProps<typeof SheetHeader>) { return ( <SheetHeader className={cn("bg-background sticky top-0 border-b", className)} {...props} > {children} </SheetHeader> );}
export function FormSheetFooter({ children, className, ...props}: React.ComponentProps<typeof SheetFooter>) { return ( <SheetFooter className={cn("bg-background sticky bottom-0 border-t", className)} {...props} > {children} </SheetFooter> );}
export function FormSheetFooterInfo({ children, className, ...props}: React.ComponentProps<"p">) { return ( <p className={cn("text-muted-foreground/70 text-xs", className)} {...props}> {children} </p> );}
export function FormSheetTrigger({ children, className, disabled, ...props}: React.ComponentProps<typeof SheetTrigger>) { return ( <SheetTrigger className={cn( "cursor-pointer data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50", className, )} data-disabled={disabled} disabled={disabled} {...props} > {children} </SheetTrigger> );}
export function FormSheetAlertDialog({ onConfirm, ...props}: React.ComponentProps<typeof AlertDialog> & { onConfirm: () => void;}) { return ( <AlertDialog {...props}> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Discard changes?</AlertDialogTitle> <AlertDialogDescription> You have unsaved changes. Are you sure you want to discard them? </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Continue editing</AlertDialogCancel> <AlertDialogAction onClick={onConfirm}> Discard changes </AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> );}
const FormSheetDirtyContext = createContext<{ isDirty: boolean; setIsDirty: (dirty: boolean) => void;} | null>(null);
export function useFormSheetDirty() { const context = useContext(FormSheetDirtyContext); if (!context) { throw new Error( "useFormSheetDirty must be used within FormSheetWithDirtyProtection", ); } return context;}
export function FormSheetWithDirtyProtection({ children, open: controlledOpen, onOpenChange: controlledOnOpenChange,}: { children: React.ReactNode; open?: boolean; onOpenChange?: (open: boolean) => void;}) { const [internalOpen, setInternalOpen] = useState(false); const [isDirty, setIsDirty] = useState(false); const [showAlert, setShowAlert] = useState(false); const shouldBypassAlert = useRef(false);
const open = controlledOpen ?? internalOpen; const setOpen = controlledOnOpenChange ?? setInternalOpen;
// Reset states when sheet closes useEffect(() => { if (!open) { setIsDirty(false); shouldBypassAlert.current = false; } }, [open]);
const handleOpenChange = (newOpen: boolean) => { if (!newOpen && isDirty && !shouldBypassAlert.current) { // User is trying to close with unsaved changes setShowAlert(true); } else { setOpen(newOpen); } };
const handleDiscardChanges = () => { shouldBypassAlert.current = true; setShowAlert(false); setOpen(false); };
const handleInteractOutside = (e: Event) => { if (isDirty) { e.preventDefault(); setShowAlert(true); } };
const handleEscapeKeyDown = (e: KeyboardEvent) => { if (isDirty) { e.preventDefault(); setShowAlert(true); } };
return ( <FormSheetDirtyContext.Provider value={{ isDirty, setIsDirty }}> <Sheet open={open} onOpenChange={handleOpenChange}> {/* Clone children and inject event handlers if it's SheetContent */} {React.Children.map(children, (child) => { if ( React.isValidElement(child) && (child.type === FormSheetContent || child.type === SheetContent) ) { return React.cloneElement( child as React.ReactElement<{ onInteractOutside?: (e: Event) => void; onEscapeKeyDown?: (e: KeyboardEvent) => void; }>, { onInteractOutside: handleInteractOutside, onEscapeKeyDown: handleEscapeKeyDown, }, ); } return child; })} </Sheet> <FormSheetAlertDialog open={showAlert} onOpenChange={setShowAlert} onConfirm={handleDiscardChanges} /> </FormSheetDirtyContext.Provider> );}
export { SheetTitle as FormSheetTitle, SheetDescription as FormSheetDescription, Sheet as FormSheet,};