import { urlOrigin } from "../../lib/urlRelay"; interface Props { /** Already validated by `sanitizeRelayUrl` — this component never opens it. */ url: string; /** Heading above the URL. Says why the toast appeared. */ label?: string; onOpen: () => void; /** Open it in the container's own browser instead of the host's. Omitted when * the project has no browser to open it in. */ onOpenInContainer?: () => void; onDismiss: () => void; } /** * Confirmation prompt for a URL something inside the container wants opened in * the host browser. * * The origin is rendered separately from the rest of the URL and is never * truncated. A single `nowrap`/`ellipsis` line looks tidy but is a spoofing * primitive: `https://accounts.example.com/....(600 chars)....@evil.tld/` shows * the reassuring half and hides the half that decides where the request goes. * `sanitizeRelayUrl` already rejects the userinfo form; showing the origin in * full is the belt to that braces, and it also covers the plainer case of a * long path pushing the host out of view. * * Render this with a `key` that changes whenever the URL does. The prompt slot * is shared and long-lived, so without one React mutates the node in place: the * text swaps with no animation, and a user reading URL A can click Open on URL * B that arrived a second later. */ export default function UrlToast({ url, label = "Long URL detected", onOpen, onOpenInContainer, onDismiss, }: Props) { const origin = urlOrigin(url); const rest = origin && url.startsWith(origin) ? url.slice(origin.length) : url; return (