chat: links open in a new tab
officer is a single-page app, so a same-tab navigation to an external url unloads it — tap a link in a message and you come back to a cold boot with the scroll position and anything mid-flight gone. `a` was simply absent from MD_COMPONENTS, so every link rendered as a bare anchor. all four ReactMarkdown call sites in MessageBubble share that object, so one override covers assistant messages, user messages, tool output and the collapsed blocks. noopener noreferrer with it: a bare target="_blank" hands the opened page a live window.opener back into the app. target is set AFTER the prop spread so raw html in a message cannot override it with _self.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import type { ComponentProps } from 'react';
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
@@ -37,7 +38,23 @@ import { injectImages } from './chat-images';
|
||||
import { randomId } from 'helpers/random-id';
|
||||
|
||||
/** Shared by the settled bubble and the streaming one, so a block gains nothing when the turn ends. */
|
||||
const MD_COMPONENTS = { pre: CodeBlock, img: ChatImage };
|
||||
/**
|
||||
* Every link in a message opens in a new tab.
|
||||
*
|
||||
* Officer is a single-page app, so a same-tab navigation to an external URL unloads it: the user taps a
|
||||
* link in a chat and comes back to a cold boot, having lost the scroll position and anything mid-flight.
|
||||
* A message is a place someone reads FROM, not a place they navigate away from.
|
||||
*
|
||||
* `noopener noreferrer` is not decoration — a bare `target="_blank"` hands the opened page a live
|
||||
* `window.opener` back into the app, which is a redirect away from anything an agent linked to.
|
||||
*/
|
||||
const ChatLink = ({ href, children, ...rest }: ComponentProps<'a'>) => (
|
||||
<a {...rest} href={href} target="_blank" rel="noopener noreferrer">
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
|
||||
const MD_COMPONENTS = { pre: CodeBlock, img: ChatImage, a: ChatLink };
|
||||
|
||||
const sanitizeSchema = {
|
||||
...defaultSchema,
|
||||
|
||||
Reference in New Issue
Block a user