@@ -4,19 +4,40 @@ 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
13
+ type keyboardEventLike = {key : string , ctrlKey : bool , metaKey : bool }
14
+
15
+ @bs. val @bs. scope ("window" )
16
+ external addKeyboardEventListener : (string , keyboardEventLike => unit ) => unit = "addEventListener"
17
+
18
+ @bs. val @bs. scope ("window" )
19
+ external removeKeyboardEventListener : (string , keyboardEventLike => unit ) => unit =
20
+ "addEventListener"
21
+
22
+ @bs. send
23
+ external keyboardEventPreventDefault : keyboardEventLike => unit = "preventDefault"
24
+
10
25
type state =
11
26
| Active
12
27
| Inactive
13
28
29
+ @bs. get external isContentEditable : Dom .element => bool = "isContentEditable"
30
+ @bs. get external tagName : Dom .element => string = "tagName"
14
31
@bs. send external focus : Dom .element => unit = "focus"
15
32
@bs. send external blur : Dom .element => unit = "blur"
16
33
@bs. set external value : (Dom .element , string ) => unit = "value"
17
34
18
35
@react.component
19
36
let make = () => {
37
+ // Used for the text input
38
+ let inputRef = React .useRef (Js .Nullable .null )
39
+ let (state , setState ) = React .useState (_ => Inactive )
40
+
20
41
React .useEffect1 (() => {
21
42
switch docsearch {
22
43
| Some (init ) =>
@@ -27,12 +48,41 @@ let make = () => {
27
48
})
28
49
| None => ()
29
50
}
51
+
30
52
None
31
53
}, [])
32
54
33
- // Used for the text input
34
- let inputRef = React .useRef (Js .Nullable .null )
35
- let (state , setState ) = React .useState (_ => Inactive )
55
+ React .useEffect1 (() => {
56
+ let isEditableTag = el =>
57
+ switch el -> tagName {
58
+ | "TEXTAREA" | "SELECT" | "INPUT" => true
59
+ | _ => false
60
+ }
61
+
62
+ let focusSearch = e => {
63
+ switch activeElement {
64
+ | Some (el ) when el -> isEditableTag => ()
65
+ | Some (el ) when el -> isContentEditable => ()
66
+ | _ => {
67
+ setState (_ => Active )
68
+ inputRef .current -> Js .Nullable .toOption -> Belt .Option .forEach (focus )
69
+
70
+ e -> keyboardEventPreventDefault
71
+ }
72
+ }
73
+ }
74
+
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 ])
36
86
37
87
let focusInput = () =>
38
88
inputRef .current -> Js .Nullable .toOption -> Belt .Option .forEach (el => el -> focus )
0 commit comments