| ... | ... | @@ -315,7 +315,7 @@ import { PullRequestThreadDialog } from "./PullRequestThreadDialog"; |
| 315 | 315 | import { MessagesTimeline } from "./chat/MessagesTimeline"; |
| 316 | 316 | import type { AssistantCitationRequest } from "./chat/AssistantCitationSource"; |
| 317 | 317 | import { resolveTimelineIsAtEnd } from "./chat/MessagesTimeline.logic"; |
| 318 | | import { resolveComposerTimelineInset } from "./composerFooterLayout"; |
| 318 | import { resolveComposerTimelineInset, resolveScrollToEndClearance } from "./composerFooterLayout"; |
| 319 | 319 | import { ChatHeader } from "./chat/ChatHeader"; |
| 320 | 320 | import { PanelLayoutControls, RightPanelMaximizeControl } from "./chat/PanelLayoutControls"; |
| 321 | 321 | import { expandedImageKey, type ExpandedImagePreview } from "./chat/ExpandedImagePreview"; |
| ... | ... | @@ -5163,27 +5163,48 @@ export default function ChatView(props: ChatViewProps) { |
| 5163 | 5163 | ? activePlan.steps |
| 5164 | 5164 | : null; |
| 5165 | 5165 | |
| 5166 | | const publishComposerOverlayHeight = useCallback((height: number) => { |
| 5167 | | const nextHeight = Math.ceil(height); |
| 5168 | | if (nextHeight <= 0) return; |
| 5169 | | const previousHeight = composerOverlayHeightRef.current; |
| 5170 | | if (previousHeight !== nextHeight) { |
| 5171 | | composerOverlayHeightRef.current = nextHeight; |
| 5172 | | setComposerOverlayHeight(nextHeight); |
| 5173 | | } |
| 5174 | | const nextInset = resolveComposerTimelineInset({ |
| 5175 | | currentInset: composerTimelineInsetRef.current, |
| 5176 | | overlayHeight: nextHeight, |
| 5177 | | isResting: composerRestingRef.current, |
| 5178 | | }); |
| 5179 | | if (composerTimelineInsetRef.current !== nextInset) { |
| 5180 | | composerTimelineInsetRef.current = nextInset; |
| 5181 | | setComposerTimelineInset(nextInset); |
| 5182 | | } |
| 5183 | | setScrollToEndClearance((currentClearance) => |
| 5184 | | currentClearance === nextHeight ? currentClearance : nextHeight, |
| 5185 | | ); |
| 5186 | | }, []); |
| 5166 | const publishComposerOverlayHeight = useCallback( |
| 5167 | (height: number) => { |
| 5168 | const nextHeight = Math.ceil(height); |
| 5169 | if (nextHeight <= 0) return; |
| 5170 | const previousHeight = composerOverlayHeightRef.current; |
| 5171 | if (previousHeight !== nextHeight) { |
| 5172 | composerOverlayHeightRef.current = nextHeight; |
| 5173 | setComposerOverlayHeight(nextHeight); |
| 5174 | } |
| 5175 | const nextInset = resolveComposerTimelineInset({ |
| 5176 | currentInset: composerTimelineInsetRef.current, |
| 5177 | overlayHeight: nextHeight, |
| 5178 | isResting: composerRestingRef.current, |
| 5179 | }); |
| 5180 | if (composerTimelineInsetRef.current !== nextInset) { |
| 5181 | composerTimelineInsetRef.current = nextInset; |
| 5182 | setComposerTimelineInset(nextInset); |
| 5183 | } |
| 5184 | const mainSurface = composerOverlayElement?.querySelector<HTMLElement>( |
| 5185 | '[data-chat-composer-main-surface="true"]', |
| 5186 | ); |
| 5187 | const button = composerOverlayElement?.parentElement?.querySelector<HTMLElement>( |
| 5188 | 'button[aria-label="Scroll to end"]', |
| 5189 | ); |
| 5190 | const clearance = |
| 5191 | composerOverlayElement && mainSurface && button |
| 5192 | ? resolveScrollToEndClearance({ |
| 5193 | overlayHeight: nextHeight, |
| 5194 | mainSurfaceTop: mainSurface.getBoundingClientRect().top, |
| 5195 | button: button.getBoundingClientRect(), |
| 5196 | attachments: Array.from( |
| 5197 | composerOverlayElement.querySelectorAll<HTMLElement>( |
| 5198 | '[data-composer-banner-surface="attached"]', |
| 5199 | ), |
| 5200 | (element) => element.getBoundingClientRect(), |
| 5201 | ), |
| 5202 | }) |
| 5203 | : nextHeight; |
| 5204 | setScrollToEndClearance(clearance); |
| 5205 | }, |
| 5206 | [composerOverlayElement], |
| 5207 | ); |
| 5187 | 5208 | // The composer reports its resting flag from a layout effect, which runs |
| 5188 | 5209 | // before this component's own layout effects and before any resize |
| 5189 | 5210 | // observation, so every measurement below sees the flag for its layout. |
| ... | ... | @@ -5216,7 +5237,7 @@ export default function ChatView(props: ChatViewProps) { |
| 5216 | 5237 | return () => { |
| 5217 | 5238 | resizeObserver.disconnect(); |
| 5218 | 5239 | }; |
| 5219 | | }, [composerOverlayElement, publishComposerOverlayHeight]); |
| 5240 | }, [composerOverlayElement, publishComposerOverlayHeight, showScrollToBottom]); |
| 5220 | 5241 | const openPanelPullRequestUrl = useOpenPanelPullRequestUrl(activeThreadRef); |
| 5221 | 5242 | const activeThreadReferenceCopyTarget = useMemo( |
| 5222 | 5243 | () => |