fix(model-picker): 模型选择 - 修复长列表溢出与渠道面板随动 (#706)

Co-authored-by: 天道酬秦 <tdcq@tiandaochouqindeMacBook-Air.local>
This commit is contained in:
qihang ma
2026-10-08 14:28:40 +08:00
committed by GitHub
parent 9ef10b7b2d
commit 9be3aa8235
3 changed files with 37 additions and 18 deletions

View File

@@ -1,4 +1,4 @@
import { useEffect, useId, useMemo, useRef, useState, type KeyboardEvent } from "react";
import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type KeyboardEvent } from "react";
import { Check, ChevronDown, Coins } from "lucide-react";
import { Popover } from "antd";
@@ -54,6 +54,7 @@ export function ModelPicker({
const rawTheme = useActiveTheme();
const theme = (canvasThemes[rawTheme as keyof typeof canvasThemes] ?? canvasThemes.dark) as CanvasTheme;
const [open, setOpen] = useState(false);
const [availableHeight, setAvailableHeight] = useState(0);
const [activeGroupKey, setActiveGroupKey] = useState<string | null>(null);
const menuRef = useRef<HTMLDivElement>(null);
const triggerRef = useRef<HTMLButtonElement>(null);
@@ -70,6 +71,21 @@ export function ModelPicker({
const [routeQuote, setRouteQuote] = useState<LogicalModelQuote | undefined>();
const creationVariant = variant === "creation";
useLayoutEffect(() => {
if (!open) return;
const updateAvailableHeight = () => {
const { top, bottom } = triggerRef.current!.getBoundingClientRect();
setAvailableHeight(Math.max(top, window.innerHeight - bottom));
};
updateAvailableHeight();
window.addEventListener("resize", updateAvailableHeight);
window.addEventListener("scroll", updateAvailableHeight, true);
return () => {
window.removeEventListener("resize", updateAvailableHeight);
window.removeEventListener("scroll", updateAvailableHeight, true);
};
}, [open]);
useEffect(() => {
if (!showSelectedPrice || !creditsEnabled || !quoteRequest) {
setRouteQuote(undefined);
@@ -156,7 +172,7 @@ export function ModelPicker({
"canvas-model-picker-menu creation-model-picker-menu max-w-[calc(100vw-24px)]",
activeGroupKey === null ? "is-brand-list" : "is-model-list",
)}
style={{ background: theme.node.panel, color: theme.node.text }}
style={{ background: theme.node.panel, color: theme.node.text, "--canvas-model-picker-available-height": `${availableHeight}px` } as CSSProperties}
role="listbox"
aria-label={placeholder}
onKeyDown={handleMenuKeyDown}
@@ -185,7 +201,7 @@ export function ModelPicker({
</button>;
})}
</div>
{optionGroups.filter((group) => group.key === activeGroupKey).map((group) => <section key={group.key} className="canvas-model-picker-group canvas-model-picker-model-pane min-w-0 overflow-hidden">
{optionGroups.filter((group) => group.key === activeGroupKey).map((group) => <section key={group.key} className="canvas-model-picker-group canvas-model-picker-model-pane min-w-0">
<div className="grid min-w-0 gap-1">
{group.models.map((modelGroup) => {
const selected = modelGroup.models.includes(current);
@@ -243,6 +259,7 @@ export function ModelPicker({
onOpenChange={setPickerOpen}
trigger="click"
placement="bottomLeft"
align={{ overflow: { adjustY: true, shiftX: true } }}
arrow={false}
content={content}
classNames={{