forked from alibaba/hooks
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add useFocusWithin (alibaba#1403)
* feat: add useFocusWithin * chore: useFocusWithin change onChange params name
- Loading branch information
1 parent
98cd86b
commit 2a0cc59
Showing
7 changed files
with
230 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,6 +94,7 @@ export const menus = [ | |
'useResponsive', | ||
'useScroll', | ||
'useSize', | ||
'useFocusWithin', | ||
], | ||
}, | ||
{ | ||
|
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,43 @@ | ||
/** | ||
* title: Basic usage | ||
* desc: Use ref to set area that needs monitoring. The focus can be switched by click the outside with the mouse, or using keys such as `tab` on the keyboard. | ||
* | ||
* title.zh-CN: 基础用法 | ||
* desc.zh-CN: 使用 ref 设置需要监听的区域。可以通过鼠标点击外部区域,或者使用键盘的 `tab` 等按键来切换焦点。 | ||
*/ | ||
|
||
import React, { useRef } from 'react'; | ||
import { useFocusWithin } from 'ahooks'; | ||
import { message } from 'antd'; | ||
|
||
export default () => { | ||
const ref = useRef(); | ||
const isFocusWithin = useFocusWithin(ref, { | ||
onFocus: () => { | ||
message.info('focus'); | ||
}, | ||
onBlur: () => { | ||
message.info('blur'); | ||
}, | ||
}); | ||
return ( | ||
<div> | ||
<div | ||
ref={ref} | ||
style={{ | ||
padding: 16, | ||
backgroundColor: isFocusWithin ? 'red' : '', | ||
border: '1px solid gray', | ||
}} | ||
> | ||
<label style={{ display: 'block' }}> | ||
First Name: <input /> | ||
</label> | ||
<label style={{ display: 'block', marginTop: 16 }}> | ||
Last Name: <input /> | ||
</label> | ||
</div> | ||
<p>isFocusWithin: {JSON.stringify(isFocusWithin)}</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,35 @@ | ||
/** | ||
* title: Pass in DOM element | ||
* desc: Pass in a function that returns the DOM element. | ||
* | ||
* title.zh-CN: 传入 DOM 元素 | ||
* desc.zh-CN: 传入 function 并返回一个 dom 元素。 | ||
*/ | ||
|
||
import { useFocusWithin } from 'ahooks'; | ||
import React from 'react'; | ||
|
||
export default () => { | ||
const isFocusWithin = useFocusWithin(() => document.getElementById('focus-area')); | ||
|
||
return ( | ||
<div> | ||
<div | ||
id="focus-area" | ||
style={{ | ||
padding: 16, | ||
backgroundColor: isFocusWithin ? 'red' : '', | ||
border: '1px solid gray', | ||
}} | ||
> | ||
<label style={{ display: 'block' }}> | ||
First Name: <input /> | ||
</label> | ||
<label style={{ display: 'block', marginTop: 16 }}> | ||
Last Name: <input /> | ||
</label> | ||
</div> | ||
<p>isFocusWithin: {JSON.stringify(isFocusWithin)}</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,52 @@ | ||
--- | ||
nav: | ||
path: /hooks | ||
--- | ||
|
||
# useFocusWithin | ||
|
||
Monitor whether the current focus is within a certain area, Same as css attribute [:focus-within](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within). | ||
|
||
## Examples | ||
|
||
### Default usage | ||
|
||
<code src="./demo/demo1.tsx" /> | ||
|
||
### Pass in DOM element | ||
|
||
<code src="./demo/demo2.tsx" /> | ||
|
||
## API | ||
|
||
```typescript | ||
const isFocusWithin = useFocusWithin( | ||
target, | ||
{ | ||
onFocus, | ||
onBlur, | ||
onChange | ||
} | ||
); | ||
``` | ||
|
||
### Params | ||
|
||
| Property | Description | Type | Default | | ||
|----------|--------------------|-------------------------------------------------------------|---------| | ||
| target | DOM element or ref | `() => Element` \| `Element` \| `MutableRefObject<Element>` | - | | ||
| options | More config | `Options` | - | | ||
|
||
### Options | ||
|
||
| Property | Description | Type | Default | | ||
|----------|-----------------------------------------|------------------------------|---------| | ||
| onFocus | Callback to be executed on focus | `(e: FocusEvent) => void` | - | | ||
| onBlur | Callback to be executed on blur | `(e: FocusEvent) => void` | - | | ||
| onChange | Callback to be executed on focus change | `(isFocusWithin: boolean) => void` | - | | ||
|
||
### Result | ||
|
||
| Property | Description | Type | | ||
|---------------|------------------------------------------|-----------| | ||
| isFocusWithin | Whether the focus is in the current area | `boolean` | |
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,45 @@ | ||
import { useState } from 'react'; | ||
import useEventListener from '../useEventListener'; | ||
import type { BasicTarget } from '../utils/domTarget'; | ||
|
||
export interface Options { | ||
onFocus?: (e: FocusEvent) => void; | ||
onBlur?: (e: FocusEvent) => void; | ||
onChange?: (isFocusWithin: boolean) => void; | ||
} | ||
|
||
export default function useFocusWithin(target: BasicTarget, options?: Options) { | ||
const [isFocusWithin, setIsFocusWithin] = useState(false); | ||
const { onFocus, onBlur, onChange } = options || {}; | ||
|
||
useEventListener( | ||
'focusin', | ||
(e: FocusEvent) => { | ||
if (!isFocusWithin) { | ||
onFocus?.(e); | ||
onChange?.(true); | ||
setIsFocusWithin(true); | ||
} | ||
}, | ||
{ | ||
target, | ||
}, | ||
); | ||
|
||
useEventListener( | ||
'focusout', | ||
(e: FocusEvent) => { | ||
// @ts-ignore | ||
if (isFocusWithin && !e.currentTarget?.contains?.(e.relatedTarget)) { | ||
onBlur?.(e); | ||
onChange?.(false); | ||
setIsFocusWithin(false); | ||
} | ||
}, | ||
{ | ||
target, | ||
}, | ||
); | ||
|
||
return isFocusWithin; | ||
} |
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 @@ | ||
--- | ||
nav: | ||
path: /hooks | ||
--- | ||
|
||
# useFocusWithin | ||
|
||
监听当前焦点是否在某个区域之内,同 css 属性 [:focus-within](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within)。 | ||
|
||
## 代码演示 | ||
|
||
### 基础用法 | ||
|
||
<code src="./demo/demo1.tsx" /> | ||
|
||
### 传入 DOM 元素 | ||
|
||
<code src="./demo/demo2.tsx" /> | ||
|
||
## API | ||
|
||
```typescript | ||
const isFocusWithin = useFocusWithin( | ||
target, | ||
{ | ||
onFocus, | ||
onBlur, | ||
onChange | ||
} | ||
); | ||
``` | ||
|
||
### Params | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
|---------|-----------------------|-------------------------------------------------------------|--------| | ||
| target | DOM 节点或者 Ref 对象 | `() => Element` \| `Element` \| `MutableRefObject<Element>` | - | | ||
| options | 额外的配置项 | `Options` | - | | ||
|
||
### Options | ||
|
||
| 参数 | 说明 | 类型 | 默认值 | | ||
|----------|----------------|------------------------------|--------| | ||
| onFocus | 获取焦点时触发 | `(e: FocusEvent) => void` | - | | ||
| onBlur | 失去焦点时触发 | `(e: FocusEvent) => void` | - | | ||
| onChange | 焦点变化时触发 | `(isFocusWithin: boolean) => void` | - | | ||
|
||
### Result | ||
|
||
| 参数 | 说明 | 类型 | | ||
|---------------|--------------------|-----------| | ||
| isFocusWithin | 焦点是否在当前区域 | `boolean` | |