From 62410e9ee28ee686aecabe885fc02033c2b65971 Mon Sep 17 00:00:00 2001 From: Su-Yong Date: Fri, 29 Dec 2023 17:52:31 +0900 Subject: [PATCH] feat(in-app-menu): add show on hover --- src/plugins/in-app-menu/menu/panel.ts | 46 +++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/plugins/in-app-menu/menu/panel.ts b/src/plugins/in-app-menu/menu/panel.ts index 3b2fd35e..e6bef9c9 100644 --- a/src/plugins/in-app-menu/menu/panel.ts +++ b/src/plugins/in-app-menu/menu/panel.ts @@ -7,13 +7,14 @@ import type { MenuItem } from 'electron'; interface PanelOptions { placement?: 'bottom' | 'right'; order?: number; + openOnHover?: boolean; } export const createPanel = ( parent: HTMLElement, anchor: HTMLElement, items: MenuItem[], - options: PanelOptions = { placement: 'bottom', order: 0 }, + options: PanelOptions = { placement: 'bottom', order: 0, openOnHover: false }, ) => { const childPanels: HTMLElement[] = []; const panel = document.createElement('menu-panel'); @@ -93,11 +94,12 @@ export const createPanel = ( { placement: 'right', order: (options?.order ?? 0) + 1, + openOnHover: true, }, ); childPanels.push(child); - children.push(...children); + childPanels.push(...children); } return panel.appendChild(menu); @@ -132,6 +134,46 @@ export const createPanel = ( } }; + if (options.openOnHover) { + let timeout: number | null = null; + anchor.addEventListener('mouseenter', () => { + if (timeout) window.clearTimeout(timeout); + timeout = window.setTimeout(() => { + if (!isOpened()) open(); + }, 225); + }); + anchor.addEventListener('mouseleave', () => { + if (timeout) window.clearTimeout(timeout); + let mouseX = 0, mouseY = 0; + const onMouseMove = (event: MouseEvent) => { + mouseX = event.clientX; + mouseY = event.clientY; + }; + document.addEventListener('mousemove', onMouseMove); + timeout = window.setTimeout(() => { + document.removeEventListener('mousemove', onMouseMove); + const now = document.elementFromPoint(mouseX, mouseY); + if (now === panel || panel.contains(now)) { + const onLeave = () => { + document.addEventListener('mousemove', onMouseMove); + timeout = window.setTimeout(() => { + document.removeEventListener('mousemove', onMouseMove); + const now = document.elementFromPoint(mouseX, mouseY); + if (now === panel || panel.contains(now) || childPanels.some((it) => it.contains(now))) return; + + if (isOpened()) close(); + panel.removeEventListener('mouseleave', onLeave); + }, 225); + }; + panel.addEventListener('mouseleave', onLeave); + return; + } + + if (isOpened()) close(); + }, 225); + }); + } + anchor.addEventListener('click', () => { if (isOpened()) close(); else open();