Skip to content

Commit fac2f2d

Browse files
committed
update
1 parent b251836 commit fac2f2d

2 files changed

Lines changed: 21 additions & 14 deletions

File tree

src/index.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -483,43 +483,45 @@ export function generateTrigger(
483483
// Between 1 frame and 1 second
484484
const refreshDelay = clamp(mouseLeaveDelay * 1000, 1000 / 60, 1000);
485485

486+
const cancelRefresh = () => {
487+
const safeHover = safeHoverRef.current;
488+
if (safeHover?.refreshTimer) {
489+
clearTimeout(safeHover.refreshTimer);
490+
safeHover.refreshTimer = null;
491+
}
492+
};
493+
486494
const scheduleRefresh = () => {
487495
const safeHover = safeHoverRef.current;
488496

489-
if (!safeHover || !refreshDelay) {
497+
if (!safeHover || safeHover.refreshTimer) {
490498
return;
491499
}
492500

493501
safeHover.refreshTimer = setTimeout(() => {
494502
if (isPointSafe(latestPoint)) {
495-
triggerOpen(false, mouseLeaveDelay);
496-
scheduleRefresh();
503+
safeHover.refreshTimer = null;
497504
} else {
498505
clearSafeHover();
499-
triggerOpen(false, mouseLeaveDelay);
506+
triggerOpen(false);
500507
}
501508
}, refreshDelay);
502509
};
503510

504-
// Keep the existing close delay alive while the cursor crosses the gap.
505511
const handler = (nativeEvent: MouseEvent) => {
506512
latestPoint = [nativeEvent.clientX, nativeEvent.clientY];
507513

508514
if (isPointSafe(latestPoint)) {
509-
triggerOpen(false, mouseLeaveDelay);
515+
cancelRefresh();
510516
} else {
511-
clearSafeHover();
512-
triggerOpen(false, mouseLeaveDelay);
517+
scheduleRefresh();
513518
}
514519
};
515520

516521
doc.addEventListener('mousemove', handler);
517522

518523
safeHoverRef.current = { doc, handler, refreshTimer: null };
519524

520-
triggerOpen(false, mouseLeaveDelay);
521-
scheduleRefresh();
522-
523525
return true;
524526
},
525527
);
@@ -536,7 +538,7 @@ export function generateTrigger(
536538
}
537539
}, [mergedOpen, clearSafeHover]);
538540

539-
function onEsc({ top }: Parameters<PortalProps['onEsc']>[0]) {
541+
function onEsc({ top }: Parameters<NonNullable<PortalProps['onEsc']>>[0]) {
540542
if (top) {
541543
triggerOpen(false);
542544
}
@@ -555,7 +557,7 @@ export function generateTrigger(
555557
);
556558

557559
const [motionPrepareResolve, setMotionPrepareResolve] =
558-
React.useState<VoidFunction>(null);
560+
React.useState<VoidFunction | null>(null);
559561

560562
// =========================== Align ============================
561563
const [mousePos, setMousePos] = React.useState<

tests/basic.test.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ describe('Trigger.Basic', () => {
298298
expect(isPopupHidden()).toBeTruthy();
299299
});
300300

301-
it('closes popup when safe hover area disappears while mouse is paused', () => {
301+
it('waits for mousemove to start refresh close detection after safe hover area disappears', () => {
302302
const { container } = render(
303303
<Trigger
304304
action={['hover']}
@@ -324,6 +324,11 @@ describe('Trigger.Basic', () => {
324324
mockRect(popup, { left: 10, top: 10, width: 60, height: 30 });
325325
act(() => jest.advanceTimersByTime(150));
326326

327+
expect(isPopupHidden()).toBeFalsy();
328+
329+
fireEvent.mouseMove(document, { clientX: 150, clientY: 40 });
330+
act(() => jest.advanceTimersByTime(100));
331+
327332
expect(isPopupHidden()).toBeTruthy();
328333
});
329334

0 commit comments

Comments
 (0)