-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
86 changed files
with
2,955 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { renderHook } from '@testing-library/react-hooks'; | ||
import useClickAway from '../index'; | ||
|
||
describe('useClickAway', () => { | ||
it('should be defined', () => { | ||
expect(useClickAway).toBeDefined(); | ||
}); | ||
|
||
let container: HTMLDivElement; | ||
let container1: HTMLDivElement; | ||
|
||
beforeEach(() => { | ||
container = document.createElement('div'); | ||
container1 = document.createElement('div'); | ||
container1.setAttribute('id', 'ele'); | ||
document.body.appendChild(container); | ||
document.body.appendChild(container1); | ||
}); | ||
|
||
afterEach(() => { | ||
document.body.removeChild(container); | ||
document.body.removeChild(container1); | ||
}); | ||
|
||
it('test on dom optional', async () => { | ||
let state: number = 0; | ||
const { rerender, unmount } = renderHook((dom: any) => | ||
useClickAway(() => { | ||
state++; | ||
}, dom), | ||
); | ||
|
||
document.body.click(); | ||
expect(state).toEqual(0); | ||
|
||
rerender(() => container); | ||
container.click(); | ||
expect(state).toEqual(0); | ||
document.body.click(); | ||
expect(state).toEqual(1); | ||
|
||
rerender(container1); | ||
container1.click(); | ||
expect(state).toEqual(1); | ||
document.body.click(); | ||
expect(state).toEqual(2); | ||
|
||
unmount(); | ||
document.body.click(); | ||
expect(state).toEqual(2); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React, { useState } from 'react'; | ||
import { Button } from 'antd'; | ||
import useClickAway from '..'; | ||
|
||
export default () => { | ||
const [counter, setCounter] = useState(0); | ||
const ref = useClickAway(() => { | ||
setCounter(s => s + 1); | ||
}); | ||
return ( | ||
<div> | ||
<span ref={ref}> | ||
<Button type="primary">box1</Button> | ||
</span> | ||
<p>counter: {counter}</p> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import React, { useState } from 'react'; | ||
import { Button } from 'antd'; | ||
import useClickAway from '..'; | ||
|
||
export default () => { | ||
const [counter, setCounter] = useState(0); | ||
|
||
const ref = useClickAway(() => { | ||
setCounter(s => s + 1); | ||
}); | ||
|
||
return ( | ||
<div> | ||
<span ref={ref}> | ||
<Button type="primary">box1</Button> | ||
</span> | ||
<p>counter: {counter}</p> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import React, { useState } from 'react'; | ||
import { Button } from 'antd'; | ||
import useClickAway from '..'; | ||
|
||
export default () => { | ||
const [counter, setCounter] = useState(0); | ||
useClickAway( | ||
() => { | ||
setCounter(s => s + 1); | ||
}, | ||
() => document.getElementById('box2'), | ||
); | ||
return ( | ||
<div> | ||
<Button type="primary" id="box2"> | ||
box2 | ||
</Button> | ||
<p>counter: {counter}</p> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React, { useState } from 'react'; | ||
import { Button } from 'antd'; | ||
import useClickAway from '..'; | ||
|
||
export default () => { | ||
const [counter, setCounter] = useState(0); | ||
|
||
useClickAway( | ||
() => { | ||
setCounter(s => s + 1); | ||
}, | ||
() => document.getElementById('box2'), | ||
); | ||
|
||
return ( | ||
<div> | ||
<Button type="primary" id="box2"> | ||
box2 | ||
</Button> | ||
<p>counter: {counter}</p> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { MutableRefObject, useRef, useEffect, useCallback, useMemo } from 'react'; | ||
|
||
// 鼠标点击事件,click 不会监听右键 | ||
const defaultEvent = 'click'; | ||
|
||
type RefType = HTMLElement | (() => HTMLElement | null) | null; | ||
|
||
export default function useClickAway<T extends HTMLElement = HTMLDivElement>( | ||
onClickAway: (event: KeyboardEvent) => void, | ||
dom?: RefType, | ||
eventName: string = defaultEvent, | ||
): MutableRefObject<T> { | ||
const element = useRef<T>(); | ||
|
||
const handler = useCallback( | ||
event => { | ||
const targetElement = typeof dom === 'function' ? dom() : dom; | ||
const el = targetElement || element.current; | ||
if (!el || el.contains(event.target)) { | ||
return; | ||
} | ||
|
||
onClickAway(event); | ||
}, | ||
[element.current, onClickAway, dom], | ||
); | ||
|
||
useEffect(() => { | ||
document.addEventListener(eventName, handler); | ||
|
||
return () => { | ||
document.removeEventListener(eventName, handler); | ||
}; | ||
}, [eventName, handler]); | ||
|
||
return element as MutableRefObject<T>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
--- | ||
name: useClickAway | ||
route: /useClickAway | ||
menu: 'Other' | ||
edit: false | ||
sidebar: true | ||
--- | ||
import JackBox from 'jackbox'; | ||
|
||
import Demo1 from './demo/demo1'; | ||
import Demo1CodeTsx from '!raw-loader!./demo/demo1.tsx'; | ||
import Demo1CodeJsx from '!raw-loader!./demo/demo1.jsx'; | ||
|
||
import Demo2 from './demo/demo2'; | ||
import Demo2CodeTsx from '!raw-loader!./demo/demo2.tsx'; | ||
import Demo2CodeJsx from '!raw-loader!./demo/demo2.jsx'; | ||
|
||
# useClickAway | ||
|
||
优雅的管理目标元素外点击事件的 Hook。 | ||
|
||
## 代码演示 | ||
|
||
<JackBox jsCode={Demo1CodeJsx} tsCode={Demo1CodeTsx} demoName='基础使用' description='请点击按钮或按钮外查看效果。'> | ||
<Demo1 /> | ||
</JackBox> | ||
|
||
<JackBox jsCode={Demo2CodeJsx} tsCode={Demo2CodeTsx} demoName='自定义 DOM' description='支持直接传入 DOM 对象或通过 function 返回一个对象的方式引入。'> | ||
<Demo2 /> | ||
</JackBox> | ||
|
||
## API | ||
|
||
```javascript | ||
const ref = useClickAway( | ||
onClickAway: (event: KeyboardEvent) => void, | ||
dom?: RefType, | ||
); | ||
``` | ||
|
||
### Result | ||
|
||
| 参数 | 说明 | 类型 | | ||
|----------|------------------------------------------|------------| | ||
| ref | 当未传入任何参数时,将 ref 绑定给需监听的节点 | - | | ||
|
||
### Params | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
|---------|----------------------------------------------|------------------------|--------| | ||
| onClickAway | 触发事件的函数 | (event) => void | - | | ||
| dom? | 可选项,如果未传入则会监听返回结果中的 ref,否则会监听传入的节点 | HTMLElement \| (() => HTMLElement) \| undefined | - | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
--- | ||
name: useClickAway | ||
route: /useClickAway | ||
menu: 'Other' | ||
edit: false | ||
sidebar: true | ||
--- | ||
import JackBox from 'jackbox'; | ||
|
||
import Demo1 from './demo/demo1'; | ||
import Demo1CodeTsx from '!raw-loader!./demo/demo1.tsx'; | ||
import Demo1CodeJsx from '!raw-loader!./demo/demo1.jsx'; | ||
|
||
import Demo2 from './demo/demo2'; | ||
import Demo2CodeTsx from '!raw-loader!./demo/demo2.tsx'; | ||
import Demo2CodeJsx from '!raw-loader!./demo/demo2.jsx'; | ||
|
||
# useClickAway | ||
|
||
A hook that elegantly manages click outside of target elements. | ||
|
||
## Examples | ||
|
||
### Default usage | ||
|
||
<JackBox jsCode={Demo1CodeJsx} tsCode={Demo1CodeTsx} demoName='Default usage' description='Please click button or outside of button to show effects.'> | ||
<Demo1 /> | ||
</JackBox> | ||
|
||
<JackBox jsCode={Demo2CodeJsx} tsCode={Demo2CodeTsx} demoName='Custom DOM' description='Support pass in a DOM element directly or a function that returns the DOM element.'> | ||
<Demo2 /> | ||
</JackBox> | ||
|
||
## API | ||
|
||
```javascript | ||
const ref = useClickAway( | ||
onClickAway: (event: KeyboardEvent) => void, | ||
dom?: RefType, | ||
); | ||
``` | ||
|
||
### Result | ||
|
||
| Property | Description | Type | | ||
|----------|------------------------------------------|------------| | ||
| ref | when no param is passed, this ref will be listened | - | | ||
|
||
### Params | ||
|
||
| Property | Description | Type | Default | | ||
|---------|----------------------------------------------|------------------------|--------| | ||
| onClickAway | Trigger Function | (event) => void | - | | ||
| dom | optional, if none is passed, this hook will subscibe to the dom that it returns | HTMLElement \| (() => HTMLElement) \| undefined | - | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks'; | ||
import useDebounce from '../index'; | ||
|
||
interface ParamsObj { | ||
value: any; | ||
wait: number; | ||
} | ||
|
||
/* 暂时关闭 act 警告 见:https://github.com/testing-library/react-testing-library/issues/281#issuecomment-480349256 */ | ||
const originalError = console.error; | ||
beforeAll(() => { | ||
console.error = (...args: any) => { | ||
if (/Warning.*not wrapped in act/.test(args[0])) { | ||
return; | ||
} | ||
originalError.call(console, ...args); | ||
}; | ||
}); | ||
afterAll(() => { | ||
console.error = originalError; | ||
}); | ||
|
||
let hook: RenderHookResult<ParamsObj, any>; | ||
|
||
describe('useDebounce', () => { | ||
beforeEach(() => { | ||
jest.useFakeTimers(); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.useRealTimers(); | ||
}); | ||
it('should be defined', () => { | ||
expect(useDebounce).toBeDefined(); | ||
}); | ||
|
||
it('useDebounce should work', () => { | ||
let mountedState = 1; | ||
act(() => { | ||
hook = renderHook(() => useDebounce(mountedState, 500)); | ||
}); | ||
act(() => { | ||
expect(hook.result.current).toEqual(1); | ||
mountedState = 2; | ||
hook.rerender(); | ||
mountedState = 3; | ||
hook.rerender(); | ||
jest.runAllTimers(); | ||
expect(hook.result.current).toEqual(3); | ||
mountedState = 4; | ||
hook.rerender(); | ||
expect(hook.result.current).toEqual(3); | ||
jest.runAllTimers(); | ||
expect(hook.result.current).toEqual(4); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.