@mcp-b/react-components 0.50.0 → 0.51.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/components/agents-sdk/AgentChat.js +2 -3
- package/dist/components/agents-sdk/BrowserLiveScreen.d.ts +8 -7
- package/dist/components/agents-sdk/BrowserLiveScreen.js +16 -21
- package/dist/components/agents-sdk/SubagentRunPanel.js +1 -1
- package/dist/styles/agent-chat.css +12 -4
- package/dist/styles/message.css +4 -0
- package/package.json +2 -2
|
@@ -252,7 +252,7 @@ function AgentChatActions({ children, ...props }) {
|
|
|
252
252
|
const { messages, busy } = useAgentChatRuntime();
|
|
253
253
|
const number = messages.slice(0, messageIndex + 1).filter((m) => m.role === message.role && !isCompactionMessage(m) && !getAgentEvent(m)).length;
|
|
254
254
|
const unavailable = busy && (message.role === "user" ? message.id === messages.findLast((item) => item.role === "user" && !getAgentEvent(item))?.id : message.id === messages.at(-1)?.id);
|
|
255
|
-
|
|
255
|
+
return /* @__PURE__ */ jsx(MessageMeta, { children: /* @__PURE__ */ jsx(MessageActions, {
|
|
256
256
|
reserveSpace: message.role === "assistant",
|
|
257
257
|
"aria-label": `Actions for ${message.role === "assistant" ? "response" : "message"} ${number}`,
|
|
258
258
|
"data-unavailable": unavailable ? true : void 0,
|
|
@@ -260,8 +260,7 @@ function AgentChatActions({ children, ...props }) {
|
|
|
260
260
|
inert: unavailable ? true : void 0,
|
|
261
261
|
...props,
|
|
262
262
|
children
|
|
263
|
-
});
|
|
264
|
-
return message.role === "user" ? /* @__PURE__ */ jsx(MessageMeta, { children: actions }) : actions;
|
|
263
|
+
}) });
|
|
265
264
|
}
|
|
266
265
|
function AgentChatCopyAction() {
|
|
267
266
|
const { message, messageIndex } = useChatMessage();
|
|
@@ -14,6 +14,7 @@ type BrowserLiveScreenSignal = {
|
|
|
14
14
|
type BrowserLiveScreenSignalPayload = {
|
|
15
15
|
kind: "offer";
|
|
16
16
|
sdp: string;
|
|
17
|
+
tabId: number;
|
|
17
18
|
} | {
|
|
18
19
|
kind: "answer";
|
|
19
20
|
sdp: string;
|
|
@@ -70,9 +71,6 @@ type BrowserLiveScreenInput = {
|
|
|
70
71
|
events: BrowserLiveScreenInputEvent[];
|
|
71
72
|
};
|
|
72
73
|
type BrowserLiveScreenCommand = {
|
|
73
|
-
kind: "selectTab";
|
|
74
|
-
tabId: number;
|
|
75
|
-
} | {
|
|
76
74
|
kind: "navigate";
|
|
77
75
|
tabId: number;
|
|
78
76
|
action: "back" | "reload";
|
|
@@ -111,14 +109,16 @@ interface BrowserLiveScreenProps {
|
|
|
111
109
|
* from state, because Chrome's screencast carries only page pixels.
|
|
112
110
|
*/
|
|
113
111
|
tabs?: readonly BrowserLiveScreenTab[];
|
|
114
|
-
/**
|
|
115
|
-
|
|
112
|
+
/** The host owns this viewer's tab selection, typically in its route. */
|
|
113
|
+
tabId?: number;
|
|
114
|
+
/** Requests a new tab selection; the host commits it through `tabId`. */
|
|
115
|
+
onTabChange(this: void, tabId: number): void;
|
|
116
116
|
}
|
|
117
117
|
/**
|
|
118
118
|
* A complete interactive viewer for an employee's claimed browser tabs.
|
|
119
119
|
*
|
|
120
120
|
* The host supplies only signaling transport, ICE configuration, and claimed
|
|
121
|
-
* tab summaries. This component owns the peer connection, remote-input
|
|
121
|
+
* tab summaries and selection. This component owns the peer connection, remote-input
|
|
122
122
|
* mapping, reconnect lifecycle, synthesized browser chrome, and cleanup.
|
|
123
123
|
*/
|
|
124
124
|
declare function BrowserLiveScreen({
|
|
@@ -129,7 +129,8 @@ declare function BrowserLiveScreen({
|
|
|
129
129
|
label,
|
|
130
130
|
controlLabel,
|
|
131
131
|
tabs,
|
|
132
|
-
|
|
132
|
+
tabId: selectedTabId,
|
|
133
|
+
onTabChange
|
|
133
134
|
}: BrowserLiveScreenProps): import("react").JSX.Element;
|
|
134
135
|
//#endregion
|
|
135
136
|
export { BrowserLiveScreen, BrowserLiveScreenCommand, BrowserLiveScreenFrameMetadata, BrowserLiveScreenInput, BrowserLiveScreenInputEvent, BrowserLiveScreenProps, BrowserLiveScreenProtocol, BrowserLiveScreenSignal, BrowserLiveScreenSignalPayload, BrowserLiveScreenStatus, BrowserLiveScreenTab };
|
|
@@ -11,10 +11,10 @@ const BROWSER_LIVE_SCREEN_NEGOTIATION_TIMEOUT_MS = 1e4;
|
|
|
11
11
|
* A complete interactive viewer for an employee's claimed browser tabs.
|
|
12
12
|
*
|
|
13
13
|
* The host supplies only signaling transport, ICE configuration, and claimed
|
|
14
|
-
* tab summaries. This component owns the peer connection, remote-input
|
|
14
|
+
* tab summaries and selection. This component owns the peer connection, remote-input
|
|
15
15
|
* mapping, reconnect lifecycle, synthesized browser chrome, and cleanup.
|
|
16
16
|
*/
|
|
17
|
-
function BrowserLiveScreen({ sendSignal: sendHostSignal, subscribeSignals, protocol, getIceServers, label = "Employee browser", controlLabel = "Control employee browser", tabs = [],
|
|
17
|
+
function BrowserLiveScreen({ sendSignal: sendHostSignal, subscribeSignals, protocol, getIceServers, label = "Employee browser", controlLabel = "Control employee browser", tabs = [], tabId: selectedTabId, onTabChange }) {
|
|
18
18
|
const video = useRef(null);
|
|
19
19
|
const input = useRef(null);
|
|
20
20
|
const [inputElement, setInputElement] = useState(null);
|
|
@@ -59,13 +59,7 @@ function BrowserLiveScreen({ sendSignal: sendHostSignal, subscribeSignals, proto
|
|
|
59
59
|
useLayoutEffect(() => {
|
|
60
60
|
currentProtocol.current = protocol;
|
|
61
61
|
}, [protocol]);
|
|
62
|
-
const
|
|
63
|
-
if (requestedTabId === void 0 || data?.readyState !== "open") return;
|
|
64
|
-
data.send(currentProtocol.current.serializeCommand({
|
|
65
|
-
kind: "selectTab",
|
|
66
|
-
tabId: requestedTabId
|
|
67
|
-
}));
|
|
68
|
-
});
|
|
62
|
+
const captureTabId = tabs.some((tab) => tab.tabId === selectedTabId) ? selectedTabId : void 0;
|
|
69
63
|
const dataChannelLabel = protocol.dataChannelLabel;
|
|
70
64
|
const handleWheel = useEffectEvent((event) => {
|
|
71
65
|
event.preventDefault();
|
|
@@ -107,6 +101,13 @@ function BrowserLiveScreen({ sendSignal: sendHostSignal, subscribeSignals, proto
|
|
|
107
101
|
}, [inputElement]);
|
|
108
102
|
const [streamed, setStreamed] = useState(null);
|
|
109
103
|
useEffect(() => {
|
|
104
|
+
if (captureTabId === void 0) {
|
|
105
|
+
setPhase("idle");
|
|
106
|
+
setStreamed(null);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const tabId = captureTabId;
|
|
110
|
+
setPhase("connecting");
|
|
110
111
|
let disposed = false;
|
|
111
112
|
let connection;
|
|
112
113
|
let viewerId = "";
|
|
@@ -220,8 +221,6 @@ function BrowserLiveScreen({ sendSignal: sendHostSignal, subscribeSignals, proto
|
|
|
220
221
|
};
|
|
221
222
|
const dataChannel = peer.createDataChannel(dataChannelLabel);
|
|
222
223
|
channel.current = dataChannel;
|
|
223
|
-
dataChannel.onopen = () => selectRequestedTab(dataChannel);
|
|
224
|
-
selectRequestedTab(dataChannel);
|
|
225
224
|
dataChannel.onmessage = (event) => {
|
|
226
225
|
if (disposed || peer !== connection || channel.current !== dataChannel) return;
|
|
227
226
|
const status = parseStatus(event.data);
|
|
@@ -236,6 +235,7 @@ function BrowserLiveScreen({ sendSignal: sendHostSignal, subscribeSignals, proto
|
|
|
236
235
|
return;
|
|
237
236
|
}
|
|
238
237
|
if (status.kind === "streaming") {
|
|
238
|
+
if (status.tabId !== tabId) return;
|
|
239
239
|
const previous = geometry.current;
|
|
240
240
|
if (previous?.tabId !== status.tabId || previous.streamGeneration !== status.streamGeneration) cancelPointerState();
|
|
241
241
|
geometry.current = status;
|
|
@@ -253,7 +253,8 @@ function BrowserLiveScreen({ sendSignal: sendHostSignal, subscribeSignals, proto
|
|
|
253
253
|
if (disposed || peer !== connection) return;
|
|
254
254
|
await sendSignal(currentViewerId, {
|
|
255
255
|
kind: "offer",
|
|
256
|
-
sdp: offer.sdp ?? ""
|
|
256
|
+
sdp: offer.sdp ?? "",
|
|
257
|
+
tabId
|
|
257
258
|
});
|
|
258
259
|
}
|
|
259
260
|
function restart() {
|
|
@@ -270,10 +271,7 @@ function BrowserLiveScreen({ sendSignal: sendHostSignal, subscribeSignals, proto
|
|
|
270
271
|
unsubscribe();
|
|
271
272
|
closeCurrent(true);
|
|
272
273
|
};
|
|
273
|
-
}, [dataChannelLabel]);
|
|
274
|
-
useEffect(() => {
|
|
275
|
-
selectRequestedTab(channel.current);
|
|
276
|
-
}, [requestedTabId]);
|
|
274
|
+
}, [dataChannelLabel, captureTabId]);
|
|
277
275
|
function sendInput(events) {
|
|
278
276
|
const open = channel.current;
|
|
279
277
|
const status = geometry.current;
|
|
@@ -628,11 +626,8 @@ function BrowserLiveScreen({ sendSignal: sendHostSignal, subscribeSignals, proto
|
|
|
628
626
|
title: tab.title || tab.url || `Tab ${String(tab.tabId)}`,
|
|
629
627
|
...tab.url === void 0 ? {} : { url: tab.url }
|
|
630
628
|
})),
|
|
631
|
-
selectedTabId:
|
|
632
|
-
onSelectTab: (id) =>
|
|
633
|
-
kind: "selectTab",
|
|
634
|
-
tabId: Number(id)
|
|
635
|
-
}),
|
|
629
|
+
selectedTabId: captureTabId === void 0 ? null : String(captureTabId),
|
|
630
|
+
onSelectTab: (id) => onTabChange(Number(id)),
|
|
636
631
|
url: displayUrl,
|
|
637
632
|
onOpenUrl: (next) => {
|
|
638
633
|
if (!streamed) return;
|
|
@@ -195,7 +195,7 @@ function SubagentRunPanelContent({ panel, renderRunLink }) {
|
|
|
195
195
|
const { runs, active, completed, visible } = getSubagentRunRows(panel);
|
|
196
196
|
const focus = useSubagentRunFocus(panel, visible);
|
|
197
197
|
const stop = panel.commands["current-work"] ?? IDLE;
|
|
198
|
-
if (
|
|
198
|
+
if (!runs.length) return null;
|
|
199
199
|
return /* @__PURE__ */ jsx(AgentChatPromptTray, {
|
|
200
200
|
"data-subagent-run-panel": "",
|
|
201
201
|
children: /* @__PURE__ */ jsx(Queue, {
|
|
@@ -168,14 +168,17 @@
|
|
|
168
168
|
the same quiet look without per-app classes. Hug the actions — a short
|
|
169
169
|
viewport (Storybook addons, a short side panel) used to stretch this into
|
|
170
170
|
a vacant slab. Space-between only when there are three slots to fill.
|
|
171
|
-
Compact control tokens keep this strip on the same ramp as the composer.
|
|
171
|
+
Compact control tokens keep this strip on the same ramp as the composer.
|
|
172
|
+
Count buttons only: opening a popup inserts non-layout focus guards. */
|
|
172
173
|
.agent-chat-start-screen__composer-tray {
|
|
173
174
|
align-self: start;
|
|
174
175
|
justify-content: start;
|
|
175
176
|
min-block-size: 0;
|
|
176
177
|
}
|
|
177
178
|
|
|
178
|
-
.agent-chat-start-screen__composer-tray:has(
|
|
179
|
+
.agent-chat-start-screen__composer-tray:has(
|
|
180
|
+
> :nth-child(3 of .button):nth-last-child(1 of .button)
|
|
181
|
+
) {
|
|
179
182
|
justify-content: space-between;
|
|
180
183
|
}
|
|
181
184
|
|
|
@@ -561,12 +564,17 @@
|
|
|
561
564
|
font-size: var(--sigvelo-text-lg);
|
|
562
565
|
}
|
|
563
566
|
|
|
564
|
-
.agent-chat-start-screen__composer-tray:has(
|
|
567
|
+
.agent-chat-start-screen__composer-tray:has(
|
|
568
|
+
> :nth-child(3 of .button):nth-last-child(1 of .button)
|
|
569
|
+
) {
|
|
565
570
|
display: grid;
|
|
566
571
|
grid-template-columns: repeat(3, var(--sigvelo-layout-track-fill));
|
|
567
572
|
}
|
|
568
573
|
|
|
569
|
-
.agent-chat-start-screen__composer-tray:has(
|
|
574
|
+
.agent-chat-start-screen__composer-tray:has(
|
|
575
|
+
> :nth-child(3 of .button):nth-last-child(1 of .button)
|
|
576
|
+
)
|
|
577
|
+
> .button {
|
|
570
578
|
inline-size: 100%;
|
|
571
579
|
justify-content: center;
|
|
572
580
|
}
|
package/dist/styles/message.css
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-b/react-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.0",
|
|
4
4
|
"description": "MCP-B React components built on Base UI and shared design tokens, including Cloudflare Think chat primitives.",
|
|
5
5
|
"homepage": "https://design-system.sigvelo.com",
|
|
6
6
|
"bugs": {
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"streamdown": "^2.5.0",
|
|
55
55
|
"unist-util-visit": "^5.1.0",
|
|
56
56
|
"yet-another-react-lightbox": "^3.32.2",
|
|
57
|
-
"@mcp-b/design-tokens": "0.
|
|
57
|
+
"@mcp-b/design-tokens": "0.51.0"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@ai-sdk/react": "^3.0.249",
|