@mcp-b/react-components 0.31.0 → 0.31.1
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.
|
@@ -67,6 +67,8 @@ interface ThinkFullAppProps<AgentT extends ThinkFullAppAgent<State>, State = unk
|
|
|
67
67
|
threadStatusSummary?: ThinkThreadStatusSummary;
|
|
68
68
|
/** Whether narrow layouts render the built-in chat/workbench switch. Defaults to true. */
|
|
69
69
|
showMobileViewSwitch?: boolean;
|
|
70
|
+
/** Whether desktop layouts render the built-in workbench switch. Defaults to true. */
|
|
71
|
+
showWorkbenchViewSwitch?: boolean;
|
|
70
72
|
/** Hide the thread app bar when a narrow workbench supplies its own navigation. */
|
|
71
73
|
hideAppBarInWorkbench?: boolean;
|
|
72
74
|
/** Whole native execution selected by the application route. */
|
|
@@ -112,6 +114,12 @@ interface ThinkFullAppProps<AgentT extends ThinkFullAppAgent<State>, State = unk
|
|
|
112
114
|
defaultWorkbenchView?: ThinkFullAppWorkbenchView;
|
|
113
115
|
/** Called when the shell toolbar asks to switch workbench lanes. */
|
|
114
116
|
onWorkbenchViewChange?: (view: ThinkFullAppWorkbenchView) => void;
|
|
117
|
+
/** Whether the desktop workbench panel is open. Omit for internal state. */
|
|
118
|
+
workbenchOpen?: boolean;
|
|
119
|
+
/** Initial desktop workbench state when `workbenchOpen` is uncontrolled. */
|
|
120
|
+
defaultWorkbenchOpen?: boolean;
|
|
121
|
+
/** Called when toolbar or resize input opens or closes the workbench. */
|
|
122
|
+
onWorkbenchOpenChange?: (open: boolean) => void;
|
|
115
123
|
}
|
|
116
124
|
/** Combines ThinkChat with an optional resizable workbench shell. */
|
|
117
125
|
declare function ThinkFullApp<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage>({
|
|
@@ -121,6 +129,7 @@ declare function ThinkFullApp<AgentT extends ThinkFullAppAgent<State>, State = u
|
|
|
121
129
|
className,
|
|
122
130
|
conversation,
|
|
123
131
|
defaultMobileView,
|
|
132
|
+
defaultWorkbenchOpen,
|
|
124
133
|
defaultWorkbenchView,
|
|
125
134
|
defaultThreadSidebarOpen,
|
|
126
135
|
hideAppBarInWorkbench,
|
|
@@ -128,6 +137,7 @@ declare function ThinkFullApp<AgentT extends ThinkFullAppAgent<State>, State = u
|
|
|
128
137
|
mobileView,
|
|
129
138
|
onMobileViewChange,
|
|
130
139
|
onThreadSidebarOpenChange,
|
|
140
|
+
onWorkbenchOpenChange,
|
|
131
141
|
onWorkbenchViewChange,
|
|
132
142
|
plugins,
|
|
133
143
|
ref,
|
|
@@ -135,11 +145,13 @@ declare function ThinkFullApp<AgentT extends ThinkFullAppAgent<State>, State = u
|
|
|
135
145
|
renderExecutionRunLink,
|
|
136
146
|
selectedExecutionRun,
|
|
137
147
|
showMobileViewSwitch,
|
|
148
|
+
showWorkbenchViewSwitch,
|
|
138
149
|
sourceKey,
|
|
139
150
|
style,
|
|
140
151
|
threadSidebar,
|
|
141
152
|
threadSidebarOpen,
|
|
142
153
|
threadStatusSummary,
|
|
154
|
+
workbenchOpen,
|
|
143
155
|
workbenchPanels,
|
|
144
156
|
workbenchView,
|
|
145
157
|
workspace,
|
|
@@ -21,6 +21,7 @@ const workbenchPanelDefaultWidth = 340;
|
|
|
21
21
|
const workbenchPanelMinWidth = 300;
|
|
22
22
|
const workbenchPanelMaxWidth = 600;
|
|
23
23
|
const workbenchPanelKeyboardStep = 24;
|
|
24
|
+
const workbenchPanelCollapseThreshold = 240;
|
|
24
25
|
function WorkspacePanel({ config }) {
|
|
25
26
|
const selectedPath = config.navigation.current.destination.kind === "file" ? config.navigation.current.destination.path : null;
|
|
26
27
|
return /* @__PURE__ */ jsx(WorkspaceExplorer, {
|
|
@@ -81,15 +82,17 @@ function ThinkFullAppThreadChat({ agent, chat, messages, renderAgentToolRunLink,
|
|
|
81
82
|
});
|
|
82
83
|
}
|
|
83
84
|
/** Combines ThinkChat with an optional resizable workbench shell. */
|
|
84
|
-
function ThinkFullApp({ appBarActions, appBarLeading, appBarTitle, className, conversation, defaultMobileView, defaultWorkbenchView, defaultThreadSidebarOpen, hideAppBarInWorkbench = false, messages, mobileView, onMobileViewChange, onThreadSidebarOpenChange, onWorkbenchViewChange, plugins, ref, renderAgentToolRunLink, renderExecutionRunLink, selectedExecutionRun = null, showMobileViewSwitch = true, sourceKey, style, threadSidebar, threadSidebarOpen, threadStatusSummary, workbenchPanels, workbenchView, workspace, ...props }) {
|
|
85
|
+
function ThinkFullApp({ appBarActions, appBarLeading, appBarTitle, className, conversation, defaultMobileView, defaultWorkbenchOpen, defaultWorkbenchView, defaultThreadSidebarOpen, hideAppBarInWorkbench = false, messages, mobileView, onMobileViewChange, onThreadSidebarOpenChange, onWorkbenchOpenChange, onWorkbenchViewChange, plugins, ref, renderAgentToolRunLink, renderExecutionRunLink, selectedExecutionRun = null, showMobileViewSwitch = true, showWorkbenchViewSwitch = true, sourceKey, style, threadSidebar, threadSidebarOpen, threadStatusSummary, workbenchOpen, workbenchPanels, workbenchView, workspace, ...props }) {
|
|
85
86
|
const agent = conversation?.agent;
|
|
86
87
|
const appRef = React.useRef(null);
|
|
87
88
|
const workbenchPanelRef = React.useRef(null);
|
|
88
89
|
const pendingPanelFocusRef = React.useRef(null);
|
|
89
90
|
const [innerMobileView, setInnerMobileView] = React.useState(defaultMobileView ?? "chat");
|
|
90
91
|
const [innerWorkbenchView, setInnerWorkbenchView] = React.useState(defaultWorkbenchView ?? "files");
|
|
92
|
+
const [innerWorkbenchOpen, setInnerWorkbenchOpen] = React.useState(defaultWorkbenchOpen ?? true);
|
|
91
93
|
const requestedMobileView = mobileView ?? innerMobileView;
|
|
92
94
|
const requestedWorkbenchView = workbenchView ?? innerWorkbenchView;
|
|
95
|
+
const requestedWorkbenchOpen = workbenchOpen ?? innerWorkbenchOpen;
|
|
93
96
|
const setWorkbenchView = React.useCallback((next) => {
|
|
94
97
|
if (workbenchView === void 0) setInnerWorkbenchView(next);
|
|
95
98
|
onWorkbenchViewChange?.(next);
|
|
@@ -98,6 +101,10 @@ function ThinkFullApp({ appBarActions, appBarLeading, appBarTitle, className, co
|
|
|
98
101
|
if (mobileView === void 0) setInnerMobileView(next);
|
|
99
102
|
onMobileViewChange?.(next);
|
|
100
103
|
}, [mobileView, onMobileViewChange]);
|
|
104
|
+
const setWorkbenchOpen = React.useCallback((next) => {
|
|
105
|
+
if (workbenchOpen === void 0) setInnerWorkbenchOpen(next);
|
|
106
|
+
onWorkbenchOpenChange?.(next);
|
|
107
|
+
}, [onWorkbenchOpenChange, workbenchOpen]);
|
|
101
108
|
const updateAppView = React.useCallback((update) => {
|
|
102
109
|
React.startTransition(update);
|
|
103
110
|
}, []);
|
|
@@ -135,13 +142,15 @@ function ThinkFullApp({ appBarActions, appBarLeading, appBarTitle, className, co
|
|
|
135
142
|
render: () => /* @__PURE__ */ jsx(PluginsPanel, { config: plugins })
|
|
136
143
|
});
|
|
137
144
|
if (workbenchPanels) availableWorkbenchPanels.push(...workbenchPanels);
|
|
138
|
-
const
|
|
145
|
+
const selectedPanel = availableWorkbenchPanels.find((panel) => panel.id === requestedWorkbenchView) ?? availableWorkbenchPanels[0];
|
|
146
|
+
const activePanel = requestedWorkbenchOpen ? selectedPanel : void 0;
|
|
139
147
|
const activeWorkbenchView = activePanel?.id;
|
|
140
148
|
const hasWorkbench = activePanel !== void 0;
|
|
149
|
+
const hasAvailableWorkbench = selectedPanel !== void 0;
|
|
141
150
|
const activeMobileView = hasWorkbench ? requestedMobileView : "chat";
|
|
142
|
-
const
|
|
151
|
+
const shouldShowWorkbenchViewSwitch = showWorkbenchViewSwitch && availableWorkbenchPanels.length > 0;
|
|
143
152
|
const workbenchViews = availableWorkbenchPanels;
|
|
144
|
-
const shouldRenderInlineAppBar = !threadSidebar && (Boolean(appBarActions || appBarLeading || appBarTitle || threadSidebar) ||
|
|
153
|
+
const shouldRenderInlineAppBar = !threadSidebar && (Boolean(appBarActions || appBarLeading || appBarTitle || threadSidebar) || hasAvailableWorkbench);
|
|
145
154
|
const hasAppBarRow = shouldRenderInlineAppBar;
|
|
146
155
|
React.useLayoutEffect(() => {
|
|
147
156
|
const pendingFocus = pendingPanelFocusRef.current;
|
|
@@ -189,19 +198,27 @@ function ThinkFullApp({ appBarActions, appBarLeading, appBarTitle, className, co
|
|
|
189
198
|
}) : null] }) : null,
|
|
190
199
|
/* @__PURE__ */ jsxs(AppTopBar.Trailing, { children: [
|
|
191
200
|
appBarActions,
|
|
192
|
-
|
|
201
|
+
shouldShowWorkbenchViewSwitch && selectedPanel ? /* @__PURE__ */ jsx(ThinkFullAppViewSwitch, {
|
|
193
202
|
className: "think-full-app__workbench-view-switch",
|
|
194
203
|
views: workbenchViews,
|
|
195
204
|
value: activeWorkbenchView,
|
|
205
|
+
allowEmpty: true,
|
|
196
206
|
onValueChange: (next) => {
|
|
197
|
-
|
|
207
|
+
updateAppView(() => {
|
|
208
|
+
if (!next) {
|
|
209
|
+
setWorkbenchOpen(false);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
updateWorkbenchPanel(next);
|
|
213
|
+
setWorkbenchOpen(true);
|
|
214
|
+
});
|
|
198
215
|
},
|
|
199
216
|
"aria-label": "Workbench views"
|
|
200
217
|
}) : null,
|
|
201
|
-
|
|
218
|
+
selectedPanel && showMobileViewSwitch ? /* @__PURE__ */ jsx(ThinkFullAppViewSwitch, {
|
|
202
219
|
className: "think-full-app__mobile-view-switch",
|
|
203
220
|
views: workbenchViews,
|
|
204
|
-
value: activeMobileView === "workbench" ?
|
|
221
|
+
value: activeMobileView === "workbench" ? activeWorkbenchView : void 0,
|
|
205
222
|
allowEmpty: true,
|
|
206
223
|
onValueChange: (next) => {
|
|
207
224
|
updateAppView(() => {
|
|
@@ -227,6 +244,8 @@ function ThinkFullApp({ appBarActions, appBarLeading, appBarTitle, className, co
|
|
|
227
244
|
minSize: workbenchPanelMinWidth,
|
|
228
245
|
maxSize: workbenchPanelMaxWidth,
|
|
229
246
|
keyboardStep: workbenchPanelKeyboardStep,
|
|
247
|
+
collapseThreshold: workbenchPanelCollapseThreshold,
|
|
248
|
+
onCollapse: () => setWorkbenchOpen(false),
|
|
230
249
|
"data-has-thread-sidebar": threadSidebar ? "true" : "false",
|
|
231
250
|
"data-has-workbench": hasWorkbench ? "true" : "false",
|
|
232
251
|
"data-has-workbench-topbar": hasAppBarRow ? "true" : "false",
|
|
@@ -41,7 +41,11 @@ interface ThinkThreadPickerProps extends Omit<React.HTMLAttributes<HTMLElement>,
|
|
|
41
41
|
* inferred from the consuming application's registered route tree.
|
|
42
42
|
*/
|
|
43
43
|
renderThreadLink: (thread: ThinkThreadItem) => React.ReactElement;
|
|
44
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Optional create action. An app whose threads are minted by their first
|
|
46
|
+
* message should navigate to its new-thread screen here rather than create
|
|
47
|
+
* one: a thread created on click is an empty thread until someone writes in it.
|
|
48
|
+
*/
|
|
45
49
|
onCreate?: () => void | Promise<void>;
|
|
46
50
|
/**
|
|
47
51
|
* Notified on unmodified primary activation. The link still navigates — the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-b/react-components",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.1",
|
|
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": {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"streamdown": "^2.5.0",
|
|
59
59
|
"unist-util-visit": "^5.1.0",
|
|
60
60
|
"yet-another-react-lightbox": "^3.32.1",
|
|
61
|
-
"@mcp-b/design-tokens": "0.31.
|
|
61
|
+
"@mcp-b/design-tokens": "0.31.1"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@ai-sdk/react": "^3.0.230",
|