| @@ -47,8 +47,15 @@ | ||
| 47 | 47 | const isFreshPageLoad = useRef(true); |
| 48 | 48 | const [ready, setReady] = useState(false); |
| 49 | 49 | const userScrolledAway = useRef(false); |
| 50 | 50 | const confirmScrolledFor = useRef(null); |
| 51 | + // Remounting into another layout would otherwise animate the whole backlog past. | |
| 52 | + const settling = useRef(true); | |
| 53 | + const behavior = () => { | |
| 54 | + if (!settling.current) return 'smooth'; | |
| 55 | + settling.current = false; | |
| 56 | + return 'auto'; | |
| 57 | + }; | |
| 51 | 58 | |
| 52 | 59 | const lastId = messages.at(-1)?.id; |
| 53 | 60 | const lastDetails = messages.at(-1)?.details; |
| 54 | 61 | const pendingTool = |
| @@ -129,9 +136,9 @@ | ||
| 129 | 136 | // block:'end' scrolls UP for already-visible content — only reveal overflow. |
| 130 | 137 | const overflows = |
| 131 | 138 | last.getBoundingClientRect().bottom > c.getBoundingClientRect().bottom; |
| 132 | 139 | if (!overflows) return; |
| 133 | - last.scrollIntoView({ behavior: 'smooth', block: 'end' }); | |
| 140 | + last.scrollIntoView({ behavior: behavior(), block: 'end' }); | |
| 134 | 141 | }); |
| 135 | 142 | return () => cancelAnimationFrame(id); |
| 136 | 143 | }, [ready, isUserMessage, messages, pinTarget]); |
| 137 | 144 | |
| @@ -159,9 +166,9 @@ | ||
| 159 | 166 | const offset = |
| 160 | 167 | target.getBoundingClientRect().top - |
| 161 | 168 | scrollArea.getBoundingClientRect().top; |
| 162 | 169 | scrollArea.style.minHeight = `${offset + c.clientHeight}px`; |
| 163 | - target.scrollIntoView({ behavior: 'smooth', block: 'start' }); | |
| 170 | + target.scrollIntoView({ behavior: behavior(), block: 'start' }); | |
| 164 | 171 | }; |
| 165 | 172 | pinWhenOutOfView(); |
| 166 | 173 | // The confirm grows while its preview loads and can leave the viewport. |
| 167 | 174 | const observer = new ResizeObserver(pinWhenOutOfView); |
| @@ -261,8 +268,21 @@ | ||
| 261 | 268 | return <WorkflowMessage key={message.id} message={message} />; |
| 262 | 269 | } |
| 263 | 270 | if (message.type === 'workflow-component') { |
| 264 | 271 | return <WorkflowComponent key={message.id} message={message} />; |
| 272 | + } | |
| 273 | + if (message.type === 'canvas-notice') { | |
| 274 | + return ( | |
| 275 | + <ToolReceipt key={message.id}> | |
| 276 | + { | |
| 277 | + // translators: Shown in the agent chat when the user asks for something the open canvas cannot do. Canvas is the panel open on screen beside the chat. | |
| 278 | + __( | |
| 279 | + 'Canvas interactions are limited. When finished, use the button in the top corner to exit.', | |
| 280 | + 'extendify-local', | |
| 281 | + ) | |
| 282 | + } | |
| 283 | + </ToolReceipt> | |
| 284 | + ); | |
| 265 | 285 | } |
| 266 | 286 | if ( |
| 267 | 287 | message.type === 'tool' && |
| 268 | 288 | message.details?.id === 'acquire-image' |