@mcp-b/react-components 0.5.4 → 0.5.6
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/AgentChat.d.ts +3 -0
- package/dist/components/AgentChat.js +14 -3
- package/dist/components/McpServerPicker.d.ts +10 -3
- package/dist/components/McpServerPicker.js +26 -20
- package/dist/components/PromptInput.d.ts +2 -2
- package/dist/components/PromptInput.js +3 -3
- package/dist/components/ThinkChat.d.ts +2 -0
- package/dist/styles/agent-chat.css +8 -0
- package/dist/styles/mcp-server-picker.css +6 -0
- package/package.json +2 -7
|
@@ -30,6 +30,8 @@ interface AgentChatProps<MessageT extends UIMessage = UIMessage> {
|
|
|
30
30
|
emptyState?: React.ReactNode;
|
|
31
31
|
/** Extra controls rendered in the composer toolbar. */
|
|
32
32
|
composerTools?: React.ReactNode;
|
|
33
|
+
/** Extra rows rendered in the built-in plus menu after files. */
|
|
34
|
+
composerAddMenuItems?: React.ReactNode;
|
|
33
35
|
/**
|
|
34
36
|
* Transient status rendered between the transcript and the composer —
|
|
35
37
|
* e.g. a "Reconnecting…" pill. `ThinkChat.Messages` fills this from the
|
|
@@ -86,6 +88,7 @@ declare function AgentChat<MessageT extends UIMessage = UIMessage>({
|
|
|
86
88
|
disabled,
|
|
87
89
|
emptyState,
|
|
88
90
|
composerTools,
|
|
91
|
+
composerAddMenuItems,
|
|
89
92
|
notice,
|
|
90
93
|
onRegenerate,
|
|
91
94
|
onApprovalResponse,
|
|
@@ -4,7 +4,7 @@ import { Activity, ActivityContent, ActivityPanel, ActivityTrigger } from "./Act
|
|
|
4
4
|
import { Context, ContextContent, ContextContentBody, ContextContentHeader, ContextTrigger, getContextUsage, getContextUsedTokens } from "./Context.js";
|
|
5
5
|
import { Conversation, ConversationContent, ConversationEmptyState, ConversationScrollButton } from "./Conversation.js";
|
|
6
6
|
import { Message, MessageAction, MessageActions, MessageAttachment, MessageContent, MessageResponse } from "./Message.js";
|
|
7
|
-
import { PromptInput, PromptInputApproval, PromptInputAttachments, PromptInputBody, PromptInputButton, PromptInputFooter, PromptInputPermissionSelector, PromptInputSubmit, PromptInputTextarea, PromptInputTools, getApprovalRequestId, getPendingToolApprovals, usePromptInputAttachments } from "./PromptInput.js";
|
|
7
|
+
import { PromptInput, PromptInputActionAddAttachments, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuTrigger, PromptInputApproval, PromptInputAttachments, PromptInputBody, PromptInputButton, PromptInputFooter, PromptInputPermissionSelector, PromptInputSubmit, PromptInputTextarea, PromptInputTools, getApprovalRequestId, getPendingToolApprovals, usePromptInputAttachments } from "./PromptInput.js";
|
|
8
8
|
import { Reasoning, ReasoningContent, ReasoningTrigger } from "./Reasoning.js";
|
|
9
9
|
import * as React from "react";
|
|
10
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -18,6 +18,17 @@ function AgentChatAttachButton() {
|
|
|
18
18
|
children: /* @__PURE__ */ jsx(PlusIcon, {})
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
|
+
function AgentChatAddMenu({ children }) {
|
|
22
|
+
if (!children) return /* @__PURE__ */ jsx(AgentChatAttachButton, {});
|
|
23
|
+
return /* @__PURE__ */ jsxs(PromptInputActionMenu, { children: [/* @__PURE__ */ jsx(PromptInputActionMenuTrigger, { "aria-label": "Add context" }), /* @__PURE__ */ jsxs(PromptInputActionMenuContent, {
|
|
24
|
+
side: "top",
|
|
25
|
+
align: "start",
|
|
26
|
+
sideOffset: 12,
|
|
27
|
+
collisionPadding: 8,
|
|
28
|
+
className: "agent-chat__add-menu",
|
|
29
|
+
children: [/* @__PURE__ */ jsx(PromptInputActionAddAttachments, {}), children]
|
|
30
|
+
})] });
|
|
31
|
+
}
|
|
21
32
|
function isCompactedPart(message, part, partIndex) {
|
|
22
33
|
const metadata = message.metadata;
|
|
23
34
|
if (isTextUIPart(part)) return Array.isArray(metadata?.compactedTextParts) && metadata.compactedTextParts.includes(partIndex);
|
|
@@ -88,7 +99,7 @@ function renderDefaultPart(part) {
|
|
|
88
99
|
* transport. Use it directly with plain AI SDK `useChat` or a read-only
|
|
89
100
|
* transcript; if you have a Cloudflare Think agent, use `ThinkChat` instead.
|
|
90
101
|
*/
|
|
91
|
-
function AgentChat({ className, messages, status = "ready", onSubmit, onStop, placeholder = "Ask anything...", disabled, emptyState, composerTools, notice, onRegenerate, onApprovalResponse, executionApprovals, contextWindow, renderPart, renderMessageAfter, ref }) {
|
|
102
|
+
function AgentChat({ className, messages, status = "ready", onSubmit, onStop, placeholder = "Ask anything...", disabled, emptyState, composerTools, composerAddMenuItems, notice, onRegenerate, onApprovalResponse, executionApprovals, contextWindow, renderPart, renderMessageAfter, ref }) {
|
|
92
103
|
const handleSubmit = React.useCallback((message) => {
|
|
93
104
|
onSubmit?.(message);
|
|
94
105
|
}, [onSubmit]);
|
|
@@ -194,7 +205,7 @@ function AgentChat({ className, messages, status = "ready", onSubmit, onStop, pl
|
|
|
194
205
|
disabled
|
|
195
206
|
}) }),
|
|
196
207
|
/* @__PURE__ */ jsxs(PromptInputFooter, { children: [/* @__PURE__ */ jsxs(PromptInputTools, { children: [
|
|
197
|
-
/* @__PURE__ */ jsx(
|
|
208
|
+
/* @__PURE__ */ jsx(AgentChatAddMenu, { children: composerAddMenuItems }),
|
|
198
209
|
approvalsWired ? /* @__PURE__ */ jsx(PromptInputPermissionSelector, {
|
|
199
210
|
value: permissionMode,
|
|
200
211
|
onValueChange: setPermissionMode
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { Icon } from "@modelcontextprotocol/sdk/types.js";
|
|
3
2
|
|
|
4
3
|
//#region src/components/McpServerPicker.d.ts
|
|
5
4
|
type McpServerPickerStatus = "connecting" | "needs-auth" | "authenticating" | "ready" | "failed";
|
|
5
|
+
interface McpServerCardIcon {
|
|
6
|
+
src: string;
|
|
7
|
+
}
|
|
6
8
|
interface McpServerCard {
|
|
7
9
|
id: string;
|
|
8
10
|
name: string;
|
|
9
11
|
url: string;
|
|
10
12
|
description?: string;
|
|
11
13
|
category?: string;
|
|
12
|
-
icon?:
|
|
14
|
+
icon?: string | McpServerCardIcon;
|
|
13
15
|
status?: McpServerPickerStatus;
|
|
14
16
|
statusLabel?: string;
|
|
15
17
|
}
|
|
@@ -21,6 +23,7 @@ interface McpServerPickerProps {
|
|
|
21
23
|
/** Offset from the plus trigger to the menu, useful for prompt composers. */
|
|
22
24
|
sideOffset?: number;
|
|
23
25
|
}
|
|
26
|
+
type McpServerPickerItemsProps = Pick<McpServerPickerProps, "servers" | "onConnect">;
|
|
24
27
|
/**
|
|
25
28
|
* Prompt plus-menu picker for choosing an MCP server and handing connection
|
|
26
29
|
* work back to the host app.
|
|
@@ -30,5 +33,9 @@ declare function McpServerPicker({
|
|
|
30
33
|
onConnect,
|
|
31
34
|
sideOffset
|
|
32
35
|
}: McpServerPickerProps): React.JSX.Element;
|
|
36
|
+
declare function McpServerPickerItems({
|
|
37
|
+
servers,
|
|
38
|
+
onConnect
|
|
39
|
+
}: McpServerPickerItemsProps): React.JSX.Element | React.JSX.Element[];
|
|
33
40
|
//#endregion
|
|
34
|
-
export { McpServerCard, McpServerPicker, McpServerPickerProps, McpServerPickerStatus };
|
|
41
|
+
export { McpServerCard, McpServerCardIcon, McpServerPicker, McpServerPickerItems, McpServerPickerItemsProps, McpServerPickerProps, McpServerPickerStatus };
|
|
@@ -9,8 +9,6 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
* work back to the host app.
|
|
10
10
|
*/
|
|
11
11
|
function McpServerPicker({ servers, onConnect, sideOffset = 80 }) {
|
|
12
|
-
const groups = groupServers(servers);
|
|
13
|
-
const showHeadings = groups.some((group) => group.category);
|
|
14
12
|
return /* @__PURE__ */ jsx("div", {
|
|
15
13
|
className: "mcp-server-picker",
|
|
16
14
|
children: /* @__PURE__ */ jsxs(MenuRoot, { children: [/* @__PURE__ */ jsx(MenuTrigger, { render: /* @__PURE__ */ jsx(Button, {
|
|
@@ -28,30 +26,42 @@ function McpServerPicker({ servers, onConnect, sideOffset = 80 }) {
|
|
|
28
26
|
collisionPadding: 8,
|
|
29
27
|
"aria-label": "MCP servers",
|
|
30
28
|
className: "mcp-server-picker__popup",
|
|
31
|
-
children:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}) : groups.map((group) => /* @__PURE__ */ jsxs(MenuGroup, {
|
|
36
|
-
className: "mcp-server-picker__group",
|
|
37
|
-
children: [showHeadings ? /* @__PURE__ */ jsx(MenuGroupLabel, { children: group.category || "Servers" }) : null, group.servers.map((server) => /* @__PURE__ */ jsx(McpServerPickerRow, {
|
|
38
|
-
server,
|
|
39
|
-
onConnect
|
|
40
|
-
}, server.id))]
|
|
41
|
-
}, group.category))
|
|
29
|
+
children: /* @__PURE__ */ jsx(McpServerPickerItems, {
|
|
30
|
+
servers,
|
|
31
|
+
onConnect
|
|
32
|
+
})
|
|
42
33
|
})] })
|
|
43
34
|
});
|
|
44
35
|
}
|
|
36
|
+
function McpServerPickerItems({ servers, onConnect }) {
|
|
37
|
+
const groups = groupServers(servers);
|
|
38
|
+
const showHeadings = groups.some((group) => group.category);
|
|
39
|
+
if (servers.length === 0) return /* @__PURE__ */ jsx(MenuItem, {
|
|
40
|
+
disabled: true,
|
|
41
|
+
className: "mcp-server-picker__empty",
|
|
42
|
+
children: "No MCP servers available."
|
|
43
|
+
});
|
|
44
|
+
return groups.map((group) => /* @__PURE__ */ jsxs(MenuGroup, {
|
|
45
|
+
className: "mcp-server-picker__group",
|
|
46
|
+
children: [showHeadings ? /* @__PURE__ */ jsx(MenuGroupLabel, { children: group.category || "Servers" }) : null, group.servers.map((server) => /* @__PURE__ */ jsx(McpServerPickerRow, {
|
|
47
|
+
server,
|
|
48
|
+
onConnect
|
|
49
|
+
}, server.id))]
|
|
50
|
+
}, group.category));
|
|
51
|
+
}
|
|
45
52
|
function McpServerPickerRow({ server, onConnect }) {
|
|
46
53
|
const descriptionId = React.useId();
|
|
47
54
|
const statusText = server.statusLabel ?? getStatusLabel(server.status);
|
|
48
55
|
const busy = server.status === "connecting" || server.status === "authenticating";
|
|
56
|
+
const disabled = busy || server.status === "ready";
|
|
49
57
|
return /* @__PURE__ */ jsxs(MenuItem, {
|
|
50
58
|
className: "mcp-server-picker__row",
|
|
59
|
+
closeOnClick: false,
|
|
51
60
|
"data-status": server.status,
|
|
61
|
+
disabled,
|
|
52
62
|
"aria-busy": busy || void 0,
|
|
53
63
|
"aria-describedby": server.description ? descriptionId : void 0,
|
|
54
|
-
onClick: () => void onConnect(server),
|
|
64
|
+
onClick: disabled ? void 0 : () => void onConnect(server),
|
|
55
65
|
children: [
|
|
56
66
|
/* @__PURE__ */ jsx("span", {
|
|
57
67
|
className: "mcp-server-picker__icon",
|
|
@@ -93,9 +103,8 @@ function getStatusLabel(status) {
|
|
|
93
103
|
return "";
|
|
94
104
|
}
|
|
95
105
|
function renderIcon(icon, name) {
|
|
96
|
-
if (React.isValidElement(icon)) return icon;
|
|
97
106
|
if (typeof icon === "string") return /* @__PURE__ */ jsx(IconImage, { src: icon });
|
|
98
|
-
if (
|
|
107
|
+
if (icon) return /* @__PURE__ */ jsx(IconImage, { src: icon.src });
|
|
99
108
|
return /* @__PURE__ */ jsx("span", {
|
|
100
109
|
className: "mcp-server-picker__fallback-icon",
|
|
101
110
|
children: name.slice(0, 1)
|
|
@@ -110,9 +119,6 @@ function IconImage({ src }) {
|
|
|
110
119
|
referrerPolicy: "no-referrer"
|
|
111
120
|
});
|
|
112
121
|
}
|
|
113
|
-
function isMcpIcon(icon) {
|
|
114
|
-
return Boolean(icon && typeof icon === "object" && "src" in icon && typeof icon.src === "string");
|
|
115
|
-
}
|
|
116
122
|
function groupServers(servers) {
|
|
117
123
|
const groups = [];
|
|
118
124
|
for (const server of servers) {
|
|
@@ -130,4 +136,4 @@ function groupServers(servers) {
|
|
|
130
136
|
return groups;
|
|
131
137
|
}
|
|
132
138
|
//#endregion
|
|
133
|
-
export { McpServerPicker };
|
|
139
|
+
export { McpServerPicker, McpServerPickerItems };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { A as SelectTriggerProps, M as SelectValueProps, S as SelectProps, f as SelectOption, j as SelectValue, r as SelectContentProps, s as SelectItemProps, t as Select } from "../Select-CRsKCJ9x.js";
|
|
2
2
|
import { c as ComboboxGroup, d as ComboboxLabel, f as ComboboxList, g as ComboboxTrigger, h as ComboboxSeparator, l as ComboboxInput, m as ComboboxPositioner, p as ComboboxPopup, s as ComboboxEmpty, t as Combobox, u as ComboboxItem } from "../Combobox-D9anamNr.js";
|
|
3
|
-
import { h as MenuItemProps,
|
|
3
|
+
import { h as MenuItemProps, l as MenuContentProps, w as MenuProps } from "../Menu-B5vDqZe_.js";
|
|
4
4
|
import { c as TabsList, n as TabPanel, t as Tab } from "../Tabs-D9EAq09D.js";
|
|
5
5
|
import { r as ButtonProps } from "../Button-Ct5I6aTu.js";
|
|
6
6
|
import * as React from "react";
|
|
@@ -261,7 +261,7 @@ declare function PromptInputActionMenuTrigger({
|
|
|
261
261
|
children,
|
|
262
262
|
...props
|
|
263
263
|
}: PromptInputActionMenuTriggerProps): React.JSX.Element;
|
|
264
|
-
type PromptInputActionMenuContentProps =
|
|
264
|
+
type PromptInputActionMenuContentProps = MenuContentProps;
|
|
265
265
|
declare function PromptInputActionMenuContent({
|
|
266
266
|
className,
|
|
267
267
|
children,
|
|
@@ -4,7 +4,7 @@ import { Button } from "./Button.js";
|
|
|
4
4
|
import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
|
|
5
5
|
import { t as AttachmentPreview } from "../attachment-preview-ChtC3HiU.js";
|
|
6
6
|
import { Combobox, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxList, ComboboxSeparator } from "./Combobox.js";
|
|
7
|
-
import { MenuItem, MenuPopup, MenuPortal, MenuPositioner, MenuRadioGroup, MenuRadioItem, MenuRadioItemIndicator, MenuRoot, MenuTrigger } from "./Menu.js";
|
|
7
|
+
import { MenuContent, MenuItem, MenuPopup, MenuPortal, MenuPositioner, MenuRadioGroup, MenuRadioItem, MenuRadioItemIndicator, MenuRoot, MenuTrigger } from "./Menu.js";
|
|
8
8
|
import { Select, SelectContent, SelectItem, SelectPortal, SelectPositioner, SelectTrigger, SelectValue } from "./Select.js";
|
|
9
9
|
import { Tab, TabPanel, TabsList } from "./Tabs.js";
|
|
10
10
|
import * as React from "react";
|
|
@@ -538,11 +538,11 @@ function PromptInputActionMenuTrigger({ className, children, ...props }) {
|
|
|
538
538
|
}) });
|
|
539
539
|
}
|
|
540
540
|
function PromptInputActionMenuContent({ className, children, ...props }) {
|
|
541
|
-
return /* @__PURE__ */ jsx(
|
|
541
|
+
return /* @__PURE__ */ jsx(MenuContent, {
|
|
542
542
|
className: cx("prompt-input__action-menu", className),
|
|
543
543
|
...props,
|
|
544
544
|
children
|
|
545
|
-
})
|
|
545
|
+
});
|
|
546
546
|
}
|
|
547
547
|
function PromptInputActionMenuItem({ className, ...props }) {
|
|
548
548
|
return /* @__PURE__ */ jsx(MenuItem, {
|
|
@@ -31,6 +31,8 @@ interface ThinkChatMessagesProps extends ThinkChatActivityRendererOptions {
|
|
|
31
31
|
emptyState?: React.ReactNode;
|
|
32
32
|
/** Extra controls rendered inside the composer, next to the send button. */
|
|
33
33
|
composerTools?: React.ReactNode;
|
|
34
|
+
/** Extra rows rendered in the built-in plus menu after files. */
|
|
35
|
+
composerAddMenuItems?: AgentChatProps["composerAddMenuItems"];
|
|
34
36
|
/** Composer placeholder text. */
|
|
35
37
|
placeholder?: string;
|
|
36
38
|
/** Rendered after each message (e.g. per-message actions). */
|
|
@@ -43,6 +43,14 @@
|
|
|
43
43
|
margin-inline: auto;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
.agent-chat__add-menu {
|
|
47
|
+
inline-size: min(32rem, calc(100dvw - 1rem));
|
|
48
|
+
max-block-size: min(28rem, calc(100dvh - 2rem));
|
|
49
|
+
overflow-y: auto;
|
|
50
|
+
overscroll-behavior: contain;
|
|
51
|
+
scrollbar-gutter: stable;
|
|
52
|
+
}
|
|
53
|
+
|
|
46
54
|
/* Transient status pill between transcript and composer (recovery, errors). */
|
|
47
55
|
.agent-chat__notice {
|
|
48
56
|
display: flex;
|
|
@@ -108,6 +108,12 @@
|
|
|
108
108
|
animation: mcp-server-picker-spin 900ms linear infinite;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
@media (prefers-reduced-motion: reduce) {
|
|
112
|
+
.mcp-server-picker__spinner {
|
|
113
|
+
animation: none;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
111
117
|
.mcp-server-picker__empty {
|
|
112
118
|
padding-block: 0.5rem;
|
|
113
119
|
padding-inline: 0.75rem;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-b/react-components",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
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": {
|
|
@@ -49,14 +49,13 @@
|
|
|
49
49
|
"anser": "^2.3.5",
|
|
50
50
|
"shiki": "^3.23.0",
|
|
51
51
|
"streamdown": "^2.5.0",
|
|
52
|
-
"@mcp-b/design-tokens": "0.5.
|
|
52
|
+
"@mcp-b/design-tokens": "0.5.6"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@ai-sdk/react": "^3.0.194",
|
|
56
56
|
"@cloudflare/shell": "^0.4.1",
|
|
57
57
|
"@cloudflare/think": "^0.12.1",
|
|
58
58
|
"@cloudflare/workers-types": "^4.20260630.1",
|
|
59
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
60
59
|
"@storybook/addon-a11y": "^10.4.6",
|
|
61
60
|
"@storybook/addon-docs": "^10.4.6",
|
|
62
61
|
"@storybook/addon-mcp": "^0.6.0",
|
|
@@ -84,7 +83,6 @@
|
|
|
84
83
|
"@ai-sdk/react": "^3.0.194",
|
|
85
84
|
"@cloudflare/shell": "^0.4.1",
|
|
86
85
|
"@cloudflare/think": "^0.12.1",
|
|
87
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
88
86
|
"agents": "^0.17.3",
|
|
89
87
|
"ai": "^6.0.182",
|
|
90
88
|
"react": "^19.0.0",
|
|
@@ -100,9 +98,6 @@
|
|
|
100
98
|
"@cloudflare/think": {
|
|
101
99
|
"optional": true
|
|
102
100
|
},
|
|
103
|
-
"@modelcontextprotocol/sdk": {
|
|
104
|
-
"optional": true
|
|
105
|
-
},
|
|
106
101
|
"agents": {
|
|
107
102
|
"optional": true
|
|
108
103
|
},
|