29 lines
1.1 KiB
TypeScript
29 lines
1.1 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|||
|
|
import { isKeyHotkey } from 'is-hotkey';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Enter picks the top suggestion while an autocomplete list is showing, as in
|
||
|
|
* Discord / Slack / Element, instead of sending the half-typed text ("hey @bo").
|
||
|
|
*
|
||
|
|
* The listener runs in the window's capture phase so it sees Enter before the
|
||
|
|
* composer's own handler (which would submit), and only claims the key when
|
||
|
|
* `active` (the list has suggestions) — otherwise Enter sends as normal. IME
|
||
|
|
* composition and modified Enter (Shift/Ctrl/Alt/Meta) are left alone.
|
||
|
|
*/
|
||
|
|
export function useAutocompleteEnter(active: boolean, onSelect: () => void): void {
|
||
|
|
const selectRef = useRef(onSelect);
|
||
|
|
selectRef.current = onSelect;
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (!active) return undefined;
|
||
|
|
const onKeyDown = (evt: KeyboardEvent) => {
|
||
|
|
if (evt.isComposing || !isKeyHotkey('enter', evt)) return;
|
||
|
|
evt.preventDefault();
|
||
|
|
evt.stopPropagation();
|
||
|
|
selectRef.current();
|
||
|
|
};
|
||
|
|
window.addEventListener('keydown', onKeyDown, true);
|
||
|
|
return () => window.removeEventListener('keydown', onKeyDown, true);
|
||
|
|
}, [active]);
|
||
|
|
}
|