fix: tools popover overflowing screen on small viewports (#5549)
* fix tools popover from expanding beyond screen height limits * fix max height clamp | remove unneeded useLayoutEffect dependency --------- Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
This commit is contained in:
parent
2c82e9df5f
commit
ce900cb517
@ -1,4 +1,11 @@
|
||||
import { useState, useEffect, useCallback, useRef, useMemo } from "react";
|
||||
import {
|
||||
useState,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useCallback,
|
||||
useRef,
|
||||
useMemo,
|
||||
} from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import useUser from "@/hooks/useUser";
|
||||
import AgentSkillsTab from "./Tabs/AgentSkills";
|
||||
@ -50,7 +57,9 @@ export default function ToolsMenu({
|
||||
const TABS = useMemo(() => getTabs(t, user), [t, user]);
|
||||
const [activeTab, setActiveTab] = useState(TABS[0].key);
|
||||
const [highlightedIndex, setHighlightedIndex] = useState(-1);
|
||||
const [maxHeight, setMaxHeight] = useState(360);
|
||||
const itemCountRef = useRef(0);
|
||||
const popoverRef = useRef(null);
|
||||
|
||||
// Always open to the slash commands
|
||||
useEffect(() => {
|
||||
@ -62,6 +71,24 @@ export default function ToolsMenu({
|
||||
setHighlightedIndex(-1);
|
||||
}, [activeTab, showing]);
|
||||
|
||||
// Constrain popover height to the space available in the viewport so it
|
||||
// never overflows off-screen on shorter windows (e.g. centered home view).
|
||||
useLayoutEffect(() => {
|
||||
if (!showing) return;
|
||||
const update = () => {
|
||||
const el = popoverRef.current;
|
||||
if (!el) return;
|
||||
const rect = el.getBoundingClientRect();
|
||||
const available = centered
|
||||
? window.innerHeight - rect.top - 16
|
||||
: rect.bottom - 16;
|
||||
setMaxHeight(Math.max(0, Math.min(360, available)));
|
||||
};
|
||||
update();
|
||||
window.addEventListener("resize", update);
|
||||
return () => window.removeEventListener("resize", update);
|
||||
}, [showing, centered]);
|
||||
|
||||
// Keep the parent ref in sync so PromptInput can check it on Enter
|
||||
useEffect(() => {
|
||||
if (highlightedIndexRef) highlightedIndexRef.current = highlightedIndex;
|
||||
@ -119,15 +146,15 @@ export default function ToolsMenu({
|
||||
onClick={() => setShowing(false)}
|
||||
/>
|
||||
<div
|
||||
ref={popoverRef}
|
||||
onMouseDown={(e) => {
|
||||
// Prevents prompt textarea from losing focus when clicking inside the menu.
|
||||
// Skip for portaled modals so their inputs can still receive focus.
|
||||
if (e.currentTarget.contains(e.target)) e.preventDefault();
|
||||
}}
|
||||
style={{ maxHeight }}
|
||||
className={`absolute left-2 right-2 md:left-14 md:right-auto md:w-[400px] z-50 bg-zinc-800 light:bg-white border border-zinc-700 light:border-slate-300 rounded-lg p-3 flex flex-col gap-2.5 shadow-lg overflow-hidden ${
|
||||
centered
|
||||
? "top-full mt-2 max-h-[min(360px,calc(100dvh-25rem))]"
|
||||
: "bottom-full mb-2 max-h-[min(360px,calc(100dvh-11rem))]"
|
||||
centered ? "top-full mt-2" : "bottom-full mb-2"
|
||||
}`}
|
||||
>
|
||||
<div className="flex shrink-0 gap-2.5 items-center">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user