@mcp-b/react-components 0.11.0 → 0.12.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.
Files changed (83) hide show
  1. package/dist/{AgentChat-B9LD_WF1.d.ts → AgentChat-CRmsKg9B.d.ts} +10 -6
  2. package/dist/{BrowserLiveView-ZktFZiMD.d.ts → BrowserLiveView-BV5qgFgI.d.ts} +11 -10
  3. package/dist/{BrowserReplay-6G-mnwcn.d.ts → BrowserReplay-xWvRjRAC.d.ts} +2 -1
  4. package/dist/{Menu-B5vDqZe_.d.ts → Menu-BLhnNnRK.d.ts} +3 -0
  5. package/dist/{ModelSelector-DXtpcRmT.js → ModelSelector-BB-xB-Es.js} +16 -13
  6. package/dist/{PromptInput-D6-G24p7.d.ts → PromptInput-IyM6ZETj.d.ts} +13 -45
  7. package/dist/ThinkChat-B3wYahor.js +190 -0
  8. package/dist/{ThinkChatActivity-B2UD95My.d.ts → ThinkChatActivity-F4KFPcJA.d.ts} +4 -4
  9. package/dist/ThinkChatContext-C3Eb1Xpi.d.ts +16 -0
  10. package/dist/{ThinkChatToolParts-DnUiZgCC.d.ts → ThinkChatToolParts-Cv4o7j6F.d.ts} +13 -5
  11. package/dist/components/AgentChat.d.ts +1 -1
  12. package/dist/components/AgentChat.js +57 -23
  13. package/dist/components/AgentConnection.js +4 -20
  14. package/dist/components/Badge.js +1 -15
  15. package/dist/components/BrowserLiveView.d.ts +1 -1
  16. package/dist/components/BrowserLiveView.js +14 -10
  17. package/dist/components/BrowserReplay.d.ts +1 -1
  18. package/dist/components/BrowserRunPanel.js +91 -55
  19. package/dist/components/ChatGptSignInScreen.js +1 -1
  20. package/dist/components/CodexModelSelector.d.ts +63 -0
  21. package/dist/components/CodexModelSelector.js +148 -0
  22. package/dist/components/Commit.d.ts +2 -2
  23. package/dist/components/Commit.js +10 -22
  24. package/dist/components/Conversation.d.ts +2 -6
  25. package/dist/components/Conversation.js +2 -3
  26. package/dist/components/EnvironmentVariables.d.ts +2 -7
  27. package/dist/components/EnvironmentVariables.js +10 -33
  28. package/dist/components/Marker.js +1 -15
  29. package/dist/components/McpServerPicker.d.ts +31 -6
  30. package/dist/components/McpServerPicker.js +129 -67
  31. package/dist/components/Menu.d.ts +1 -1
  32. package/dist/components/Menu.js +2 -2
  33. package/dist/components/Message.d.ts +3 -2
  34. package/dist/components/Message.js +10 -3
  35. package/dist/components/ModelSelector.d.ts +11 -8
  36. package/dist/components/ModelSelector.js +1 -1
  37. package/dist/components/PromptInput.d.ts +2 -2
  38. package/dist/components/PromptInput.js +49 -98
  39. package/dist/components/Queue.d.ts +1 -12
  40. package/dist/components/Reasoning.js +2 -15
  41. package/dist/components/Stepper.js +1 -7
  42. package/dist/components/ThinkChat.d.ts +30 -30
  43. package/dist/components/ThinkChat.js +1 -152
  44. package/dist/components/ThinkChatActivity.d.ts +2 -2
  45. package/dist/components/ThinkChatActivity.js +3 -10
  46. package/dist/components/ThinkChatContext.d.ts +2 -2
  47. package/dist/components/ThinkChatContext.js +9 -2
  48. package/dist/components/ThinkChatToolPanels.d.ts +1 -1
  49. package/dist/components/ThinkChatToolPanels.js +19 -7
  50. package/dist/components/ThinkChatToolParts.d.ts +1 -1
  51. package/dist/components/ThinkExecutionWorkbench.d.ts +10 -7
  52. package/dist/components/ThinkExecutionWorkbench.js +382 -359
  53. package/dist/components/ThinkFullApp.d.ts +16 -13
  54. package/dist/components/ThinkFullApp.js +28 -18
  55. package/dist/components/ThinkThreadPicker.d.ts +1 -31
  56. package/dist/components/ThinkThreadPicker.js +32 -171
  57. package/dist/components/ThinkThreadShell.d.ts +35 -0
  58. package/dist/components/ThinkThreadShell.js +146 -0
  59. package/dist/components/WorkspaceExplorer.js +3 -1
  60. package/dist/merge-refs-DF_7w2x_.js +18 -0
  61. package/dist/styles/agent-chat.css +4 -1
  62. package/dist/styles/browser-run-panel.css +57 -110
  63. package/dist/styles/codex-model-selector.css +197 -0
  64. package/dist/styles/index.css +4 -1
  65. package/dist/styles/mcp-server-picker.css +62 -15
  66. package/dist/styles/message.css +1 -1
  67. package/dist/styles/model-selector.css +20 -8
  68. package/dist/styles/prompt-input.css +5 -0
  69. package/dist/styles/streamdown.css +2 -48
  70. package/dist/styles/think-execution-workbench.css +337 -0
  71. package/dist/styles/think-full-app.css +15 -390
  72. package/dist/styles/think-resize-handle.css +33 -0
  73. package/dist/styles/think-thread-picker.css +0 -238
  74. package/dist/styles/think-thread-shell.css +219 -0
  75. package/dist/styles/workspace-explorer.css +8 -2
  76. package/dist/summarize-tool-input-BUJsENSn.js +12 -0
  77. package/package.json +2 -2
  78. package/dist/ThinkChatContext-BLAAb8J5.d.ts +0 -28
  79. package/dist/components/McpServerConnections.d.ts +0 -41
  80. package/dist/components/McpServerConnections.js +0 -188
  81. package/dist/components/useStickToBottom.d.ts +0 -33
  82. package/dist/components/useStickToBottom.js +0 -107
  83. package/dist/styles/mcp-server-connections.css +0 -145
@@ -1,41 +1,44 @@
1
1
  import { WorkspaceSource } from "./WorkspaceExplorer.js";
2
2
  import { ThinkChatMessagesProps } from "./ThinkChat.js";
3
- import { ThinkExecutionAgent, ThinkExecutionWorkbench, ThinkExecutionWorkbenchProps, ThinkExecutionWorkbenchSource } from "./ThinkExecutionWorkbench.js";
4
3
  import * as React from "react";
5
4
  import { useAgentChat } from "@cloudflare/think/react";
6
5
  import { UIMessage } from "ai";
7
6
  import { useAgent } from "agents/react";
8
7
  import { Think } from "@cloudflare/think";
9
8
 
9
+ //#region src/components/_internal/think-agent.d.ts
10
+ /** Shared complete Think specialization for stateful React agent hooks. */
11
+ type ThinkAgent<State = unknown> = Think<object, State>;
12
+ //#endregion
10
13
  //#region src/components/ThinkFullApp.d.ts
11
- type ThinkFullAppAgent<State = unknown> = Think<object, State>;
14
+ type ThinkFullAppAgent<State = unknown> = ThinkAgent<State>;
12
15
  type ThinkFullAppWorkbenchView = "files" | "execution" | (string & {});
13
- interface ThinkFullAppPanelContext<AgentT extends ThinkFullAppAgent<State>, State = unknown> {
16
+ interface ThinkFullAppPanelContext<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage> {
14
17
  agent: ReturnType<typeof useAgent<AgentT, State>>;
15
- chat: ReturnType<typeof useAgentChat<State, UIMessage>>;
18
+ chat: ReturnType<typeof useAgentChat<State, MessageT>>;
16
19
  workspace?: WorkspaceSource;
17
20
  workspaceRoot?: string;
18
21
  }
19
- interface ThinkFullAppPanel<AgentT extends ThinkFullAppAgent<State>, State = unknown> {
22
+ interface ThinkFullAppPanel<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage> {
20
23
  /** Unique panel id used by `workbenchView`; custom panels should not reuse built-in ids. */
21
24
  id: ThinkFullAppWorkbenchView;
22
25
  label: string;
23
26
  icon: React.ReactNode;
24
- render: (context: ThinkFullAppPanelContext<AgentT, State>) => React.ReactNode;
27
+ render: (context: ThinkFullAppPanelContext<AgentT, State, MessageT>) => React.ReactNode;
25
28
  }
26
- interface ThinkFullAppProps<AgentT extends ThinkFullAppAgent<State>, State = unknown> extends React.HTMLAttributes<HTMLDivElement> {
29
+ interface ThinkFullAppProps<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage> extends React.HTMLAttributes<HTMLDivElement> {
27
30
  /** The `useAgent` value from `agents/react`; its stub drives approvals and execution records. */
28
31
  agent: ReturnType<typeof useAgent<AgentT, State>>;
29
32
  /** The `useAgentChat` value from `@cloudflare/think/react` used by the chat surface. */
30
- chat: ReturnType<typeof useAgentChat<State, UIMessage>>;
33
+ chat: ReturnType<typeof useAgentChat<State, MessageT>>;
31
34
  /** Optional workspace source shown in the file explorer pane. */
32
35
  workspace?: WorkspaceSource;
33
36
  /** Root path passed to the workspace explorer. */
34
37
  workspaceRoot?: string;
35
38
  /** Message rendering labels and approval overrides for ThinkChat. */
36
- messages?: ThinkChatMessagesProps;
39
+ messages?: ThinkChatMessagesProps<MessageT>;
37
40
  /** Extra workbench panels appended after the built-in Files and Execution panels. */
38
- workbenchPanels?: readonly ThinkFullAppPanel<AgentT, State>[];
41
+ workbenchPanels?: readonly ThinkFullAppPanel<AgentT, State, MessageT>[];
39
42
  /** Optional parent-owned thread picker/sidebar rendered beside the selected child app. */
40
43
  threadSidebar?: React.ReactNode;
41
44
  /** Whether the thread sidebar is open. Omit for internal state. */
@@ -52,7 +55,7 @@ interface ThinkFullAppProps<AgentT extends ThinkFullAppAgent<State>, State = unk
52
55
  onWorkbenchViewChange?: (view: ThinkFullAppWorkbenchView) => void;
53
56
  }
54
57
  /** Combines ThinkChat with an optional resizable workbench shell. */
55
- declare function ThinkFullApp<AgentT extends ThinkFullAppAgent<State>, State = unknown>({
58
+ declare function ThinkFullApp<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage>({
56
59
  agent,
57
60
  chat,
58
61
  className,
@@ -70,8 +73,8 @@ declare function ThinkFullApp<AgentT extends ThinkFullAppAgent<State>, State = u
70
73
  workspace,
71
74
  workspaceRoot,
72
75
  ...props
73
- }: ThinkFullAppProps<AgentT, State> & {
76
+ }: ThinkFullAppProps<AgentT, State, MessageT> & {
74
77
  ref?: React.Ref<HTMLDivElement>;
75
78
  }): React.JSX.Element;
76
79
  //#endregion
77
- export { type ThinkExecutionAgent, ThinkExecutionWorkbench, type ThinkExecutionWorkbenchProps, type ThinkExecutionWorkbenchSource, ThinkFullApp, ThinkFullAppAgent, ThinkFullAppPanel, ThinkFullAppPanelContext, ThinkFullAppProps, ThinkFullAppWorkbenchView };
80
+ export { ThinkFullApp, ThinkFullAppAgent, ThinkFullAppPanel, ThinkFullAppPanelContext, ThinkFullAppProps, ThinkFullAppWorkbenchView };
@@ -1,12 +1,13 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
2
  import { P as TerminalIcon, h as FileIcon, n as ArrowLeftIcon } from "../icons-D2Q5n5C1.js";
3
+ import { Separator } from "./Separator.js";
3
4
  import { Button } from "./Button.js";
4
5
  import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
5
6
  import { ToggleGroup, ToggleGroupItem } from "./ToggleGroup.js";
7
+ import { o as useThinkPendingApprovals, s as resolveThinkApprovalProps, t as ThinkChat } from "../ThinkChat-B3wYahor.js";
6
8
  import { WorkspaceExplorer, useWorkspace } from "./WorkspaceExplorer.js";
7
- import { ThinkChat, useThinkPendingApprovals } from "./ThinkChat.js";
8
9
  import { ThinkExecutionWorkbench } from "./ThinkExecutionWorkbench.js";
9
- import { ThinkThreadShell } from "./ThinkThreadPicker.js";
10
+ import { ThinkThreadShell } from "./ThinkThreadShell.js";
10
11
  import * as React from "react";
11
12
  import { jsx, jsxs } from "react/jsx-runtime";
12
13
  //#region src/components/ThinkFullApp.tsx
@@ -27,9 +28,9 @@ function beginWorkbenchPanelResize(event, current, apply) {
27
28
  window.removeEventListener("pointermove", onMove);
28
29
  window.removeEventListener("pointerup", onUp);
29
30
  window.removeEventListener("pointercancel", onUp);
30
- document.body.classList.remove("is-resizing-columns");
31
+ document.body.classList.remove("is-resizing-think-full-app");
31
32
  };
32
- document.body.classList.add("is-resizing-columns");
33
+ document.body.classList.add("is-resizing-think-full-app");
33
34
  window.addEventListener("pointermove", onMove);
34
35
  window.addEventListener("pointerup", onUp);
35
36
  window.addEventListener("pointercancel", onUp);
@@ -88,13 +89,24 @@ function WorkbenchViewSwitch({ panels, value, onValueChange }) {
88
89
  /** Combines ThinkChat with an optional resizable workbench shell. */
89
90
  function ThinkFullApp({ agent, chat, className, defaultWorkbenchView, defaultThreadSidebarOpen, messages, onThreadSidebarOpenChange, onWorkbenchViewChange, ref, style, threadSidebar, threadSidebarOpen, workbenchPanels, workbenchView, workspace, workspaceRoot, ...props }) {
90
91
  const approvals = useThinkPendingApprovals(agent.stub, `${chat.messages.length}:${chat.status}`);
91
- const resolvedMessages = React.useMemo(() => ({
92
- ...messages,
93
- executionApprovals: messages?.executionApprovals ?? approvals.executionApprovals,
94
- pendingApprovals: messages?.pendingApprovals ?? approvals.pendingApprovals
95
- }), [
96
- approvals.executionApprovals,
92
+ const resolvedMessages = React.useMemo(() => {
93
+ const approvalProps = resolveThinkApprovalProps({
94
+ thinkStub: messages?.thinkStub,
95
+ pendingApprovals: messages?.pendingApprovals,
96
+ onExecutionSettled: messages?.onExecutionSettled
97
+ }, {
98
+ thinkStub: agent.stub,
99
+ pendingApprovals: approvals.pendingApprovals,
100
+ onExecutionSettled: approvals.refreshPendingApprovals
101
+ });
102
+ return {
103
+ ...messages,
104
+ ...approvalProps
105
+ };
106
+ }, [
107
+ agent.stub,
97
108
  approvals.pendingApprovals,
109
+ approvals.refreshPendingApprovals,
98
110
  messages
99
111
  ]);
100
112
  const [mobileView, setMobileView] = React.useState("chat");
@@ -160,9 +172,7 @@ function ThinkFullApp({ agent, chat, className, defaultWorkbenchView, defaultThr
160
172
  const app = /* @__PURE__ */ jsxs("div", {
161
173
  ref,
162
174
  className: cx("think-full-app", className),
163
- "data-has-files": hasWorkspace ? "true" : "false",
164
175
  "data-has-thread-sidebar": threadSidebar ? "true" : "false",
165
- "data-has-workbench": "true",
166
176
  "data-has-workbench-topbar": showWorkbenchViewSwitch ? "true" : "false",
167
177
  "data-mobile-view": activeMobileView,
168
178
  style: rootStyle,
@@ -220,15 +230,15 @@ function ThinkFullApp({ agent, chat, className, defaultWorkbenchView, defaultThr
220
230
  })
221
231
  })
222
232
  }),
223
- /* @__PURE__ */ jsx("button", {
224
- type: "button",
225
- role: "separator",
233
+ /* @__PURE__ */ jsx(Separator, {
234
+ decorative: false,
235
+ orientation: "vertical",
236
+ tabIndex: 0,
226
237
  "aria-label": "Resize workbench panel",
227
- "aria-orientation": "vertical",
228
238
  "aria-valuemin": workbenchPanelMinWidth,
229
239
  "aria-valuemax": workbenchPanelMaxWidth,
230
240
  "aria-valuenow": workbenchPanelWidth,
231
- className: "think-full-app__resizer",
241
+ className: "think-resize-handle think-full-app__resizer",
232
242
  onPointerDown: (event) => beginWorkbenchPanelResize(event, workbenchPanelWidth, setWorkbenchPanelWidth),
233
243
  onKeyDown: (event) => {
234
244
  if (event.key === "ArrowLeft") {
@@ -270,4 +280,4 @@ function ThinkFullApp({ agent, chat, className, defaultWorkbenchView, defaultThr
270
280
  });
271
281
  }
272
282
  //#endregion
273
- export { ThinkExecutionWorkbench, ThinkFullApp };
283
+ export { ThinkFullApp };
@@ -33,16 +33,6 @@ interface ThinkThreadPickerProps extends Omit<React.HTMLAttributes<HTMLElement>,
33
33
  /** Accessible label for the list navigation. */
34
34
  "aria-label"?: string;
35
35
  }
36
- interface ThinkThreadShellProps extends React.HTMLAttributes<HTMLDivElement> {
37
- /** Thread picker or app-owned sidebar shown beside the selected child shell. */
38
- sidebar: React.ReactNode;
39
- /** Whether the thread drawer is open. Omit for internal state. */
40
- sidebarOpen?: boolean;
41
- /** Initial thread drawer state when `sidebarOpen` is uncontrolled. */
42
- defaultSidebarOpen?: boolean;
43
- /** Called when the thread drawer is opened or closed. */
44
- onSidebarOpenChange?: (open: boolean) => void;
45
- }
46
36
  /**
47
37
  * Thread roster UI for sub-agent chat apps.
48
38
  *
@@ -64,25 +54,5 @@ declare function ThinkThreadPicker({
64
54
  }: ThinkThreadPickerProps & {
65
55
  ref?: React.Ref<HTMLElement>;
66
56
  }): React.JSX.Element;
67
- /**
68
- * Layout wrapper for a thread picker beside one selected `ThinkFullApp`.
69
- *
70
- * Mobile keeps the drawer at about 80% width so the selected chat remains
71
- * visible as a preview. It only owns layout; callers still own the parent agent,
72
- * selected child agent, chat hook, and shared workspace.
73
- */
74
- declare function ThinkThreadShell({
75
- sidebar,
76
- sidebarOpen,
77
- defaultSidebarOpen,
78
- onSidebarOpenChange,
79
- className,
80
- children,
81
- ref,
82
- style,
83
- ...props
84
- }: ThinkThreadShellProps & {
85
- ref?: React.Ref<HTMLDivElement>;
86
- }): React.JSX.Element;
87
57
  //#endregion
88
- export { ThinkThreadItem, ThinkThreadPicker, ThinkThreadPickerProps, ThinkThreadShell, ThinkThreadShellProps };
58
+ export { ThinkThreadItem, ThinkThreadPicker, ThinkThreadPickerProps };
@@ -1,42 +1,10 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { M as SpinnerIcon, O as PlusIcon, j as SidebarIcon, u as DotIcon } from "../icons-D2Q5n5C1.js";
2
+ import { M as SpinnerIcon, O as PlusIcon, u as DotIcon } from "../icons-D2Q5n5C1.js";
3
3
  import { Button } from "./Button.js";
4
- import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
5
4
  import { ScrollArea } from "./ScrollArea.js";
6
- import * as React from "react";
5
+ import "react";
7
6
  import { jsx, jsxs } from "react/jsx-runtime";
8
7
  //#region src/components/ThinkThreadPicker.tsx
9
- const threadSidebarDefaultWidth = 256;
10
- const threadSidebarMinWidth = 224;
11
- const threadSidebarMaxWidth = 384;
12
- const threadSidebarKeyboardStep = 24;
13
- function useControllableSidebar({ sidebarOpen, defaultSidebarOpen, onSidebarOpenChange }) {
14
- const [innerOpen, setInnerOpen] = React.useState(defaultSidebarOpen ?? true);
15
- return [sidebarOpen ?? innerOpen, React.useCallback((next) => {
16
- if (sidebarOpen === void 0) setInnerOpen(next);
17
- onSidebarOpenChange?.(next);
18
- }, [sidebarOpen, onSidebarOpenChange])];
19
- }
20
- function clampThreadSidebarWidth(width) {
21
- return Math.min(threadSidebarMaxWidth, Math.max(threadSidebarMinWidth, width));
22
- }
23
- function beginThreadSidebarResize(event, current, apply) {
24
- event.preventDefault();
25
- const startX = event.clientX;
26
- const onMove = (move) => {
27
- apply(clampThreadSidebarWidth(current + move.clientX - startX));
28
- };
29
- const onUp = () => {
30
- window.removeEventListener("pointermove", onMove);
31
- window.removeEventListener("pointerup", onUp);
32
- window.removeEventListener("pointercancel", onUp);
33
- document.body.classList.remove("is-resizing-columns");
34
- };
35
- document.body.classList.add("is-resizing-columns");
36
- window.addEventListener("pointermove", onMove);
37
- window.addEventListener("pointerup", onUp);
38
- window.addEventListener("pointercancel", onUp);
39
- }
40
8
  function toThreadDate(value) {
41
9
  if (value === void 0) return void 0;
42
10
  const date = value instanceof Date ? value : new Date(value);
@@ -116,38 +84,35 @@ function ThinkThreadPicker({ threads, selectedId, onSelect, onCreate, className,
116
84
  const timestamp = formatThreadTimestamp(thread);
117
85
  const statusLabel = formatThreadStatus(thread);
118
86
  const busy = isThreadBusy(thread.status);
119
- return /* @__PURE__ */ jsx("li", {
120
- className: "think-thread-picker__item",
121
- children: /* @__PURE__ */ jsxs(Button, {
122
- type: "button",
123
- variant: "ghost",
124
- color: "neutral",
125
- size: "sm",
126
- className: "think-thread-picker__thread",
127
- "data-selected": thread.id === selectedId ? "true" : "false",
128
- "data-status": thread.status,
129
- "aria-current": thread.id === selectedId ? "page" : void 0,
130
- onClick: () => onSelect(thread.id),
131
- children: [/* @__PURE__ */ jsx("span", {
132
- className: "think-thread-picker__thread-title",
133
- children: thread.title
134
- }), statusLabel ? /* @__PURE__ */ jsx("span", {
135
- className: "think-thread-picker__thread-status",
136
- role: "img",
137
- "aria-label": statusLabel,
138
- title: statusLabel,
139
- children: busy ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : /* @__PURE__ */ jsx(DotIcon, {})
140
- }) : timestamp?.date ? /* @__PURE__ */ jsx("time", {
141
- className: "think-thread-picker__thread-time",
142
- dateTime: timestamp.date.toISOString(),
143
- title: timestamp.date.toLocaleString(),
144
- children: timestamp.label
145
- }) : timestamp ? /* @__PURE__ */ jsx("span", {
146
- className: "think-thread-picker__thread-time",
147
- children: timestamp.label
148
- }) : null]
149
- })
150
- }, thread.id);
87
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Button, {
88
+ type: "button",
89
+ variant: "ghost",
90
+ color: "neutral",
91
+ size: "sm",
92
+ className: "think-thread-picker__thread",
93
+ "data-selected": thread.id === selectedId ? "true" : "false",
94
+ "data-status": thread.status,
95
+ "aria-current": thread.id === selectedId ? "page" : void 0,
96
+ onClick: () => onSelect(thread.id),
97
+ children: [/* @__PURE__ */ jsx("span", {
98
+ className: "think-thread-picker__thread-title",
99
+ children: thread.title
100
+ }), statusLabel ? /* @__PURE__ */ jsx("span", {
101
+ className: "think-thread-picker__thread-status",
102
+ role: "img",
103
+ "aria-label": statusLabel,
104
+ title: statusLabel,
105
+ children: busy ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : /* @__PURE__ */ jsx(DotIcon, {})
106
+ }) : timestamp?.date ? /* @__PURE__ */ jsx("time", {
107
+ className: "think-thread-picker__thread-time",
108
+ dateTime: timestamp.date.toISOString(),
109
+ title: timestamp.date.toLocaleString(),
110
+ children: timestamp.label
111
+ }) : timestamp ? /* @__PURE__ */ jsx("span", {
112
+ className: "think-thread-picker__thread-time",
113
+ children: timestamp.label
114
+ }) : null]
115
+ }) }, thread.id);
151
116
  })
152
117
  }) : /* @__PURE__ */ jsx("p", {
153
118
  className: "think-thread-picker__empty",
@@ -174,109 +139,5 @@ function ThinkThreadPicker({ threads, selectedId, onSelect, onCreate, className,
174
139
  ]
175
140
  });
176
141
  }
177
- /**
178
- * Layout wrapper for a thread picker beside one selected `ThinkFullApp`.
179
- *
180
- * Mobile keeps the drawer at about 80% width so the selected chat remains
181
- * visible as a preview. It only owns layout; callers still own the parent agent,
182
- * selected child agent, chat hook, and shared workspace.
183
- */
184
- function ThinkThreadShell({ sidebar, sidebarOpen, defaultSidebarOpen, onSidebarOpenChange, className, children, ref, style, ...props }) {
185
- const sidebarId = React.useId();
186
- const [isSidebarOpen, setSidebarOpen] = useControllableSidebar({
187
- sidebarOpen,
188
- defaultSidebarOpen,
189
- onSidebarOpenChange
190
- });
191
- const [sidebarWidth, setSidebarWidth] = React.useState(threadSidebarDefaultWidth);
192
- const toggleLabel = isSidebarOpen ? "Hide threads" : "Show threads";
193
- const rootStyle = {
194
- ...style,
195
- "--think-thread-sidebar-w": `${sidebarWidth}px`
196
- };
197
- const resizeThreadSidebarBy = (delta) => {
198
- setSidebarWidth((current) => clampThreadSidebarWidth(current + delta));
199
- };
200
- return /* @__PURE__ */ jsx("div", {
201
- ref,
202
- className: cx("think-thread-shell", className),
203
- style: rootStyle,
204
- ...props,
205
- children: /* @__PURE__ */ jsxs("div", {
206
- className: "think-thread-shell__frame",
207
- "data-sidebar-open": isSidebarOpen ? "true" : "false",
208
- children: [
209
- /* @__PURE__ */ jsx("div", {
210
- className: "think-thread-shell__toolbar",
211
- role: "toolbar",
212
- "aria-label": "Thread controls",
213
- children: /* @__PURE__ */ jsx("div", {
214
- className: "think-thread-shell__panel-toggle",
215
- children: /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: /* @__PURE__ */ jsx(Button, {
216
- type: "button",
217
- variant: "ghost",
218
- color: "neutral",
219
- size: "icon",
220
- "aria-label": toggleLabel,
221
- "aria-controls": sidebarId,
222
- "aria-expanded": isSidebarOpen,
223
- "aria-pressed": isSidebarOpen,
224
- "data-selected": isSidebarOpen,
225
- onClick: () => setSidebarOpen(!isSidebarOpen),
226
- children: /* @__PURE__ */ jsx(SidebarIcon, {})
227
- }) }), /* @__PURE__ */ jsx(TooltipPortal, { children: /* @__PURE__ */ jsx(TooltipPositioner, {
228
- side: "bottom",
229
- sideOffset: 6,
230
- children: /* @__PURE__ */ jsx(TooltipPopup, { children: toggleLabel })
231
- }) })] })
232
- })
233
- }),
234
- isSidebarOpen ? /* @__PURE__ */ jsx("button", {
235
- type: "button",
236
- role: "separator",
237
- "aria-label": "Resize threads panel",
238
- "aria-orientation": "vertical",
239
- "aria-valuemin": threadSidebarMinWidth,
240
- "aria-valuemax": threadSidebarMaxWidth,
241
- "aria-valuenow": sidebarWidth,
242
- className: "think-thread-shell__resizer",
243
- onPointerDown: (event) => beginThreadSidebarResize(event, sidebarWidth, setSidebarWidth),
244
- onKeyDown: (event) => {
245
- if (event.key === "ArrowLeft") {
246
- event.preventDefault();
247
- resizeThreadSidebarBy(-24);
248
- } else if (event.key === "ArrowRight") {
249
- event.preventDefault();
250
- resizeThreadSidebarBy(threadSidebarKeyboardStep);
251
- } else if (event.key === "Home") {
252
- event.preventDefault();
253
- setSidebarWidth(threadSidebarMinWidth);
254
- } else if (event.key === "End") {
255
- event.preventDefault();
256
- setSidebarWidth(threadSidebarMaxWidth);
257
- }
258
- }
259
- }) : null,
260
- /* @__PURE__ */ jsx("div", {
261
- id: sidebarId,
262
- className: "think-thread-shell__sidebar",
263
- "aria-hidden": isSidebarOpen ? void 0 : true,
264
- inert: isSidebarOpen ? void 0 : true,
265
- children: sidebar
266
- }),
267
- /* @__PURE__ */ jsx("div", {
268
- className: "think-thread-shell__main",
269
- children
270
- }),
271
- isSidebarOpen ? /* @__PURE__ */ jsx("button", {
272
- type: "button",
273
- className: "think-thread-shell__peek",
274
- "aria-label": "Show selected thread",
275
- onClick: () => setSidebarOpen(false)
276
- }) : null
277
- ]
278
- })
279
- });
280
- }
281
142
  //#endregion
282
- export { ThinkThreadPicker, ThinkThreadShell };
143
+ export { ThinkThreadPicker };
@@ -0,0 +1,35 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/components/ThinkThreadShell.d.ts
4
+ interface ThinkThreadShellProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ /** Thread picker or app-owned sidebar shown beside the selected child shell. */
6
+ sidebar: React.ReactNode;
7
+ /** Whether the thread drawer is open. Omit for internal state. */
8
+ sidebarOpen?: boolean;
9
+ /** Initial thread drawer state when `sidebarOpen` is uncontrolled. */
10
+ defaultSidebarOpen?: boolean;
11
+ /** Called when the thread drawer is opened or closed. */
12
+ onSidebarOpenChange?: (open: boolean) => void;
13
+ }
14
+ /**
15
+ * Layout wrapper for a thread picker beside one selected `ThinkFullApp`.
16
+ *
17
+ * Mobile keeps the drawer at about 80% width so the selected chat remains
18
+ * visible as a preview. It only owns layout; callers still own the parent agent,
19
+ * selected child agent, chat hook, and shared workspace.
20
+ */
21
+ declare function ThinkThreadShell({
22
+ sidebar,
23
+ sidebarOpen,
24
+ defaultSidebarOpen,
25
+ onSidebarOpenChange,
26
+ className,
27
+ children,
28
+ ref,
29
+ style,
30
+ ...props
31
+ }: ThinkThreadShellProps & {
32
+ ref?: React.Ref<HTMLDivElement>;
33
+ }): React.JSX.Element;
34
+ //#endregion
35
+ export { ThinkThreadShell, ThinkThreadShellProps };
@@ -0,0 +1,146 @@
1
+ import { t as cx } from "../class-names-9UtZwb0J.js";
2
+ import { j as SidebarIcon } from "../icons-D2Q5n5C1.js";
3
+ import { Separator } from "./Separator.js";
4
+ import { Button } from "./Button.js";
5
+ import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
6
+ import * as React from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/components/ThinkThreadShell.tsx
9
+ const threadSidebarDefaultWidth = 256;
10
+ const threadSidebarMinWidth = 224;
11
+ const threadSidebarMaxWidth = 384;
12
+ const threadSidebarKeyboardStep = 24;
13
+ function useControllableSidebar({ sidebarOpen, defaultSidebarOpen, onSidebarOpenChange }) {
14
+ const [innerOpen, setInnerOpen] = React.useState(defaultSidebarOpen ?? true);
15
+ return [sidebarOpen ?? innerOpen, React.useCallback((next) => {
16
+ if (sidebarOpen === void 0) setInnerOpen(next);
17
+ onSidebarOpenChange?.(next);
18
+ }, [sidebarOpen, onSidebarOpenChange])];
19
+ }
20
+ function clampThreadSidebarWidth(width) {
21
+ return Math.min(threadSidebarMaxWidth, Math.max(threadSidebarMinWidth, width));
22
+ }
23
+ function beginThreadSidebarResize(event, current, apply) {
24
+ event.preventDefault();
25
+ const startX = event.clientX;
26
+ const onMove = (move) => {
27
+ apply(clampThreadSidebarWidth(current + move.clientX - startX));
28
+ };
29
+ const onUp = () => {
30
+ window.removeEventListener("pointermove", onMove);
31
+ window.removeEventListener("pointerup", onUp);
32
+ window.removeEventListener("pointercancel", onUp);
33
+ document.body.classList.remove("is-resizing-think-thread-shell");
34
+ };
35
+ document.body.classList.add("is-resizing-think-thread-shell");
36
+ window.addEventListener("pointermove", onMove);
37
+ window.addEventListener("pointerup", onUp);
38
+ window.addEventListener("pointercancel", onUp);
39
+ }
40
+ /**
41
+ * Layout wrapper for a thread picker beside one selected `ThinkFullApp`.
42
+ *
43
+ * Mobile keeps the drawer at about 80% width so the selected chat remains
44
+ * visible as a preview. It only owns layout; callers still own the parent agent,
45
+ * selected child agent, chat hook, and shared workspace.
46
+ */
47
+ function ThinkThreadShell({ sidebar, sidebarOpen, defaultSidebarOpen, onSidebarOpenChange, className, children, ref, style, ...props }) {
48
+ const sidebarId = React.useId();
49
+ const [isSidebarOpen, setSidebarOpen] = useControllableSidebar({
50
+ sidebarOpen,
51
+ defaultSidebarOpen,
52
+ onSidebarOpenChange
53
+ });
54
+ const [sidebarWidth, setSidebarWidth] = React.useState(threadSidebarDefaultWidth);
55
+ const toggleLabel = isSidebarOpen ? "Hide threads" : "Show threads";
56
+ const rootStyle = {
57
+ ...style,
58
+ "--think-thread-sidebar-w": `${sidebarWidth}px`
59
+ };
60
+ const resizeThreadSidebarBy = (delta) => {
61
+ setSidebarWidth((current) => clampThreadSidebarWidth(current + delta));
62
+ };
63
+ return /* @__PURE__ */ jsx("div", {
64
+ ref,
65
+ className: cx("think-thread-shell", className),
66
+ style: rootStyle,
67
+ ...props,
68
+ children: /* @__PURE__ */ jsxs("div", {
69
+ className: "think-thread-shell__frame",
70
+ "data-sidebar-open": isSidebarOpen ? "true" : "false",
71
+ children: [
72
+ /* @__PURE__ */ jsx("div", {
73
+ className: "think-thread-shell__toolbar",
74
+ role: "toolbar",
75
+ "aria-label": "Thread controls",
76
+ children: /* @__PURE__ */ jsx("div", {
77
+ className: "think-thread-shell__panel-toggle",
78
+ children: /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: /* @__PURE__ */ jsx(Button, {
79
+ type: "button",
80
+ variant: "ghost",
81
+ color: "neutral",
82
+ size: "icon",
83
+ "aria-label": toggleLabel,
84
+ "aria-controls": sidebarId,
85
+ "aria-expanded": isSidebarOpen,
86
+ "aria-pressed": isSidebarOpen,
87
+ "data-selected": isSidebarOpen,
88
+ onClick: () => setSidebarOpen(!isSidebarOpen),
89
+ children: /* @__PURE__ */ jsx(SidebarIcon, {})
90
+ }) }), /* @__PURE__ */ jsx(TooltipPortal, { children: /* @__PURE__ */ jsx(TooltipPositioner, {
91
+ side: "bottom",
92
+ sideOffset: 6,
93
+ children: /* @__PURE__ */ jsx(TooltipPopup, { children: toggleLabel })
94
+ }) })] })
95
+ })
96
+ }),
97
+ isSidebarOpen ? /* @__PURE__ */ jsx(Separator, {
98
+ decorative: false,
99
+ orientation: "vertical",
100
+ tabIndex: 0,
101
+ "aria-label": "Resize threads panel",
102
+ "aria-valuemin": threadSidebarMinWidth,
103
+ "aria-valuemax": threadSidebarMaxWidth,
104
+ "aria-valuenow": sidebarWidth,
105
+ className: "think-resize-handle think-thread-shell__resizer",
106
+ onPointerDown: (event) => beginThreadSidebarResize(event, sidebarWidth, setSidebarWidth),
107
+ onKeyDown: (event) => {
108
+ if (event.key === "ArrowLeft") {
109
+ event.preventDefault();
110
+ resizeThreadSidebarBy(-24);
111
+ } else if (event.key === "ArrowRight") {
112
+ event.preventDefault();
113
+ resizeThreadSidebarBy(threadSidebarKeyboardStep);
114
+ } else if (event.key === "Home") {
115
+ event.preventDefault();
116
+ setSidebarWidth(threadSidebarMinWidth);
117
+ } else if (event.key === "End") {
118
+ event.preventDefault();
119
+ setSidebarWidth(threadSidebarMaxWidth);
120
+ }
121
+ }
122
+ }) : null,
123
+ /* @__PURE__ */ jsx("div", {
124
+ id: sidebarId,
125
+ className: "think-thread-shell__sidebar",
126
+ "aria-hidden": isSidebarOpen ? void 0 : true,
127
+ inert: isSidebarOpen ? void 0 : true,
128
+ children: sidebar
129
+ }),
130
+ /* @__PURE__ */ jsx("div", {
131
+ className: "think-thread-shell__main",
132
+ children
133
+ }),
134
+ isSidebarOpen ? /* @__PURE__ */ jsx(Button, {
135
+ variant: "ghost",
136
+ color: "neutral",
137
+ className: "think-thread-shell__peek",
138
+ "aria-label": "Show selected thread",
139
+ onClick: () => setSidebarOpen(false)
140
+ }) : null
141
+ ]
142
+ })
143
+ });
144
+ }
145
+ //#endregion
146
+ export { ThinkThreadShell };
@@ -2,6 +2,7 @@ import { t as cx } from "../class-names-9UtZwb0J.js";
2
2
  import { A as SearchIcon, h as FileIcon, k as RefreshIcon, n as ArrowLeftIcon } from "../icons-D2Q5n5C1.js";
3
3
  import { Button } from "./Button.js";
4
4
  import { a as CodeBlockCopyButton, i as CodeBlockContent, n as CodeBlockActions, o as CodeBlockFilename, p as CodeBlockTitle, r as CodeBlockContainer, s as CodeBlockHeader, t as CodeBlock } from "../CodeBlock-XNQOupQ3.js";
5
+ import { Input } from "./Input.js";
5
6
  import { i as FileTreeFolder, r as FileTreeFile, t as FileTree } from "../FileTree-wMyZhhHO.js";
6
7
  import * as React from "react";
7
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -277,11 +278,12 @@ function WorkspaceExplorer({ workspace, className, title = "Workspace", actions,
277
278
  className: "workspace-explorer__body",
278
279
  children: [showFilter ? /* @__PURE__ */ jsxs("label", {
279
280
  className: "workspace-explorer__filter",
280
- children: [/* @__PURE__ */ jsx(SearchIcon, { "aria-hidden": "true" }), /* @__PURE__ */ jsx("input", {
281
+ children: [/* @__PURE__ */ jsx(SearchIcon, { "aria-hidden": "true" }), /* @__PURE__ */ jsx(Input, {
281
282
  type: "search",
282
283
  value: filter,
283
284
  onChange: (event) => setFilter(event.currentTarget.value),
284
285
  placeholder: filterPlaceholder,
286
+ className: "workspace-explorer__filter-input",
285
287
  "aria-label": "Filter workspace files",
286
288
  autoComplete: "off"
287
289
  })]
@@ -0,0 +1,18 @@
1
+ //#region src/components/_internal/merge-refs.ts
2
+ function assignRef(ref, value) {
3
+ if (!ref) return;
4
+ if (typeof ref === "function") {
5
+ ref(value);
6
+ return;
7
+ }
8
+ ref.current = value;
9
+ }
10
+ function mergeRefs(...refs) {
11
+ const activeRefs = refs.filter(Boolean);
12
+ if (activeRefs.length === 0) return void 0;
13
+ return (value) => {
14
+ for (const activeRef of activeRefs) assignRef(activeRef, value);
15
+ };
16
+ }
17
+ //#endregion
18
+ export { mergeRefs as n, assignRef as t };