テーマ固有のカラースタイルをペースト時のテーブルセルから除去する
テーブルをコピー&ペーストする際、クリップボードのHTMLにはコピー元テーマ(ダークモード・ライトモード)のインラインカラースタイルが混入する問題がありました。このPRでは、Lexicalがペースト処理を行う前にDOMから該当スタイルを除去することで、ペースト後のテーブルが常に閲覧者のテーマカラーを継承するようになります。
背景
ダークモードのページからテーブルをコピーすると、各セルには background-color: rgb(26, 26, 46) のようなインラインスタイルがクリップボードのHTMLに含まれます。ペーストした本人はダークモード環境で閲覧しているため気づきにくいですが、ライトモードで同じドキュメントを開いた別の閲覧者には、暗い背景色が白いテキストの上に残ったまま表示されてしまいます。逆のケース(ライトモードからダークモードへのペースト)でも同様の問題が発生します。
この問題はブラウザがクリップボードHTMLを生成する仕様に起因しており、コピー元のDOM要素に付与されているインラインスタイルがそのまま text/html 形式でクリップボードに書き込まれます。LexicalはそのクリップボードのHTMLをパースしてノードを生成するため、スタイルがそのまま引き継がれる構造になっています。
技術的な変更
src/editor/contents.js の insertDOM メソッドに、ペースト操作時のみ実行されるスタイル除去処理が追加されました。
Lexicalが提供する PASTE_TAG 定数を使って、呼び出し元の操作種別を判別しています。insertDOM は汎用的なDOM挿入メソッドであるため、ペースト以外の呼び出し経路(例: プログラムによるコンテンツ挿入)には影響を与えません。
変更前:
importDOM(doc, { tag } = {}) {
this.#unwrapPlaceholderAnchors(doc)
this.editor.update(() => {
変更後:
importDOM(doc, { tag } = {}) {
this.#unwrapPlaceholderAnchors(doc)
if (tag === PASTE_TAG) this.#stripTableCellColorStyles(doc)
this.editor.update(() => {
実際の除去処理はプライベートメソッド #stripTableCellColorStyles として分離されています。querySelectorAll("td, th") で <td> と <th> の両方を対象に取り、style.removeProperty() で background-color、background、color の3プロパティを削除します。
#stripTableCellColorStyles(doc) {
for (const cell of doc.querySelectorAll("td, th")) {
cell.style.removeProperty("background-color")
cell.style.removeProperty("background")
cell.style.removeProperty("color")
}
}
removeProperty はプロパティが存在しない場合も例外を投げないため、スタイルが付与されていないセルが含まれていても安全に動作します。
設計判断
DOMをLexical処理前に書き換える方式 が採用されました。
Lexicalのノード変換フックやデコレータで対応する方法も考えられますが、Lexicalがノードを生成する前のDOMレイヤーで介入することで、Lexicalの内部処理に依存しない実装になっています。パース済みのLexicalノードからスタイルを除去するよりも、HTMLのDOM操作として完結するためコードが単純です。
また、PASTE_TAG による判別により、既存の insertDOM メソッドのインターフェースを変えずに動作を限定しています。ペースト以外のコンテンツ挿入でテーブルのスタイルが除去されることを防ぐ、最小限の変更範囲に抑えた判断といえます。
テストは test/browser/tests/paste/table_cell_styles.test.js にPlaywrightのブラウザテストとして追加されています。ダークモード由来(rgb(26, 26, 46))とライトモード由来(rgb(255, 255, 255))のそれぞれのケースで background-color が空文字列になることを検証しており、実際のクリップボードペーストのシナリオを直接テストしています。
まとめ
この変更は、テーマ間のカラー汚染という視覚的には見落としやすいが閲覧環境によって顕在化するバグを、Lexicalの処理パイプラインの入口でDOMを書き換えるという最小限のアプローチで解決しています。PASTE_TAG を軸にした条件分岐により既存の動作を保護しつつ、ペーストされたテーブルが常に閲覧者のテーマに従って表示される一貫したユーザー体験を実現しています。