Skip to content

Commit 6a54ab5

Browse files
committed
frontend: refactor use-capslock into a hook
1 parent 34cf15c commit 6a54ab5

File tree

2 files changed

+30
-42
lines changed

2 files changed

+30
-42
lines changed

frontends/web/src/components/password.tsx

Lines changed: 4 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,11 @@
1717

1818
import { useEffect, useRef, useState, ChangeEvent, ClipboardEvent } from 'react';
1919
import { useTranslation } from 'react-i18next';
20+
import { useCapsLock } from '@/hooks/keyboard';
2021
import { Input, Checkbox, Field } from './forms';
2122
import { alertUser } from './alert/Alert';
2223
import style from './password.module.css';
2324

24-
const excludeKeys = /^(Shift|Alt|Backspace|CapsLock|Tab)$/i;
25-
26-
const hasCaps = (event: KeyboardEvent) => {
27-
const key = event.key;
28-
// will return null, when we cannot clearly detect if capsLock is active or not
29-
if (key.length > 1 || key.toUpperCase() === key.toLowerCase() || excludeKeys.test(key)) {
30-
return null;
31-
}
32-
// ideally we return event.getModifierState('CapsLock')) but this currently does always return false in Qt
33-
return key.toUpperCase() === key && key.toLowerCase() !== key && !event.shiftKey;
34-
};
3525

3626
type TPropsPasswordInput = {
3727
seePlaintext?: boolean;
@@ -76,9 +66,10 @@ export const PasswordSingleInput = ({
7666
onValidPassword,
7767
}: TProps) => {
7868
const { t } = useTranslation();
69+
const capsLock = useCapsLock();
70+
7971
const [password, setPassword] = useState('');
8072
const [seePlaintext, setSeePlaintext] = useState(false);
81-
const [capsLock, setCapsLock] = useState(false);
8273

8374
const passwordRef = useRef<HTMLInputElement>(null);
8475
const regexRef = useRef<RegExp>();
@@ -93,20 +84,6 @@ export const PasswordSingleInput = ({
9384
}
9485
}, [pattern, autoFocus]);
9586

96-
// Listen to caps lock key events
97-
useEffect(() => {
98-
const handleCheckCaps = (event: KeyboardEvent) => {
99-
const result = hasCaps(event);
100-
if (result !== null) {
101-
setCapsLock(result);
102-
}
103-
};
104-
window.addEventListener('keydown', handleCheckCaps);
105-
return () => {
106-
window.removeEventListener('keydown', handleCheckCaps);
107-
};
108-
}, []);
109-
11087
const tryPaste = (event: ClipboardEvent<HTMLInputElement>) => {
11188
if (event.currentTarget.type === 'password') {
11289
event.preventDefault();
@@ -196,11 +173,11 @@ export const PasswordRepeatInput = ({
196173
onValidPassword,
197174
}: TPasswordRepeatProps) => {
198175
const { t } = useTranslation();
176+
const capsLock = useCapsLock();
199177

200178
const [password, setPassword] = useState('');
201179
const [passwordRepeat, setPasswordRepeat] = useState('');
202180
const [seePlaintext, setSeePlaintext] = useState(false);
203-
const [capsLock, setCapsLock] = useState(false);
204181

205182
const passwordRef = useRef<HTMLInputElement>(null);
206183
const passwordRepeatRef = useRef<HTMLInputElement>(null);
@@ -216,20 +193,6 @@ export const PasswordRepeatInput = ({
216193
}
217194
}, [pattern, autoFocus]);
218195

219-
// Listen to caps lock key events
220-
useEffect(() => {
221-
const handleCheckCaps = (event: KeyboardEvent) => {
222-
const result = hasCaps(event);
223-
if (result !== null) {
224-
setCapsLock(result);
225-
}
226-
};
227-
window.addEventListener('keydown', handleCheckCaps);
228-
return () => {
229-
window.removeEventListener('keydown', handleCheckCaps);
230-
};
231-
}, []);
232-
233196
const tryPaste = (event: ClipboardEvent<HTMLInputElement>) => {
234197
if (event.currentTarget.type === 'password') {
235198
event.preventDefault();

frontends/web/src/hooks/keyboard.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { useEffect, useRef } from 'react';
17+
import { useEffect, useRef, useState } from 'react';
1818

1919
/**
2020
* gets fired on each keydown and executes the provided callback.
@@ -54,6 +54,31 @@ export const useEsc = (
5454
});
5555
};
5656

57+
const excludeKeys = /^(Shift|Alt|Backspace|CapsLock|Tab)$/i;
58+
59+
const hasCaps = (event: KeyboardEvent) => {
60+
const key = event.key;
61+
// will return null, when we cannot clearly detect if capsLock is active or not
62+
if (key.length > 1 || key.toUpperCase() === key.toLowerCase() || excludeKeys.test(key)) {
63+
return null;
64+
}
65+
// ideally we return event.getModifierState('CapsLock')) but this currently does always return false in Qt
66+
return key.toUpperCase() === key && key.toLowerCase() !== key && !event.shiftKey;
67+
};
68+
69+
export const useCapsLock = () => {
70+
const [capsLock, setCapsLock] = useState(false);
71+
72+
useKeydown((event) => {
73+
const result = hasCaps(event);
74+
if (result !== null) {
75+
setCapsLock(result);
76+
}
77+
});
78+
79+
return capsLock;
80+
};
81+
5782
const FOCUSABLE_SELECTOR = `
5883
a:not(:disabled),
5984
button:not(:disabled),

0 commit comments

Comments
 (0)