diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx index 383c3f3..5bab4f2 100644 --- a/src/components/ui/sheet.tsx +++ b/src/components/ui/sheet.tsx @@ -6,27 +6,28 @@ import { cn } from '@/lib/utils' // Bug conocido de Radix/react-remove-scroll: si un re-render externo coincide con la // animación de cierre, el cleanup que restaura `pointer-events` del body no se ejecuta -// — toda la página queda no interactiva hasta refrescar manualmente. El defer de 350ms -// en algunos callers (ej. ProfileSheet) mitiga UNA causa, pero no es estructural: este -// fallback corrige el estado real del DOM sin asumir cuál fue la causa de la falla. -// 400ms > duración de la animación de salida (300ms, ver sheetVariants). -function Sheet({ onOpenChange, ...props }: React.ComponentPropsWithoutRef) { - return ( - { - onOpenChange?.(open) - if (!open) { - window.setTimeout(() => { - const stillHasOpenDialog = document.querySelector('[role="dialog"][data-state="open"]') - if (!stillHasOpenDialog && document.body.style.pointerEvents === 'none') { - document.body.style.pointerEvents = '' - } - }, 400) - } - }} - {...props} - /> - ) +// — toda la página queda no interactiva hasta refrescar manualmente. +// +// `onOpenChange` de Radix NO es un canal confiable para detectar esto: solo se dispara +// cuando RADIX decide cerrar internamente (Escape, click en overlay, botón X). Cuando el +// padre cierra el Sheet cambiando el prop `open` directamente (ej. ProfileSheet.handleSave +// llama onOpenChange(false), que es setProfileOpen(false) del padre), Radix nunca invoca +// su propio onOpenChange — por eso un wrapper de ese callback no detecta este caso. +// Observar el prop `open` en sí cubre ambos canales de cierre. +function Sheet({ open, ...props }: React.ComponentPropsWithoutRef) { + React.useEffect(() => { + if (open) return + // 400ms > duración de la animación de salida (300ms, ver sheetVariants). + const timeoutId = window.setTimeout(() => { + const stillHasOpenDialog = document.querySelector('[role="dialog"][data-state="open"]') + if (!stillHasOpenDialog && document.body.style.pointerEvents === 'none') { + document.body.style.pointerEvents = '' + } + }, 400) + return () => window.clearTimeout(timeoutId) + }, [open]) + + return } const SheetTrigger = SheetPrimitive.Trigger const SheetClose = SheetPrimitive.Close