Lexical: support hotkeys in autosuggest plugin

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2023-05-20 00:18:54 +02:00
parent 4557fb98b6
commit 0255b85e18

View file

@ -14,7 +14,11 @@ import {
$isRangeSelection, $isRangeSelection,
$isTextNode, $isTextNode,
COMMAND_PRIORITY_LOW, COMMAND_PRIORITY_LOW,
KEY_ARROW_DOWN_COMMAND,
KEY_ARROW_UP_COMMAND,
KEY_ENTER_COMMAND,
KEY_ESCAPE_COMMAND, KEY_ESCAPE_COMMAND,
KEY_TAB_COMMAND,
LexicalEditor, LexicalEditor,
RangeSelection, RangeSelection,
} from 'lexical'; } from 'lexical';
@ -288,19 +292,24 @@ const AutosuggestPlugin = ({
const [editor] = useLexicalComposerContext(); const [editor] = useLexicalComposerContext();
const [resolution, setResolution] = useState<Resolution | null>(null); const [resolution, setResolution] = useState<Resolution | null>(null);
const [selectedSuggestion] = useState(0); const [selectedSuggestion, setSelectedSuggestion] = useState(0);
const anchorElementRef = useMenuAnchorRef( const anchorElementRef = useMenuAnchorRef(
resolution, resolution,
setResolution, setResolution,
); );
const onSelectSuggestion: React.MouseEventHandler<HTMLDivElement> = (e) => { const handleSelectSuggestion: React.MouseEventHandler<HTMLDivElement> = (e) => {
e.preventDefault(); e.preventDefault();
const suggestion = suggestions.get(e.currentTarget.getAttribute('data-index') as any) as AutoSuggestion; const index = e.currentTarget.getAttribute('data-index');
return onSelectSuggestion(index);
};
const onSelectSuggestion = (index: any) => {
const suggestion = suggestions.get(index) as AutoSuggestion;
editor.update(() => { editor.update(() => {
dispatch((dispatch, getState) => { dispatch((dispatch, getState) => {
const state = editor.getEditorState(); const state = editor.getEditorState();
const node = (state._selection as RangeSelection)?.anchor?.getNode(); const node = (state._selection as RangeSelection)?.anchor?.getNode();
@ -385,7 +394,7 @@ const AutosuggestPlugin = ({
'px-4 py-2.5 text-sm text-gray-700 dark:text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gray-100 dark:focus:bg-primary-800 group': true, 'px-4 py-2.5 text-sm text-gray-700 dark:text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 focus:bg-gray-100 dark:focus:bg-primary-800 group': true,
'bg-gray-100 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-800': i === selectedSuggestion, 'bg-gray-100 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-800': i === selectedSuggestion,
})} })}
onMouseDown={onSelectSuggestion} onMouseDown={handleSelectSuggestion}
> >
{inner} {inner}
</div> </div>
@ -466,6 +475,62 @@ const AutosuggestPlugin = ({
}, [resolution, suggestionsHidden, suggestions.isEmpty()]); }, [resolution, suggestionsHidden, suggestions.isEmpty()]);
useEffect(() => mergeRegister( useEffect(() => mergeRegister(
editor.registerCommand<KeyboardEvent>(
KEY_ARROW_UP_COMMAND,
(payload) => {
const event = payload;
if (suggestions !== null && suggestions.size && selectedSuggestion !== null) {
const newSelectedSuggestion = selectedSuggestion !== 0 ? selectedSuggestion - 1 : suggestions.size - 1;
setSelectedSuggestion(newSelectedSuggestion);
event.preventDefault();
event.stopImmediatePropagation();
}
return true;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand<KeyboardEvent>(
KEY_ARROW_DOWN_COMMAND,
(payload) => {
const event = payload;
if (suggestions !== null && suggestions.size && selectedSuggestion !== null) {
const newSelectedSuggestion = selectedSuggestion !== suggestions.size - 1 ? selectedSuggestion + 1 : 0;
setSelectedSuggestion(newSelectedSuggestion);
event.preventDefault();
event.stopImmediatePropagation();
}
return true;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand<KeyboardEvent>(
KEY_TAB_COMMAND,
(payload) => {
const event = payload;
if (suggestions !== null && suggestions.size && selectedSuggestion !== null) {
const newSelectedSuggestion = event.shiftKey
? (selectedSuggestion !== 0 ? selectedSuggestion - 1 : suggestions.size - 1)
: (selectedSuggestion !== suggestions.size - 1 ? selectedSuggestion + 1 : 0);
setSelectedSuggestion(newSelectedSuggestion);
event.preventDefault();
event.stopImmediatePropagation();
}
return true;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand<KeyboardEvent>(
KEY_ENTER_COMMAND,
(payload) => {
const event = payload;
event.preventDefault();
event.stopImmediatePropagation();
onSelectSuggestion(selectedSuggestion);
setResolution(null);
return true;
},
COMMAND_PRIORITY_LOW,
),
editor.registerCommand<KeyboardEvent>( editor.registerCommand<KeyboardEvent>(
KEY_ESCAPE_COMMAND, KEY_ESCAPE_COMMAND,
(payload) => { (payload) => {
@ -477,7 +542,7 @@ const AutosuggestPlugin = ({
}, },
COMMAND_PRIORITY_LOW, COMMAND_PRIORITY_LOW,
), ),
), [editor]); ), [editor, selectedSuggestion]);
return resolution === null || editor === null ? null : ( return resolution === null || editor === null ? null : (
<LexicalPopoverMenu <LexicalPopoverMenu