fix(chat): unify expand and drag-to-max rendering (MUL-2653) (#3235)

* fix(chat): unify expand and drag-to-max rendering so both produce same dimensions (MUL-2653)

Expand button used CSS `inset-3` (parent minus 24px each side) while
drag-to-max used explicit 90%-of-parent pixel dimensions — different
sizes for the same conceptual state. Expand also hid resize handles,
preventing drag-back. Now both paths render with explicit width/height
at bottom-right and resize handles stay visible in all states.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>

* fix(chat): animate width/height via framer-motion for smooth expand toggle (MUL-2653)

Move width/height from style prop into animate prop so framer-motion
interpolates size changes. Remove layout="position" which only tracked
position. Drag uses duration:0 for instant feedback.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
Naiyuan Qing
2026-05-26 08:27:31 +08:00
committed by GitHub
parent e351f89843
commit c5b4c45e41

View File

@@ -442,11 +442,8 @@ export function ChatWindow() {
const isVisible = isOpen && (isExpanded || boundsReady);
const containerClass = isExpanded
? "absolute inset-3 z-50 flex flex-col rounded-xl ring-1 ring-foreground/10 bg-sidebar shadow-2xl overflow-hidden"
: "absolute bottom-2 right-2 z-50 flex flex-col rounded-xl ring-1 ring-foreground/10 bg-sidebar shadow-2xl overflow-hidden";
const containerClass = "absolute bottom-2 right-2 z-50 flex flex-col rounded-xl ring-1 ring-foreground/10 bg-sidebar shadow-2xl overflow-hidden";
const containerStyle: React.CSSProperties = {
...(!isExpanded ? { width: renderWidth, height: renderHeight } : {}),
transformOrigin: "bottom right",
pointerEvents: isOpen ? "auto" : "none",
};
@@ -456,21 +453,21 @@ export function ChatWindow() {
ref={windowRef}
className={containerClass}
style={containerStyle}
layout="position"
initial={{ opacity: 0, scale: 0.95 }}
initial={{ opacity: 0, scale: 0.95, width: renderWidth, height: renderHeight }}
animate={{
opacity: isVisible ? 1 : 0,
scale: isVisible ? 1 : 0.95,
width: renderWidth,
height: renderHeight,
}}
transition={{
layout: isDragging
? { duration: 0 }
: { type: "spring", duration: 0.3, bounce: 0 },
width: isDragging ? { duration: 0 } : { type: "spring", duration: 0.3, bounce: 0 },
height: isDragging ? { duration: 0 } : { type: "spring", duration: 0.3, bounce: 0 },
opacity: { duration: 0.15 },
scale: { type: "spring", duration: 0.2, bounce: 0 },
}}
>
{!isExpanded && <ChatResizeHandles onDragStart={startDrag} />}
<ChatResizeHandles onDragStart={startDrag} />
{/* Header — ⊕ new + session dropdown | window tools */}
<div className="flex items-center justify-between border-b px-4 py-2.5 gap-2">
<div className="flex items-center gap-1 min-w-0">