プロンプトメニューの表示方向を強制指定する `vertical-direction` 属性を追加

basecamp/lexxy

lexxy-prompt 要素に vertical-direction 属性が追加され、プロンプトメニューの開く方向を top(上向き)または bottom(下向き)に強制指定できるようになりました。固定要素やフローティング要素がビューポート内の領域を視覚的に覆っているレイアウトでも、意図した方向にメニューを表示できます。

背景

Lexxy はデフォルトで、ウィンドウのビューポートに基づいてプロンプトメニューの表示方向を自動計算します。しかし、固定配置やフローティング配置の要素が画面の一部を覆っている場合、ビューポートの境界内にあるにもかかわらずメニューが隠れてしまう問題が起きていました。

このような状況では、自動計算が「利用可能なスペースがある」と判断してしまうため、アプリケーション側から方向を上書きする手段が必要でした。vertical-direction 属性はこのユースケースに対応するためのエスケープハッチとして設計されています。

技術的な変更

src/elements/prompt.jsverticalDirection ゲッターが追加され、表示方向の決定ロジックが更新されました。変更の核心は、既存の「ビューポートからはみ出したら上に開く」という単一条件に、強制指定フラグを組み合わせた論理式への置き換えです。

変更前:

if (popoverRect.bottom > window.innerHeight) {
  this.#setPopoverOffsetY(contentRect.height - y + fontSize)
  this.popoverElement.toggleAttribute("data-clipped-at-bottom", true)
}

変更後:

get verticalDirection() {
  return this.getAttribute("vertical-direction")
}

// ...

const forceTop = this.verticalDirection === "top"
const forceBottom = this.verticalDirection === "bottom"
const overflowsWindow = popoverRect.bottom > window.innerHeight

if (!forceBottom && (forceTop || overflowsWindow)) {
  this.#setPopoverOffsetY(contentRect.height - y + fontSize)
  this.popoverElement.toggleAttribute("data-clipped-at-bottom", true)
}

条件式 !forceBottom && (forceTop || overflowsWindow) によって、3つのケースが整理されています。forceBottom が真の場合は他の条件に関わらず下向きを維持し、forceTop が真の場合は overflowsWindow の結果を無視して上向きに強制し、どちらも指定がなければ従来の自動計算が適用されます。

使用方法はシンプルで、HTML属性として指定するだけです:

<lexxy-prompt trigger="@" src="..." name="mention" vertical-direction="top"></lexxy-prompt>

設計判断

属性値による宣言的な上書きという設計が採用されました。JavaScriptからプログラム的に制御するAPIではなく、HTML属性として表現されている点が重要です。これにより、サーバーサイドレンダリングのテンプレートから直接制御でき、コンポーネントの利用者がJavaScriptを記述せずに挙動を変更できます。

また、vertical-direction が指定されない場合の挙動は既存と完全に同一であり、後方互換性が保たれています。forceTopforceBottom が両方とも偽の場合、条件式は overflowsWindow のみに依存するため、既存のコードパスへの影響はありません。

テストは test/browser/tests/prompts/vertical_direction.test.js にブラウザテストとして追加されており、ビューポートサイズを 500×340px に固定した上で、vertical-direction="top" でメニューが編集エリアの上に表示されること、vertical-direction="bottom" でビューポート端でも下向きを維持することをそれぞれ検証しています。

まとめ

本PRは、自動計算では対処できないレイアウト上の制約に対して、宣言的な属性による脱出口を提供する変更です。条件式の最小限の拡張によって既存の自動判定ロジックを壊さずに強制指定を実現しており、フローティングUIを持つアプリケーションでの実用性を高めています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
293b6e32

この記事は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:src/elements/prompt.js)やGitHubのPRリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

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

ビューポートやDOM属性に関する知識を前提としており、専門知識を持つエンジニアという対象読者に適した技術レベルと表現で書かれています。

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

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

各セクション、各パラグラフがトピックセンテンスで始まり、1段落1トピックが守られているため、非常に読みやすく構成されています。

Diff内容との照合 ✓ PASS

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

記事で引用されている変更前後のコードブロックは、提供されたDiff情報と完全に一致しており、正確に内容を反映しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「vertical-direction」「viewport」などの技術用語や、PRから引用した「forceTop」「forceBottom」といった変数名が正確に使用されています。

説明の技術的正確性 ✓ PASS

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

変更点である条件式「!forceBottom && (forceTop || overflowsWindow)」の動作解説が論理的かつ技術的に正確です。

事実の突合 ✓ PASS

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

記事内のすべての主張(属性追加の背景、テストの存在、後方互換性の担保など)は、提供されたPR DescriptionやDiffのコードから裏付けられており、ハルシネーションは一切見られません。

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

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

PR番号「#1080」やテストコードで言及されているビューポートサイズ「500×340px」など、数値や固有名詞はすべて正確です。

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

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

記事のタイトルは、PRの「Prompt vertical direction」という内容をより具体的に、かつ正確に表現しており、主題と一致しています。

外部知識の正確性 ✓ PASS

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

記事はPR情報とDiffのみに基づいており、バージョンのサポート状況など、PRに記載のない外部知識を持ち込んでいません。

時間表現の正確性 ✓ PASS

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

完了した変更に対し「追加され...ました」といった過去・完了形の時制が正しく使われており、時間表現の歪曲はありません。