authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-10-08 18:44:05-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-08 18:44:05-03:00
log48b71f0eb323d08c8fcadfe54adf34becb2984da
tree9348f14ba95ce97e55a0a3679045101e05718b59
parent7b57b723d3b7490b50fffbd99fe89c6aa98fae1f
signature Signed by PGP key B5690EEEBB952194

fix(web): collapsed composer reserves room for wide send actions (#17016)


1 files changed, 20 insertions(+), 11 deletions(-)

apps/web/src/components/chat/ChatComposer.tsx+20-11
......@@ -5220,6 +5220,19 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
52205220 useLayoutEffect(() => {
52215221 onRestingChange(isComposerResting);
52225222 }, [isComposerResting, onRestingChange]);
5223 // The resting footer floats over the prompt row, so the row reserves its
5224 // measured width. Wide actions like the compact-before-send chip vary too much for a fixed inset.
5225 const [restingActionsElement, setRestingActionsElement] = useState<HTMLDivElement | null>(null);
5226 const [restingActionsWidth, setRestingActionsWidth] = useState<number | null>(null);
5227 useLayoutEffect(() => {
5228 if (!isComposerResting || !restingActionsElement) return;
5229 const measure = () => setRestingActionsWidth(restingActionsElement.offsetWidth);
5230 measure();
5231 if (typeof ResizeObserver === "undefined") return;
5232 const observer = new ResizeObserver(measure);
5233 observer.observe(restingActionsElement);
5234 return () => observer.disconnect();
5235 }, [isComposerResting, restingActionsElement]);
52235236 const restingImagePreviewCounts = getRestingComposerImagePreviewCounts(
52245237 standaloneComposerImages.length,
52255238 );
......@@ -7376,17 +7389,12 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
73767389 )}
73777390
73787391 <div
7379 className={cn(
7380 "relative",
7381 isComposerResting && "flex min-w-0 items-center gap-1",
7382 isComposerResting &&
7383 ((settings.contextWindowMeterEnabled && activeContextWindow) ||
7384 reserveContextWindowMeter
7385 ? "pr-28"
7386 : showComposerAttachAction
7387 ? "pr-20"
7388 : "pr-12"),
7389 )}
7392 className={cn("relative", isComposerResting && "flex min-w-0 items-center gap-1")}
7393 style={
7394 isComposerResting && restingActionsWidth !== null
7395 ? { paddingRight: `calc(${restingActionsWidth}px + 1rem)` }
7396 : undefined
7397 }
73907398 >
73917399 {previewFile ? (
73927400 <Dialog
......@@ -7565,6 +7573,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
75657573
75667574 {/* Right side: send / stop button */}
75677575 <div
7576 ref={setRestingActionsElement}
75687577 data-chat-composer-actions="right"
75697578 data-chat-composer-transition-actions="true"
75707579 data-chat-composer-primary-actions-compact={