fix(modal): clear stale data-closing flag when re-opened mid-close
If the modal is re-enabled within the 150ms close transition the <dialog> element is still mounted and [open], so the dialogRef watcher does not re-fire. Clear the leftover data-closing flag directly in openDialog() so the dialog doesn't remain stuck at opacity 0. Addresses augmentcode review on #2604.
This commit is contained in:
parent
e932ee759a
commit
e01a599418
|
|
@ -153,4 +153,36 @@ describe('Modal.vue — open race condition (#2590)', () => {
|
|||
|
||||
wrapper.unmount()
|
||||
})
|
||||
|
||||
it('clears data-closing when re-opened mid-close transition', async () => {
|
||||
// Regression guard: if the user toggles enabled back to true while the
|
||||
// 150ms close transition is still in flight, the <dialog> is still
|
||||
// mounted and [open], so the dialogRef watcher does not re-fire. Make
|
||||
// sure openDialog() clears the leftover data-closing flag itself;
|
||||
// otherwise the dialog stays stuck at opacity 0.
|
||||
const wrapper = mount(Modal, {
|
||||
attachTo: document.body,
|
||||
props: {enabled: true},
|
||||
slots: {default: '<p class="test-body">hi</p>'},
|
||||
})
|
||||
await flushPromises()
|
||||
await nextTick()
|
||||
|
||||
const dialog = document.querySelector('dialog.modal-dialog') as HTMLDialogElement
|
||||
expect(dialog.hasAttribute('open')).toBe(true)
|
||||
|
||||
// Start closing — this sets data-closing and schedules the unmount.
|
||||
await wrapper.setProps({enabled: false})
|
||||
await nextTick()
|
||||
expect(dialog.dataset.closing).toBe('')
|
||||
|
||||
// Re-open well before the 150ms close timer fires.
|
||||
await wrapper.setProps({enabled: true})
|
||||
await nextTick()
|
||||
|
||||
expect(dialog.dataset.closing).toBeUndefined()
|
||||
expect(dialog.hasAttribute('open')).toBe(true)
|
||||
|
||||
wrapper.unmount()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -97,7 +97,14 @@ function openDialog() {
|
|||
previouslyFocused.value = document.activeElement
|
||||
showDialog.value = true
|
||||
document.body.style.overflow = 'hidden'
|
||||
// The actual `showModal()` call happens in the `watch(dialogRef, …)`
|
||||
// If we're re-opening while the previous close transition is still in
|
||||
// flight the <dialog> is still mounted and [open], so the dialogRef
|
||||
// watcher below won't re-fire. Clear the data-closing flag here so the
|
||||
// dialog doesn't stay stuck at opacity 0.
|
||||
if (dialogRef.value) {
|
||||
delete dialogRef.value.dataset.closing
|
||||
}
|
||||
// The initial `showModal()` call happens in the `watch(dialogRef, …)`
|
||||
// below, which fires the moment Vue mounts the <dialog>. We cannot call
|
||||
// it synchronously here because the element is not in the DOM yet
|
||||
// (v-if="showDialog" only just became true), and we cannot rely on a
|
||||
|
|
|
|||
Loading…
Reference in New Issue