ツールバーのオーバーフロー制御に「固定ボタン」機能を追加

basecamp/lexxy

data-prevent-overflow="true" 属性を持つボタンは、ツールバーが幅不足でオーバーフローしても常にツールバー本体に残留するようになりました。モバイル環境でも添付ファイルボタンが常時アクセス可能になります。

背景

ツールバーが狭い画面幅に収まらない場合、lexxy-toolbar はボタンをオーバーフローメニューへ移動する「オーバーフロー機構」を持っています。しかし、アクション種別に関わらず全ボタンが移動対象になっていたため、モバイル環境で「添付ファイルのアップロード」のような頻繁に使われる重要なボタンがオーバーフローメニューの奥に隠れてしまうケースがありました。

PR本文では「Attachments button is one of the most important actions on mobile」として、この問題が明示されています。

技術的な変更

src/elements/toolbar.js#buttons ゲッター にセレクタの除外条件を追加することで、オーバーフロー移動の対象から特定ボタンを除外できるようになりました。

変更箇所は #buttons ゲッターのクエリセレクタ1行のみです。

変更前:

get #buttons() {
  return Array.from(this.querySelectorAll(":scope > button"))
}

変更後:

get #buttons() {
  return Array.from(this.querySelectorAll(":scope > button:not([data-prevent-overflow='true'])"))
}

このゲッターがオーバーフロー発生時に「移動対象として取り出すボタンのリスト」を返しているため、:not([data-prevent-overflow='true']) を追加するだけで、当該属性を持つボタンは移動対象から自動的に除外されます。

あわせて、添付ファイルボタン(name="upload")に data-prevent-overflow="true" が付与されました。

変更後のボタン定義:

<button class="lexxy-editor__toolbar-button" type="button" name="upload"
  data-command="uploadAttachments"
  data-prevent-overflow="true"
  title="Upload file">
  ${ToolbarIcons.attachment}
</button>

設計判断

HTMLデータ属性によるオプトイン方式 が採用されました。JavaScriptコード側でボタン名をハードコードして除外リストを持つのではなく、マークアップ側で data-prevent-overflow="true" を付与するだけで固定化できるため、将来的に他のボタンにも同じ振る舞いを適用しやすい設計です。

オーバーフロー対象のリストアップを :not(...) セレクタで表現していることも特徴的です。「除外したいものを除外する」という記述になっており、デフォルトはすべてのボタンが移動対象という方針を維持しつつ、例外をマークアップで宣言的に表現しています。

テストの追加

test/browser/tests/formatting/toolbar.test.js"overflow compaction keeps upload button visible" テストが追加されました。ビューポート幅を300pxに縮小してオーバーフロー状態を発生させ、以下を検証します:

  • アップロードボタンがツールバーに残留していること(toBeVisible()toHaveCount(1)
  • オーバーフローメニュー内にアップロードボタンが存在しないこと(toHaveCount(0)
  • アップロードボタンがクリック可能な状態であること(toBeEnabled()
  • ビューポートを元に戻すとオーバーフロー状態が解消されること

ビューポートサイズの動的変更でオーバーフロー状態を再現するアプローチにより、実際のモバイル利用シナリオに即したE2Eテストになっています。

まとめ

data-prevent-overflow="true" というHTMLデータ属性を1つ追加するだけで、ボタンをオーバーフロー移動から除外できる仕組みが導入されました。JavaScriptロジックへの変更を最小限に抑えつつ、マークアップ側の宣言で挙動を制御できる拡張性の高い設計です。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
98b8f900

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「リード文(総論)→背景・技術詳細・設計判断・テスト(各論)→まとめ(結論)」という構成が明確で、ガイドラインに完全に準拠しています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(```javascript:path/to/file.js)とPR番号のリンク記法([#874](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

「ゲッター」「クエリセレクタ」「オプトイン方式」などの専門用語が適切に使用されており、対象読者であるエンジニアに適した技術レベルです。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論の構成になっており、各段落はトピックセンテンスで始まり、1段落1トピックの原則が守られています。可読性が非常に高いです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されている3つのコードブロックは、提供されたDiff情報と完全に一致しています。ファイルパスも正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「data-*属性」「:not()セレクタ」「E2Eテスト」「ビューポート」など、使用されている技術用語はすべて正確かつ文脈に適しています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

「:not()セレクタで除外する」という変更内容の説明や、テストコードで検証している内容の説明が、Diff情報と一致しており技術的に正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張は、PRのDescriptionやDiff内のコードで裏付けられています。設計判断に関する記述も、コードから読み取れる妥当な解説であり、ハルシネーションは検出されませんでした。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号「#874」やテストコード内のビューポート幅「300px」など、記事に含まれる数値や固有名詞はすべて正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトル「ツールバーのオーバーフロー制御に「固定ボタン」機能を追加」は、PRの主題「Prevent overflow for certain items」を的確かつ分かりやすく要約しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に記載のないバージョンサポート状況やリリース日程などの外部知識の追記はなく、事実に基づいた記述がされています。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

マージされた変更を報告する文脈として「〜ようになりました」といった完了形の表現が使われており、時間表現に歪曲はありません。