// HoverPopover hook: opens a native Popover-API element on hover/keyboard focus // of its trigger, so the popover renders in the browser TOP LAYER and escapes // any ancestor `overflow` clipping (the members table forces overflow-y:auto, // which clips an absolutely-positioned daisyUI tooltip/dropdown-content). Unlike // the older SortTooltip, placement is handed to CSS anchor positioning // (`anchor-name` on the trigger, `position-anchor`/`position-area` on the // popover) — this hook does no coordinate math, it only toggles visibility. // // WCAG 2.2 AA / SC 1.4.13 (Content on Hover or Focus): the popover is shown on // both hover and focus, is dismissible via Escape, and is hoverable/persistent — // a short close delay plus the popover's own hover keep it open while the pointer // travels from the trigger onto the popover content. // // Expected DOM: // //
const HoverPopover = { mounted() { this.tip = document.getElementById(this.el.dataset.popoverTarget) // Feature-detect: without Popover API support fall back to no visual popover // (the trigger's aria-label still conveys the summary to assistive tech). if (!this.tip || typeof this.tip.showPopover !== "function") return this.open = () => { try { if (!this.tip.matches(":popover-open")) this.tip.showPopover() } catch (_e) {} } this.close = () => { try { if (this.tip.matches(":popover-open")) this.tip.hidePopover() } catch (_e) {} } this.cancelClose = () => { if (this.closeTimer) { clearTimeout(this.closeTimer) this.closeTimer = null } } this.show = () => { this.cancelClose() this.open() } this.scheduleClose = () => { this.cancelClose() this.closeTimer = setTimeout(() => this.close(), 120) } this.onKey = (e) => { if (e.key === "Escape") this.close() } this.el.addEventListener("mouseenter", this.show) this.el.addEventListener("focus", this.show) this.el.addEventListener("mouseleave", this.scheduleClose) this.el.addEventListener("blur", this.scheduleClose) this.el.addEventListener("keydown", this.onKey) // Keep it open while the pointer is over the popover itself (hoverable). this.tip.addEventListener("mouseenter", this.show) this.tip.addEventListener("mouseleave", this.scheduleClose) }, destroyed() { if (!this.tip) return this.cancelClose() this.close() this.el.removeEventListener("mouseenter", this.show) this.el.removeEventListener("focus", this.show) this.el.removeEventListener("mouseleave", this.scheduleClose) this.el.removeEventListener("blur", this.scheduleClose) this.el.removeEventListener("keydown", this.onKey) this.tip.removeEventListener("mouseenter", this.show) this.tip.removeEventListener("mouseleave", this.scheduleClose) } } export default HoverPopover