javascript - Hur kan jag lyssna på en tangentkombination med lexical.js?
Jag är ny på lexical.js och förstår inte fullt ut hur jag kan lyssna på olika tangenttryckningskombinationer. Jag vill lyssna på "Ctrl/Cmd+S" och sedan köra en callback (för att spara data). Hur kan jag göra det?
Med ett textområde kan jag göra något som:
const onKeyDown = (event) => {
// "Ctrl" or "Cmd" + "s"
if ((event.ctrlKey || event.metaKey) && event.which === 83) {
// save data
}
}
<textarea onKeyDown={onKeyDown} />
Med lexikal har jag försökt göra något som:
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,
)
vilket inte fungerar. Var infogar jag delen där jag lyssnar på tangenttryckningarna, eller finns det ett annat sätt att göra detta på?
Svar #1
Anpassade kommandon är mer som globala händelsetyper. Lexical tillhandahåller mycket direkt som du kan lyssna på, men för saker som vanliga händelselyssnare, är det du förmodligen vill göra att fästa händelsen till rootElement via editor.registerRootListener.
Du kan använda ett anpassat plugin för att hantera att fästa och ta bort denna händelselyssnare. I exemplet nedan implementerar jag inte onKeyDown, men du skulle göra det precis som med vilken annan vanlig händelsehanterare som helst.
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>
);
}
Svar #2
Tack för svaren, de hjälpte mig mycket. Nedan är den fullständiga lösningen som jag slutade med att använda. Jag skapade en <GlobalEventsPlugin /> med ett SAVE_COMMAND-kommando som sedan kan användas av vilken plugin som helst:
// GlobalEventsPlugin.tsx
import { useLayoutEffect } from 'react'
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
import { LexicalCommand, createCommand } from 'lexical'
export const SAVE_COMMAND: LexicalCommand<KeyboardEvent> = createCommand('SAVE_COMMAND')
const GlobalEventsPlugin = () => {
const [editor] = useLexicalComposerContext()
useLayoutEffect(() => {
const onKeyDown = (event: KeyboardEvent) => {
// "Ctrl" or "Cmd" + "s"
if ((event.ctrlKey || event.metaKey) && event.which === 83) {
editor.dispatchCommand(SAVE_COMMAND, event)
}
}
return editor.registerRootListener((rootElement: HTMLElement | null, prevRootElement: HTMLElement | null) => {
if (prevRootElement !== null) {
prevRootElement.removeEventListener('keydown', onKeyDown)
}
if (rootElement !== null) {
rootElement.addEventListener('keydown', onKeyDown)
}
})
}, [editor])
return null
}
export default GlobalEventsPlugin
// Editor.tsx
const initialConfig = { /* ... */ }
function App() {
return (
<LexicalComposer initialConfig={initialConfig}>
<GlobalEventsPlugin />
<YourEditorHere />
</LexicalComposer>
)
}
// Any other context that has access to `editor`
editor.registerCommand(
SAVE_COMMAND,
(event) => {
// Do something with `event`, e.g. `event.preventDefault() && saveData()`
},
COMMAND_PRIORITY_HIGH,
)
