Skip to content

Commit 04e3906

Browse files
diondiondionClearlyClaire
authored andcommitted
[Glitch] Prevent hover card from showing unintentionally
Port 316290b to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
1 parent 3b517fc commit 04e3906

1 file changed

Lines changed: 24 additions & 11 deletions

File tree

app/javascript/flavours/glitch/components/hover_card_controller.tsx

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ import { useTimeout } from 'flavours/glitch/hooks/useTimeout';
1414
const offset = [-12, 4] as OffsetValue;
1515
const enterDelay = 750;
1616
const leaveDelay = 150;
17+
// Only open the card if the mouse was moved within this time,
18+
// to avoid triggering the card without intentional mouse movement
19+
// (e.g. when content changed underneath the mouse cursor)
20+
const activeMovementThreshold = 150;
1721
const popperConfig = { strategy: 'fixed' } as UsePopperOptions;
1822

1923
const isHoverCardAnchor = (element: HTMLElement) =>
@@ -23,10 +27,10 @@ export const HoverCardController: React.FC = () => {
2327
const [open, setOpen] = useState(false);
2428
const [accountId, setAccountId] = useState<string | undefined>();
2529
const [anchor, setAnchor] = useState<HTMLElement | null>(null);
26-
const isUsingTouchRef = useRef(false);
2730
const cardRef = useRef<HTMLDivElement | null>(null);
2831
const [setLeaveTimeout, cancelLeaveTimeout] = useTimeout();
2932
const [setEnterTimeout, cancelEnterTimeout, delayEnterTimeout] = useTimeout();
33+
const [setMoveTimeout, cancelMoveTimeout] = useTimeout();
3034
const [setScrollTimeout] = useTimeout();
3135
const location = useLocation();
3236

@@ -43,6 +47,8 @@ export const HoverCardController: React.FC = () => {
4347

4448
useEffect(() => {
4549
let isScrolling = false;
50+
let isUsingTouch = false;
51+
let isActiveMouseMovement = false;
4652
let currentAnchor: HTMLElement | null = null;
4753
let currentTitle: string | null = null;
4854

@@ -64,7 +70,7 @@ export const HoverCardController: React.FC = () => {
6470
const handleTouchStart = () => {
6571
// Keeping track of touch events to prevent the
6672
// hover card from being displayed on touch devices
67-
isUsingTouchRef.current = true;
73+
isUsingTouch = true;
6874
};
6975

7076
const handleMouseEnter = (e: MouseEvent) => {
@@ -76,13 +82,14 @@ export const HoverCardController: React.FC = () => {
7682
return;
7783
}
7884

79-
// Bail out if a touch is active
80-
if (isUsingTouchRef.current) {
85+
// Bail out if we're scrolling, a touch is active,
86+
// or if there was no active mouse movement
87+
if (isScrolling || !isActiveMouseMovement || isUsingTouch) {
8188
return;
8289
}
8390

8491
// We've entered an anchor
85-
if (!isScrolling && isHoverCardAnchor(target)) {
92+
if (isHoverCardAnchor(target)) {
8693
cancelLeaveTimeout();
8794

8895
currentAnchor?.removeAttribute('aria-describedby');
@@ -97,10 +104,7 @@ export const HoverCardController: React.FC = () => {
97104
}
98105

99106
// We've entered the hover card
100-
if (
101-
!isScrolling &&
102-
(target === currentAnchor || target === cardRef.current)
103-
) {
107+
if (target === currentAnchor || target === cardRef.current) {
104108
cancelLeaveTimeout();
105109
}
106110
};
@@ -139,10 +143,17 @@ export const HoverCardController: React.FC = () => {
139143
};
140144

141145
const handleMouseMove = () => {
142-
if (isUsingTouchRef.current) {
143-
isUsingTouchRef.current = false;
146+
if (isUsingTouch) {
147+
isUsingTouch = false;
144148
}
149+
145150
delayEnterTimeout(enterDelay);
151+
152+
cancelMoveTimeout();
153+
isActiveMouseMovement = true;
154+
setMoveTimeout(() => {
155+
isActiveMouseMovement = false;
156+
}, activeMovementThreshold);
146157
};
147158

148159
document.body.addEventListener('touchstart', handleTouchStart, {
@@ -186,6 +197,8 @@ export const HoverCardController: React.FC = () => {
186197
setOpen,
187198
setAccountId,
188199
setAnchor,
200+
setMoveTimeout,
201+
cancelMoveTimeout,
189202
]);
190203

191204
return (

0 commit comments

Comments
 (0)