fix(ui): close track menu on outside click and idle timeout
cx
This commit is contained in:
1 parent
9cf345921e
commit
99dfd4f0a3
1 file changed
+42
-2
@@ -81,6 +81,7 @@
|
|||||||
let menuStyle = $state('');
|
let menuStyle = $state('');
|
||||||
let submenuStyle = $state('');
|
let submenuStyle = $state('');
|
||||||
let downloadSubmenuStyle = $state('');
|
let downloadSubmenuStyle = $state('');
|
||||||
|
let isHoveringAnyMenu = $state(false);
|
||||||
|
|
||||||
// Portal action - moves element to body to escape stacking context
|
// Portal action - moves element to body to escape stacking context
|
||||||
function portal(node: HTMLElement) {
|
function portal(node: HTMLElement) {
|
||||||
@@ -250,7 +251,40 @@
|
|||||||
// Ensure position + openSide classes are applied even if the initial openMenu()
|
// Ensure position + openSide classes are applied even if the initial openMenu()
|
||||||
// call returns early due to timing.
|
// call returns early due to timing.
|
||||||
setMenuPosition();
|
setMenuPosition();
|
||||||
document.addEventListener('mousedown', handleClickOutside);
|
|
||||||
|
// Use capture phase so stopPropagation in other UI doesn't prevent close.
|
||||||
|
const outsideListenerOptions: AddEventListenerOptions = { capture: true };
|
||||||
|
document.addEventListener('pointerdown', handleClickOutside as unknown as EventListener, outsideListenerOptions);
|
||||||
|
|
||||||
|
// Auto-close after inactivity when the cursor is not hovering any menu/submenu.
|
||||||
|
let idleTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
const idleMs = 20_000;
|
||||||
|
|
||||||
|
const scheduleIdleClose = () => {
|
||||||
|
if (idleTimer) clearTimeout(idleTimer);
|
||||||
|
idleTimer = setTimeout(() => {
|
||||||
|
if (isOpen && !isHoveringAnyMenu) closeMenu();
|
||||||
|
}, idleMs);
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelIdleClose = () => {
|
||||||
|
if (idleTimer) {
|
||||||
|
clearTimeout(idleTimer);
|
||||||
|
idleTimer = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start the timer if the mouse isn't currently hovering the menu.
|
||||||
|
if (!isHoveringAnyMenu) scheduleIdleClose();
|
||||||
|
|
||||||
|
const onAnyActivity = () => {
|
||||||
|
if (!isHoveringAnyMenu) scheduleIdleClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('pointermove', onAnyActivity, true);
|
||||||
|
window.addEventListener('wheel', onAnyActivity, true);
|
||||||
|
window.addEventListener('keydown', onAnyActivity, true);
|
||||||
|
|
||||||
const handleResize = () => setMenuPosition();
|
const handleResize = () => setMenuPosition();
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
setMenuPosition();
|
setMenuPosition();
|
||||||
@@ -261,9 +295,13 @@
|
|||||||
window.addEventListener('resize', handleResize);
|
window.addEventListener('resize', handleResize);
|
||||||
window.addEventListener('scroll', handleScroll, true);
|
window.addEventListener('scroll', handleScroll, true);
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('mousedown', handleClickOutside);
|
document.removeEventListener('pointerdown', handleClickOutside as unknown as EventListener, outsideListenerOptions);
|
||||||
|
window.removeEventListener('pointermove', onAnyActivity, true);
|
||||||
|
window.removeEventListener('wheel', onAnyActivity, true);
|
||||||
|
window.removeEventListener('keydown', onAnyActivity, true);
|
||||||
window.removeEventListener('resize', handleResize);
|
window.removeEventListener('resize', handleResize);
|
||||||
window.removeEventListener('scroll', handleScroll, true);
|
window.removeEventListener('scroll', handleScroll, true);
|
||||||
|
cancelIdleClose();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -300,6 +338,8 @@
|
|||||||
bind:this={menuEl}
|
bind:this={menuEl}
|
||||||
style={menuStyle}
|
style={menuStyle}
|
||||||
use:portal
|
use:portal
|
||||||
|
onmouseenter={() => { isHoveringAnyMenu = true; }}
|
||||||
|
onmouseleave={() => { isHoveringAnyMenu = false; }}
|
||||||
>
|
>
|
||||||
<div class="menu-panel">
|
<div class="menu-panel">
|
||||||
{#if hasPlayback}
|
{#if hasPlayback}
|
||||||
|
|||||||
Reference in new issue
Block a user