選択したノードをマウスで削除できるコントロールの追加
Rich text editor「Lexxy」に、添付ファイルや水平線などの特定ノードをマウス操作で削除できるコントロールが追加されました。ノード選択時にデリートボタンが表示され、キーボードだけでなくマウスでも直感的な削除操作が可能になります。
背景
これまでLexxyでは、添付ファイルや水平線といった装飾ノードを削除するにはキーボードの Delete / Backspace キーを使う必要がありました。#755 は、これらのノードをマウスクリックだけで削除できる機能を追加しています。
UIコンポーネントとしての整合性を保つため、既存のcode language pickerやtable toolsと同じ lexxy-floating-controls クラスを用いたフローティングコントロールとして実装されました。
技術的な変更
新しいカスタム要素 <lexxy-node-delete-button> が導入され、削除可能な各ノードのDOM構造に組み込まれます。
ノードへのデリートボタンの組み込み
ActionTextAttachmentNode、CustomActionTextAttachmentNode、HorizontalDividerNode の3つのノードクラスで、DOM生成時にデリートボタンが追加されるようになりました。
変更例(ActionTextAttachmentNode):
createAttachmentFigure() {
const figure = createAttachmentFigure(this.contentType, this.isPreviewableAttachment, this.fileName)
const deleteButton = createElement("lexxy-node-delete-button")
figure.appendChild(deleteButton)
return figure
}
各ノードの figure 要素に <lexxy-node-delete-button> が追加され、ノード選択時に削除UIが表示される構造になっています。
NodeDeleteButtonの実装
src/elements/node_delete_button.js として新規追加されたこのカスタム要素は、ゴミ箱アイコンのボタンを提供し、クリック時に該当ノードをLexicalエディタから削除します。
#deleteNode() {
this.editor.update(() => {
const node = $getNearestNodeFromDOMNode(this)
node?.remove()
})
}
Lexicalの $getNearestNodeFromDOMNode を使って、DOMノードから対応するLexicalノードを取得し、remove() で削除を実行しています。この設計により、各ノードクラスに削除ロジックを個別実装する必要がなくなりました。
フローティングコントロールの統一
既存のcode language pickerやtable toolsと同様に、lexxy-floating-controls クラスが適用されます。
connectedCallback() {
this.editorElement = this.closest("lexxy-editor")
this.editor = this.editorElement.editor
this.classList.add("lexxy-floating-controls")
// ...
}
この共通クラスにより、コントロールの表示スタイル、ボタンサイズ(--button-size: 2.3lh)、ボーダーラジアス(--table-tools-radius)などのCSS変数が統一的に適用されます。
スタイリングの調整
app/assets/stylesheets/lexxy-content.css では、削除ボタンの配置のため figure 要素に position: relative が追加され、添付ファイルプレビューの最小高さ設定(min-block-size: 3em)により小さなアイコンでもクリック領域が確保されました。
figure,
.attachment {
margin-block: 0 var(--lexxy-content-margin);
position: relative;
// ...
}
object {
inline-size: auto;
margin-inline: auto;
min-block-size: 3em;
max-block-size: 32rem;
// ...
}
設計判断
Custom Elementベースのモジュラー設計 が採用されました。
Lexicalエディタのプラグイン機構ではなく、Web Components(Custom Elements)としてUIコントロールを実装する方針が維持されています。これにより、<lexxy-node-delete-button> は単なるDOMノードとして各ノード型に追加でき、Lexicalの内部状態管理から独立した実装が可能です。
disconnectedCallback() での明示的なクリーンアップ処理(イベントリスナーの削除、参照の解放)も追加されており、メモリリークを防ぐ配慮がなされています。既存のcode language pickerにも同様のクリーンアップが追加されました。
また、削除ボタンの tabIndex = -1 設定により、キーボードナビゲーションからは除外しつつマウス操作は可能にする設計になっています。これは、キーボードユーザーには既存の Delete / Backspace キーによる削除手段があるためです。
まとめ
本PRは、Lexxyに初めてマウスベースのノード削除機能を導入した変更です。Custom Elementを活用したモジュラー設計により、各ノード型への影響を最小限に抑えつつ、既存のフローティングコントロール群と統一されたUIを提供しています。キーボード操作を補完するマウス操作の追加により、より幅広いユーザーに対応したエディタUIとなりました。