fix : scroll-lock empilable, contenteditable focusable et tests focus-trap du MalioDrawer

This commit is contained in:
2026-05-21 16:44:46 +02:00
parent e7af92808f
commit 527766ab4c
2 changed files with 72 additions and 4 deletions

View File

@@ -95,6 +95,9 @@ import { twMerge } from 'tailwind-merge'
defineOptions({ name: 'MalioDrawer', inheritAttrs: false })
// Module-level counter shared across all drawer instances to support stacked drawers.
let openDrawerCount = 0
const props = withDefaults(
defineProps<{
id?: string
@@ -150,18 +153,26 @@ const isRendered = ref(isOpen.value)
const panelRef = ref<HTMLElement | null>(null)
let previouslyFocused: HTMLElement | null = null
// Per-instance flag: true while this drawer holds a scroll-lock count slot.
let lockedByThisInstance = false
function getFocusable(container: HTMLElement): HTMLElement[] {
return Array.from(
container.querySelectorAll<HTMLElement>(
'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])',
'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"]), [contenteditable]:not([contenteditable="false"])',
),
).filter((el) => el.tabIndex !== -1)
}
function onOpen() {
previouslyFocused = (document.activeElement as HTMLElement | null) ?? null
document.body.style.overflow = 'hidden'
if (!lockedByThisInstance) {
lockedByThisInstance = true
openDrawerCount++
if (openDrawerCount === 1) {
document.body.style.overflow = 'hidden'
}
}
nextTick(() => {
const panel = panelRef.value
if (!panel) return
@@ -171,7 +182,13 @@ function onOpen() {
}
function onClose() {
document.body.style.overflow = ''
if (lockedByThisInstance) {
lockedByThisInstance = false
openDrawerCount = Math.max(0, openDrawerCount - 1)
if (openDrawerCount === 0) {
document.body.style.overflow = ''
}
}
previouslyFocused?.focus?.()
previouslyFocused = null
}
@@ -191,7 +208,14 @@ onMounted(() => {
})
onBeforeUnmount(() => {
document.body.style.overflow = ''
// If this instance is still holding a scroll-lock slot, release it.
if (lockedByThisInstance) {
lockedByThisInstance = false
openDrawerCount = Math.max(0, openDrawerCount - 1)
if (openDrawerCount === 0) {
document.body.style.overflow = ''
}
}
})
function onBackdropClick() {