From 1aa1486d888f648b1c002c2c7c935eec08b09abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Ben=C3=ADtez?= Date: Tue, 23 Jun 2026 09:53:14 -0300 Subject: [PATCH] =?UTF-8?q?fix(sprint-5/etapa-4h):=20safety=20net=20en=20S?= =?UTF-8?q?heet=20=E2=80=94=20body=20queda=20con=20pointer-events:none=20s?= =?UTF-8?q?tuck=20tras=20cerrar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug de Radix/react-remove-scroll: el cleanup que restaura pointer-events del body al cerrar un Dialog/Sheet puede no ejecutarse (race con re-renders externos durante la animación de salida). Resultado: toda la página queda no interactiva hasta refrescar manualmente — confirmado en producción tras guardar perfil pese al defer de 350ms ya aplicado en ProfileSheet (mitigaba una causa, no era estructural). Fix a nivel del primitivo Sheet (cubre todos los usos, no solo ProfileSheet): al cerrar, espera 400ms (> 300ms de la animación) y si no queda ningún [role="dialog"][data-state="open"] en el DOM pero el body sigue con pointer-events:none, lo limpia explícitamente. Co-Authored-By: Claude Sonnet 4.6 --- src/components/ui/sheet.tsx | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx index 06605e3..383c3f3 100644 --- a/src/components/ui/sheet.tsx +++ b/src/components/ui/sheet.tsx @@ -4,7 +4,30 @@ import { cva, type VariantProps } from 'class-variance-authority' import { X } from 'lucide-react' import { cn } from '@/lib/utils' -const Sheet = SheetPrimitive.Root +// 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} + /> + ) +} const SheetTrigger = SheetPrimitive.Trigger const SheetClose = SheetPrimitive.Close const SheetPortal = SheetPrimitive.Portal