I'm new to lexical.js and don't fully understand how I can listen to different keystroke combinations. I want to listen to "Ctrl/Cmd+S" and then fire off a callback (to save data). How can I do that?
With a textarea I can do something like:
const onKeyDown = (event) => {
// "Ctrl" or "Cmd" + "s"
if ((event.ctrlKey || event.metaKey) && event.which === 83) {
// save data
}
}
<textarea onKeyDown={onKeyDown} />
With lexical I've tried to do something like:
const MY_SAVE_COMMAND: LexicalCommand<string> = createCommand('MY_SAVE_COMMAND')
editor.registerCommand<KeyboardEvent>(
MY_SAVE_COMMAND,
(event) => {
console.log('[MY_SAVE_COMMAND] event', event)
return true
},
COMMAND_PRIORITY_HIGH,
)
which does not work. Where do I insert the part where I listen to the keystrokes, or is there a different way of doing this altogether?
Custom commands are more like global event types. Lexical provides a lot out of the box you can listen to, but for things like regular event listeners, what you probably want is to attach the event to the rootElement via editor.registerRootListener
.
You can use a custom plugin to manage attaching and removing this event listener. In the example below, I don't implement onKeyDown
, but you would just like any other normal event handler.
import {useLayoutEffect} from 'react';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
function CommandSPlugin() {
const [editor] = useLexicalComposerContext();
useLayoutEffect(() => {
const onKeyDown = () => { /* Your handler logic here */ };
return editor.registerRootListener(
(
rootElement: null | HTMLElement,
prevRootElement: null | HTMLElement,
) => {
if (prevRootElement !== null) {
prevRootElement.removeEventListener('keydown', onKeyDown);
}
if (rootElement !== null) {
rootElement.addEventListener('keydown', onKeyDown);
}
}
);
}, [editor]);
}
// Then later...
const initialConfig = { /* ... */ };
function App() {
return (
<LexicalComposer initialConfig={initialConfig}>
<CommandSPlugin />
<YourEditorHere />
</LexicalComposer>
);
}