From 2fe499a47d0b634bafa5d99e125faa660a7b3c35 Mon Sep 17 00:00:00 2001 From: Luncode <1370655052@qq.com> Date: Wed, 2 Jul 2025 17:04:33 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20useHover=E4=B8=AD=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=95=BF=E6=97=B6=E9=97=B4=E6=82=AC=E5=81=9C=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/useHover/__tests__/index.test.tsx | 59 +++++++++++++++++++ packages/hooks/src/useHover/demo/demo3.tsx | 31 ++++++++++ packages/hooks/src/useHover/index.en-US.md | 4 ++ packages/hooks/src/useHover/index.ts | 17 +++++- packages/hooks/src/useHover/index.zh-CN.md | 4 ++ 5 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 packages/hooks/src/useHover/demo/demo3.tsx diff --git a/packages/hooks/src/useHover/__tests__/index.test.tsx b/packages/hooks/src/useHover/__tests__/index.test.tsx index a9a6e652e8..f39c94e064 100644 --- a/packages/hooks/src/useHover/__tests__/index.test.tsx +++ b/packages/hooks/src/useHover/__tests__/index.test.tsx @@ -30,3 +30,62 @@ describe('useHover', () => { expect(trigger).toBe(2); }); }); + +describe('useHover - onLongHover', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('should call onLongHover(true) after longHoverDuration', () => { + const onLongHover = jest.fn(); + const { getByText } = render(); + renderHook(() => + useHover(getByText('Hover'), { onLongHover, longHoverDuration: 300 }) + ); + + act(() => { + fireEvent.mouseEnter(getByText('Hover')); + }); + expect(onLongHover).not.toBeCalled(); + act(() => { + jest.advanceTimersByTime(300); + }); + expect(onLongHover).toHaveBeenCalledWith(true); + }); + + it('should call onLongHover(false) on mouseleave if timer exists', () => { + const onLongHover = jest.fn(); + const { getByText } = render(); + renderHook(() => + useHover(getByText('Hover'), { onLongHover, longHoverDuration: 300 }) + ); + act(() => { + fireEvent.mouseEnter(getByText('Hover')); + }); + act(() => { + fireEvent.mouseLeave(getByText('Hover')); + }); + expect(onLongHover).toHaveBeenCalledWith(false); + }); + + it('should not call onLongHover(true) if mouse leaves before duration', () => { + const onLongHover = jest.fn(); + const { getByText } = render(); + renderHook(() => + useHover(getByText('Hover'), { onLongHover, longHoverDuration: 300 }) + ); + act(() => { + fireEvent.mouseEnter(getByText('Hover')); + }); + act(() => { + jest.advanceTimersByTime(200); + fireEvent.mouseLeave(getByText('Hover')); + }); + expect(onLongHover).toHaveBeenCalledTimes(1); + expect(onLongHover).toHaveBeenCalledWith(false); + }); +}); diff --git a/packages/hooks/src/useHover/demo/demo3.tsx b/packages/hooks/src/useHover/demo/demo3.tsx new file mode 100644 index 0000000000..c4986413dd --- /dev/null +++ b/packages/hooks/src/useHover/demo/demo3.tsx @@ -0,0 +1,31 @@ +/** + * title: Basic usage + * desc: Use ref or Pass in DOM element. + * + * title.zh-CN: 基础用法 + * desc.zh-CN: 使用 ref 或者传入 DOM 元素。 + */ + +import React, { useRef, useState } from "react"; +import { useHover } from "ahooks"; + +export default () => { + const ref = useRef(null); + const [isLongHovering, setIsLongHovering] = useState(false); + const isHovering = useHover(ref, { + longHoverDuration: 1000, + onLongHover: (value) => { + setIsLongHovering(value); + }, + }); + return ( +
+### Long term hover event
+
+
+
## API
```javascript
diff --git a/packages/hooks/src/useHover/index.ts b/packages/hooks/src/useHover/index.ts
index 0e319680d7..53a42d122c 100644
--- a/packages/hooks/src/useHover/index.ts
+++ b/packages/hooks/src/useHover/index.ts
@@ -1,24 +1,34 @@
import useBoolean from '../useBoolean';
import useEventListener from '../useEventListener';
import type { BasicTarget } from '../utils/domTarget';
+import { useRef } from 'react';
export interface Options {
onEnter?: () => void;
onLeave?: () => void;
onChange?: (isHovering: boolean) => void;
+ onLongHover?: (isLongHovering: boolean) => void;
+ longHoverDuration?: number;
}
export default (target: BasicTarget, options?: Options): boolean => {
- const { onEnter, onLeave, onChange } = options || {};
+ const { onEnter, onLeave, onChange, onLongHover, longHoverDuration = 500 } = options || {};
const [state, { setTrue, setFalse }] = useBoolean(false);
+ const timerRef = useRef
+### 长时间悬停事件
+
+
+
## API
```javascript
From 9b462df8c3bdb9540d5bec512d24992e1cefec4f Mon Sep 17 00:00:00 2001
From: Luncode <1370655052@qq.com>
Date: Wed, 2 Jul 2025 17:05:55 +0800
Subject: [PATCH 2/2] =?UTF-8?q?chore:=20=E6=96=B0=E5=A2=9E=E7=BB=84?=
=?UTF-8?q?=E4=BB=B6=E5=92=8C=E6=B5=8B=E8=AF=95=E6=96=87=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
packages/hooks/src/useHover/__tests__/index.test.tsx | 12 +++---------
packages/hooks/src/useHover/demo/demo3.tsx | 11 ++++-------
2 files changed, 7 insertions(+), 16 deletions(-)
diff --git a/packages/hooks/src/useHover/__tests__/index.test.tsx b/packages/hooks/src/useHover/__tests__/index.test.tsx
index f39c94e064..c21ba3b697 100644
--- a/packages/hooks/src/useHover/__tests__/index.test.tsx
+++ b/packages/hooks/src/useHover/__tests__/index.test.tsx
@@ -43,9 +43,7 @@ describe('useHover - onLongHover', () => {
it('should call onLongHover(true) after longHoverDuration', () => {
const onLongHover = jest.fn();
const { getByText } = render();
- renderHook(() =>
- useHover(getByText('Hover'), { onLongHover, longHoverDuration: 300 })
- );
+ renderHook(() => useHover(getByText('Hover'), { onLongHover, longHoverDuration: 300 }));
act(() => {
fireEvent.mouseEnter(getByText('Hover'));
@@ -60,9 +58,7 @@ describe('useHover - onLongHover', () => {
it('should call onLongHover(false) on mouseleave if timer exists', () => {
const onLongHover = jest.fn();
const { getByText } = render();
- renderHook(() =>
- useHover(getByText('Hover'), { onLongHover, longHoverDuration: 300 })
- );
+ renderHook(() => useHover(getByText('Hover'), { onLongHover, longHoverDuration: 300 }));
act(() => {
fireEvent.mouseEnter(getByText('Hover'));
});
@@ -75,9 +71,7 @@ describe('useHover - onLongHover', () => {
it('should not call onLongHover(true) if mouse leaves before duration', () => {
const onLongHover = jest.fn();
const { getByText } = render();
- renderHook(() =>
- useHover(getByText('Hover'), { onLongHover, longHoverDuration: 300 })
- );
+ renderHook(() => useHover(getByText('Hover'), { onLongHover, longHoverDuration: 300 }));
act(() => {
fireEvent.mouseEnter(getByText('Hover'));
});
diff --git a/packages/hooks/src/useHover/demo/demo3.tsx b/packages/hooks/src/useHover/demo/demo3.tsx
index c4986413dd..a602a6e921 100644
--- a/packages/hooks/src/useHover/demo/demo3.tsx
+++ b/packages/hooks/src/useHover/demo/demo3.tsx
@@ -6,8 +6,8 @@
* desc.zh-CN: 使用 ref 或者传入 DOM 元素。
*/
-import React, { useRef, useState } from "react";
-import { useHover } from "ahooks";
+import React, { useRef, useState } from 'react';
+import { useHover } from 'ahooks';
export default () => {
const ref = useRef(null);
@@ -20,12 +20,9 @@ export default () => {
});
return (