@メンション後のカンマが改行される問題をCSSとUnicode文字で修正
display: inline-flex が生み出すアトミックインラインボックスと、importDOM が注入するスペース文字が組み合わさり、@メンション直後のカンマが次の行に折り返される問題が発生していました。本PRはCSS・Unicode・削除ボタンの3点を同時に修正することでこの問題を根本解決しています。
背景
アトミックインラインボックスとソフトラップ機会という2つの要因が重なり、メンション後の句読点が意図しない位置で折り返されていました。CustomActionTextAttachmentNode のカスタム要素に適用されていた display: inline-flex は、要素全体を単一のインラインボックスとして扱います。これにより、要素の前後にライン折り返しの機会が生まれます。
さらに、importDOM の実装がメンション要素の末尾にスペース文字を注入していました。スペースはそれ自体がソフトラップ機会となるため、幅の狭い画面ではブラウザがスペースの位置で折り返し、直後のカンマだけが次の行に取り残される現象が発生していました。エディタ幅を250pxから120pxに縮小するリグレッションテストによってこの問題が再現・検証されています。
技術的な変更
修正は「CSS変更」「スペース文字の置き換え」「削除ボタンの表示制御」の3つで構成されており、それぞれが前述の問題に対応します。
CSS: display: inline-flex から display: inline へ
lexxy-content.css のカスタムアタッチメントに対するスタイルを変更し、アトミックインラインボックスを解消しました。
変更前:
action-text-attachment {
align-items: center;
display: inline-flex;
gap: 0.25ch;
/* ... */
}
変更後:
action-text-attachment {
display: inline;
/* ... */
img {
margin-inline-end: 0.25ch;
vertical-align: middle;
}
}
inline-flex で実現していたアバター画像の整列(align-items: center と gap)は、display: inline への変更により機能しなくなります。これを補うために img 要素へ vertical-align: middle と margin-inline-end: 0.25ch を追加し、レイアウトを維持しています。
Word Joiner (U+2060) によるソフトラップ機会の抑制
PRの説明によれば、importDOM が注入していたトレーリングスペースを Word Joiner (U+2060) に置き換えることで、メンション要素と後続テキスト間のソフトラップ機会を明示的に抑制しています。U+2060 はゼロ幅の非改行文字であり、前後の文字を「接着」してブラウザが改行できないようにします。
削除ボタンの表示制御
display: inline はポジション指定された子要素のレイアウトをサポートしないため、lexxy-node-delete-button を常時表示したままにすることができなくなりました。lexxy-editor.css を修正し、削除ボタンをデフォルトで非表示にし、ノード選択時のみ表示する方式に変更しています。
変更前:
lexxy-node-delete-button {
inset-inline-start: 0;
/* ... */
}
変更後:
lexxy-node-delete-button {
display: none;
inset-inline-start: 0;
/* ... */
}
&.node--selected lexxy-node-delete-button {
display: block;
}
削除ボタンは .node--selected クラスが付与された場合にのみ表示されるため、選択時の操作性は維持されています。
テストの整備
mentions.test.js に幅スイープ型のリグレッションテストが追加されました。エディタ幅を250pxから120pxまで段階的に縮小し、メンションが1行に収まる全ての幅でカンマが同じ行に表示されることを検証します。既存のテストは test.describe("via prompt system") 配下に整理され、新テストと明確に区別されています。
設計判断
display: inline への変更は、アトミックインラインボックスを根本的に排除する最もシンプルなアプローチです。inline-flex や inline-block を維持しながら white-space: nowrap でラップを抑制する案も考えられますが、それではメンション要素そのものの途中での折り返しは防げても、要素境界でのラップ機会は残ります。display: inline への変更はこの問題を構造的に解決します。
アバター画像のレイアウト維持に vertical-align: middle を使用している点も注目に値します。inline-flex の align-items: center が提供していた垂直中央揃えを、インラインボックスモデルの範囲内で再現する手法として、古典的かつ堅牢な選択です。
削除ボタンを「常時表示から選択時のみ表示」へと変更した判断は、display: inline への移行が強いる制約への対応ですが、結果的にUIとして自然な振る舞いにもなっています。
まとめ
本PRは、CSS表示モデルの根本的な性質(アトミックインラインボックス)とUnicodeの制御文字(Word Joiner)を組み合わせて、句読点の不正な折り返しを解消しました。display: inline-flex から display: inline への一見シンプルな変更が、削除ボタンのレイアウト戦略の見直しまで波及するという、インラインボックスモデルの影響範囲の広さを示す好例といえます。