@@ -4,10 +4,13 @@ type options = {
4
4
inputSelector : string ,
5
5
}
6
6
7
+ @bs. val @bs. scope ("document" )
8
+ external activeElement : option <Dom .element > = "activeElement"
9
+
7
10
@bs. val @bs. scope ("window" )
8
11
external docsearch : option <options => unit > = "docsearch"
9
12
10
- type keyboardEventLike = {key : string }
13
+ type keyboardEventLike = {key : string , ctrlKey : bool , metaKey : bool }
11
14
12
15
@bs. val @bs. scope ("window" )
13
16
external addKeyboardEventListener : (string , keyboardEventLike => unit ) => unit = "addEventListener"
@@ -16,10 +19,15 @@ external addKeyboardEventListener: (string, keyboardEventLike => unit) => unit =
16
19
external removeKeyboardEventListener : (string , keyboardEventLike => unit ) => unit =
17
20
"addEventListener"
18
21
22
+ @bs. send
23
+ external keyboardEventPreventDefault : keyboardEventLike => unit = "preventDefault"
24
+
19
25
type state =
20
26
| Active
21
27
| Inactive
22
28
29
+ @bs. get external isContentEditable : Dom .element => bool = "isContentEditable"
30
+ @bs. get external tagName : Dom .element => string = "tagName"
23
31
@bs. send external focus : Dom .element => unit = "focus"
24
32
@bs. send external blur : Dom .element => unit = "blur"
25
33
@bs. set external value : (Dom .element , string ) => unit = "value"
@@ -41,20 +49,40 @@ let make = () => {
41
49
| None => ()
42
50
}
43
51
44
- let handleKeyDown = e => {
45
- if e .key == "/" {
46
- setState (_ => Active )
52
+ None
53
+ }, [])
54
+
55
+ React .useEffect1 (() => {
56
+ let isEditableTag = el =>
57
+ switch el -> tagName {
58
+ | "TEXTAREA" | "SELECT" | "INPUT" => true
59
+ | _ => false
60
+ }
47
61
48
- Js .Global .setTimeout (() => {
49
- // execture focus in the next tick to avoid setting / inside input
62
+ let focusSearch = e => {
63
+ switch activeElement {
64
+ | Some (el ) when el -> isEditableTag => ()
65
+ | Some (el ) when el -> isContentEditable => ()
66
+ | _ => {
67
+ setState (_ => Active )
50
68
inputRef .current -> Js .Nullable .toOption -> Belt .Option .forEach (focus )
51
- }, 0 )-> ignore
69
+
70
+ e -> keyboardEventPreventDefault
71
+ }
52
72
}
53
73
}
54
74
55
- addKeyboardEventListener ("keydown" , handleKeyDown )
56
- Some (() => removeKeyboardEventListener ("keydown" , handleKeyDown ))
57
- }, [])
75
+ let handleGlobalKeyDown = e => {
76
+ switch e .key {
77
+ | "/" => focusSearch (e )
78
+ | "k" when e .ctrlKey || e .metaKey => focusSearch (e )
79
+ | _ => ()
80
+ }
81
+ }
82
+
83
+ addKeyboardEventListener ("keydown" , handleGlobalKeyDown )
84
+ Some (() => removeKeyboardEventListener ("keydown" , handleGlobalKeyDown ))
85
+ }, [setState ])
58
86
59
87
let focusInput = () =>
60
88
inputRef .current -> Js .Nullable .toOption -> Belt .Option .forEach (el => el -> focus )
0 commit comments