https://github.com/basecamp/lexxy
ブロッククォートへのペースト時にテキストが引用外に脱出するバグ(#4979)に対するPlaywrightリグレッションテスト3件が追加されました。バグ自体はツールバーリワーク(PR #891)のリファクタリングで偶発的に修正済みでしたが、同時にオリジナルの修正(PR #839)のテストも削除されており、本PRはそのテストの空白を補完するものです。
ソフトブレーク(Shift+Enter)とハードブレーク(Enter)が混在するテキストで、選択範囲の一部にのみ引用フォーマットを適用すると選択外の行まで巻き込まれるバグを修正。`selection.getNodes()` が部分選択された段落の全子ノードを返すLexicalの仕様に起因しており、選択範囲の判定を `getNodes()` からアンカー・フォーカス位置のチェックに切り替えることで解決しています。
Firefox / Gecko 系ブラウザでカット&ペーストを行うとコンテンツが二重挿入されるバグを修正。リッチテキストのペースト処理パスで `event.preventDefault()` が呼ばれておらず、Firefox のネイティブペースト処理と Lexical のカスタムハンドラが二重に DOM を変更していたことが原因。ハンドラが処理を行った場合のみ `preventDefault` を呼ぶよう修正し、Lexical 本体のハンドラと一貫した設計に揃えた。
混在するインラインフォーマット(太字・斜体など)を含む選択範囲にコードフォーマットを適用すると、フォーマットごとに `<code>` 要素が分割されてしまうバグを修正しました。コード適用前に選択範囲のインラインフォーマットを除去する前処理を追加することで、Lexicalのノードマージを有効化して単一の `<code>` 要素を生成します。部分選択時は `splitText()` で境界ノードを分割し、選択外テキストのフォーマットを保持します。
Lexicalエディタで空のリストアイテムをBackspaceで削除した際、Lexicalのデフォルト動作(collapseAtStart)がアイテムを段落へ変換しカーソルをドキュメント上部へジャンプさせる問題を修正。`#removeEmptyListItem` メソッドで兄弟アイテムが存在する場合のみインターセプトし、リスト最終アイテムでの「リスト終了」動作は意図的にデフォルトへ委ねる設計になっています。
DOM の `getAttribute` が返す文字列 `"false"` が truthy と評価されてしまう問題を `parseBoolean` ヘルパーで正規化し、`previewable="false"` の添付ファイルが壊れた画像として表示されるバグを修正しました。また、パスワード保護されたPDFなどプレビュー生成が失敗するケースでは `onerror` フォールバックでDOMをファイル表示に切り替え、ノードの `previewable` プロパティはサーバー向けシリアライズのために変更しない設計を採用しています。
Lexxyのツールバーが大幅に再設計され、単一の見出しサイクルコマンドをh2/h3/h4/段落の4つの明示的コマンドへ置き換えた。Lexicalの組み込み`$setBlocksType` APIを活用してカスタムのノード操作ロジック約374行を削除し、アップロードボタンの分割や`toolbar.upload`設定の追加、アンダーライン対応など複数の改善を同時に達成している。
`<code>` 要素内のテキストをすべて削除するとLexicalの選択状態にコードフォーマットフラグが残存し、以降の入力が誤って `<code>` タグで包まれるバグを修正しました。フォーマットフラグが実際のコード書式付きコンテンツに裏付けられているかを検証する `#isInCode()` メソッドを追加し、staleなフォーマットを検出・除去するアップデートリスナーとの2段構えで対処しています。
投稿済みコメントからコピーしたメンションをLexxyエディタに貼り付けると文字化けが発生していた問題を修正。原因はexportDOM()でのJSON.stringify()使用によるHTMLエンティティとJSONエスケープの衝突であり、Trix/ActionText形式に合わせてcontent属性を生HTMLで格納するよう変更。parseAttachmentContent()が既にJSON/生HTMLの両フォールバックに対応していたため、過去データとの後方互換性を維持しながら修正が実現された。
空のエディタに画像をアップロードした後、キャレットの表示位置と実際の入力位置がずれる問題を修正しました。アップロード完了後の選択管理を `$createNodeSelectionWith` + `$setSelection` から `selectNext()` の呼び出しに変更し、カーソルを添付ファイル直後の仮段落へ移動させます。あわせて `ProvisionalParagraphNode.isSelected()` を拡張し、element型アンカーによるカーソル位置でも仮段落が選択中と判定されるようにすることで、キャレットの正しい視覚的レンダリングを実現しています。
テーブルをコピー&ペーストする際にクリップボードHTMLへ混入するテーマ固有のインラインカラースタイルを、Lexicalがノードを生成する前のDOMレイヤーで除去するようになりました。`PASTE_TAG` を使ってペースト操作のみに処理を限定し、`<td>` と `<th>` から `background-color`、`background`、`color` の3プロパティを削除することで、ペースト後のテーブルが常に閲覧者のテーマカラーを継承します。
Lexicalのコード再トークナイザが`<mark>`ハイライトスタイルを破壊するバグを修正。HTMLインポート時にハイライト範囲を`WeakMap`に退避し、再トークナイズ完了後にミューテーションリスナーで再適用する2フェーズ設計を採用。`Object.assign`によるコンバータ衝突・再トークナイザとのスタイル競合・`splitText()`の型問題という3つのLexical内部制約を回避し、保存・再編集サイクルでコードブロックのハイライトが失われなくなった。
`FormatEscaper`クラス(388行)を廃止し、`FormatEscapeExtension`と`EarlyEscapeCodeNode`・`EarlyEscapeListItemNode`の2ノードに再設計。エスケープロジックをノードの`insertNewAfter`メソッドへ委譲することでLexicalのアーキテクチャと整合させ、`INSERT_PARAGRAPH_COMMAND`への切り替えにより`RangeSelection`の保証も得ています。
Turbo Driveの非同期ナビゲーションと`lexxy-editor`カスタム要素の初期化タイミングの競合により、CIで断続的にタイムアウトしていたシステムテストを修正。`click_on "Update Post"`後に編集ページへ戻ってからアサーションするよう変更し、`wait_for_editor`をナビゲーション直後に統一配置することで競合を解消した。
`#` トリガーの遅延ソース読み込み中にスペースを押すとエディタが操作不能になるレースコンディションを修正。`#showPopover()` の各 `await` 後に世代カウンタ(`showPopoverId`)を比較するアボートガードを挿入し、`#hidePopover()` が呼ばれた後は後続の処理(キーリスナー登録など)を実行しないようにしています。
メンション挿入時に付与していたワードジョイナー文字(U+2060)を削除し、通常スペースと条件付きロジックに置き換えました。不可視文字への依存を断ち切ることで、カーソル操作や編集時の意図しない動作を解消し、`isAttachmentSpacerTextNode` ヘルパーで各処理レイヤーでの一貫したスペース管理を実現しています。
リストアイテム内のインラインメンション直後でBackspaceを押すと、メンションが選択される代わりにリストがアウトデントされるバグが修正されました。`#collapseListItemToParagraph`メソッドにデコレータノードへの参照を引数として渡し、`listItem.isParentOf(decoratorNode)`でノードの位置を確認することで、インラインメンションとブロック添付ファイルの2つのケースを正しく区別できるようになりました。
Up/Downキーで段落から画像へ移動する際、カーソルが単語の途中にある場合に画像がスキップされるバグを修正。テキストオフセットのみによる判定から、DOM ジオメトリ(Y座標比較)を用いたビジュアル行検出へと移行することで、カーソル位置によらず一貫した画像選択を実現しました。
LexxyエディタにHTML5ドラッグイベントを使った添付ファイルの再配置機能が追加されました。カスタムMIMEタイプ `application/x-lexxy-node-key` で内部ドラッグと外部ファイルドロップを区別し、ギャラリーへのマージ・リスト分割・ブロック間移動の3シナリオをアンドゥ/リドゥ対応で実現しています。
`data-prevent-overflow="true"` 属性を持つボタンをオーバーフローメニューへの移動対象から除外する仕組みが追加されました。`#buttons` ゲッターのCSSセレクタに `:not([data-prevent-overflow='true'])` を追加するだけの最小変更で実現しており、添付ファイルボタンがモバイルでも常にツールバーに表示されるようになります。