Close the Datei menu on Escape or a click outside it
Listens in the capture phase while the menu is open, so canvas and grid handlers that stop propagation can't keep it open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue';
|
import { computed, onBeforeUnmount, ref, watch } from 'vue';
|
||||||
import { useDocument } from '../store/document';
|
import { useDocument } from '../store/document';
|
||||||
import { useTheme } from '../composables/useTheme';
|
import { useTheme } from '../composables/useTheme';
|
||||||
import { useToasts } from '../composables/useToasts';
|
import { useToasts } from '../composables/useToasts';
|
||||||
@@ -30,6 +30,29 @@ const { mode: themeMode, cycle: cycleTheme } = useTheme();
|
|||||||
const toasts = useToasts();
|
const toasts = useToasts();
|
||||||
|
|
||||||
const fileMenuOpen = ref(false);
|
const fileMenuOpen = ref(false);
|
||||||
|
const fileMenuWrap = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
// Close the Datei menu on Escape or on a press anywhere outside it. Capture
|
||||||
|
// phase, so canvas/grid handlers that stop propagation can't swallow it.
|
||||||
|
function onOutsidePointer(e: PointerEvent) {
|
||||||
|
if (!fileMenuWrap.value?.contains(e.target as Node)) fileMenuOpen.value = false;
|
||||||
|
}
|
||||||
|
function onMenuKey(e: KeyboardEvent) {
|
||||||
|
if (e.key === 'Escape') fileMenuOpen.value = false;
|
||||||
|
}
|
||||||
|
function detachMenuListeners() {
|
||||||
|
document.removeEventListener('pointerdown', onOutsidePointer, true);
|
||||||
|
document.removeEventListener('keydown', onMenuKey, true);
|
||||||
|
}
|
||||||
|
watch(fileMenuOpen, (open) => {
|
||||||
|
if (open) {
|
||||||
|
document.addEventListener('pointerdown', onOutsidePointer, true);
|
||||||
|
document.addEventListener('keydown', onMenuKey, true);
|
||||||
|
} else {
|
||||||
|
detachMenuListeners();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onBeforeUnmount(detachMenuListeners);
|
||||||
const aboutOpen = ref(false);
|
const aboutOpen = ref(false);
|
||||||
const functionsOpen = ref(false);
|
const functionsOpen = ref(false);
|
||||||
const namedRangesOpen = ref(false);
|
const namedRangesOpen = ref(false);
|
||||||
@@ -295,7 +318,7 @@ function onSample() {
|
|||||||
|
|
||||||
<div class="spacer" />
|
<div class="spacer" />
|
||||||
|
|
||||||
<div class="menu-wrap">
|
<div ref="fileMenuWrap" class="menu-wrap">
|
||||||
<button class="btn" @click="fileMenuOpen = !fileMenuOpen">Datei ▾</button>
|
<button class="btn" @click="fileMenuOpen = !fileMenuOpen">Datei ▾</button>
|
||||||
<ul v-if="fileMenuOpen" class="menu" @click="fileMenuOpen = false">
|
<ul v-if="fileMenuOpen" class="menu" @click="fileMenuOpen = false">
|
||||||
<li><button @click="onNew">Neu</button></li>
|
<li><button @click="onNew">Neu</button></li>
|
||||||
|
|||||||
Reference in New Issue
Block a user