fix(modal): open dialog reliably in electron desktop
Replace the nextTick-based showModal() call with a watch on the template ref so the dialog is opened exactly when the <dialog> element mounts. The previous implementation could silently skip showModal() if the mount was deferred past the first nextTick, leaving the dialog in the DOM with opacity: 0 and no click target. Observed in the Vikunja Desktop v2.3.0 Electron build where the search (quick actions) button was unresponsive. Closes #2590
This commit is contained in:
parent
f29f985386
commit
e932ee759a
|
|
@ -61,7 +61,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import BaseButton from '@/components/base/BaseButton.vue'
|
||||
import {ref, useAttrs, watch, onBeforeUnmount, onMounted, nextTick} from 'vue'
|
||||
import {ref, useAttrs, watch, onBeforeUnmount} from 'vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
enabled?: boolean,
|
||||
|
|
@ -96,14 +96,12 @@ function openDialog() {
|
|||
}
|
||||
previouslyFocused.value = document.activeElement
|
||||
showDialog.value = true
|
||||
nextTick(() => {
|
||||
const dialog = dialogRef.value
|
||||
if (dialog) {
|
||||
delete dialog.dataset.closing
|
||||
dialog.showModal()
|
||||
}
|
||||
document.body.style.overflow = 'hidden'
|
||||
})
|
||||
document.body.style.overflow = 'hidden'
|
||||
// The actual `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
|
||||
// single nextTick because the mount can be deferred past it (#2590).
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
|
|
@ -136,13 +134,17 @@ watch(
|
|||
closeDialog()
|
||||
}
|
||||
},
|
||||
{immediate: false},
|
||||
{immediate: true},
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
if (props.enabled) {
|
||||
openDialog()
|
||||
}
|
||||
// Actually call showModal() the moment the <dialog> element is mounted.
|
||||
// `dialogRef` is populated by Vue during the render flush after
|
||||
// `showDialog.value = true`, so this fires deterministically, no matter
|
||||
// how many flushes the renderer needs (see #2590).
|
||||
watch(dialogRef, (dialog) => {
|
||||
if (!dialog) return
|
||||
delete dialog.dataset.closing
|
||||
dialog.showModal()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue