https://github.com/basecamp/lexxy
エクステンションがツールバーボタンを非同期で追加した後にオーバーフロー計算が再実行されない問題を修正。`requestOverflowRefresh()` をパブリックAPIとして公開し、`initializeToolbars()` から呼び出す設計に変更。あわせて、右端寄せボタンの実装をスペーサー要素から `margin-inline-start: auto` へ切り替え、`timing_helpers.js` のファイル名統一も行われた。
Chromeの「`<summary>` 内のインタラクティブ要素」警告を解消するため、ツールバードロップダウンを `<details>`/`<summary>` ベースからJSで制御するカスタム要素(`<lexxy-toolbar-dropdown>`)へ刷新。ドロップダウンのトリガー・パネル・開閉ロジックを単一の要素に集約し、`HighlightDropdown`/`LinkDropdown` はカスタム要素のサブクラスからプレーンなコントローラークラスへ変更された。ユーザー向けの動作変更はなく、構造的な整理が目的。
`LexicalPromptElement#showEmptyResults`で`empty-results`属性値を`innerHTML`に直接代入していたHTML注入脆弱性を、`textContent`への切り替えで修正しました。ユーザー入力が属性に反映されるホストアプリでDOMベースの注入やオープンリダイレクトが可能な状態でしたが、属性をHTMLとして解釈させない根本的な対処により解消されています。
gemのリネーム(`actiontext/lexical` → `lexxy`)に伴い壊れていた `bin/rails` の `ENGINE_PATH` と `bin/setup` のDBタスクを修正。`ENGINE_PATH` を削除済みの旧パスから `lib/lexxy` に修正して `bin/rails console` を復旧し、`db:prepare` を `app:db:prepare` に変更してダミーアプリへのタスクディスパッチを正しく行うようにした。
`Foo::Bar::Baz` や `port:8080` などコロンを含むプレーンテキストが誤ってリンク変換される問題を修正。`new URL()` による広範なURL判定を廃止し、`scheme://` または `www.` で始まる文字列のみを対象とする正規表現ベースの `isAutolinkableURL()` に置き換えています。
Google DocsなどからペーストされたHTMLに含まれるdata-URI形式のインライン画像を検出し、Active Storageのアップロードパイプラインへ自動変換する機能を実装。ペースト操作時のみ変換を実行する設計で、既存の`lexxy:file-accept`イベントによる許可制御も再利用している。あわせて`$generateNodesFromDOM`への責務統合と`$createUploadNode`の抽出によるリファクタリングも実施。
`<pre>`要素のinnerHTMLを直接書き換える方式に変更し、中間の`<code>`要素と`createElement`ヘルパーを廃止したリファクタリング。DOM操作が「要素生成→属性付与→子要素置換」の3ステップから`innerHTML`の直接代入1ステップに簡略化され、`data-language`属性やハイライト範囲処理の適用先が`<pre>`に統一されました。
Lexxyのエクステンション基底クラスに `dispose()` ライフサイクルフックが追加されました。エディタの切断・再接続時に `Extensions.dispose()` が既存の `#disposables` パターンを通じて呼ばれ、`initializeToolbar()` でツールバーに付与したリスナーなどのリソースを逆順でクリーンアップできます。Turboのback/forwardナビゲーションで発生していた重複ハンドラ問題が根本的に解消されます。
Lexicalエディタの更新リスナーがキーストロークごとにツールバーのaria属性を無条件で書き換えていた問題を修正。書き込み前に現在値を確認してno-op書き込みをスキップするガードを追加し、Turboブロードキャスト等でグローバルスタイル再計算が走る状況下でのキーストロークレイテンシをp50で約63%削減しました。
Lexicalのテーブル選択オブザーバーをDOMルート要素が存在するタイミングで初期化するよう変更し、マウスのドラッグ操作で3セル以上を選択できないリグレッションを修正しました。`registerRootListener` を活用することで、ポインターハンドラーのアタッチ先となるルートが確実に存在する状態で `registerTableSelectionObserver` が呼び出されるようになります。
Lexxy内でコピーしたリンクを貼り付けるとhrefが失われプレーンテキストになるバグを修正。`Clipboard`クラスが`SELECTION_INSERT_CLIPBOARD_NODES_COMMAND`を直接インターセプトし、シングルリンクのペイロードを検知して既存のURLペーストロジックで処理するよう変更されました。合わせてペースト処理の責務が`CommandDispatcher`から`Clipboard`クラスに移管されています。
Lexxyで2枚以上の画像を連続してペーストすると、自動的にギャラリーとしてグループ化されるようになりました。`GalleryUploader` に「カーソル直前にギャラリーまたは画像がある」ことを検出する `selectionIsAfterGalleryEdge` を追加し、`fromPaste` フラグでペースト操作のみにスコープを限定することで、ツールバーからの意図的なアップロードには影響を与えない設計が実現されています。
`editor.flush()` を `getEditorState().read(() => {})` に簡略化したコミットを差し戻しました。簡略化された形式はトランスフォームやRAFスケジュールされたディスパッチといった非同期サイドエフェクトの完了を待機しないため、テストヘルパーとして「エディタが安定した状態に達した」ことを保証できませんでした。空の `editor.update()` を発行して保留中の更新をコミットし、`requestAnimationFrame` でブラウザ描画サイクルの完了を待機する元の実装に戻しています。
`>` + スペースのマークダウンショートカットで作成した引用ブロックへの複数行HTMLペーストが引用外に脱出するバグを修正。`QuoteNode` のノードトランスフォームを登録し、`ParagraphNode` を持たない空の `QuoteNode` を検出したタイミングで自動的に `ParagraphNode` を補完することで、ペースト処理の前提構造を保証する設計になっています。
`<lexxy-editor>` に `permitted-attachment-types` 属性を追加し、HTMLインポート・ファイルドロップ・プロンプト起動・プログラム挿入の全経路で添付ファイルのコンテンツタイプを一括制御できるようにした変更です。エディタ要素に `permittedAttachmentTypes` ゲッターと `permitsAttachmentContentType()` 述語を追加し、全エントリポイントがこの単一の判定ロジックを参照する設計で、ホスト側でのフィルタリング実装が不要になりました。
クォートブロックへのペースト時に発生していた「カーソル位置の無視」「エディタの応答不能」「余分な空行の挿入」という3つのバグを修正しました。原因はカスタム実装の `QuoteNodeInserter` がテキストノード内のカーソルオフセットを無視していたことで、クラス全体を削除してLexicalのデフォルト処理に委ねることで解決しています。
ブロッククォート適用時に `<br>` が消失する問題と、選択外の行まで引用されてしまう問題を修正。従来の「全BRをパラグラフに分割」方式を廃止し、選択境界に最も近いBRのみで分割する `$splitParagraphsAtLineBreakBoundaries` に置き換えることで、選択範囲内のBRを保持しつつ、選択した行のみを正確に引用できるようになりました。
コードブロックへ空行を含むテキストをペーストすると内容がブロック外のパラグラフに分割されてしまうバグを修正。原因はLexicalがペースト操作を複数の `insertNewAfter()` 呼び出しに分解する際に `EarlyEscapeCodeNode` の脱出ロジックが誤発火することで、`$hasUpdateTag(PASTE_TAG)` によるガードを追加し、ペースト中は基底クラスの安全な動作に委譲することで解決。
コードブロックの末尾行がスペースやタブのみの場合、Enterキーで脱出できなかったバグを修正。`#isCursorOnWhitespaceOnlyLastLine` メソッドを追加し、1回目のEnterで空白をクリア、2回目のEnterで既存の脱出フローに乗せる2段階処理で対応しました。
コードブロックのシンタックスハイライト後に `<pre>` 要素が失われ、コピー時に改行が折り畳まれていたバグを `replaceWith` → `replaceChildren` の1行変更で修正。合わせてコードブロックへのペーストを平文専用ハンドラで処理し、HTML形式のクリップボードデータがコードブロック構造を破壊する問題も解消した。