@mcp-b/react-components 0.30.0 → 0.31.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 (28) hide show
  1. package/dist/MenuDisclosureGroup-yJRq7YXa.js +32 -0
  2. package/dist/{ThinkChat-Dsm1xF3a.js → ThinkChat-ldbrNiAx.js} +29 -16
  3. package/dist/{WorkspaceFileView-hd1-cpuz.js → WorkspaceFileView-BtzVKAed.js} +64 -87
  4. package/dist/components/agents-sdk/McpServerPicker.d.ts +9 -1
  5. package/dist/components/agents-sdk/McpServerPicker.js +5 -5
  6. package/dist/components/agents-sdk/ThinkChat.d.ts +24 -1
  7. package/dist/components/agents-sdk/ThinkChat.js +1 -1
  8. package/dist/components/agents-sdk/ThinkFullApp.d.ts +16 -12
  9. package/dist/components/agents-sdk/ThinkFullApp.js +33 -26
  10. package/dist/components/agents-sdk/ThinkRoutineLibrary.d.ts +3 -0
  11. package/dist/components/agents-sdk/ThinkRoutineLibrary.js +35 -30
  12. package/dist/components/agents-sdk/ThinkThreadPicker.d.ts +5 -1
  13. package/dist/components/agents-sdk/ThinkThreadPicker.js +1 -3
  14. package/dist/components/agents-sdk/WorkspaceExplorer.js +1 -3
  15. package/dist/components/agents-sdk/WorkspaceFileView.js +1 -1
  16. package/dist/components/agents-sdk/WorkspaceMountManager.js +2 -2
  17. package/dist/components/general-purpose/ResizableSidePanel.d.ts +6 -0
  18. package/dist/components/general-purpose/ResizableSidePanel.js +10 -2
  19. package/dist/components/general-purpose/SetupChecklist.d.ts +3 -0
  20. package/dist/components/general-purpose/SetupChecklist.js +19 -13
  21. package/dist/components/nanites/AgentToolDetail.js +1 -1
  22. package/dist/styles/file-tree.css +1 -0
  23. package/dist/styles/index.css +1 -0
  24. package/dist/styles/mcp-server-picker.css +1 -3
  25. package/dist/styles/menu-disclosure-group.css +13 -0
  26. package/dist/styles/think-full-app.css +1 -1
  27. package/dist/styles/workspace-explorer.css +0 -9
  28. package/package.json +2 -2
@@ -0,0 +1,32 @@
1
+ import { n as mergeBaseClassName } from "./class-names-BiMDVpUo.js";
2
+ import { f as ChevronDownIcon } from "./icons-B1Qw05te.js";
3
+ import { Menu } from "./components/foundations/Menu.js";
4
+ import * as React from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/_internal/MenuDisclosureGroup.tsx
7
+ /**
8
+ * A menu-native disclosure: its trigger stays in the menu roving-focus model,
9
+ * while its rows mount only after the user expands the section.
10
+ */
11
+ function MenuDisclosureGroup({ children, className, defaultOpen = false, label, triggerClassName, ...props }) {
12
+ const [open, setOpen] = React.useState(defaultOpen);
13
+ return /* @__PURE__ */ jsxs(Menu.Group, {
14
+ className: mergeBaseClassName("menu-disclosure-group", className),
15
+ ...props,
16
+ children: [/* @__PURE__ */ jsxs(Menu.Item, {
17
+ "aria-expanded": open,
18
+ className: mergeBaseClassName("menu-disclosure-group__trigger", triggerClassName),
19
+ closeOnClick: false,
20
+ onClick: () => setOpen((current) => !current),
21
+ children: [/* @__PURE__ */ jsx("span", {
22
+ className: "sigvelo-truncate-grow",
23
+ children: label
24
+ }), /* @__PURE__ */ jsx(ChevronDownIcon, { "aria-hidden": "true" })]
25
+ }), open ? /* @__PURE__ */ jsx("div", {
26
+ className: "menu-disclosure-group__items",
27
+ children
28
+ }) : null]
29
+ });
30
+ }
31
+ //#endregion
32
+ export { MenuDisclosureGroup as t };
@@ -3,7 +3,7 @@ import { TransitionSurface } from "./components/foundations/TransitionSurface.js
3
3
  import { AgentChat } from "./components/agents-sdk/AgentChat.js";
4
4
  import { AgentToolRunsProvider, useOptionalAgentToolRuns } from "./components/agents-sdk/AgentToolRunsContext.js";
5
5
  import { SubagentRunList } from "./components/agents-sdk/SubagentRunList.js";
6
- import { ThinkChatContext, ThinkChatLiveContext, useThinkChatContext } from "./components/agents-sdk/ThinkChatContext.js";
6
+ import { ThinkChatContext, ThinkChatLiveContext, useOptionalThinkChatContext, useThinkChatContext } from "./components/agents-sdk/ThinkChatContext.js";
7
7
  import { ThinkChatActivity, createThinkChatActivityRenderer, renderThinkChatActivityPart } from "./components/agents-sdk/ThinkChatActivity.js";
8
8
  import { ThinkRecoveryNotice } from "./components/agents-sdk/ThinkRecoveryNotice.js";
9
9
  import { t as WorkspaceMessageResponse } from "./WorkspaceMessageResponse-BWbkIELl.js";
@@ -202,11 +202,10 @@ const ThinkChatApprovalsContext = React.createContext(null);
202
202
  * inside the log) or `excludeTools` + your own `renderPart` (standalone
203
203
  * card) — see README "App-specific tools" and the Custom Tool Panel story.
204
204
  */
205
- function ThinkChatMessages({ composerHeader, renderPart, excludeTools, renderAgentToolRunLink, toolRenderers, thinkStub, onExecutionSettled, pendingApprovals, notice, sessionCompaction, ...props }) {
206
- const chat = useThinkChatContext("ThinkChat.Messages");
205
+ function ThinkChatMessages({ composerHeader, draft, renderPart, excludeTools, renderAgentToolRunLink, toolRenderers, thinkStub, onExecutionSettled, pendingApprovals, notice, sessionCompaction, ...props }) {
206
+ const chat = useOptionalThinkChatContext();
207
207
  const agentTools = useOptionalAgentToolRuns();
208
208
  const approvals = React.useContext(ThinkChatApprovalsContext);
209
- const status = toAgentChatStatus(chat);
210
209
  const resolvedApprovals = resolveThinkApprovalProps({
211
210
  thinkStub,
212
211
  pendingApprovals,
@@ -241,7 +240,7 @@ function ThinkChatMessages({ composerHeader, renderPart, excludeTools, renderAge
241
240
  });
242
241
  return custom === void 0 ? renderBuiltIn() : custom;
243
242
  } : defaultRenderPart, [defaultRenderPart, renderPart]);
244
- const defaultNotice = /* @__PURE__ */ jsx(ThinkRecoveryNotice, { chat });
243
+ const defaultNotice = chat ? /* @__PURE__ */ jsx(ThinkRecoveryNotice, { chat }) : null;
245
244
  const [dismissedCompaction, setDismissedCompaction] = React.useState(null);
246
245
  const landedCompaction = sessionCompaction?.lastCompaction && sessionCompaction.lastCompaction !== dismissedCompaction ? sessionCompaction.lastCompaction : null;
247
246
  const sessionCompactionNotice = sessionCompaction?.compacting ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SpinnerIcon, {}), "Compacting context…"] }) : sessionCompaction?.sessionError ? /* @__PURE__ */ jsxs(TransitionSurface, {
@@ -256,7 +255,7 @@ function ThinkChatMessages({ composerHeader, renderPart, excludeTools, renderAge
256
255
  className: "think-recovery-notice",
257
256
  children: [compactionSizeText(landedCompaction), " Context usage updates after your next message."]
258
257
  }) : null;
259
- const recoveryActive = chat.isRecovering || chat.connectionError || chat.error;
258
+ const recoveryActive = chat && (chat.isRecovering || chat.connectionError || chat.error);
260
259
  const backgroundRuns = renderAgentToolRunLink ? agentTools?.unboundRuns : void 0;
261
260
  const resolvedComposerHeader = composerHeader || backgroundRuns?.length ? /* @__PURE__ */ jsxs(Fragment, { children: [composerHeader, backgroundRuns?.length && renderAgentToolRunLink ? /* @__PURE__ */ jsxs("div", {
262
261
  className: "subagent-run__tray",
@@ -270,11 +269,32 @@ function ThinkChatMessages({ composerHeader, renderPart, excludeTools, renderAge
270
269
  renderRunLink: renderAgentToolRunLink
271
270
  })]
272
271
  }) : null] }) : void 0;
272
+ const submit = ({ text, files, references }, send) => {
273
+ setDismissedCompaction(sessionCompaction?.lastCompaction ?? null);
274
+ const prompt = [...references?.map(({ trigger, value }) => trigger ? `${trigger}${value}` : value) ?? [], text.trim()].filter(Boolean).join(" ");
275
+ if (!prompt && !files.length) return;
276
+ return send({
277
+ text: prompt,
278
+ files
279
+ });
280
+ };
281
+ if (!chat) {
282
+ if (!draft) throw new Error("ThinkChat.Messages must be used inside <ThinkChat.Provider> or <ThinkChat.Root>, or given a `draft`.");
283
+ return /* @__PURE__ */ jsx(AgentChat, {
284
+ ...props,
285
+ renderPart: resolvedRenderPart,
286
+ messages: draft.messages ?? EMPTY_DRAFT_MESSAGES,
287
+ status: draft.status ?? "ready",
288
+ notice: notice ?? sessionCompactionNotice,
289
+ composerHeader: resolvedComposerHeader,
290
+ onSubmit: (message) => submit(message, draft.onSubmit)
291
+ });
292
+ }
273
293
  return /* @__PURE__ */ jsx(AgentChat, {
274
294
  ...props,
275
295
  renderPart: resolvedRenderPart,
276
296
  messages: chat.messages,
277
- status,
297
+ status: toAgentChatStatus(chat),
278
298
  onStop: chat.stop,
279
299
  onApprovalResponse: chat.addToolApprovalResponse,
280
300
  thinkStub: resolvedApprovals.thinkStub,
@@ -283,17 +303,10 @@ function ThinkChatMessages({ composerHeader, renderPart, excludeTools, renderAge
283
303
  notice: notice ?? (recoveryActive ? defaultNotice : sessionCompactionNotice),
284
304
  composerHeader: resolvedComposerHeader,
285
305
  onRegenerate: (messageId) => void chat.regenerate({ messageId }),
286
- onSubmit: ({ text, files, references }) => {
287
- setDismissedCompaction(sessionCompaction?.lastCompaction ?? null);
288
- const prompt = [...references?.map(({ trigger, value }) => trigger ? `${trigger}${value}` : value) ?? [], text.trim()].filter(Boolean).join(" ");
289
- if (!prompt && !files.length) return;
290
- return chat.sendMessage({
291
- text: prompt,
292
- files
293
- });
294
- }
306
+ onSubmit: (message) => submit(message, chat.sendMessage)
295
307
  });
296
308
  }
309
+ const EMPTY_DRAFT_MESSAGES = [];
297
310
  /**
298
311
  * The ambient chat value from `ThinkChat.Root`/`Provider` — for custom tool
299
312
  * panels, cards, or composer actions that need `messages`, `status`, or
@@ -1,6 +1,4 @@
1
- import { A as MaximizeIcon, d as CheckIcon, h as CodeIcon, rt as XIcon, tt as WarningIcon, x as EyeIcon, y as DownloadIcon } from "./icons-B1Qw05te.js";
2
- import { t as NavigationLink } from "./navigation-link-kqMa81v5.js";
3
- import { buttonVariants } from "./components/foundations/Button.js";
1
+ import { A as MaximizeIcon, d as CheckIcon, h as CodeIcon, r as ArrowLeftIcon, tt as WarningIcon, x as EyeIcon, y as DownloadIcon } from "./icons-B1Qw05te.js";
4
2
  import { r as formatClock } from "./format-CmopcfqJ.js";
5
3
  import { a as CodeBlockCopyButton, i as CodeBlockContent, r as CodeBlockContainer, t as CodeBlock } from "./CodeBlock-CM5gfmdq.js";
6
4
  import { inferWorkspaceLanguage, inferWorkspaceMedia, isWorkspaceMarkdownPath, isWorkspaceSkillPath, parseWorkspaceSkill } from "./components/agents-sdk/WorkspaceFile.js";
@@ -555,22 +553,13 @@ function WorkspaceFileView({ appearance = "contained", file, path, isLoading, is
555
553
  downloadUrl: assetUrl.downloadUrl,
556
554
  allowOpen: media?.mimeType !== "image/svg+xml"
557
555
  }) : null;
558
- const closeAction = workspaceNavigation ? /* @__PURE__ */ jsx(NavigationLink, {
559
- "aria-label": "Close file",
560
- className: buttonVariants({
561
- color: "neutral",
562
- variant: "ghost",
563
- size: "sm",
564
- className: "workspace-explorer__file-close"
565
- }),
566
- "data-icon-only": "",
567
- "data-slot": "button",
568
- render: workspaceNavigation.navigation.renderLink({ kind: "files" }),
569
- children: /* @__PURE__ */ jsx(XIcon, { "aria-hidden": "true" })
570
- }) : null;
571
556
  const headerProps = {
572
557
  path,
573
- leading,
558
+ leading: workspaceNavigation ? /* @__PURE__ */ jsx(AppTopBar.Link, {
559
+ label: "Back to workspace",
560
+ render: workspaceNavigation.navigation.renderLink({ kind: "files" }),
561
+ children: /* @__PURE__ */ jsx(ArrowLeftIcon, { "aria-hidden": "true" })
562
+ }) : leading,
574
563
  actions: isMarkdown ? /* @__PURE__ */ jsxs(Fragment, { children: [
575
564
  actions,
576
565
  assetActions,
@@ -606,17 +595,13 @@ function WorkspaceFileView({ appearance = "contained", file, path, isLoading, is
606
595
  className: "workspace-explorer__file",
607
596
  "data-appearance": appearance,
608
597
  "data-workspace-restoration-scope": "file",
609
- children: [
610
- /* @__PURE__ */ jsx(WorkspaceHeader, { ...headerProps }),
611
- closeAction,
612
- /* @__PURE__ */ jsx("div", {
613
- className: "workspace-explorer__empty",
614
- "data-workspace-file-content": "",
615
- "data-workspace-focus-target": "",
616
- role,
617
- children: message
618
- })
619
- ]
598
+ children: [/* @__PURE__ */ jsx(WorkspaceHeader, { ...headerProps }), /* @__PURE__ */ jsx("div", {
599
+ className: "workspace-explorer__empty",
600
+ "data-workspace-file-content": "",
601
+ "data-workspace-focus-target": "",
602
+ role,
603
+ children: message
604
+ })]
620
605
  });
621
606
  }
622
607
  if (file.asset && media && assetUrl.url) return /* @__PURE__ */ jsxs("div", {
@@ -624,18 +609,14 @@ function WorkspaceFileView({ appearance = "contained", file, path, isLoading, is
624
609
  className: "workspace-explorer__file",
625
610
  "data-appearance": appearance,
626
611
  "data-workspace-restoration-scope": "file",
627
- children: [
628
- /* @__PURE__ */ jsx(WorkspaceHeader, { ...headerProps }),
629
- closeAction,
630
- /* @__PURE__ */ jsx(WorkspaceMediaPreview, {
631
- asset: file.asset,
632
- fileName: file.name,
633
- media,
634
- url: assetUrl.url,
635
- downloadUrl: assetUrl.downloadUrl,
636
- onScroll: handleScroll
637
- })
638
- ]
612
+ children: [/* @__PURE__ */ jsx(WorkspaceHeader, { ...headerProps }), /* @__PURE__ */ jsx(WorkspaceMediaPreview, {
613
+ asset: file.asset,
614
+ fileName: file.name,
615
+ media,
616
+ url: assetUrl.url,
617
+ downloadUrl: assetUrl.downloadUrl,
618
+ onScroll: handleScroll
619
+ })]
639
620
  });
640
621
  if (file.content === null) return null;
641
622
  if (isMarkdown && markdownView === "preview") {
@@ -652,60 +633,56 @@ function WorkspaceFileView({ appearance = "contained", file, path, isLoading, is
652
633
  className: "workspace-explorer__file",
653
634
  "data-appearance": appearance,
654
635
  "data-workspace-restoration-scope": "file",
655
- children: [
656
- /* @__PURE__ */ jsx(WorkspaceHeader, { ...headerProps }),
657
- closeAction,
658
- /* @__PURE__ */ jsx("div", {
659
- ref: scrollRef,
660
- className: "workspace-explorer__markdown-scroll",
661
- "data-workspace-file-content": "",
662
- "data-workspace-scroll": "",
663
- onScroll: handleScroll,
664
- children: /* @__PURE__ */ jsxs("article", {
665
- className: "workspace-explorer__markdown",
666
- children: [skill ? /* @__PURE__ */ jsxs("header", {
667
- className: "workspace-explorer__skill",
668
- "data-skill-identity": showSkillIdentity ? "" : void 0,
669
- children: [
670
- showSkillIdentity ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
671
- className: "workspace-explorer__skill-kicker",
672
- children: "Agent Skill"
673
- }), skill.parsed ? /* @__PURE__ */ jsxs(Fragment, { children: [
674
- /* @__PURE__ */ jsx("p", {
675
- className: "workspace-explorer__skill-name",
676
- children: skill.parsed.properties.name
677
- }),
678
- /* @__PURE__ */ jsx("p", {
679
- className: "workspace-explorer__skill-description",
680
- children: skill.parsed.properties.description
681
- }),
682
- /* @__PURE__ */ jsxs("dl", {
683
- className: "workspace-explorer__skill-metadata",
684
- children: [skill.parsed.properties.compatibility ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("dt", { children: "Compatibility" }), /* @__PURE__ */ jsx("dd", { children: skill.parsed.properties.compatibility })] }) : null, skill.parsed.properties.allowedTools ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("dt", { children: "Allowed tools" }), /* @__PURE__ */ jsx("dd", { children: skill.parsed.properties.allowedTools })] }) : null]
685
- })
686
- ] }) : null] }) : null,
687
- /* @__PURE__ */ jsxs("div", {
688
- className: "workspace-explorer__skill-status",
689
- "data-invalid": skill.validationErrors.length > 0 ? "" : void 0,
690
- children: [skill.validationErrors.length > 0 ? /* @__PURE__ */ jsx(WarningIcon, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(CheckIcon, { "aria-hidden": "true" }), skill.validationErrors.length > 0 ? `${skill.validationErrors.length.toLocaleString()} validation ${skill.validationErrors.length === 1 ? "issue" : "issues"}` : "Valid Agent Skill"]
636
+ children: [/* @__PURE__ */ jsx(WorkspaceHeader, { ...headerProps }), /* @__PURE__ */ jsx("div", {
637
+ ref: scrollRef,
638
+ className: "workspace-explorer__markdown-scroll",
639
+ "data-workspace-file-content": "",
640
+ "data-workspace-scroll": "",
641
+ onScroll: handleScroll,
642
+ children: /* @__PURE__ */ jsxs("article", {
643
+ className: "workspace-explorer__markdown",
644
+ children: [skill ? /* @__PURE__ */ jsxs("header", {
645
+ className: "workspace-explorer__skill",
646
+ "data-skill-identity": showSkillIdentity ? "" : void 0,
647
+ children: [
648
+ showSkillIdentity ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
649
+ className: "workspace-explorer__skill-kicker",
650
+ children: "Agent Skill"
651
+ }), skill.parsed ? /* @__PURE__ */ jsxs(Fragment, { children: [
652
+ /* @__PURE__ */ jsx("p", {
653
+ className: "workspace-explorer__skill-name",
654
+ children: skill.parsed.properties.name
691
655
  }),
692
- skill.validationErrors.length > 0 ? /* @__PURE__ */ jsx("ul", {
693
- className: "workspace-explorer__skill-errors",
694
- children: skill.validationErrors.map((error) => /* @__PURE__ */ jsx("li", { children: error }, error))
695
- }) : null
696
- ]
697
- }) : null, response]
698
- })
656
+ /* @__PURE__ */ jsx("p", {
657
+ className: "workspace-explorer__skill-description",
658
+ children: skill.parsed.properties.description
659
+ }),
660
+ /* @__PURE__ */ jsxs("dl", {
661
+ className: "workspace-explorer__skill-metadata",
662
+ children: [skill.parsed.properties.compatibility ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("dt", { children: "Compatibility" }), /* @__PURE__ */ jsx("dd", { children: skill.parsed.properties.compatibility })] }) : null, skill.parsed.properties.allowedTools ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("dt", { children: "Allowed tools" }), /* @__PURE__ */ jsx("dd", { children: skill.parsed.properties.allowedTools })] }) : null]
663
+ })
664
+ ] }) : null] }) : null,
665
+ /* @__PURE__ */ jsxs("div", {
666
+ className: "workspace-explorer__skill-status",
667
+ "data-invalid": skill.validationErrors.length > 0 ? "" : void 0,
668
+ children: [skill.validationErrors.length > 0 ? /* @__PURE__ */ jsx(WarningIcon, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(CheckIcon, { "aria-hidden": "true" }), skill.validationErrors.length > 0 ? `${skill.validationErrors.length.toLocaleString()} validation ${skill.validationErrors.length === 1 ? "issue" : "issues"}` : "Valid Agent Skill"]
669
+ }),
670
+ skill.validationErrors.length > 0 ? /* @__PURE__ */ jsx("ul", {
671
+ className: "workspace-explorer__skill-errors",
672
+ children: skill.validationErrors.map((error) => /* @__PURE__ */ jsx("li", { children: error }, error))
673
+ }) : null
674
+ ]
675
+ }) : null, response]
699
676
  })
700
- ]
677
+ })]
701
678
  });
702
679
  }
703
- return /* @__PURE__ */ jsxs("div", {
680
+ return /* @__PURE__ */ jsx("div", {
704
681
  ref: fileViewRef,
705
682
  className: "workspace-explorer__file",
706
683
  "data-appearance": appearance,
707
684
  "data-workspace-restoration-scope": "file",
708
- children: [closeAction, /* @__PURE__ */ jsxs(CodeBlock, {
685
+ children: /* @__PURE__ */ jsxs(CodeBlock, {
709
686
  className: "workspace-explorer__code",
710
687
  code: file.content,
711
688
  "data-workspace-file-content": "",
@@ -724,7 +701,7 @@ function WorkspaceFileView({ appearance = "contained", file, path, isLoading, is
724
701
  onScroll: handleScroll,
725
702
  children: /* @__PURE__ */ jsx(CodeBlockContent, {})
726
703
  })]
727
- })]
704
+ })
728
705
  });
729
706
  }
730
707
  //#endregion
@@ -5,6 +5,14 @@ import { l as DialogProps } from "../../Dialog-DeOSJ0Oy.js";
5
5
  import * as React from "react";
6
6
  import { MCPServersState } from "agents";
7
7
 
8
+ //#region src/components/_internal/MenuDisclosureGroup.d.ts
9
+ interface MenuDisclosureGroupProps extends Omit<React.ComponentProps<typeof Menu.Group>, "children"> {
10
+ label: React.ReactNode;
11
+ children: React.ReactNode;
12
+ defaultOpen?: boolean;
13
+ triggerClassName?: string;
14
+ }
15
+ //#endregion
8
16
  //#region src/components/agents-sdk/McpServerPicker.d.ts
9
17
  interface McpServerPickerProps {
10
18
  /** MCP servers to show in the plus-menu picker. */
@@ -24,7 +32,7 @@ interface McpServerPickerProps {
24
32
  triggerLabel?: string;
25
33
  }
26
34
  type McpServerPickerItemsProps = Omit<McpServerPickerProps, "sideOffset" | "triggerLabel">;
27
- interface McpServerPickerGroupProps extends Omit<React.ComponentProps<typeof Menu.Group>, "children" | "label"> {
35
+ interface McpServerPickerGroupProps extends Omit<MenuDisclosureGroupProps, "children" | "label" | "triggerClassName"> {
28
36
  /** Quiet visible heading for a related set of picker actions. */
29
37
  label: React.ReactNode;
30
38
  children: React.ReactNode;
@@ -8,6 +8,7 @@ import { Menu } from "../foundations/Menu.js";
8
8
  import { PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuTrigger } from "../ai-sdk/PromptInput.js";
9
9
  import { n as getMcpServerConnectionKind, t as McpServerIcon } from "../../mcp-server-U71zhxFF.js";
10
10
  import { McpConnectorForm } from "./McpConnectorForm.js";
11
+ import { t as MenuDisclosureGroup } from "../../MenuDisclosureGroup-yJRq7YXa.js";
11
12
  import * as React from "react";
12
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
14
  //#region src/components/agents-sdk/McpServerPicker.tsx
@@ -127,13 +128,12 @@ function McpServerPickerItems({ servers, onConnect, mcp, onDisconnect, actions,
127
128
  ] });
128
129
  }
129
130
  function McpServerPickerGroup({ label, children, className, ...props }) {
130
- return /* @__PURE__ */ jsxs(Menu.Group, {
131
+ return /* @__PURE__ */ jsx(MenuDisclosureGroup, {
131
132
  className: mergeBaseClassName("mcp-server-picker__group", className),
133
+ label,
134
+ triggerClassName: "mcp-server-picker__group-trigger",
132
135
  ...props,
133
- children: [/* @__PURE__ */ jsx(Menu.GroupLabel, {
134
- className: "mcp-server-picker__group-label",
135
- children: label
136
- }), children]
136
+ children
137
137
  });
138
138
  }
139
139
  function McpServerPickerAction({ icon, label, description, className, ...props }) {
@@ -1,4 +1,5 @@
1
1
  import { i as AgentMessageRenderPartContext } from "../../AgentMessageParts-C7L-Mv9U.js";
2
+ import { ct as PromptInputMessage } from "../../PromptInput-DOyee1kM.js";
2
3
  import { r as AgentChatProps } from "../../AgentChat-CV-GuYA6.js";
3
4
  import { i as useOptionalAgentToolRuns, n as AgentToolRunsProvider, r as AgentToolRunsProviderProps, t as AgentToolEventsValue } from "../../AgentToolRunsContext-Cgve-Upx.js";
4
5
  import { n as BrowserLiveViewProps, t as BrowserLiveView } from "../../BrowserLiveView-tJTWkoyu.js";
@@ -46,8 +47,29 @@ interface ThinkChatRootProps<State = unknown> {
46
47
  sourceKey: string;
47
48
  children: React.ReactNode;
48
49
  }
50
+ /**
51
+ * The first-turn surface with no conversation behind it. Supply this instead of
52
+ * a chat provider when the composer's submission is what creates the
53
+ * conversation: connecting early is what leaves empty threads behind.
54
+ */
55
+ interface ThinkChatDraft<MessageT extends UIMessage = UIMessage> {
56
+ /** Client-only transcript rows, such as a locally rendered guide. */
57
+ messages?: readonly MessageT[];
58
+ /** Receives the first message, normalized the same way a live thread's is. */
59
+ onSubmit: (message: {
60
+ text: string;
61
+ files: PromptInputMessage["files"];
62
+ }) => void | Promise<void>;
63
+ /** Set while the app is creating the conversation, so the composer reads busy. */
64
+ status?: AgentChatProps<MessageT>["status"];
65
+ }
49
66
  interface ThinkChatMessagesProps<MessageT extends UIMessage = UIMessage> extends ThinkChatActivityRendererOptions<MessageT> {
50
67
  className?: string;
68
+ /**
69
+ * Renders without a chat provider, for the first turn of a conversation that
70
+ * does not exist yet. Everything else here behaves as it does on a live thread.
71
+ */
72
+ draft?: ThinkChatDraft<MessageT>;
51
73
  /** Disable the composer (e.g. while the agent is unreachable). */
52
74
  disabled?: boolean;
53
75
  /** Hide the composer while retaining the normal Think transcript rendering. */
@@ -179,6 +201,7 @@ declare function ThinkChatRoot<State = unknown, MessageT extends UIMessage = UIM
179
201
  */
180
202
  declare function ThinkChatMessages<State = unknown, MessageT extends UIMessage = UIMessage>({
181
203
  composerHeader,
204
+ draft,
182
205
  renderPart,
183
206
  excludeTools,
184
207
  renderAgentToolRunLink,
@@ -230,4 +253,4 @@ declare const ThinkChat: {
230
253
  createActivityRenderer: typeof createThinkChatActivityRenderer;
231
254
  };
232
255
  //#endregion
233
- export { type AgentToolEventsValue, AgentToolRunsProvider, type AgentToolRunsProviderProps, BrowserLiveView, type BrowserLiveViewProps, BrowserReplay, type BrowserReplayProps, ThinkChat, ThinkChatActivity, type ThinkChatActivityProps, type ThinkChatActivityRendererOptions, ThinkChatMessages, ThinkChatMessagesProps, ThinkChatProvider, ThinkChatProviderProps, ThinkChatRoot, ThinkChatRootProps, type ThinkChatToolRenderer, type ThinkChatToolRenderers, ThinkPendingExecutionApprovalsQueryKey, ThinkPendingExecutionApprovalsQueryOptions, ThinkRecoveryNotice, type ThinkRecoveryNoticeProps, type UseWorkspaceOptions, WorkspaceExplorer, type WorkspaceExplorerProps, type WorkspaceFileReadTarget, type WorkspaceFileState, type WorkspaceInfo, type WorkspaceQueryKey, type WorkspaceSource, type WorkspaceState, createThinkChatActivityRenderer, describeThinkChatActivityPart, inferWorkspaceLanguage, isThinkChatActivityPart, renderThinkChatActivityPart, thinkPendingExecutionApprovalsQueryOptions, useOptionalAgentToolRuns, useThinkChat, useThinkPendingExecutionApprovals, useWorkspace, workspaceBinaryFileQueryOptions, workspaceDirectoryQueryKey, workspaceDirectoryQueryOptions, workspaceDirectoryQueryPrefix, workspaceFileAssetQueryOptions, workspaceFileStatQueryOptions, workspaceInfoQueryOptions, workspaceQueryKey, workspaceTextFileQueryOptions };
256
+ export { type AgentToolEventsValue, AgentToolRunsProvider, type AgentToolRunsProviderProps, BrowserLiveView, type BrowserLiveViewProps, BrowserReplay, type BrowserReplayProps, ThinkChat, ThinkChatActivity, type ThinkChatActivityProps, type ThinkChatActivityRendererOptions, ThinkChatDraft, ThinkChatMessages, ThinkChatMessagesProps, ThinkChatProvider, ThinkChatProviderProps, ThinkChatRoot, ThinkChatRootProps, type ThinkChatToolRenderer, type ThinkChatToolRenderers, ThinkPendingExecutionApprovalsQueryKey, ThinkPendingExecutionApprovalsQueryOptions, ThinkRecoveryNotice, type ThinkRecoveryNoticeProps, type UseWorkspaceOptions, WorkspaceExplorer, type WorkspaceExplorerProps, type WorkspaceFileReadTarget, type WorkspaceFileState, type WorkspaceInfo, type WorkspaceQueryKey, type WorkspaceSource, type WorkspaceState, createThinkChatActivityRenderer, describeThinkChatActivityPart, inferWorkspaceLanguage, isThinkChatActivityPart, renderThinkChatActivityPart, thinkPendingExecutionApprovalsQueryOptions, useOptionalAgentToolRuns, useThinkChat, useThinkPendingExecutionApprovals, useWorkspace, workspaceBinaryFileQueryOptions, workspaceDirectoryQueryKey, workspaceDirectoryQueryOptions, workspaceDirectoryQueryPrefix, workspaceFileAssetQueryOptions, workspaceFileStatQueryOptions, workspaceInfoQueryOptions, workspaceQueryKey, workspaceTextFileQueryOptions };
@@ -6,7 +6,7 @@ import { isThinkChatActivityPart } from "./ThinkChatToolParts.js";
6
6
  import { describeThinkChatActivityPart } from "./ThinkChatActivitySummary.js";
7
7
  import { ThinkChatActivity, createThinkChatActivityRenderer, renderThinkChatActivityPart } from "./ThinkChatActivity.js";
8
8
  import { ThinkRecoveryNotice } from "./ThinkRecoveryNotice.js";
9
- import { a as thinkPendingExecutionApprovalsQueryOptions, i as ThinkChatRoot, n as ThinkChatMessages, o as useThinkChat, r as ThinkChatProvider, s as useThinkPendingExecutionApprovals, t as ThinkChat } from "../../ThinkChat-Dsm1xF3a.js";
9
+ import { a as thinkPendingExecutionApprovalsQueryOptions, i as ThinkChatRoot, n as ThinkChatMessages, o as useThinkChat, r as ThinkChatProvider, s as useThinkPendingExecutionApprovals, t as ThinkChat } from "../../ThinkChat-ldbrNiAx.js";
10
10
  import { useWorkspace, workspaceBinaryFileQueryOptions, workspaceDirectoryQueryKey, workspaceDirectoryQueryOptions, workspaceDirectoryQueryPrefix, workspaceFileAssetQueryOptions, workspaceFileStatQueryOptions, workspaceInfoQueryOptions, workspaceQueryKey, workspaceTextFileQueryOptions } from "./Workspace.js";
11
11
  import { WorkspaceExplorer } from "./WorkspaceExplorer.js";
12
12
  export { AgentToolRunsProvider, BrowserLiveView, BrowserReplay, ThinkChat, ThinkChatActivity, ThinkChatMessages, ThinkChatProvider, ThinkChatRoot, ThinkRecoveryNotice, WorkspaceExplorer, createThinkChatActivityRenderer, describeThinkChatActivityPart, inferWorkspaceLanguage, isThinkChatActivityPart, renderThinkChatActivityPart, thinkPendingExecutionApprovalsQueryOptions, useOptionalAgentToolRuns, useThinkChat, useThinkPendingExecutionApprovals, useWorkspace, workspaceBinaryFileQueryOptions, workspaceDirectoryQueryKey, workspaceDirectoryQueryOptions, workspaceDirectoryQueryPrefix, workspaceFileAssetQueryOptions, workspaceFileStatQueryOptions, workspaceInfoQueryOptions, workspaceQueryKey, workspaceTextFileQueryOptions };
@@ -33,21 +33,26 @@ interface ThinkFullAppWorkspaceConfig {
33
33
  leading?: React.ReactNode;
34
34
  actions?: React.ReactNode;
35
35
  }
36
- interface ThinkFullAppPanelContext<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage> {
37
- agent: ReturnType<typeof useAgent<AgentT, State>>;
38
- chat: ReturnType<typeof useAgentChat<State, MessageT>>;
39
- workspace?: ThinkFullAppWorkspaceConfig;
40
- }
41
- interface ThinkFullAppPanel<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage> extends ThinkFullAppView {
36
+ interface ThinkFullAppPanel extends ThinkFullAppView {
42
37
  /** Unique panel id used by `workbenchView`; custom panels should not reuse built-in ids. */
43
38
  id: ThinkFullAppWorkbenchView;
44
- render: (context: ThinkFullAppPanelContext<AgentT, State, MessageT>) => React.ReactNode;
39
+ /** Panels are app-authored, so anything one needs is already in its scope. */
40
+ render: () => React.ReactNode;
45
41
  }
46
- interface ThinkFullAppProps<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage> extends React.HTMLAttributes<HTMLDivElement> {
42
+ /** The live conversation the chat lane, approvals, and executions belong to. */
43
+ interface ThinkFullAppConversation<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage> {
47
44
  /** The `useAgent` value from `agents/react`; its stub drives approvals and execution records. */
48
45
  agent: ReturnType<typeof useAgent<AgentT, State>>;
49
46
  /** The `useAgentChat` value from `@cloudflare/think/react` used by the chat surface. */
50
47
  chat: ReturnType<typeof useAgentChat<State, MessageT>>;
48
+ }
49
+ interface ThinkFullAppProps<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage> extends React.HTMLAttributes<HTMLDivElement> {
50
+ /**
51
+ * Omit it and supply `messages.draft` for the first turn of a conversation
52
+ * that does not exist yet. The approvals, execution, and background-agent
53
+ * surfaces wait for a conversation to belong to; everything else is unchanged.
54
+ */
55
+ conversation?: ThinkFullAppConversation<AgentT, State, MessageT>;
51
56
  /** Atomic workspace source, navigation, media, and header configuration. */
52
57
  workspace?: ThinkFullAppWorkspaceConfig;
53
58
  /** Plugin directory backed by the host's live Agents MCP state and connection callbacks. */
@@ -78,7 +83,7 @@ interface ThinkFullAppProps<AgentT extends ThinkFullAppAgent<State>, State = unk
78
83
  /** Message rendering labels and approval overrides for ThinkChat. */
79
84
  messages?: ThinkChatMessagesProps<MessageT>;
80
85
  /** Extra workbench panels appended after the enabled built-in panels. */
81
- workbenchPanels?: readonly ThinkFullAppPanel<AgentT, State, MessageT>[];
86
+ workbenchPanels?: readonly ThinkFullAppPanel[];
82
87
  /** Returns an application-authored TanStack Router Link and enables retained Agent Tool runs. */
83
88
  renderAgentToolRunLink?: NonNullable<ThinkChatMessagesProps<MessageT>["renderAgentToolRunLink"]>;
84
89
  /**
@@ -110,12 +115,11 @@ interface ThinkFullAppProps<AgentT extends ThinkFullAppAgent<State>, State = unk
110
115
  }
111
116
  /** Combines ThinkChat with an optional resizable workbench shell. */
112
117
  declare function ThinkFullApp<AgentT extends ThinkFullAppAgent<State>, State = unknown, MessageT extends UIMessage = UIMessage>({
113
- agent,
114
118
  appBarActions,
115
119
  appBarLeading,
116
120
  appBarTitle,
117
- chat,
118
121
  className,
122
+ conversation,
119
123
  defaultMobileView,
120
124
  defaultWorkbenchView,
121
125
  defaultThreadSidebarOpen,
@@ -144,4 +148,4 @@ declare function ThinkFullApp<AgentT extends ThinkFullAppAgent<State>, State = u
144
148
  ref?: React.Ref<HTMLDivElement>;
145
149
  }): React.JSX.Element;
146
150
  //#endregion
147
- export { ThinkFullApp, ThinkFullAppAgent, ThinkFullAppMobileView, ThinkFullAppPanel, ThinkFullAppPanelContext, ThinkFullAppProps, ThinkFullAppWorkbenchView, ThinkFullAppWorkspaceConfig };
151
+ export { ThinkFullApp, ThinkFullAppAgent, ThinkFullAppConversation, ThinkFullAppMobileView, ThinkFullAppPanel, ThinkFullAppProps, ThinkFullAppWorkbenchView, ThinkFullAppWorkspaceConfig };
@@ -4,7 +4,7 @@ import { Button } from "../foundations/Button.js";
4
4
  import { n as mergeRefs } from "../../merge-refs-DF_7w2x_.js";
5
5
  import { ScrollArea } from "../foundations/ScrollArea.js";
6
6
  import { McpPluginCatalog } from "./McpPluginCatalog.js";
7
- import { c as resolveThinkApprovalProps, l as useSourceScopedAgentToolEvents, s as useThinkPendingExecutionApprovals, t as ThinkChat } from "../../ThinkChat-Dsm1xF3a.js";
7
+ import { c as resolveThinkApprovalProps, l as useSourceScopedAgentToolEvents, s as useThinkPendingExecutionApprovals, t as ThinkChat } from "../../ThinkChat-ldbrNiAx.js";
8
8
  import { a as WorkspaceNavigationRestorationBoundary, i as WorkspaceNavigationFocusRestorer, n as WorkspaceNavigationProvider } from "../../WorkspaceLink-DZeLe_jN.js";
9
9
  import { AppTopBar } from "../general-purpose/AppTopBar.js";
10
10
  import { useWorkspace } from "./Workspace.js";
@@ -44,11 +44,12 @@ function PluginsPanel({ config }) {
44
44
  children: [/* @__PURE__ */ jsx(ScrollArea.Viewport, { children: /* @__PURE__ */ jsx(McpPluginCatalog, { ...config }) }), /* @__PURE__ */ jsx(ScrollArea.Scrollbar, { children: /* @__PURE__ */ jsx(ScrollArea.Thumb, {}) })]
45
45
  });
46
46
  }
47
- /** Combines ThinkChat with an optional resizable workbench shell. */
48
- function ThinkFullApp({ agent, appBarActions, appBarLeading, appBarTitle, chat, className, 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 }) {
49
- const appRef = React.useRef(null);
50
- const workbenchPanelRef = React.useRef(null);
51
- const pendingPanelFocusRef = React.useRef(null);
47
+ /**
48
+ * Approval discovery and background-agent events need a live connection, so they
49
+ * live here rather than in the shell, which also renders before there is one.
50
+ */
51
+ function ThinkFullAppThreadChat({ agent, chat, messages, renderAgentToolRunLink, sourceKey }) {
52
+ const agentTools = useSourceScopedAgentToolEvents(agent);
52
53
  const approvals = useThinkPendingExecutionApprovals(agent.stub, sourceKey, `${chat.messages.length}:${chat.status}`, messages?.approvalsEnabled !== false);
53
54
  const resolvedMessages = React.useMemo(() => {
54
55
  const approvalProps = resolveThinkApprovalProps({
@@ -70,9 +71,23 @@ function ThinkFullApp({ agent, appBarActions, appBarLeading, appBarTitle, chat,
70
71
  approvals.refreshPendingApprovals,
71
72
  messages
72
73
  ]);
74
+ return /* @__PURE__ */ jsx(ThinkChat.Provider, {
75
+ chat,
76
+ agentTools,
77
+ children: /* @__PURE__ */ jsx(ThinkChat.Messages, {
78
+ ...resolvedMessages,
79
+ renderAgentToolRunLink
80
+ })
81
+ });
82
+ }
83
+ /** 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
+ const agent = conversation?.agent;
86
+ const appRef = React.useRef(null);
87
+ const workbenchPanelRef = React.useRef(null);
88
+ const pendingPanelFocusRef = React.useRef(null);
73
89
  const [innerMobileView, setInnerMobileView] = React.useState(defaultMobileView ?? "chat");
74
90
  const [innerWorkbenchView, setInnerWorkbenchView] = React.useState(defaultWorkbenchView ?? "files");
75
- const agentTools = useSourceScopedAgentToolEvents(agent);
76
91
  const requestedMobileView = mobileView ?? innerMobileView;
77
92
  const requestedWorkbenchView = workbenchView ?? innerWorkbenchView;
78
93
  const setWorkbenchView = React.useCallback((next) => {
@@ -86,15 +101,6 @@ function ThinkFullApp({ agent, appBarActions, appBarLeading, appBarTitle, chat,
86
101
  const updateAppView = React.useCallback((update) => {
87
102
  React.startTransition(update);
88
103
  }, []);
89
- const panelContext = React.useMemo(() => ({
90
- agent,
91
- chat,
92
- workspace
93
- }), [
94
- agent,
95
- chat,
96
- workspace
97
- ]);
98
104
  const availableWorkbenchPanels = [];
99
105
  if (workspace !== void 0) availableWorkbenchPanels.push({
100
106
  id: "files",
@@ -102,11 +108,11 @@ function ThinkFullApp({ agent, appBarActions, appBarLeading, appBarTitle, chat,
102
108
  icon: /* @__PURE__ */ jsx(FileIcon, {}),
103
109
  render: () => /* @__PURE__ */ jsx(WorkspacePanel, { config: workspace })
104
110
  });
105
- if (renderExecutionRunLink) availableWorkbenchPanels.push({
111
+ if (renderExecutionRunLink && agent) availableWorkbenchPanels.push({
106
112
  id: "execution",
107
113
  label: "Execution",
108
114
  icon: /* @__PURE__ */ jsx(TerminalIcon, {}),
109
- render: ({ agent }) => /* @__PURE__ */ jsx(React.Suspense, {
115
+ render: () => /* @__PURE__ */ jsx(React.Suspense, {
110
116
  fallback: /* @__PURE__ */ jsx("div", {
111
117
  className: "think-full-app__workbench",
112
118
  role: "status",
@@ -241,13 +247,14 @@ function ThinkFullApp({ agent, appBarActions, appBarLeading, appBarTitle, chat,
241
247
  className: "think-full-app__chat",
242
248
  children: /* @__PURE__ */ jsx("div", {
243
249
  className: "think-full-app__chat-inner",
244
- children: /* @__PURE__ */ jsx(ThinkChat.Provider, {
245
- chat,
246
- agentTools,
247
- children: /* @__PURE__ */ jsx(ThinkChat.Messages, {
248
- ...resolvedMessages,
249
- renderAgentToolRunLink
250
- })
250
+ children: conversation ? /* @__PURE__ */ jsx(ThinkFullAppThreadChat, {
251
+ ...conversation,
252
+ messages,
253
+ renderAgentToolRunLink,
254
+ sourceKey
255
+ }) : /* @__PURE__ */ jsx(ThinkChat.Messages, {
256
+ ...messages,
257
+ renderAgentToolRunLink
251
258
  })
252
259
  })
253
260
  })
@@ -263,7 +270,7 @@ function ThinkFullApp({ agent, appBarActions, appBarLeading, appBarTitle, chat,
263
270
  className: "think-full-app__workbench-panel",
264
271
  "data-view": activeWorkbenchView,
265
272
  tabIndex: -1,
266
- children: activePanel.render(panelContext)
273
+ children: activePanel.render()
267
274
  })
268
275
  })
269
276
  })
@@ -32,6 +32,8 @@ interface ThinkRoutineLibraryProps<TRoutine extends ThinkRoutine = ThinkRoutine>
32
32
  error?: React.ReactNode;
33
33
  /** Product navigation rendered after the built-in schedule navigation control. */
34
34
  appBarLeading?: React.ReactNode;
35
+ /** Product navigation rendered before the selected schedule actions. */
36
+ appBarActions?: React.ReactNode;
35
37
  /** Starts the selected routine immediately. */
36
38
  onRunRoutine?: (routine: TRoutine) => void | Promise<void>;
37
39
  /** Activates or pauses the selected app-owned routine. */
@@ -53,6 +55,7 @@ interface ThinkRoutineLibraryProps<TRoutine extends ThinkRoutine = ThinkRoutine>
53
55
  * route and may also use these surfaces independently.
54
56
  */
55
57
  declare function ThinkRoutineLibrary<TRoutine extends ThinkRoutine = ThinkRoutine>({
58
+ appBarActions,
56
59
  appBarLeading,
57
60
  className,
58
61
  createRoutineLink,
@@ -12,41 +12,45 @@ import { ThinkRoutineDetail } from "./ThinkRoutineDetail.js";
12
12
  import * as React from "react";
13
13
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
14
14
  //#region src/components/agents-sdk/ThinkRoutineLibrary.tsx
15
- function RoutineTopBarActions({ busy, onDelete, editLink, onRun, routineName }) {
15
+ function RoutineTopBarActions({ appBarActions, busy, onDelete, editLink, onRun, routineName }) {
16
16
  const [deleteOpen, setDeleteOpen] = React.useState(false);
17
17
  const moreActionsRef = React.useRef(null);
18
18
  const hasMenu = Boolean(editLink || onDelete);
19
- if (!onRun && !hasMenu) return null;
19
+ if (!appBarActions && !onRun && !hasMenu) return null;
20
20
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(AppTopBar.Trailing, {
21
21
  "aria-label": "Schedule actions",
22
- children: [onRun ? /* @__PURE__ */ jsx(AppTopBar.Button, {
23
- label: "Run schedule",
24
- tooltip: "Run now",
25
- disabled: busy,
26
- onClick: onRun,
27
- children: busy ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : /* @__PURE__ */ jsx(PlayIcon, {})
28
- }) : null, hasMenu ? /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsx(AppTopBar.Button, {
29
- label: "More schedule actions",
30
- tooltip: "More actions",
31
- disabled: busy,
32
- render: /* @__PURE__ */ jsx(Menu.Trigger, {
33
- ref: moreActionsRef,
34
- unstyled: true
35
- }),
36
- children: /* @__PURE__ */ jsx(EllipsisIcon, {})
37
- }), /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
38
- align: "end",
39
- sideOffset: 4,
40
- children: /* @__PURE__ */ jsxs(Menu.Popup, { children: [editLink ? /* @__PURE__ */ jsx(Menu.Item, {
41
- render: editLink,
42
- children: "Edit schedule"
43
- }) : null, onDelete ? /* @__PURE__ */ jsx(Menu.Item, {
44
- variant: "destructive",
22
+ children: [
23
+ appBarActions,
24
+ onRun ? /* @__PURE__ */ jsx(AppTopBar.Button, {
25
+ label: "Run schedule",
26
+ tooltip: "Run now",
27
+ disabled: busy,
28
+ onClick: onRun,
29
+ children: busy ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : /* @__PURE__ */ jsx(PlayIcon, {})
30
+ }) : null,
31
+ hasMenu ? /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsx(AppTopBar.Button, {
32
+ label: "More schedule actions",
33
+ tooltip: "More actions",
45
34
  disabled: busy,
46
- onClick: () => setDeleteOpen(true),
47
- children: "Delete schedule"
48
- }) : null] })
49
- }) })] }) : null]
35
+ render: /* @__PURE__ */ jsx(Menu.Trigger, {
36
+ ref: moreActionsRef,
37
+ unstyled: true
38
+ }),
39
+ children: /* @__PURE__ */ jsx(EllipsisIcon, {})
40
+ }), /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, {
41
+ align: "end",
42
+ sideOffset: 4,
43
+ children: /* @__PURE__ */ jsxs(Menu.Popup, { children: [editLink ? /* @__PURE__ */ jsx(Menu.Item, {
44
+ render: editLink,
45
+ children: "Edit schedule"
46
+ }) : null, onDelete ? /* @__PURE__ */ jsx(Menu.Item, {
47
+ variant: "destructive",
48
+ disabled: busy,
49
+ onClick: () => setDeleteOpen(true),
50
+ children: "Delete schedule"
51
+ }) : null] })
52
+ }) })] }) : null
53
+ ]
50
54
  }), onDelete ? /* @__PURE__ */ jsx(AlertDialog.Root, {
51
55
  open: deleteOpen,
52
56
  onOpenChange: setDeleteOpen,
@@ -80,7 +84,7 @@ function RoutineTopBarActions({ busy, onDelete, editLink, onRun, routineName })
80
84
  * and `ThinkRoutineRuns`; consumers compose `ThinkRoutineForm` in their create
81
85
  * route and may also use these surfaces independently.
82
86
  */
83
- function ThinkRoutineLibrary({ appBarLeading, className, createRoutineLink, error: catalogError, onDeleteRoutine, onRoutineEnabledChange, onRunRoutine, renderEditRoutineLink, renderRoutineLink, renderRoutineDetail, renderRunLink, ref, routines, selectedRoutineId, showOwner = true, ...props }) {
87
+ function ThinkRoutineLibrary({ appBarActions, appBarLeading, className, createRoutineLink, error: catalogError, onDeleteRoutine, onRoutineEnabledChange, onRunRoutine, renderEditRoutineLink, renderRoutineLink, renderRoutineDetail, renderRunLink, ref, routines, selectedRoutineId, showOwner = true, ...props }) {
84
88
  const [busy, setBusy] = React.useState(false);
85
89
  const [announcement, setAnnouncement] = React.useState("");
86
90
  const [actionError, setActionError] = React.useState(null);
@@ -140,6 +144,7 @@ function ThinkRoutineLibrary({ appBarLeading, className, createRoutineLink, erro
140
144
  children: [/* @__PURE__ */ jsx("span", { children: selectedRoutine.name }), /* @__PURE__ */ jsx(ChevronDownIcon, { "aria-hidden": "true" })]
141
145
  }) : null] }),
142
146
  /* @__PURE__ */ jsx(RoutineTopBarActions, {
147
+ appBarActions,
143
148
  busy,
144
149
  routineName: selectedRoutine?.name ?? "schedule",
145
150
  editLink: selectedRoutine && renderEditRoutineLink ? renderEditRoutineLink(selectedRoutine) : void 0,
@@ -43,7 +43,11 @@ interface ThinkThreadPickerProps extends Omit<React.HTMLAttributes<HTMLElement>,
43
43
  renderThreadLink: (thread: ThinkThreadItem) => React.ReactElement;
44
44
  /** Optional parent-agent create action, usually `parent.stub.createThread()`. */
45
45
  onCreate?: () => void | Promise<void>;
46
- /** Handles unmodified primary activation while preserving link modifier behavior. */
46
+ /**
47
+ * Notified on unmodified primary activation. The link still navigates — the
48
+ * route is the selection — so this is for side effects such as closing a
49
+ * compact drawer, never for performing the selection itself.
50
+ */
47
51
  onSelect?: (thread: ThinkThreadItem) => void;
48
52
  /** Optional parent-agent delete action, usually `parent.stub.deleteThread(thread.id)`. */
49
53
  onDelete?: (thread: ThinkThreadItem) => void | Promise<void>;
@@ -209,9 +209,7 @@ function ThinkThreadPicker({ threads, renderThreadLink, onCreate, onSelect, onDe
209
209
  }),
210
210
  "data-thread-status": thread.status,
211
211
  onClick: onSelect ? (event) => {
212
- if (!isPlainPrimaryLinkActivation(event)) return;
213
- event.preventDefault();
214
- onSelect(thread);
212
+ if (isPlainPrimaryLinkActivation(event)) onSelect(thread);
215
213
  } : void 0,
216
214
  children: [/* @__PURE__ */ jsx("span", {
217
215
  className: "think-thread-picker__thread-title sigvelo-truncate",
@@ -3,7 +3,7 @@ import { n as mergeRefs } from "../../merge-refs-DF_7w2x_.js";
3
3
  import { inferWorkspaceLanguage, inferWorkspaceMedia, isWorkspaceMarkdownPath, isWorkspaceMediaPath, isWorkspaceSkillPath, parseWorkspaceSkill } from "./WorkspaceFile.js";
4
4
  import { a as WorkspaceNavigationRestorationBoundary, n as WorkspaceNavigationProvider, o as useRequiredWorkspaceNavigationRestoration, r as resolveWorkspaceLink, t as WorkspaceFileLink } from "../../WorkspaceLink-DZeLe_jN.js";
5
5
  import { WorkspaceBrowser } from "./WorkspaceBrowser.js";
6
- import { t as WorkspaceFileView } from "../../WorkspaceFileView-hd1-cpuz.js";
6
+ import { t as WorkspaceFileView } from "../../WorkspaceFileView-BtzVKAed.js";
7
7
  import { useWorkspace, workspaceBinaryFileQueryOptions, workspaceDirectoryQueryKey, workspaceDirectoryQueryOptions, workspaceDirectoryQueryPrefix, workspaceFileAssetQueryOptions, workspaceFileStatQueryOptions, workspaceInfoQueryOptions, workspaceQueryKey, workspaceTextFileQueryOptions } from "./Workspace.js";
8
8
  import * as React from "react";
9
9
  import { jsx } from "react/jsx-runtime";
@@ -104,8 +104,6 @@ function WorkspaceExplorerContent({ workspace, navigation, className, title = "W
104
104
  path: fileDestination.path,
105
105
  isLoading: selectedPath !== fileDestination.path || loadingPaths.has(fileDestination.path),
106
106
  isRefreshing: isLoading,
107
- leading,
108
- actions,
109
107
  onRefresh: refresh
110
108
  })
111
109
  }) : /* @__PURE__ */ jsx(WorkspaceBrowser, {
@@ -1,2 +1,2 @@
1
- import { t as WorkspaceFileView } from "../../WorkspaceFileView-hd1-cpuz.js";
1
+ import { t as WorkspaceFileView } from "../../WorkspaceFileView-BtzVKAed.js";
2
2
  export { WorkspaceFileView };
@@ -1,4 +1,4 @@
1
- import { w as FolderIcon } from "../../icons-B1Qw05te.js";
1
+ import { R as PaperclipIcon } from "../../icons-B1Qw05te.js";
2
2
  import { Button } from "../foundations/Button.js";
3
3
  import { Popover } from "../foundations/Popover.js";
4
4
  import { EmptyState } from "../foundations/EmptyState.js";
@@ -26,7 +26,7 @@ function WorkspaceMountManager({ mounts, adding = false, busyMountId = null, err
26
26
  return /* @__PURE__ */ jsxs(Popover.Root, { children: [/* @__PURE__ */ jsx(AppTopBar.Button, {
27
27
  label: triggerLabel,
28
28
  render: /* @__PURE__ */ jsx(Popover.Trigger, { unstyled: true }),
29
- children: /* @__PURE__ */ jsx(FolderIcon, {})
29
+ children: /* @__PURE__ */ jsx(PaperclipIcon, {})
30
30
  }), /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
31
31
  side: "bottom",
32
32
  align: "end",
@@ -18,6 +18,10 @@ interface ResizableSidePanelRootProps extends React.HTMLAttributes<HTMLDivElemen
18
18
  keyboardStep?: number;
19
19
  /** Called whenever pointer or keyboard input changes the panel size. */
20
20
  onSizeChange?: (size: number) => void;
21
+ /** Pointer size below which the consumer should collapse the panel. */
22
+ collapseThreshold?: number;
23
+ /** Called once pointer resizing crosses `collapseThreshold`. */
24
+ onCollapse?: () => void;
21
25
  }
22
26
  interface ResizableSidePanelHandleProps extends Omit<SeparatorProps, "aria-label" | "aria-orientation" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "decorative" | "orientation"> {}
23
27
  /**
@@ -27,12 +31,14 @@ interface ResizableSidePanelHandleProps extends Omit<SeparatorProps, "aria-label
27
31
  declare function ResizableSidePanelRoot({
28
32
  children,
29
33
  className,
34
+ collapseThreshold,
30
35
  defaultSize,
31
36
  keyboardStep,
32
37
  label,
33
38
  maxSize,
34
39
  minSize,
35
40
  onSizeChange,
41
+ onCollapse,
36
42
  ref,
37
43
  side,
38
44
  style,
@@ -14,7 +14,7 @@ function panelSizeDelta(physicalDelta, side, direction) {
14
14
  * Shared sizing seam for a logical start- or end-side panel. Consumers retain
15
15
  * ownership of panel placement, visibility, compact behavior, and top bars.
16
16
  */
17
- function ResizableSidePanelRoot({ children, className, defaultSize, keyboardStep = 24, label, maxSize, minSize, onSizeChange, ref, side = "start", style, ...props }) {
17
+ function ResizableSidePanelRoot({ children, className, collapseThreshold, defaultSize, keyboardStep = 24, label, maxSize, minSize, onSizeChange, onCollapse, ref, side = "start", style, ...props }) {
18
18
  const [size, setInnerSize] = React.useState(() => clamp(defaultSize, minSize, maxSize));
19
19
  const cleanupResizeRef = React.useRef(null);
20
20
  const setSize = React.useCallback((nextSize) => {
@@ -41,7 +41,13 @@ function ResizableSidePanelRoot({ children, className, defaultSize, keyboardStep
41
41
  const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? "rtl" : "ltr";
42
42
  const onMove = (move) => {
43
43
  if (move.pointerId !== pointerId) return;
44
- setSize(startSize + panelSizeDelta(move.clientX - startX, side, direction));
44
+ const nextSize = startSize + panelSizeDelta(move.clientX - startX, side, direction);
45
+ if (collapseThreshold !== void 0 && nextSize < collapseThreshold) {
46
+ onCollapse?.();
47
+ stopResize();
48
+ return;
49
+ }
50
+ setSize(nextSize);
45
51
  };
46
52
  const onEnd = (end) => {
47
53
  if (end.pointerId === pointerId) stopResize();
@@ -58,6 +64,8 @@ function ResizableSidePanelRoot({ children, className, defaultSize, keyboardStep
58
64
  window.addEventListener("pointerup", onEnd);
59
65
  window.addEventListener("pointercancel", onEnd);
60
66
  }, [
67
+ collapseThreshold,
68
+ onCollapse,
61
69
  setSize,
62
70
  side,
63
71
  size,
@@ -15,6 +15,8 @@ interface SetupChecklistGroupProps<Id extends string = string> {
15
15
  /** Quiet visible heading above the checklist rows. */
16
16
  label: React.ReactNode;
17
17
  entries: readonly SetupChecklistEntry<Id>[];
18
+ /** Whether rows are visible when the containing menu first opens. */
19
+ defaultOpen?: boolean;
18
20
  /** Called with the selected entry id — complete rows re-run their setup. */
19
21
  onSelect: (id: Id) => void;
20
22
  }
@@ -22,6 +24,7 @@ interface SetupChecklistGroupProps<Id extends string = string> {
22
24
  declare function SetupChecklistGroup<Id extends string = string>({
23
25
  label,
24
26
  entries,
27
+ defaultOpen,
25
28
  onSelect
26
29
  }: SetupChecklistGroupProps<Id>): React.JSX.Element;
27
30
  interface SetupChecklistActionProps<Id extends string = string> extends SetupChecklistGroupProps<Id> {
@@ -1,23 +1,28 @@
1
1
  import { H as PlusIcon, d as CheckIcon, tt as WarningIcon } from "../../icons-B1Qw05te.js";
2
2
  import { Button } from "../foundations/Button.js";
3
3
  import { Menu } from "../foundations/Menu.js";
4
+ import { t as MenuDisclosureGroup } from "../../MenuDisclosureGroup-yJRq7YXa.js";
4
5
  import "react";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  //#region src/components/general-purpose/SetupChecklist.tsx
7
8
  /** Checklist rows for any Menu surface (composer plus menu, tray menu). */
8
- function SetupChecklistGroup({ label, entries, onSelect }) {
9
- return /* @__PURE__ */ jsxs(Menu.Group, { children: [/* @__PURE__ */ jsx(Menu.GroupLabel, { children: label }), entries.map((entry) => /* @__PURE__ */ jsxs(Menu.Item, {
10
- "aria-label": `${entry.name}, ${entry.complete ? "complete" : "not set up"}`,
11
- onClick: () => onSelect(entry.id),
12
- children: [
13
- entry.icon,
14
- /* @__PURE__ */ jsx("span", {
15
- className: "sigvelo-truncate-grow",
16
- children: entry.description
17
- }),
18
- entry.complete ? /* @__PURE__ */ jsx(CheckIcon, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(PlusIcon, { "aria-hidden": "true" })
19
- ]
20
- }, entry.id))] });
9
+ function SetupChecklistGroup({ label, entries, defaultOpen = false, onSelect }) {
10
+ return /* @__PURE__ */ jsx(MenuDisclosureGroup, {
11
+ label,
12
+ defaultOpen,
13
+ children: entries.map((entry) => /* @__PURE__ */ jsxs(Menu.Item, {
14
+ "aria-label": `${entry.name}, ${entry.complete ? "complete" : "not set up"}`,
15
+ onClick: () => onSelect(entry.id),
16
+ children: [
17
+ entry.icon,
18
+ /* @__PURE__ */ jsx("span", {
19
+ className: "sigvelo-truncate-grow",
20
+ children: entry.description
21
+ }),
22
+ entry.complete ? /* @__PURE__ */ jsx(CheckIcon, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(PlusIcon, { "aria-hidden": "true" })
23
+ ]
24
+ }, entry.id))
25
+ });
21
26
  }
22
27
  /** Progress-aware tray trigger opening the checklist in its own menu. */
23
28
  function SetupChecklistAction({ actionLabel, label, entries, onSelect }) {
@@ -35,6 +40,7 @@ function SetupChecklistAction({ actionLabel, label, entries, onSelect }) {
35
40
  align: "start",
36
41
  sideOffset: 4,
37
42
  children: /* @__PURE__ */ jsx(Menu.Popup, { children: /* @__PURE__ */ jsx(SetupChecklistGroup, {
43
+ defaultOpen: true,
38
44
  label,
39
45
  entries,
40
46
  onSelect
@@ -3,7 +3,7 @@ import { r as ArrowLeftIcon } from "../../icons-B1Qw05te.js";
3
3
  import { TransitionSurface } from "../foundations/TransitionSurface.js";
4
4
  import { SubagentRunMilestone, SubagentRunMilestones, SubagentRunProgress } from "../agents-sdk/SubagentRunDetails.js";
5
5
  import { SubagentRunIndicator, getSubagentRunName } from "../agents-sdk/SubagentRunIndicator.js";
6
- import { t as ThinkChat } from "../../ThinkChat-Dsm1xF3a.js";
6
+ import { t as ThinkChat } from "../../ThinkChat-ldbrNiAx.js";
7
7
  import { AppTopBar } from "../general-purpose/AppTopBar.js";
8
8
  import { NaniteMark } from "./NaniteScene.js";
9
9
  import * as React from "react";
@@ -81,6 +81,7 @@
81
81
  font-family: inherit;
82
82
  font-size: var(--sigvelo-text-compact);
83
83
  text-align: start;
84
+ text-decoration: none;
84
85
  cursor: pointer;
85
86
  border-radius: var(--sigvelo-radius-sm);
86
87
  transition: background-color var(--sigvelo-motion-duration-interaction)
@@ -49,6 +49,7 @@
49
49
  @import "./mcp-server-picker.css" layer(components);
50
50
  @import "./media-preview-card.css" layer(components);
51
51
  @import "./menu.css" layer(components);
52
+ @import "./menu-disclosure-group.css" layer(components);
52
53
  @import "./menubar.css" layer(components);
53
54
  @import "./message-scroller.css" layer(components);
54
55
  @import "./meter.css" layer(components);
@@ -2,9 +2,7 @@
2
2
  margin-block-start: var(--sigvelo-spacing-0-5);
3
3
  }
4
4
 
5
- .mcp-server-picker__group-label {
6
- padding-block: var(--sigvelo-spacing-1-5) var(--sigvelo-spacing-0-5);
7
- padding-inline: var(--sigvelo-spacing-2);
5
+ .mcp-server-picker__group-trigger {
8
6
  color: var(--sigvelo-color-text);
9
7
  font-size: var(--sigvelo-text-xs);
10
8
  font-weight: var(--sigvelo-font-weight-normal);
@@ -0,0 +1,13 @@
1
+ .menu-disclosure-group__trigger > svg {
2
+ flex: 0 0 auto;
3
+ transition: rotate var(--sigvelo-motion-duration-interaction) var(--sigvelo-motion-ease-change);
4
+ }
5
+
6
+ .menu-disclosure-group__trigger[aria-expanded="true"] > svg {
7
+ rotate: 180deg;
8
+ }
9
+
10
+ .menu-disclosure-group__items {
11
+ display: flex;
12
+ flex-direction: column;
13
+ }
@@ -11,7 +11,7 @@
11
11
  position: relative;
12
12
  container: think-full-app / inline-size;
13
13
  block-size: 100%;
14
- min-block-size: 32rem;
14
+ min-block-size: 0;
15
15
  min-inline-size: 0;
16
16
  display: grid;
17
17
  grid-template-rows: minmax(0, 1fr);
@@ -125,15 +125,6 @@
125
125
  position: relative;
126
126
  }
127
127
 
128
- .workspace-explorer__file-close {
129
- position: absolute;
130
- z-index: 2;
131
- inset-block-start: calc(var(--sigvelo-density-compact-control-height) + var(--sigvelo-spacing-2));
132
- inset-inline-end: var(--sigvelo-spacing-2);
133
- background-color: var(--sigvelo-color-surface-raised);
134
- box-shadow: var(--sigvelo-elevation-floating);
135
- }
136
-
137
128
  .workspace-explorer__filter {
138
129
  --sigvelo-recipe-control-height: var(--sigvelo-density-compact-control-height);
139
130
  --sigvelo-recipe-control-font-size: var(--sigvelo-density-compact-control-font-size);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-b/react-components",
3
- "version": "0.30.0",
3
+ "version": "0.31.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": {
@@ -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.30.0"
61
+ "@mcp-b/design-tokens": "0.31.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@ai-sdk/react": "^3.0.230",