feat: Added hover-to-open with 150ms leave delay and matchMedia desktop…
- "frontend/src/components/AdminDropdown.tsx" GSD-Task: S05/T01
This commit is contained in:
parent
82998c6d8d
commit
b4bea10067
1 changed files with 46 additions and 2 deletions
|
|
@ -1,9 +1,48 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const DESKTOP_MQ = "(min-width: 769px)";
|
||||
const LEAVE_DELAY_MS = 150;
|
||||
|
||||
export default function AdminDropdown() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const isDesktopRef = useRef(false);
|
||||
const leaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
// Track desktop breakpoint via matchMedia
|
||||
useEffect(() => {
|
||||
const mql = window.matchMedia(DESKTOP_MQ);
|
||||
isDesktopRef.current = mql.matches;
|
||||
const onChange = (e: MediaQueryListEvent) => {
|
||||
isDesktopRef.current = e.matches;
|
||||
};
|
||||
mql.addEventListener("change", onChange);
|
||||
return () => mql.removeEventListener("change", onChange);
|
||||
}, []);
|
||||
|
||||
// Clear leave timer on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (leaveTimerRef.current) clearTimeout(leaveTimerRef.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleMouseEnter = useCallback(() => {
|
||||
if (leaveTimerRef.current) {
|
||||
clearTimeout(leaveTimerRef.current);
|
||||
leaveTimerRef.current = null;
|
||||
}
|
||||
if (isDesktopRef.current) setOpen(true);
|
||||
}, []);
|
||||
|
||||
const handleMouseLeave = useCallback(() => {
|
||||
if (!isDesktopRef.current) return;
|
||||
leaveTimerRef.current = setTimeout(() => {
|
||||
setOpen(false);
|
||||
leaveTimerRef.current = null;
|
||||
}, LEAVE_DELAY_MS);
|
||||
}, []);
|
||||
|
||||
// Close on outside click
|
||||
useEffect(() => {
|
||||
|
|
@ -31,7 +70,12 @@ export default function AdminDropdown() {
|
|||
}, [open]);
|
||||
|
||||
return (
|
||||
<div className="admin-dropdown" ref={dropdownRef}>
|
||||
<div
|
||||
className="admin-dropdown"
|
||||
ref={dropdownRef}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<button
|
||||
className="admin-dropdown__trigger"
|
||||
onClick={() => setOpen((prev) => !prev)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue