@mcp-b/react-components 0.38.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{CodeBlock-DO4Hdu1R.js → CodeBlock-CWk1FVtm.js} +1 -1
- package/dist/{FileTree-DbQMpvxV.js → FileTree-xqHYBw4g.js} +1 -1
- package/dist/{WorkspaceFileView-DeGzWwhK.js → WorkspaceFileView-Lab3om3F.js} +2 -2
- package/dist/components/agents-sdk/AgentActivity.js +1 -1
- package/dist/components/agents-sdk/AgentActivityPreview.js +1 -1
- package/dist/components/agents-sdk/AgentChat.js +7 -7
- package/dist/components/agents-sdk/BrowserLiveView.d.ts +73 -25
- package/dist/components/agents-sdk/BrowserLiveView.js +95 -65
- package/dist/components/agents-sdk/BrowserReplay.js +1 -1
- package/dist/components/agents-sdk/BrowserRunPanel.d.ts +72 -25
- package/dist/components/agents-sdk/BrowserRunPanel.js +109 -62
- package/dist/components/agents-sdk/McpConnectionRequest.js +1 -1
- package/dist/components/agents-sdk/McpPluginCatalog.js +1 -1
- package/dist/components/agents-sdk/McpServerPicker.js +1 -1
- package/dist/components/agents-sdk/ModelSelector.js +1 -1
- package/dist/components/agents-sdk/PromptInputCommands.js +1 -1
- package/dist/components/agents-sdk/SubagentRunIndicator.js +1 -1
- package/dist/components/agents-sdk/SubagentRunSelector.js +1 -1
- package/dist/components/agents-sdk/ThinkChatToolPanels.js +1 -1
- package/dist/components/agents-sdk/ThinkExecutionDetail.js +1 -1
- package/dist/components/agents-sdk/ThinkExecutionStatus.js +1 -1
- package/dist/components/agents-sdk/ThinkExecutionWorkbench.js +1 -1
- package/dist/components/agents-sdk/ThinkFullApp.js +8 -7
- package/dist/components/agents-sdk/ThinkRoutineBrowser.js +1 -1
- package/dist/components/agents-sdk/ThinkRoutineForm.js +1 -1
- package/dist/components/agents-sdk/ThinkRoutineLibrary.js +1 -1
- package/dist/components/agents-sdk/ThinkThreadPicker.js +1 -1
- package/dist/components/agents-sdk/WorkspaceBrowser.js +1 -1
- package/dist/components/agents-sdk/WorkspaceExplorer.js +1 -1
- package/dist/components/agents-sdk/WorkspaceFileView.js +1 -1
- package/dist/components/agents-sdk/WorkspaceHeader.js +1 -1
- package/dist/components/agents-sdk/WorkspaceMountManager.js +1 -1
- package/dist/components/ai-sdk/Activity.js +1 -1
- package/dist/components/ai-sdk/AgentChatStartScreen.js +1 -1
- package/dist/components/ai-sdk/Approval.js +1 -1
- package/dist/components/ai-sdk/Artifact.js +1 -1
- package/dist/components/ai-sdk/ChainOfThought.d.ts +1 -1
- package/dist/components/ai-sdk/ChainOfThought.js +1 -1
- package/dist/components/ai-sdk/Checkpoint.js +1 -1
- package/dist/components/ai-sdk/CodeBlock.js +1 -1
- package/dist/components/ai-sdk/Conversation.js +1 -1
- package/dist/components/ai-sdk/Goal.js +1 -1
- package/dist/components/ai-sdk/MediaPreviewCard.js +1 -1
- package/dist/components/ai-sdk/Message.js +1 -1
- package/dist/components/ai-sdk/MessageScroller.js +1 -1
- package/dist/components/ai-sdk/MessageScrollerVirtual.js +1 -1
- package/dist/components/ai-sdk/Plan.js +1 -1
- package/dist/components/ai-sdk/PromptInput.js +1 -1
- package/dist/components/ai-sdk/Queue.js +1 -1
- package/dist/components/ai-sdk/Reasoning.js +1 -1
- package/dist/components/ai-sdk/Sources.js +1 -1
- package/dist/components/ai-sdk/Task.js +1 -1
- package/dist/components/extension/ChatGptSignInScreen.d.ts +21 -10
- package/dist/components/extension/ChatGptSignInScreen.js +42 -34
- package/dist/components/extension/CodexModelSelector.js +1 -1
- package/dist/components/extension/ConversationTabPicker.js +1 -1
- package/dist/components/foundations/Checkbox.js +1 -1
- package/dist/components/foundations/ContextMenu.js +1 -1
- package/dist/components/foundations/EmptyState.d.ts +10 -0
- package/dist/components/foundations/EmptyState.js +10 -0
- package/dist/components/foundations/Menubar.js +1 -1
- package/dist/components/foundations/SearchField.js +1 -1
- package/dist/components/foundations/Select.js +1 -1
- package/dist/components/foundations/Stepper.js +1 -1
- package/dist/components/foundations/Toast.js +1 -1
- package/dist/components/foundations/icons.d.ts +2 -2
- package/dist/components/foundations/icons.js +2 -2
- package/dist/components/general-purpose/Commit.js +2 -2
- package/dist/components/general-purpose/EnvironmentVariables.js +2 -2
- package/dist/components/general-purpose/FileTree.js +1 -1
- package/dist/components/general-purpose/PricingPlanCard.js +1 -1
- package/dist/components/general-purpose/ResponsiveSidebarShell.js +1 -1
- package/dist/components/general-purpose/SetupChecklist.js +1 -1
- package/dist/components/general-purpose/Terminal.js +2 -2
- package/dist/components/general-purpose/TestResults.js +1 -1
- package/dist/components/general-purpose/ThemeModeControl.js +1 -1
- package/dist/components/general-purpose/WebPreview.js +1 -1
- package/dist/components/nanites/AgentConnection.js +2 -2
- package/dist/components/nanites/AgentToolDetail.js +1 -1
- package/dist/{copy-button-4YvddK4e.js → copy-button-Bc7jsYv_.js} +1 -1
- package/dist/{icons-BGZ916hb.d.ts → icons-DwgNir1Q.d.ts} +6 -1
- package/dist/{icons-B4mGvCvc.js → icons-MmIXciMO.js} +3 -2
- package/dist/styles/agent-chat.css +2 -2
- package/dist/styles/base.css +4 -0
- package/dist/styles/browser-live-view.css +45 -0
- package/dist/styles/browser-run-panel.css +3 -1
- package/dist/styles/chatgpt-sign-in-screen.css +6 -0
- package/dist/styles/think-full-app.css +14 -0
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as cx } from "./class-names-BiMDVpUo.js";
|
|
2
2
|
import { Select } from "./components/foundations/Select.js";
|
|
3
|
-
import { t as CopyButton } from "./copy-button-
|
|
3
|
+
import { t as CopyButton } from "./copy-button-Bc7jsYv_.js";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { createHighlighter } from "shiki";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as cx } from "./class-names-BiMDVpUo.js";
|
|
2
|
-
import { C as FileIcon, T as FolderOpenIcon, m as ChevronRightIcon, w as FolderIcon } from "./icons-
|
|
2
|
+
import { C as FileIcon, T as FolderOpenIcon, m as ChevronRightIcon, w as FolderIcon } from "./icons-MmIXciMO.js";
|
|
3
3
|
import { t as NavigationLink } from "./navigation-link-kqMa81v5.js";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as CheckIcon, h as CodeIcon, j as MaximizeIcon, nt as WarningIcon, r as ArrowLeftIcon, x as EyeIcon, y as DownloadIcon } from "./icons-MmIXciMO.js";
|
|
2
2
|
import { r as formatClock } from "./format-DB2mX9DA.js";
|
|
3
|
-
import { a as CodeBlockCopyButton, i as CodeBlockContent, r as CodeBlockContainer, t as CodeBlock } from "./CodeBlock-
|
|
3
|
+
import { a as CodeBlockCopyButton, i as CodeBlockContent, r as CodeBlockContainer, t as CodeBlock } from "./CodeBlock-CWk1FVtm.js";
|
|
4
4
|
import { AppTopBar } from "./components/general-purpose/AppTopBar.js";
|
|
5
5
|
import { inferWorkspaceLanguage, inferWorkspaceMedia, isWorkspaceMarkdownPath, isWorkspaceSkillPath, parseWorkspaceSkill } from "./components/agents-sdk/WorkspaceFile.js";
|
|
6
6
|
import { c as useWorkspaceNavigationContext, s as useWorkspaceNavigationRestoration } from "./WorkspaceLink-DtH66bAY.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { inferFaviconUrl } from "../../utils/favicon.js";
|
|
2
|
-
import {
|
|
2
|
+
import { A as LinkIcon, C as FileIcon, I as MonitorIcon, K as SearchIcon, O as InfoIcon, V as PencilIcon, et as TerminalIcon, nt as WarningIcon, rt as WrenchIcon } from "../../icons-MmIXciMO.js";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/agents-sdk/AgentActivity.tsx
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as cx } from "../../class-names-BiMDVpUo.js";
|
|
2
|
-
import { C as FileIcon,
|
|
2
|
+
import { C as FileIcon, M as McpIcon, Y as SpinnerIcon, it as XIcon, nt as WarningIcon } from "../../icons-MmIXciMO.js";
|
|
3
3
|
import { ActivityHeader } from "../ai-sdk/Activity.js";
|
|
4
4
|
import { Button } from "../foundations/Button.js";
|
|
5
5
|
import { t as NavigationLink } from "../../navigation-link-kqMa81v5.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as cx } from "../../class-names-BiMDVpUo.js";
|
|
2
2
|
import { ExpansionStateProvider } from "../ai-sdk/ExpansionState.js";
|
|
3
|
-
import {
|
|
3
|
+
import { G as RefreshIcon, R as MoveToFrontIcon, U as PlusIcon, V as PencilIcon, W as QueueIcon, Y as SpinnerIcon, t as ArchiveIcon, tt as TrashIcon } from "../../icons-MmIXciMO.js";
|
|
4
4
|
import { Button } from "../foundations/Button.js";
|
|
5
5
|
import { AgentChatMessageEditor } from "../ai-sdk/AgentChatMessageEditor.js";
|
|
6
6
|
import { IconButton } from "../foundations/IconButton.js";
|
|
@@ -10,7 +10,7 @@ import { AgentChatStartScreen } from "../ai-sdk/AgentChatStartScreen.js";
|
|
|
10
10
|
import { Message, MessageAction, MessageActions } from "../ai-sdk/Message.js";
|
|
11
11
|
import { AgentMessageParts } from "../ai-sdk/AgentMessageParts.js";
|
|
12
12
|
import { Marker, MarkerContent } from "../foundations/Marker.js";
|
|
13
|
-
import { t as CopyButton } from "../../copy-button-
|
|
13
|
+
import { t as CopyButton } from "../../copy-button-Bc7jsYv_.js";
|
|
14
14
|
import { Context, ContextContent, ContextContentBody, ContextContentHeader, ContextTrigger, getContextUsage, getContextUsedTokens } from "../ai-sdk/Context.js";
|
|
15
15
|
import { VirtualMessageScroller } from "../ai-sdk/MessageScrollerVirtual.js";
|
|
16
16
|
import { QueueItem, QueueItemActions, QueueItemContent } from "../ai-sdk/Queue.js";
|
|
@@ -666,13 +666,13 @@ function AgentChat({ className, messages, status = "ready", onSubmit, showCompos
|
|
|
666
666
|
"aria-atomic": "true",
|
|
667
667
|
children: copyAnnouncement
|
|
668
668
|
}),
|
|
669
|
-
loading ? /* @__PURE__ */
|
|
669
|
+
loading ? /* @__PURE__ */ jsx("div", {
|
|
670
670
|
className: "agent-chat__transcript-loading",
|
|
671
671
|
role: "status",
|
|
672
|
-
children:
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
})
|
|
672
|
+
children: /* @__PURE__ */ jsx(EmptyState, {
|
|
673
|
+
icon: /* @__PURE__ */ jsx(SpinnerIcon, {}),
|
|
674
|
+
description: "Loading conversation"
|
|
675
|
+
})
|
|
676
676
|
}) : showsStartScreen ? /* @__PURE__ */ jsx(AgentChatStartScreen, {
|
|
677
677
|
...startScreenProps,
|
|
678
678
|
composer
|
|
@@ -2,27 +2,85 @@ import * as React from "react";
|
|
|
2
2
|
import { BrowserLiveViewUrl } from "agents/browser";
|
|
3
3
|
|
|
4
4
|
//#region src/components/agents-sdk/BrowserLiveView.d.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
receivedAt?: number;
|
|
10
|
-
/** The page the session was showing — used for the ended-state text. */
|
|
5
|
+
/** Where a live view is in its lifecycle, however the pixels arrive. */
|
|
6
|
+
type BrowserLiveViewPhase = "connecting" | "streaming" | "reconnecting" | "idle" | "failed";
|
|
7
|
+
interface BrowserLiveViewCommonProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
/** The page being shown — names the surface and labels its ended state. */
|
|
11
9
|
pageTitle?: string;
|
|
12
10
|
/**
|
|
13
|
-
*
|
|
11
|
+
* Replaces the built-in text for the current phase — e.g. a failure reason.
|
|
12
|
+
* Set it while the view is live and it reads as a notice over the picture,
|
|
13
|
+
* which is where a fault that does not end the session belongs.
|
|
14
|
+
*/
|
|
15
|
+
statusLabel?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Shown once the view stops — pass the last screenshot the agent took
|
|
14
18
|
* (`<img>`) to keep the final frame on screen. Defaults to a quiet
|
|
15
19
|
* "Live view ended" state.
|
|
16
20
|
*/
|
|
17
21
|
fallback?: React.ReactNode;
|
|
22
|
+
/** Omits the expand control for a view that already fills its viewport. */
|
|
23
|
+
expandable?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Takes the whole container instead of standing in it as a 16/10 card.
|
|
26
|
+
* The card treatment — the aspect box, the hairline, the rounded corners —
|
|
27
|
+
* is there to separate the view from what sits beside it; a view that is
|
|
28
|
+
* the entire surface, as it is on a phone, has nothing to separate from and
|
|
29
|
+
* spends real pixels saying so. Usually paired with `expandable={false}`,
|
|
30
|
+
* since there is nowhere larger to expand into.
|
|
31
|
+
*/
|
|
32
|
+
fill?: boolean;
|
|
18
33
|
}
|
|
34
|
+
type BrowserLiveViewProps = BrowserLiveViewCommonProps & ({
|
|
35
|
+
/** Complete upstream value returned by `cdp.getLiveViewUrl()`. */source: BrowserLiveViewUrl; /** Epoch ms when `source` was received. Defaults to its first render. */
|
|
36
|
+
receivedAt?: number;
|
|
37
|
+
renderMedia?: never;
|
|
38
|
+
phase?: never;
|
|
39
|
+
} | {
|
|
40
|
+
/**
|
|
41
|
+
* The picture, drawn by the host — a `<video>` on its own transport, a
|
|
42
|
+
* canvas, whatever it carries. Called once per placement because
|
|
43
|
+
* neither a video nor an iframe can occupy two places at once.
|
|
44
|
+
*
|
|
45
|
+
* Remote-control surfaces belong in here too: coordinate mapping and
|
|
46
|
+
* key handling are the host's, since only it knows what its input API
|
|
47
|
+
* expects. This component owns the frame around them. An overlay drawn
|
|
48
|
+
* here covers the picture and stays under the frame's own chrome, so a
|
|
49
|
+
* control surface can take every pointer the picture gets without
|
|
50
|
+
* swallowing the Live badge or the expand control.
|
|
51
|
+
*
|
|
52
|
+
* `statusId` names whatever element currently states the phase, for a
|
|
53
|
+
* control surface to point `aria-describedby` at.
|
|
54
|
+
*/
|
|
55
|
+
renderMedia: (placement: "inline" | "dialog", statusId: string) => React.ReactNode; /** The host draws, so the host owns the lifecycle. A URL derives its own. */
|
|
56
|
+
phase: BrowserLiveViewPhase;
|
|
57
|
+
source?: never;
|
|
58
|
+
receivedAt?: never;
|
|
59
|
+
});
|
|
19
60
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
61
|
+
* A live, interactive view of an agent's browser session.
|
|
62
|
+
*
|
|
63
|
+
* It takes the session either way round. Give it `source` — a Browser Run
|
|
64
|
+
* `BrowserLiveViewUrl` — and it embeds the hosted viewer, expiring the frame
|
|
65
|
+
* on its own once `expiresInMs` passes. Give it `renderMedia` and a `phase`
|
|
66
|
+
* instead and the host draws the picture on its own transport while this keeps
|
|
67
|
+
* the frame around it. The Live badge, the connecting overlay, the ended
|
|
68
|
+
* state, and the fullscreen expand are the same either way, because to the
|
|
69
|
+
* person watching it is the same thing.
|
|
70
|
+
*
|
|
71
|
+
* `fill` drops the card treatment for a view that is the whole surface rather
|
|
72
|
+
* than a block on one — the phone's screen, or a panel that already sizes
|
|
73
|
+
* itself. Everything else about the frame is unchanged.
|
|
74
|
+
*
|
|
75
|
+
* A host-drawn view keeps its own input surface, because coordinate mapping
|
|
76
|
+
* and key handling depend on what the host's input API expects — a screencast
|
|
77
|
+
* wants CSS pixels offset by its viewport, and nothing generic here could know
|
|
78
|
+
* that. This component owns the frame; the host owns the picture and control.
|
|
79
|
+
*
|
|
80
|
+
* The two sources differ in what the host must trust. A hosted URL embeds a
|
|
81
|
+
* third-party origin and runs its script; the iframe is unsandboxed by design
|
|
82
|
+
* because the viewer needs scripts and its own origin to stream the session,
|
|
83
|
+
* so only pass trusted Live View URLs. Host-drawn media embeds no origin.
|
|
26
84
|
*
|
|
27
85
|
* Where URLs come from (upstream: `agents/browser` in
|
|
28
86
|
* github.com/cloudflare/agents — `BrowserLiveViewUrl`): the model calls
|
|
@@ -32,17 +90,7 @@ interface BrowserLiveViewProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
32
90
|
*
|
|
33
91
|
* Styling rides `@mcp-b/react-components/styles` (browser-live-view.css),
|
|
34
92
|
* which think-chat consumers load anyway.
|
|
35
|
-
*
|
|
36
|
-
* The iframe is unsandboxed by design: the hosted Live View UI needs scripts
|
|
37
|
-
* and its own origin to stream the session. Only pass trusted Live View URLs.
|
|
38
93
|
*/
|
|
39
|
-
declare function BrowserLiveView(
|
|
40
|
-
source,
|
|
41
|
-
receivedAt,
|
|
42
|
-
pageTitle,
|
|
43
|
-
fallback,
|
|
44
|
-
className,
|
|
45
|
-
...props
|
|
46
|
-
}: BrowserLiveViewProps): React.JSX.Element;
|
|
94
|
+
declare function BrowserLiveView(props: BrowserLiveViewProps): React.JSX.Element;
|
|
47
95
|
//#endregion
|
|
48
|
-
export { BrowserLiveView, BrowserLiveViewProps };
|
|
96
|
+
export { BrowserLiveView, BrowserLiveViewPhase, BrowserLiveViewProps };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as cx } from "../../class-names-BiMDVpUo.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Y as SpinnerIcon, j as MaximizeIcon } from "../../icons-MmIXciMO.js";
|
|
3
3
|
import { Button } from "../foundations/Button.js";
|
|
4
4
|
import { Dialog } from "../foundations/Dialog.js";
|
|
5
5
|
import { StatusPill } from "../foundations/StatusPill.js";
|
|
@@ -8,6 +8,13 @@ import * as React from "react";
|
|
|
8
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/components/agents-sdk/BrowserLiveView.tsx
|
|
10
10
|
const FRAME_LOAD_TIMEOUT_MS = 15e3;
|
|
11
|
+
const PHASE_TEXT = {
|
|
12
|
+
connecting: "Connecting live view…",
|
|
13
|
+
streaming: "Live",
|
|
14
|
+
reconnecting: "Reconnecting live view…",
|
|
15
|
+
idle: "Live view ended",
|
|
16
|
+
failed: "Live view unavailable"
|
|
17
|
+
};
|
|
11
18
|
function EndedState({ title, detail }) {
|
|
12
19
|
return /* @__PURE__ */ jsxs("div", {
|
|
13
20
|
className: "browser-live-view__ended",
|
|
@@ -21,12 +28,29 @@ function EndedState({ title, detail }) {
|
|
|
21
28
|
});
|
|
22
29
|
}
|
|
23
30
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
31
|
+
* A live, interactive view of an agent's browser session.
|
|
32
|
+
*
|
|
33
|
+
* It takes the session either way round. Give it `source` — a Browser Run
|
|
34
|
+
* `BrowserLiveViewUrl` — and it embeds the hosted viewer, expiring the frame
|
|
35
|
+
* on its own once `expiresInMs` passes. Give it `renderMedia` and a `phase`
|
|
36
|
+
* instead and the host draws the picture on its own transport while this keeps
|
|
37
|
+
* the frame around it. The Live badge, the connecting overlay, the ended
|
|
38
|
+
* state, and the fullscreen expand are the same either way, because to the
|
|
39
|
+
* person watching it is the same thing.
|
|
40
|
+
*
|
|
41
|
+
* `fill` drops the card treatment for a view that is the whole surface rather
|
|
42
|
+
* than a block on one — the phone's screen, or a panel that already sizes
|
|
43
|
+
* itself. Everything else about the frame is unchanged.
|
|
44
|
+
*
|
|
45
|
+
* A host-drawn view keeps its own input surface, because coordinate mapping
|
|
46
|
+
* and key handling depend on what the host's input API expects — a screencast
|
|
47
|
+
* wants CSS pixels offset by its viewport, and nothing generic here could know
|
|
48
|
+
* that. This component owns the frame; the host owns the picture and control.
|
|
49
|
+
*
|
|
50
|
+
* The two sources differ in what the host must trust. A hosted URL embeds a
|
|
51
|
+
* third-party origin and runs its script; the iframe is unsandboxed by design
|
|
52
|
+
* because the viewer needs scripts and its own origin to stream the session,
|
|
53
|
+
* so only pass trusted Live View URLs. Host-drawn media embeds no origin.
|
|
30
54
|
*
|
|
31
55
|
* Where URLs come from (upstream: `agents/browser` in
|
|
32
56
|
* github.com/cloudflare/agents — `BrowserLiveViewUrl`): the model calls
|
|
@@ -36,22 +60,21 @@ function EndedState({ title, detail }) {
|
|
|
36
60
|
*
|
|
37
61
|
* Styling rides `@mcp-b/react-components/styles` (browser-live-view.css),
|
|
38
62
|
* which think-chat consumers load anyway.
|
|
39
|
-
*
|
|
40
|
-
* The iframe is unsandboxed by design: the hosted Live View UI needs scripts
|
|
41
|
-
* and its own origin to stream the session. Only pass trusted Live View URLs.
|
|
42
63
|
*/
|
|
43
|
-
function BrowserLiveView(
|
|
44
|
-
const
|
|
64
|
+
function BrowserLiveView(props) {
|
|
65
|
+
const { source, receivedAt, renderMedia, phase, pageTitle, statusLabel, fallback, expandable = true, fill, className, ...rest } = props;
|
|
66
|
+
const [expired, setExpired] = React.useState(() => source !== void 0 && receivedAt !== void 0 && receivedAt + source.expiresInMs <= Date.now());
|
|
45
67
|
const [reportedFrameState, setReportedFrameState] = React.useState(() => ({
|
|
46
|
-
url: source
|
|
68
|
+
url: source?.url ?? "",
|
|
47
69
|
value: "loading"
|
|
48
70
|
}));
|
|
49
|
-
if (reportedFrameState.url !== source.url) setReportedFrameState({
|
|
71
|
+
if (source && reportedFrameState.url !== source.url) setReportedFrameState({
|
|
50
72
|
url: source.url,
|
|
51
73
|
value: "loading"
|
|
52
74
|
});
|
|
53
|
-
const frameState = reportedFrameState.url === source.url ? reportedFrameState.value : "loading";
|
|
75
|
+
const frameState = source && reportedFrameState.url === source.url ? reportedFrameState.value : "loading";
|
|
54
76
|
React.useEffect(() => {
|
|
77
|
+
if (!source) return;
|
|
55
78
|
const remaining = (receivedAt ?? Date.now()) + source.expiresInMs - Date.now();
|
|
56
79
|
if (remaining <= 0) {
|
|
57
80
|
setExpired(true);
|
|
@@ -60,57 +83,71 @@ function BrowserLiveView({ source, receivedAt, pageTitle, fallback, className, .
|
|
|
60
83
|
setExpired(false);
|
|
61
84
|
const timer = setTimeout(() => setExpired(true), remaining);
|
|
62
85
|
return () => clearTimeout(timer);
|
|
63
|
-
}, [
|
|
64
|
-
receivedAt,
|
|
65
|
-
source.expiresInMs,
|
|
66
|
-
source.targetId,
|
|
67
|
-
source.url
|
|
68
|
-
]);
|
|
86
|
+
}, [receivedAt, source]);
|
|
69
87
|
React.useEffect(() => {
|
|
70
|
-
if (frameState !== "loading") return;
|
|
88
|
+
if (!source || frameState !== "loading") return;
|
|
71
89
|
const url = source.url;
|
|
72
90
|
const timer = setTimeout(() => setReportedFrameState({
|
|
73
91
|
url,
|
|
74
92
|
value: "failed"
|
|
75
93
|
}), FRAME_LOAD_TIMEOUT_MS);
|
|
76
94
|
return () => clearTimeout(timer);
|
|
77
|
-
}, [frameState, source
|
|
78
|
-
const
|
|
79
|
-
const live =
|
|
95
|
+
}, [frameState, source]);
|
|
96
|
+
const activePhase = source ? expired ? "idle" : frameState === "failed" ? "failed" : frameState === "loading" ? "connecting" : "streaming" : phase ?? "connecting";
|
|
97
|
+
const live = activePhase === "streaming";
|
|
98
|
+
const connecting = activePhase === "connecting" || activePhase === "reconnecting";
|
|
80
99
|
const frameTitle = pageTitle ? `Live browser view — ${pageTitle}` : "Live browser view";
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
const statusId = React.useId();
|
|
101
|
+
const renderView = (placement) => {
|
|
102
|
+
const placementStatusId = `${statusId}-${placement}`;
|
|
103
|
+
if (!live && !connecting) return fallback ?? /* @__PURE__ */ jsx(EndedState, {
|
|
104
|
+
title: statusLabel ?? PHASE_TEXT[activePhase],
|
|
105
|
+
detail: pageTitle
|
|
106
|
+
});
|
|
107
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
108
|
+
live && placement === "inline" ? /* @__PURE__ */ jsx(StatusPill, {
|
|
109
|
+
busy: true,
|
|
110
|
+
size: "sm",
|
|
111
|
+
color: "destructive",
|
|
112
|
+
className: "browser-live-view__badge",
|
|
113
|
+
children: "Live"
|
|
114
|
+
}) : null,
|
|
115
|
+
source ? placement === "dialog" ? /* @__PURE__ */ jsx("iframe", {
|
|
116
|
+
src: source.url,
|
|
117
|
+
title: frameTitle,
|
|
118
|
+
allow: "clipboard-read; clipboard-write"
|
|
119
|
+
}) : /* @__PURE__ */ jsx("iframe", {
|
|
120
|
+
className: "browser-live-view__frame",
|
|
121
|
+
src: source.url,
|
|
122
|
+
title: frameTitle,
|
|
123
|
+
allow: "clipboard-read; clipboard-write",
|
|
124
|
+
onLoad: () => setReportedFrameState({
|
|
125
|
+
url: source.url,
|
|
126
|
+
value: "ready"
|
|
127
|
+
})
|
|
128
|
+
}, source.url) : renderMedia?.(placement, placementStatusId),
|
|
129
|
+
connecting ? /* @__PURE__ */ jsxs(TransitionSurface, {
|
|
130
|
+
className: "browser-live-view__state",
|
|
131
|
+
id: placementStatusId,
|
|
132
|
+
role: "status",
|
|
133
|
+
children: [/* @__PURE__ */ jsx(SpinnerIcon, {}), statusLabel ?? PHASE_TEXT[activePhase]]
|
|
134
|
+
}) : null,
|
|
135
|
+
live && statusLabel ? /* @__PURE__ */ jsx("p", {
|
|
136
|
+
className: "browser-live-view__notice",
|
|
137
|
+
id: placementStatusId,
|
|
138
|
+
role: "status",
|
|
139
|
+
children: statusLabel
|
|
140
|
+
}) : null
|
|
141
|
+
] });
|
|
142
|
+
};
|
|
108
143
|
return /* @__PURE__ */ jsxs("div", {
|
|
109
|
-
...
|
|
144
|
+
...rest,
|
|
110
145
|
className: cx("browser-live-view", className),
|
|
111
|
-
"data-expired":
|
|
112
|
-
"data-
|
|
113
|
-
|
|
146
|
+
"data-expired": activePhase === "idle" || activePhase === "failed" || void 0,
|
|
147
|
+
"data-fill": fill || void 0,
|
|
148
|
+
"data-frame-state": source ? frameState : void 0,
|
|
149
|
+
"data-phase": activePhase,
|
|
150
|
+
children: [renderView("inline"), expandable ? /* @__PURE__ */ jsxs(Dialog.Root, { children: [/* @__PURE__ */ jsx(Dialog.Trigger, { render: /* @__PURE__ */ jsx(Button, {
|
|
114
151
|
variant: "ghost",
|
|
115
152
|
color: "neutral",
|
|
116
153
|
size: "sm",
|
|
@@ -126,16 +163,9 @@ function BrowserLiveView({ source, receivedAt, pageTitle, fallback, className, .
|
|
|
126
163
|
children: frameTitle
|
|
127
164
|
}), /* @__PURE__ */ jsx("div", {
|
|
128
165
|
className: "browser-live-view__dialog-body",
|
|
129
|
-
children:
|
|
130
|
-
src: source.url,
|
|
131
|
-
title: frameTitle,
|
|
132
|
-
allow: "clipboard-read; clipboard-write"
|
|
133
|
-
}) : fallback ?? /* @__PURE__ */ jsx(EndedState, {
|
|
134
|
-
title: failed ? "Live view unavailable" : "Live view ended",
|
|
135
|
-
detail: pageTitle
|
|
136
|
-
})
|
|
166
|
+
children: renderView("dialog")
|
|
137
167
|
})]
|
|
138
|
-
}) })] })] })]
|
|
168
|
+
}) })] })] }) : null]
|
|
139
169
|
});
|
|
140
170
|
}
|
|
141
171
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as cx } from "../../class-names-BiMDVpUo.js";
|
|
2
|
-
import {
|
|
2
|
+
import { B as PauseIcon, H as PlayIcon } from "../../icons-MmIXciMO.js";
|
|
3
3
|
import { IconButton } from "../foundations/IconButton.js";
|
|
4
4
|
import { r as formatClock } from "../../format-DB2mX9DA.js";
|
|
5
5
|
import { EmptyState } from "../foundations/EmptyState.js";
|
|
@@ -2,7 +2,26 @@ import * as React from "react";
|
|
|
2
2
|
import { BrowserLiveView } from "agents/browser";
|
|
3
3
|
|
|
4
4
|
//#region src/components/agents-sdk/BrowserRunPanel.d.ts
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* One entry of the drawn tab strip. The panel synthesizes browser chrome
|
|
7
|
+
* around content Chrome itself never paints, so a tab is whatever record of a
|
|
8
|
+
* page the host holds — a Browser Run target, a claimed extension tab — cut
|
|
9
|
+
* down to the identity and words the strip needs.
|
|
10
|
+
*/
|
|
11
|
+
interface BrowserRunPanelTab {
|
|
12
|
+
/** Stable identity; the strip's selection value. Hosts stringify their own ids. */
|
|
13
|
+
id: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
url?: string;
|
|
16
|
+
}
|
|
17
|
+
interface BrowserRunPanelCommonProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
18
|
+
/** Error from the host's browser session or transport. */
|
|
19
|
+
error?: React.ReactNode;
|
|
20
|
+
/** Panel heading. */
|
|
21
|
+
label?: React.ReactNode;
|
|
22
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
23
|
+
}
|
|
24
|
+
interface BrowserRunPanelHostedProps extends BrowserRunPanelCommonProps {
|
|
6
25
|
/** Host-side Browser Run Live View data from `connector.liveView()`. */
|
|
7
26
|
liveView?: BrowserLiveView;
|
|
8
27
|
/** Refreshes the Live View URL before it expires. */
|
|
@@ -11,36 +30,64 @@ interface BrowserRunPanelProps extends Omit<React.HTMLAttributes<HTMLDivElement>
|
|
|
11
30
|
onCloseSession?: () => void | Promise<void>;
|
|
12
31
|
/** True while the app is fetching Live View data. */
|
|
13
32
|
loading?: boolean;
|
|
14
|
-
/** Error from the app-owned browser session fetch/refresh path. */
|
|
15
|
-
error?: React.ReactNode;
|
|
16
|
-
/** Panel heading. */
|
|
17
|
-
label?: React.ReactNode;
|
|
18
33
|
/** Empty state shown when there is no shared browser session. */
|
|
19
34
|
empty?: React.ReactNode;
|
|
20
35
|
/** Fallback passed through to `BrowserLiveView` after URL expiry/failure. */
|
|
21
36
|
fallback?: React.ReactNode;
|
|
37
|
+
children?: never;
|
|
38
|
+
tabs?: never;
|
|
39
|
+
selectedTabId?: never;
|
|
40
|
+
onSelectTab?: never;
|
|
41
|
+
url?: never;
|
|
42
|
+
onOpenUrl?: never;
|
|
43
|
+
urlPlaceholder?: never;
|
|
44
|
+
urlDisabled?: never;
|
|
45
|
+
urlLabel?: never;
|
|
46
|
+
navigation?: never;
|
|
47
|
+
}
|
|
48
|
+
interface BrowserRunPanelStreamedProps extends BrowserRunPanelCommonProps {
|
|
49
|
+
/**
|
|
50
|
+
* The host's own browser surface — typically a `BrowserLiveView` carrying a
|
|
51
|
+
* host-fed stream. The panel frames it with the drawn tab strip and address
|
|
52
|
+
* bar; the host keeps everything transport: media, input, reconnection.
|
|
53
|
+
*/
|
|
54
|
+
children: React.ReactNode;
|
|
55
|
+
/** The drawn tab strip; it renders only with more than one entry. */
|
|
56
|
+
tabs?: readonly BrowserRunPanelTab[];
|
|
57
|
+
/** Controlled selection over `tabs`; null selects nothing. */
|
|
58
|
+
selectedTabId?: string | null;
|
|
59
|
+
/** A viewer picked a tab it is not watching; the host grants or ignores it. */
|
|
60
|
+
onSelectTab?: (tabId: string) => void;
|
|
61
|
+
/** Address bar value: the streamed page's current URL. */
|
|
62
|
+
url?: string;
|
|
63
|
+
/** Commits an address-bar entry. Absent, the address bar is read-only. */
|
|
64
|
+
onOpenUrl?: (url: string) => void;
|
|
65
|
+
urlPlaceholder?: string;
|
|
66
|
+
urlDisabled?: boolean;
|
|
67
|
+
/** Accessible name for the address input. */
|
|
68
|
+
urlLabel?: string;
|
|
69
|
+
/** Navigation controls before the address input, e.g. Back and Reload. */
|
|
70
|
+
navigation?: React.ReactNode;
|
|
71
|
+
liveView?: never;
|
|
72
|
+
onRefresh?: never;
|
|
73
|
+
onCloseSession?: never;
|
|
74
|
+
loading?: never;
|
|
75
|
+
empty?: never;
|
|
76
|
+
fallback?: never;
|
|
22
77
|
}
|
|
78
|
+
type BrowserRunPanelProps = BrowserRunPanelHostedProps | BrowserRunPanelStreamedProps;
|
|
23
79
|
/**
|
|
24
|
-
*
|
|
80
|
+
* Browser panel chrome — drawn tab strip, address bar, framed body — for
|
|
81
|
+
* browser surfaces Chrome itself never paints.
|
|
25
82
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
83
|
+
* Two hosts fill it in. A Browser Run host passes upstream `BrowserLiveView`
|
|
84
|
+
* data from `connector.liveView()`, and the panel derives tabs, address, and
|
|
85
|
+
* an embedded live view itself, calling app-provided refresh/close callbacks.
|
|
86
|
+
* A streaming host instead passes `children` — its own live surface — with
|
|
87
|
+
* the tab strip, address bar, and navigation controlled from the host's own
|
|
88
|
+
* records, because a remote screencast carries only page pixels and every
|
|
89
|
+
* piece of chrome around it has to be synthesized from host state.
|
|
29
90
|
*/
|
|
30
|
-
declare function BrowserRunPanel(
|
|
31
|
-
liveView,
|
|
32
|
-
onRefresh,
|
|
33
|
-
onCloseSession,
|
|
34
|
-
loading,
|
|
35
|
-
error,
|
|
36
|
-
label,
|
|
37
|
-
empty,
|
|
38
|
-
fallback,
|
|
39
|
-
className,
|
|
40
|
-
ref,
|
|
41
|
-
...props
|
|
42
|
-
}: BrowserRunPanelProps & {
|
|
43
|
-
ref?: React.Ref<HTMLDivElement>;
|
|
44
|
-
}): React.JSX.Element;
|
|
91
|
+
declare function BrowserRunPanel(props: BrowserRunPanelProps): React.JSX.Element;
|
|
45
92
|
//#endregion
|
|
46
|
-
export { BrowserRunPanel, BrowserRunPanelProps };
|
|
93
|
+
export { BrowserRunPanel, BrowserRunPanelProps, BrowserRunPanelTab };
|