Closed10
lexicalでenterで改行するときの挙動を調整する
lexicalで開発を試している
そこで改行のときのデフォルト挙動が気になった
どこの文化かわからないけど、自分にとっては文字がないリストで改行をしたらリストでなくなるという挙動がしっくりくるのだが、lexicalのデフォルトの挙動ではそうならなかった
Enterを押したときの挙動を制御するプラグインを作る方向で考える
registerCommandでキーボードのイベントをハンドルできるっぽい
useEffect(() => {
editor.registerCommand(
KEY_ENTER_COMMAND,
(payload) => {
if (!payload) return true;
const event: KeyboardEvent = payload;
event.preventDefault();
// 何かをする
},
COMMAND_PRIORITY_EDITOR
);
}, [editor]);
event.preventDefault()
ができるのありがたい
確かに、改行も何も動かなくなる
対象のノードを取得
lexical全然情報がないけど、各所の限られた情報を見ながらAPIの使い方を邪推する
const selection = $getSelection();
if (!selection) return false;
if (!$isRangeSelection(selection)) return false;
const anchorNode = selection.anchor.getNode();
挙動をすべて自分でハンドルしようかと思ったけど、気になるところ以外はevent.preventDefault()
しないでおまかせする方針にした
とりあえずリストにしか興味がないので、それ以外は早期リターン
if (!$isListItemNode(anchorNode)) return false;
選択中のリストアイテムに文字がないときにはリストではなくただのパラグラフを追加する仕様にした
if (anchorNode.getTextContentSize() === 0) {
event.preventDefault();
editor.update(() => {
selection.insertNodes([$createParagraphNode()]);
});
}
APIの使い方が適切なのかはわからないけどとりあえず意図通りに動くので良し
やっぱり、リストの途中ではリストを終わらせてほしくないのでリストの中で最後のアイテムであるという条件も足す
if (anchorNode.getTextContentSize() === 0 && anchorNode.isLastChild()) {
event.preventDefault();
editor.update(() => {
selection.insertNodes([$createParagraphNode()]);
});
}
リファクタリングするなどして最終的にプラグインはこんな感じになった
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
import {
$getSelection,
$isRangeSelection,
COMMAND_PRIORITY_EDITOR,
KEY_ENTER_COMMAND,
$createParagraphNode,
RangeSelection,
} from "lexical";
import { FC, useEffect } from "react";
import { $isListItemNode } from "@lexical/list";
// 条件をチェックする関数を定義
const shouldPreventDefaultEnter = (selection: RangeSelection) => {
const anchorNode = selection.anchor.getNode();
if (!$isListItemNode(anchorNode)) return false;
// リストアイテムノードで、テキストが0以上で最後の子ではない場合にtrueを返す
return anchorNode.getTextContentSize() === 0 && anchorNode.isLastChild();
};
export const EnterPlugin: FC = () => {
const [editor] = useLexicalComposerContext();
useEffect(() => {
editor.registerCommand(
KEY_ENTER_COMMAND,
(payload) => {
if (!payload) return true;
const event: KeyboardEvent = payload;
const selection = $getSelection();
if (!selection) return false;
if (!$isRangeSelection(selection)) return false;
if (shouldPreventDefaultEnter(selection)) {
event.preventDefault();
editor.update(() => {
selection.insertNodes([$createParagraphNode()]);
});
}
return true;
},
COMMAND_PRIORITY_EDITOR
);
}, [editor]);
return null;
};
lexical何もわからないという気持ちだったけど、少しは自分の思ったとおりにいじれたので少しずつカスタマイズの仕方がつかめてきたかもしれない
挙動としてはこんな感じになりました
このスクラップは2024/03/01にクローズされました