Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions packages/hooks/src/useHover/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,56 @@ 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(<button>Hover</button>);
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(<button>Hover</button>);
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(<button>Hover</button>);
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);
});
});
28 changes: 28 additions & 0 deletions packages/hooks/src/useHover/demo/demo3.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* 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 (
<div ref={ref}>
<div>isHovering: {isHovering ? 'hover' : 'leave hover'}</div>

<div>isLongHovering: {isLongHovering ? 'long Hover' : 'leave Hover'} (delay:1000ms)</div>
</div>
);
};
4 changes: 4 additions & 0 deletions packages/hooks/src/useHover/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ A hook that tracks whether the element is being hovered.

<code src="./demo/demo2.tsx" />

### Long term hover event

<code src="./demo/demo3.tsx" />

## API

```javascript
Expand Down
17 changes: 16 additions & 1 deletion packages/hooks/src/useHover/index.ts
Original file line number Diff line number Diff line change
@@ -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<number | null>(null);

useEventListener(
'mouseenter',
() => {
onEnter?.();
setTrue();
onChange?.(true);
if (onLongHover) {
timerRef.current = window.setTimeout(() => {
onLongHover?.(true);
}, longHoverDuration);
}
},
{
target,
Expand All @@ -31,6 +41,11 @@ export default (target: BasicTarget, options?: Options): boolean => {
onLeave?.();
setFalse();
onChange?.(false);
if (timerRef.current) {
clearTimeout(timerRef.current);
timerRef.current = null;
onLongHover?.(false);
}
},
{
target,
Expand Down
4 changes: 4 additions & 0 deletions packages/hooks/src/useHover/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ nav:

<code src="./demo/demo2.tsx" />

### 长时间悬停事件

<code src="./demo/demo3.tsx" />

## API

```javascript
Expand Down
Loading