Skip to content

Commit

Permalink
Merge branch 'feature'
Browse files Browse the repository at this point in the history
  • Loading branch information
ttys026 committed Nov 22, 2019
2 parents e2cee93 + fe3c26a commit ff61317
Show file tree
Hide file tree
Showing 86 changed files with 2,955 additions and 68 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module.exports = {
"no-restricted-syntax": "off",
"no-plusplus": "off",
"no-underscore-dangle": "off",
"consistent-return": "off",
"@typescript-eslint/ban-ts-ignore": "off",
"@typescript-eslint/no-object-literal-type-assertion": "off",
}
Expand Down
20 changes: 20 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,21 @@ import useVirtualList from './useVirtualList';
import { configResponsive, useResponsive } from './useResponsive';
import useSize from './useSize';
import useLocalStorageState from './useLocalStorageState';
import useSessionStorageState from './useSessionStorageState';
import useUpdateEffect from './useUpdateEffect';
import useUpdateLayoutEffect from './useUpdateLayoutEffect';
import usePagination from './usePagination';
import useBoolean from './useBoolean';
import useToggle from './useToggle';
import useSelections from './useSelections';
import useThrottle from './useThrottle';
import useThrottleFn from './useThrottleFn';
import useDebounce from './useDebounce';
import useDebounceFn from './useDebounceFn';
import usePrevious from './usePrevious';
import useMouse from './useMouse';
import useScroll from './useScroll';
import useClickAway from './useClickAway';

const useControlledValue: typeof useControllableValue = function (...args) {
console.warn(
Expand All @@ -36,12 +46,22 @@ export {
useResponsive,
useEventEmitter,
useLocalStorageState,
useSessionStorageState,
useSize,
configResponsive,
configRequest,
useUpdateEffect,
useUpdateLayoutEffect,
usePagination,
useBoolean,
useToggle,
useSelections,
useThrottle,
useThrottleFn,
useDebounce,
useDebounceFn,
usePrevious,
useMouse,
useScroll,
useClickAway,
};
52 changes: 52 additions & 0 deletions src/useClickAway/__tests__/index.test.ts
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);
});
});
18 changes: 18 additions & 0 deletions src/useClickAway/demo/demo1.jsx
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>
);
};
20 changes: 20 additions & 0 deletions src/useClickAway/demo/demo1.tsx
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>
);
};
21 changes: 21 additions & 0 deletions src/useClickAway/demo/demo2.jsx
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>
);
};
23 changes: 23 additions & 0 deletions src/useClickAway/demo/demo2.tsx
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>
);
};
37 changes: 37 additions & 0 deletions src/useClickAway/index.ts
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>;
}
52 changes: 52 additions & 0 deletions src/useClickAway/index_cn.mdx
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 | - |
54 changes: 54 additions & 0 deletions src/useClickAway/index_en.mdx
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 | - |
57 changes: 57 additions & 0 deletions src/useDebounce/__tests__/index.test.ts
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);
});
});
});
Loading

0 comments on commit ff61317

Please sign in to comment.