1 | /*
|
2 | * Copyright 2020 Adobe. All rights reserved.
|
3 | * This file is licensed to you under the Apache License, Version 2.0 (the "License");
|
4 | * you may not use this file except in compliance with the License. You may obtain a copy
|
5 | * of the License at http://www.apache.org/licenses/LICENSE-2.0
|
6 | *
|
7 | * Unless required by applicable law or agreed to in writing, software distributed under
|
8 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
|
9 | * OF ANY KIND, either express or implied. See the License for the specific language
|
10 | * governing permissions and limitations under the License.
|
11 | */
|
12 |
|
13 | // Portions of the code in this file are based on code from react.
|
14 | // Original licensing for the following can be found in the
|
15 | // NOTICE file in the root directory of this source tree.
|
16 | // See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions
|
17 |
|
18 | import {FocusEvent, HTMLAttributes} from 'react';
|
19 | import {FocusEvents} from '@react-types/shared';
|
20 | import {useSyntheticBlurEvent} from './utils';
|
21 |
|
22 | interface FocusProps extends FocusEvents {
|
23 | /** Whether the focus events should be disabled. */
|
24 | isDisabled?: boolean
|
25 | }
|
26 |
|
27 | interface FocusResult {
|
28 | /** Props to spread onto the target element. */
|
29 | focusProps: HTMLAttributes<HTMLElement>
|
30 | }
|
31 |
|
32 | /**
|
33 | * Handles focus events for the immediate target.
|
34 | * Focus events on child elements will be ignored.
|
35 | */
|
36 | export function useFocus(props: FocusProps): FocusResult {
|
37 | let onBlur: FocusProps['onBlur'];
|
38 | if (!props.isDisabled && (props.onBlur || props.onFocusChange)) {
|
39 | onBlur = (e: FocusEvent) => {
|
40 | if (e.target === e.currentTarget) {
|
41 | if (props.onBlur) {
|
42 | props.onBlur(e);
|
43 | }
|
44 |
|
45 | if (props.onFocusChange) {
|
46 | props.onFocusChange(false);
|
47 | }
|
48 |
|
49 | return true;
|
50 | }
|
51 | };
|
52 | } else {
|
53 | onBlur = null;
|
54 | }
|
55 |
|
56 | let onSyntheticFocus = useSyntheticBlurEvent(onBlur);
|
57 |
|
58 | let onFocus: FocusProps['onFocus'];
|
59 | if (!props.isDisabled && (props.onFocus || props.onFocusChange || props.onBlur)) {
|
60 | onFocus = (e: FocusEvent) => {
|
61 | if (e.target === e.currentTarget) {
|
62 | if (props.onFocus) {
|
63 | props.onFocus(e);
|
64 | }
|
65 |
|
66 | if (props.onFocusChange) {
|
67 | props.onFocusChange(true);
|
68 | }
|
69 |
|
70 | onSyntheticFocus(e);
|
71 | }
|
72 | };
|
73 | }
|
74 |
|
75 | return {
|
76 | focusProps: {
|
77 | onFocus,
|
78 | onBlur
|
79 | }
|
80 | };
|
81 | }
|