1 | import {DOMAttributes} from '@react-types/shared';
|
2 | import {isFocusVisible, useFocus, useFocusVisibleListener, useFocusWithin} from '@react-aria/interactions';
|
3 | import {useCallback, useState} from 'react';
|
4 | import {useRef} from 'react';
|
5 |
|
6 | export interface AriaFocusRingProps {
|
7 | |
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | within?: boolean,
|
14 |
|
15 |
|
16 | isTextInput?: boolean,
|
17 |
|
18 |
|
19 | autoFocus?: boolean
|
20 | }
|
21 |
|
22 | export interface FocusRingAria {
|
23 |
|
24 | isFocused: boolean,
|
25 |
|
26 |
|
27 | isFocusVisible: boolean,
|
28 |
|
29 |
|
30 | focusProps: DOMAttributes
|
31 | }
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | export function useFocusRing(props: AriaFocusRingProps = {}): FocusRingAria {
|
39 | let {
|
40 | autoFocus = false,
|
41 | isTextInput,
|
42 | within
|
43 | } = props;
|
44 | let state = useRef({
|
45 | isFocused: false,
|
46 | isFocusVisible: autoFocus || isFocusVisible()
|
47 | });
|
48 | let [isFocused, setFocused] = useState(false);
|
49 | let [isFocusVisibleState, setFocusVisible] = useState(() => state.current.isFocused && state.current.isFocusVisible);
|
50 |
|
51 | let updateState = useCallback(() => setFocusVisible(state.current.isFocused && state.current.isFocusVisible), []);
|
52 |
|
53 | let onFocusChange = useCallback(isFocused => {
|
54 | state.current.isFocused = isFocused;
|
55 | setFocused(isFocused);
|
56 | updateState();
|
57 | }, [updateState]);
|
58 |
|
59 | useFocusVisibleListener((isFocusVisible) => {
|
60 | state.current.isFocusVisible = isFocusVisible;
|
61 | updateState();
|
62 | }, [], {isTextInput});
|
63 |
|
64 | let {focusProps} = useFocus({
|
65 | isDisabled: within,
|
66 | onFocusChange
|
67 | });
|
68 |
|
69 | let {focusWithinProps} = useFocusWithin({
|
70 | isDisabled: !within,
|
71 | onFocusWithinChange: onFocusChange
|
72 | });
|
73 |
|
74 | return {
|
75 | isFocused,
|
76 | isFocusVisible: state.current.isFocused && isFocusVisibleState,
|
77 | focusProps: within ? focusWithinProps : focusProps
|
78 | };
|
79 | }
|