melissa/paciente-docs: fix drawer mobile (teleport body + style global)

Bug: drawer abria mas travava — sidebar interna nao aparecia.
Duas causas combinadas:

1. position:fixed preso em stacking context: o MelissaPaciente
   tem transform/filter num ancestral, fazendo o fixed virar
   relativo ao pai em vez da viewport.
2. Styles scoped: ate corrigir o stacking context, ao teleportar
   pro body os data-v scoped attrs sumiriam e o CSS nao aplicaria.

Fix:
- <Teleport to="body"> wrap nos elementos drawer + backdrop. Saem
  da arvore do componente e ficam no body raiz.
- Styles do drawer movidos pra um <style> NAO-scoped no fim do
  arquivo. Classes globais .mpd-mobile-drawer* garantem que
  aplique nos elementos teleportados (que perdem data-v).
- Fallbacks adicionados nas vars CSS (--m-bg-medium, --m-border,
  --m-text) caso o body nao tenha o tema melissa carregado.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-21 21:48:50 -03:00
parent 51c33e73b9
commit 4e1ebeba13
+68 -37
View File
@@ -179,7 +179,10 @@ onBeforeUnmount(() => {
</script> </script>
<template> <template>
<!-- Mobile drawer (tipos) --> <!-- Mobile drawer (tipos) teleportado pro body pra escapar de
stacking contexts pais (transform/filter no MelissaPaciente
travavam o fixed) -->
<Teleport to="body">
<Transition name="mpd-drawer-fade"> <Transition name="mpd-drawer-fade">
<div <div
v-show="isMobile && drawerOpen" v-show="isMobile && drawerOpen"
@@ -196,6 +199,7 @@ onBeforeUnmount(() => {
@click="fecharDrawer" @click="fecharDrawer"
/> />
</Transition> </Transition>
</Teleport>
<section class="mpd-page"> <section class="mpd-page">
<!-- HEADER --> <!-- HEADER -->
@@ -646,42 +650,8 @@ onBeforeUnmount(() => {
padding: 12px; padding: 12px;
} }
/* ═══════ Mobile drawer ═══════ */ /* Drawer styles foram movidos pro <style> não-scoped abaixo —
.mpd-mobile-drawer { teleporte pro body perde o atributo data-v scoped */
position: fixed;
top: 0; left: 0;
height: 100vh; height: 100dvh;
width: min(320px, 86vw);
z-index: 80;
background: var(--m-bg-medium);
backdrop-filter: blur(28px) saturate(160%);
-webkit-backdrop-filter: blur(28px) saturate(160%);
border-right: 1px solid var(--m-border);
transform: translateX(-100%);
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1);
color: var(--m-text);
display: flex;
flex-direction: column;
}
.mpd-mobile-drawer.is-open { transform: translateX(0); }
.mpd-mobile-drawer:not(.is-open) { pointer-events: none; }
.mpd-mobile-drawer__scroll {
flex: 1; min-height: 0; overflow-y: auto;
padding: 12px; display: flex; flex-direction: column;
}
.mpd-mobile-drawer__scroll .mpd-side {
width: 100%; height: 100%; border: 1px solid var(--m-border);
}
.mpd-mobile-drawer__backdrop {
position: fixed; inset: 0;
background: rgba(0, 0, 0, 0.45);
backdrop-filter: blur(4px);
z-index: 79;
}
.mpd-drawer-fade-enter-active,
.mpd-drawer-fade-leave-active { transition: opacity 200ms ease; }
.mpd-drawer-fade-enter-from,
.mpd-drawer-fade-leave-to { opacity: 0; }
/* ═══════ Mobile (<1024px) ═══════ */ /* ═══════ Mobile (<1024px) ═══════ */
@media (max-width: 1023px) { @media (max-width: 1023px) {
@@ -697,3 +667,64 @@ onBeforeUnmount(() => {
.mpd-act-btn { width: 32px; padding: 0; justify-content: center; } .mpd-act-btn { width: 32px; padding: 0; justify-content: center; }
} }
</style> </style>
<!-- Styles do drawer mobile NÃO-scoped o <Teleport to="body"> tira o
elemento da árvore do componente, então perde os atributos data-v
do scoped. Classes globais .mpd-mobile-drawer* garantem que aplique. -->
<style>
.mpd-mobile-drawer {
position: fixed;
top: 0;
left: 0;
height: 100vh;
height: 100dvh;
width: min(320px, 86vw);
z-index: 80;
background: var(--m-bg-medium, #1a1d2e);
backdrop-filter: blur(28px) saturate(160%);
-webkit-backdrop-filter: blur(28px) saturate(160%);
border-right: 1px solid var(--m-border, rgba(255,255,255,0.1));
transform: translateX(-100%);
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1);
color: var(--m-text, #fff);
display: flex;
flex-direction: column;
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
}
.mpd-mobile-drawer.is-open {
transform: translateX(0);
}
.mpd-mobile-drawer:not(.is-open) {
pointer-events: none;
}
.mpd-mobile-drawer__scroll {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 12px;
display: flex;
flex-direction: column;
}
/* Sidebar teleportada herda altura plena */
.mpd-mobile-drawer__scroll .mpd-side {
width: 100%;
height: 100%;
border: 1px solid var(--m-border, rgba(255,255,255,0.1));
}
.mpd-mobile-drawer__backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.45);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
z-index: 79;
}
.mpd-drawer-fade-enter-active,
.mpd-drawer-fade-leave-active {
transition: opacity 200ms ease;
}
.mpd-drawer-fade-enter-from,
.mpd-drawer-fade-leave-to {
opacity: 0;
}
</style>