@mcp-b/react-components 0.2.2 → 0.4.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 (61) hide show
  1. package/dist/{CodeBlock-BrCoypnc.js → CodeBlock-C2Xjxu9M.js} +1 -1
  2. package/dist/FileTree-D0c9Yj9U.js +310 -0
  3. package/dist/attachment-preview-ChtC3HiU.js +25 -0
  4. package/dist/components/Activity.js +1 -1
  5. package/dist/components/AgentChat.d.ts +56 -9
  6. package/dist/components/AgentChat.js +146 -47
  7. package/dist/components/AgentConnection.js +3 -3
  8. package/dist/components/Artifact.js +1 -1
  9. package/dist/components/BrowserLiveView.d.ts +47 -0
  10. package/dist/components/BrowserLiveView.js +135 -0
  11. package/dist/components/BrowserReplay.d.ts +40 -0
  12. package/dist/components/BrowserReplay.js +187 -0
  13. package/dist/components/ChainOfThought.d.ts +1 -1
  14. package/dist/components/ChainOfThought.js +1 -1
  15. package/dist/components/CodeBlock.js +1 -1
  16. package/dist/components/Commit.js +1 -1
  17. package/dist/components/Context.d.ts +28 -27
  18. package/dist/components/Context.js +48 -47
  19. package/dist/components/ContextMenu.js +1 -1
  20. package/dist/components/Conversation.js +1 -1
  21. package/dist/components/Dialog.js +1 -1
  22. package/dist/components/EnvironmentVariables.js +1 -1
  23. package/dist/components/FileTree.js +1 -309
  24. package/dist/components/Menubar.js +1 -1
  25. package/dist/components/Message.d.ts +17 -2
  26. package/dist/components/Message.js +36 -2
  27. package/dist/components/ModelSelector.js +1 -1
  28. package/dist/components/NavigationMenu.js +1 -1
  29. package/dist/components/PricingPage.js +2 -2
  30. package/dist/components/PromptInput.d.ts +143 -10
  31. package/dist/components/PromptInput.js +318 -5
  32. package/dist/components/Queue.js +1 -1
  33. package/dist/components/Reasoning.js +1 -1
  34. package/dist/components/Select.js +1 -1
  35. package/dist/components/Sources.js +1 -1
  36. package/dist/components/Stepper.js +1 -1
  37. package/dist/components/Suggestion.d.ts +43 -0
  38. package/dist/components/Suggestion.js +39 -0
  39. package/dist/components/Task.js +1 -1
  40. package/dist/components/Terminal.js +2 -2
  41. package/dist/components/TestResults.js +1 -1
  42. package/dist/components/ThinkChat.d.ts +207 -0
  43. package/dist/components/ThinkChat.js +798 -0
  44. package/dist/components/Tool.d.ts +32 -28
  45. package/dist/components/Tool.js +29 -16
  46. package/dist/components/WebPreview.js +1 -1
  47. package/dist/components/WorkspaceExplorer.d.ts +102 -0
  48. package/dist/components/WorkspaceExplorer.js +352 -0
  49. package/dist/components/icons.d.ts +2 -2
  50. package/dist/components/icons.js +2 -2
  51. package/dist/{copy-button-DAPlB8Z0.js → copy-button-Dd6DEhOm.js} +1 -1
  52. package/dist/{icons-Bf7JMKk-.js → icons-DQC4Zw5R.js} +5 -1
  53. package/dist/{icons-BklFyZbx.d.ts → icons-ctdVxng0.d.ts} +2 -1
  54. package/dist/styles/agent-chat.css +19 -0
  55. package/dist/styles/attachment-preview.css +21 -0
  56. package/dist/styles/context.css +9 -17
  57. package/dist/styles/index.css +2 -0
  58. package/dist/styles/message.css +48 -0
  59. package/dist/styles/prompt-input.css +321 -0
  60. package/dist/styles/suggestions.css +21 -0
  61. package/package.json +26 -3
@@ -1,6 +1,6 @@
1
1
  import { CollapsiblePanel, CollapsibleRoot, CollapsibleTrigger } from "./Collapsible.js";
2
2
  import { t as cx } from "../class-names-9UtZwb0J.js";
3
- import { d as DotIcon, k as SpinnerIcon, l as ChevronRightIcon, o as CheckIcon } from "../icons-Bf7JMKk-.js";
3
+ import { A as SpinnerIcon, d as DotIcon, l as ChevronRightIcon, o as CheckIcon } from "../icons-DQC4Zw5R.js";
4
4
  import "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/components/ChainOfThought.tsx
@@ -1,2 +1,2 @@
1
- import { a as CodeBlockCopyButton, c as CodeBlockLanguageSelector, d as CodeBlockLanguageSelectorTrigger, f as CodeBlockLanguageSelectorValue, h as CODE_BLOCK_LANGUAGES, i as CodeBlockContent, l as CodeBlockLanguageSelectorContent, m as highlightCode, n as CodeBlockActions, o as CodeBlockFilename, p as CodeBlockTitle, r as CodeBlockContainer, s as CodeBlockHeader, t as CodeBlock, u as CodeBlockLanguageSelectorItem } from "../CodeBlock-BrCoypnc.js";
1
+ import { a as CodeBlockCopyButton, c as CodeBlockLanguageSelector, d as CodeBlockLanguageSelectorTrigger, f as CodeBlockLanguageSelectorValue, h as CODE_BLOCK_LANGUAGES, i as CodeBlockContent, l as CodeBlockLanguageSelectorContent, m as highlightCode, n as CodeBlockActions, o as CodeBlockFilename, p as CodeBlockTitle, r as CodeBlockContainer, s as CodeBlockHeader, t as CodeBlock, u as CodeBlockLanguageSelectorItem } from "../CodeBlock-C2Xjxu9M.js";
2
2
  export { CODE_BLOCK_LANGUAGES, CodeBlock, CodeBlockActions, CodeBlockContainer, CodeBlockContent, CodeBlockCopyButton, CodeBlockFilename, CodeBlockHeader, CodeBlockLanguageSelector, CodeBlockLanguageSelectorContent, CodeBlockLanguageSelectorItem, CodeBlockLanguageSelectorTrigger, CodeBlockLanguageSelectorValue, CodeBlockTitle, highlightCode };
@@ -1,6 +1,6 @@
1
1
  import { CollapsiblePanel, CollapsibleRoot, CollapsibleTrigger } from "./Collapsible.js";
2
2
  import { t as cx } from "../class-names-9UtZwb0J.js";
3
- import { h as FileIcon, l as ChevronRightIcon, o as CheckIcon, u as CopyIcon } from "../icons-Bf7JMKk-.js";
3
+ import { h as FileIcon, l as ChevronRightIcon, o as CheckIcon, u as CopyIcon } from "../icons-DQC4Zw5R.js";
4
4
  import { Button } from "./Button.js";
5
5
  import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
6
6
  import { Badge } from "./Badge.js";
@@ -1,31 +1,21 @@
1
- import { r as ButtonProps } from "../Button-Ct5I6aTu.js";
2
- import { PopoverProps } from "./Popover.js";
1
+ import { PopoverPositionerProps, PopoverProps } from "./Popover.js";
3
2
  import * as React from "react";
3
+ import { LanguageModelUsage, UIMessage } from "ai";
4
4
 
5
5
  //#region src/components/Context.d.ts
6
- interface ContextUsageCategory {
7
- label: string;
8
- tokens: number;
9
- costUsd?: number;
10
- }
11
- interface ContextUsage {
12
- input?: number;
13
- inputTokens?: number;
14
- output?: number;
15
- outputTokens?: number;
16
- reasoning?: number;
17
- reasoningTokens?: number;
18
- cache?: number;
19
- cachedInputTokens?: number;
20
- categories?: ContextUsageCategory[];
21
- }
6
+ /**
7
+ * The AI SDK's `LanguageModelUsage`, taken whole. `Partial` only relaxes the
8
+ * required-but-`undefined`able keys for fixtures/JSX literals — key names and
9
+ * meanings are upstream's.
10
+ */
11
+ type ContextTokenUsage = Partial<LanguageModelUsage>;
22
12
  interface ContextProps extends React.HTMLAttributes<HTMLDivElement> {
23
13
  /** Tokens currently used. */
24
14
  usedTokens: number;
25
15
  /** Maximum context window size. */
26
16
  maxTokens: number;
27
17
  /** Optional usage breakdown. */
28
- usage?: ContextUsage;
18
+ usage?: ContextTokenUsage;
29
19
  /** Optional model identifier shown in the header. */
30
20
  modelId?: string;
31
21
  /** Optional total cost in USD. */
@@ -36,8 +26,8 @@ interface ContextProps extends React.HTMLAttributes<HTMLDivElement> {
36
26
  }
37
27
  /**
38
28
  * Displays token / context usage with a hover card breakdown. The trigger is
39
- * a button showing a compact percentage indicator; hovering or clicking opens
40
- * a popover with category rows and total cost.
29
+ * a bare progress ring; clicking it opens a popover (upward by default) with
30
+ * category rows and total cost.
41
31
  *
42
32
  * @example
43
33
  * ```tsx
@@ -45,7 +35,7 @@ interface ContextProps extends React.HTMLAttributes<HTMLDivElement> {
45
35
  * usedTokens={42_300}
46
36
  * maxTokens={200_000}
47
37
  * modelId="claude-opus-4-6"
48
- * usage={{ input: 30000, output: 12300 }}
38
+ * usage={{ inputTokens: 30000, outputTokens: 12300 }}
49
39
  * totalCostUsd={0.42}
50
40
  * >
51
41
  * <ContextTrigger />
@@ -73,17 +63,19 @@ declare function Context({
73
63
  }: ContextProps & {
74
64
  ref?: React.Ref<HTMLDivElement>;
75
65
  }): React.JSX.Element;
76
- interface ContextTriggerProps extends Omit<ButtonProps, "variant" | "color" | "className"> {
77
- className?: string;
78
- }
66
+ interface ContextTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
79
67
  declare function ContextTrigger({
80
68
  className,
81
69
  children,
82
70
  ...props
83
71
  }: ContextTriggerProps): React.JSX.Element;
84
- interface ContextContentProps extends React.HTMLAttributes<HTMLDivElement> {}
72
+ interface ContextContentProps extends React.HTMLAttributes<HTMLDivElement> {
73
+ /** The trigger usually sits in a composer at the bottom, so default "top". */
74
+ side?: PopoverPositionerProps["side"];
75
+ }
85
76
  declare function ContextContent({
86
77
  className,
78
+ side,
87
79
  children,
88
80
  ...props
89
81
  }: ContextContentProps): React.JSX.Element;
@@ -125,5 +117,14 @@ declare function ContextInputUsage(props: ContextInputUsageProps): React.JSX.Ele
125
117
  declare function ContextOutputUsage(props: ContextOutputUsageProps): React.JSX.Element;
126
118
  declare function ContextReasoningUsage(props: ContextReasoningUsageProps): React.JSX.Element;
127
119
  declare function ContextCacheUsage(props: ContextCacheUsageProps): React.JSX.Element;
120
+ /**
121
+ * Latest `metadata.usage` in a transcript — the AI SDK convention for token
122
+ * accounting (`toUIMessageStreamResponse({ messageMetadata })`), which Think
123
+ * merges into `message.metadata` as turns finish. Structural: any message
124
+ * whose metadata carries a `usage` object qualifies.
125
+ */
126
+ declare function getContextUsage(messages: readonly UIMessage[]): LanguageModelUsage | undefined;
127
+ /** Tokens occupying the context window: `totalTokens`, or input + output. */
128
+ declare function getContextUsedTokens(usage: LanguageModelUsage | undefined): number;
128
129
  //#endregion
129
- export { Context, ContextCacheUsage, ContextCacheUsageProps, ContextContent, ContextContentBody, ContextContentBodyProps, ContextContentFooter, ContextContentFooterProps, ContextContentHeader, ContextContentHeaderProps, ContextContentProps, ContextInputUsage, ContextInputUsageProps, ContextOutputUsage, ContextOutputUsageProps, ContextProps, ContextReasoningUsage, ContextReasoningUsageProps, ContextTrigger, ContextTriggerProps, ContextUsage, ContextUsageCategory, ContextUsageRowProps };
130
+ export { Context, ContextCacheUsage, ContextCacheUsageProps, ContextContent, ContextContentBody, ContextContentBodyProps, ContextContentFooter, ContextContentFooterProps, ContextContentHeader, ContextContentHeaderProps, ContextContentProps, ContextInputUsage, ContextInputUsageProps, ContextOutputUsage, ContextOutputUsageProps, ContextProps, ContextReasoningUsage, ContextReasoningUsageProps, ContextTokenUsage, ContextTrigger, ContextTriggerProps, ContextUsageRowProps, getContextUsage, getContextUsedTokens };
@@ -1,5 +1,4 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { Button } from "./Button.js";
3
2
  import { Popover } from "./Popover.js";
4
3
  import { Separator } from "./Separator.js";
5
4
  import * as React from "react";
@@ -13,8 +12,8 @@ function useContextContext() {
13
12
  }
14
13
  /**
15
14
  * Displays token / context usage with a hover card breakdown. The trigger is
16
- * a button showing a compact percentage indicator; hovering or clicking opens
17
- * a popover with category rows and total cost.
15
+ * a bare progress ring; clicking it opens a popover (upward by default) with
16
+ * category rows and total cost.
18
17
  *
19
18
  * @example
20
19
  * ```tsx
@@ -22,7 +21,7 @@ function useContextContext() {
22
21
  * usedTokens={42_300}
23
22
  * maxTokens={200_000}
24
23
  * modelId="claude-opus-4-6"
25
- * usage={{ input: 30000, output: 12300 }}
24
+ * usage={{ inputTokens: 30000, outputTokens: 12300 }}
26
25
  * totalCostUsd={0.42}
27
26
  * >
28
27
  * <ContextTrigger />
@@ -68,33 +67,26 @@ function ContextTrigger({ className, children, ...props }) {
68
67
  const percent = maxTokens > 0 ? usedTokens / maxTokens * 100 : 0;
69
68
  if (React.isValidElement(children)) return /* @__PURE__ */ jsx(Popover.Trigger, { render: children });
70
69
  if (children) return /* @__PURE__ */ jsx(Popover.Trigger, { children });
71
- return /* @__PURE__ */ jsx(Popover.Trigger, { render: /* @__PURE__ */ jsxs(Button, {
72
- variant: "ghost",
73
- color: "neutral",
74
- size: "sm",
70
+ return /* @__PURE__ */ jsx(Popover.Trigger, {
75
71
  className: cx("context__trigger", className),
76
72
  "aria-label": `Context usage: ${percent.toFixed(0)}%`,
77
73
  ...props,
78
- children: [/* @__PURE__ */ jsx("span", {
79
- className: "context__trigger-ring",
80
- "aria-hidden": "true",
81
- children: /* @__PURE__ */ jsx(ProgressRing, {
82
- percent,
83
- size: 16,
84
- stroke: 2.5
85
- })
86
- }), /* @__PURE__ */ jsxs("span", {
87
- className: "context__trigger-label",
88
- children: [percent.toFixed(0), "%"]
89
- })]
90
- }) });
74
+ children: /* @__PURE__ */ jsx(ProgressRing, {
75
+ percent,
76
+ size: 16,
77
+ stroke: 2.5
78
+ })
79
+ });
91
80
  }
92
- function ContextContent({ className, children, ...props }) {
93
- return /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, { children: /* @__PURE__ */ jsx(Popover.Popup, {
94
- className: cx("context__content", className),
95
- ...props,
96
- children
97
- }) }) });
81
+ function ContextContent({ className, side = "top", children, ...props }) {
82
+ return /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
83
+ side,
84
+ children: /* @__PURE__ */ jsx(Popover.Popup, {
85
+ className: cx("context__content", className),
86
+ ...props,
87
+ children
88
+ })
89
+ }) });
98
90
  }
99
91
  function ContextContentHeader({ className, children, ref, ...props }) {
100
92
  const { usedTokens, maxTokens, modelId } = useContextContext();
@@ -173,7 +165,6 @@ function ContextContentBody({ className, children, ref, ...props }) {
173
165
  label: "Cache",
174
166
  tokens: cacheTokens
175
167
  });
176
- if (usage?.categories) rows.push(...usage.categories);
177
168
  return /* @__PURE__ */ jsxs("div", {
178
169
  ref,
179
170
  className: cx("context__body", className),
@@ -182,20 +173,13 @@ function ContextContentBody({ className, children, ref, ...props }) {
182
173
  className: "context__rows",
183
174
  children: rows.map((row) => /* @__PURE__ */ jsxs("li", {
184
175
  className: "context__row",
185
- children: [
186
- /* @__PURE__ */ jsx("span", {
187
- className: "context__row-label",
188
- children: row.label
189
- }),
190
- /* @__PURE__ */ jsx("span", {
191
- className: "context__row-value",
192
- children: row.tokens.toLocaleString()
193
- }),
194
- row.costUsd !== void 0 ? /* @__PURE__ */ jsxs("span", {
195
- className: "context__row-cost",
196
- children: ["$", row.costUsd.toFixed(4)]
197
- }) : null
198
- ]
176
+ children: [/* @__PURE__ */ jsx("span", {
177
+ className: "context__row-label",
178
+ children: row.label
179
+ }), /* @__PURE__ */ jsx("span", {
180
+ className: "context__row-value",
181
+ children: row.tokens.toLocaleString()
182
+ })]
199
183
  }, row.label))
200
184
  })]
201
185
  });
@@ -269,10 +253,27 @@ function ContextUsageRow({ className, children, label, usageKey, defaultLabel, r
269
253
  }
270
254
  function getUsageTokens(usage, key) {
271
255
  if (!usage) return void 0;
272
- if (key === "input") return usage.input ?? usage.inputTokens;
273
- if (key === "output") return usage.output ?? usage.outputTokens;
274
- if (key === "reasoning") return usage.reasoning ?? usage.reasoningTokens;
275
- return usage.cache ?? usage.cachedInputTokens;
256
+ if (key === "input") return usage.inputTokens;
257
+ if (key === "output") return usage.outputTokens;
258
+ if (key === "reasoning") return usage.outputTokenDetails?.reasoningTokens ?? usage.reasoningTokens;
259
+ return usage.inputTokenDetails?.cacheReadTokens ?? usage.cachedInputTokens;
260
+ }
261
+ /**
262
+ * Latest `metadata.usage` in a transcript — the AI SDK convention for token
263
+ * accounting (`toUIMessageStreamResponse({ messageMetadata })`), which Think
264
+ * merges into `message.metadata` as turns finish. Structural: any message
265
+ * whose metadata carries a `usage` object qualifies.
266
+ */
267
+ function getContextUsage(messages) {
268
+ for (let i = messages.length - 1; i >= 0; i--) {
269
+ const usage = messages[i].metadata?.usage;
270
+ if (usage && typeof usage === "object") return usage;
271
+ }
272
+ }
273
+ /** Tokens occupying the context window: `totalTokens`, or input + output. */
274
+ function getContextUsedTokens(usage) {
275
+ if (!usage) return 0;
276
+ return usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
276
277
  }
277
278
  function ProgressRing({ percent, size, stroke }) {
278
279
  const radius = (size - stroke) / 2;
@@ -306,4 +307,4 @@ function ProgressRing({ percent, size, stroke }) {
306
307
  });
307
308
  }
308
309
  //#endregion
309
- export { Context, ContextCacheUsage, ContextContent, ContextContentBody, ContextContentFooter, ContextContentHeader, ContextInputUsage, ContextOutputUsage, ContextReasoningUsage, ContextTrigger };
310
+ export { Context, ContextCacheUsage, ContextContent, ContextContentBody, ContextContentFooter, ContextContentHeader, ContextInputUsage, ContextOutputUsage, ContextReasoningUsage, ContextTrigger, getContextUsage, getContextUsedTokens };
@@ -1,4 +1,4 @@
1
- import { d as DotIcon, l as ChevronRightIcon, o as CheckIcon } from "../icons-Bf7JMKk-.js";
1
+ import { d as DotIcon, l as ChevronRightIcon, o as CheckIcon } from "../icons-DQC4Zw5R.js";
2
2
  import "react";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { ContextMenu as ContextMenu$1 } from "@base-ui/react/context-menu";
@@ -1,5 +1,5 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { f as DownloadIcon, t as ArrowDownIcon } from "../icons-Bf7JMKk-.js";
2
+ import { f as DownloadIcon, t as ArrowDownIcon } from "../icons-DQC4Zw5R.js";
3
3
  import { Button } from "./Button.js";
4
4
  import { useStickToBottom } from "./useStickToBottom.js";
5
5
  import * as React from "react";
@@ -1,4 +1,4 @@
1
- import { P as XIcon } from "../icons-Bf7JMKk-.js";
1
+ import { F as XIcon } from "../icons-DQC4Zw5R.js";
2
2
  import "react";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
@@ -1,5 +1,5 @@
1
1
  import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { m as EyeOffIcon, o as CheckIcon, p as EyeIcon, u as CopyIcon } from "../icons-Bf7JMKk-.js";
2
+ import { m as EyeOffIcon, o as CheckIcon, p as EyeIcon, u as CopyIcon } from "../icons-DQC4Zw5R.js";
3
3
  import { Button } from "./Button.js";
4
4
  import { Tooltip, TooltipPopup, TooltipPortal, TooltipPositioner, TooltipTrigger } from "./Tooltip.js";
5
5
  import { Badge } from "./Badge.js";
@@ -1,310 +1,2 @@
1
- import { t as cx } from "../class-names-9UtZwb0J.js";
2
- import { _ as FolderOpenIcon, g as FolderIcon, h as FileIcon, l as ChevronRightIcon } from "../icons-Bf7JMKk-.js";
3
- import * as React from "react";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
- //#region src/components/_internal/use-file-tree-nav.ts
6
- const FileTreeContext = React.createContext(null);
7
- function useFileTreeContext() {
8
- const ctx = React.useContext(FileTreeContext);
9
- if (!ctx) throw new Error("FileTree subcomponents must be used inside <FileTree>.");
10
- return ctx;
11
- }
12
- /**
13
- * Builds a FileTreeContextValue that tracks registered nodes and dispatches
14
- * keyboard navigation per the WAI-ARIA Tree Pattern.
15
- *
16
- * Call `register` from every FileTreeFolder/FileTreeFile during render. The
17
- * hook resets its internal list on each render pass so removed nodes don't
18
- * leave stale entries.
19
- */
20
- function useFileTreeNav({ expanded, selectedPath, onSelect, onExpandedChange }) {
21
- const [focusedPath, setFocusedPath] = React.useState(null);
22
- const nodesRef = React.useRef([]);
23
- nodesRef.current = [];
24
- const register = React.useCallback((path, kind, parentExpanded) => {
25
- nodesRef.current.push({
26
- path,
27
- kind,
28
- visible: parentExpanded
29
- });
30
- }, []);
31
- const visibleNodes = () => nodesRef.current.filter((n) => n.visible);
32
- const moveFocus = React.useCallback((direction, from) => {
33
- const visible = visibleNodes();
34
- const idx = visible.findIndex((n) => n.path === from);
35
- if (idx < 0) return;
36
- const next = visible[Math.max(0, Math.min(visible.length - 1, idx + direction))];
37
- if (next) setFocusedPath(next.path);
38
- }, []);
39
- const focusFirstVisibleNode = React.useCallback(() => {
40
- const first = visibleNodes()[0];
41
- if (first) setFocusedPath(first.path);
42
- }, []);
43
- const focusLastVisibleNode = React.useCallback(() => {
44
- const visible = visibleNodes();
45
- const last = visible[visible.length - 1];
46
- if (last) setFocusedPath(last.path);
47
- }, []);
48
- const setFolderExpanded = React.useCallback((path, nextExpanded) => {
49
- const next = new Set(expanded);
50
- if (nextExpanded) next.add(path);
51
- else next.delete(path);
52
- onExpandedChange(next);
53
- }, [expanded, onExpandedChange]);
54
- const toggleFolderExpanded = React.useCallback((path) => {
55
- setFolderExpanded(path, !expanded.has(path));
56
- }, [expanded, setFolderExpanded]);
57
- const keyHandlers = React.useMemo(() => ({
58
- ArrowDown(path) {
59
- moveFocus(1, path);
60
- },
61
- ArrowUp(path) {
62
- moveFocus(-1, path);
63
- },
64
- ArrowRight(path, kind) {
65
- if (!(kind === "folder")) return;
66
- if (expanded.has(path)) moveFocus(1, path);
67
- else setFolderExpanded(path, true);
68
- },
69
- ArrowLeft(path, kind) {
70
- if (kind === "folder" && expanded.has(path)) setFolderExpanded(path, false);
71
- },
72
- Enter(path, kind) {
73
- if (kind === "folder") {
74
- onSelect(path);
75
- toggleFolderExpanded(path);
76
- } else onSelect(path);
77
- },
78
- " "(path, kind) {
79
- if (kind === "folder") {
80
- onSelect(path);
81
- toggleFolderExpanded(path);
82
- } else onSelect(path);
83
- },
84
- Home() {
85
- focusFirstVisibleNode();
86
- },
87
- End() {
88
- focusLastVisibleNode();
89
- }
90
- }), [
91
- expanded,
92
- focusFirstVisibleNode,
93
- focusLastVisibleNode,
94
- moveFocus,
95
- onSelect,
96
- setFolderExpanded,
97
- toggleFolderExpanded
98
- ]);
99
- const handleKeyDown = React.useCallback((event, path, kind) => {
100
- const keyHandler = keyHandlers[event.key];
101
- if (!keyHandler) return;
102
- event.preventDefault();
103
- keyHandler(path, kind);
104
- }, [keyHandlers]);
105
- return {
106
- focusedPath,
107
- selectedPath,
108
- expanded,
109
- onFocus: React.useCallback((path) => {
110
- setFocusedPath(path);
111
- }, []),
112
- onSelect,
113
- onExpandedChange: React.useCallback((path, next) => {
114
- setFolderExpanded(path, next);
115
- }, [setFolderExpanded]),
116
- register,
117
- handleKeyDown
118
- };
119
- }
120
- //#endregion
121
- //#region src/components/FileTree.tsx
122
- /**
123
- * A keyboard-accessible hierarchical file browser. Compose with
124
- * FileTreeFolder and FileTreeFile children.
125
- *
126
- * Keyboard: ↑/↓ move focus, →/← expand/collapse folders, Enter/Space
127
- * selects files and selects/toggles folders, Home/End jump to first/last node.
128
- *
129
- * @example
130
- * ```tsx
131
- * <FileTree defaultExpanded={new Set(["src"])}>
132
- * <FileTreeFolder path="src" name="src">
133
- * <FileTreeFile path="src/index.ts" name="index.ts" />
134
- * <FileTreeFolder path="src/lib" name="lib">
135
- * <FileTreeFile path="src/lib/utils.ts" name="utils.ts" />
136
- * </FileTreeFolder>
137
- * </FileTreeFolder>
138
- * </FileTree>
139
- * ```
140
- */
141
- function FileTree({ className, "aria-label": ariaLabel = "File tree", expanded, defaultExpanded, selectedPath = null, onSelect, onExpandedChange, children, ref, ...props }) {
142
- const [internalExpanded, setInternalExpanded] = React.useState(() => defaultExpanded ?? /* @__PURE__ */ new Set());
143
- const isControlled = expanded !== void 0;
144
- const currentExpanded = isControlled ? expanded : internalExpanded;
145
- const handleExpandedChange = React.useCallback((next) => {
146
- if (!isControlled) setInternalExpanded(next);
147
- onExpandedChange?.(next);
148
- }, [isControlled, onExpandedChange]);
149
- const ctx = useFileTreeNav({
150
- expanded: currentExpanded,
151
- selectedPath,
152
- onSelect: React.useCallback((path) => {
153
- onSelect?.(path);
154
- }, [onSelect]),
155
- onExpandedChange: handleExpandedChange
156
- });
157
- return /* @__PURE__ */ jsx(FileTreeContext.Provider, {
158
- value: ctx,
159
- children: /* @__PURE__ */ jsx("div", {
160
- ref,
161
- className: cx("file-tree", className),
162
- ...props,
163
- children: /* @__PURE__ */ jsx("ul", {
164
- className: "file-tree__list",
165
- role: "tree",
166
- "aria-label": ariaLabel,
167
- tabIndex: 0,
168
- children
169
- })
170
- })
171
- });
172
- }
173
- function renderNestedFileTreeChild(child, level) {
174
- if (React.isValidElement(child) && (child.type === FileTreeFolder || child.type === FileTreeFile)) return React.cloneElement(child, { level: level + 1 });
175
- return child;
176
- }
177
- function dataFlag(enabled) {
178
- return enabled ? "" : void 0;
179
- }
180
- function getFileTreeNodeTabIndex(focusedPath, path, level) {
181
- return focusedPath === path || !focusedPath && level === 0 ? 0 : -1;
182
- }
183
- function getFileTreeNodeIndent(level, offset) {
184
- return `${level * 1.125 + offset}rem`;
185
- }
186
- function FileTreeFolder({ className, path, name, level = 0, children, ref, ...props }) {
187
- const { expanded, focusedPath, selectedPath, onFocus, onSelect, register, handleKeyDown, onExpandedChange } = useFileTreeContext();
188
- const isExpanded = expanded.has(path);
189
- const isFocused = focusedPath === path;
190
- const isSelected = selectedPath === path;
191
- register(path, "folder", true);
192
- const toggle = React.useCallback(() => {
193
- onExpandedChange(path, !isExpanded);
194
- }, [
195
- isExpanded,
196
- onExpandedChange,
197
- path
198
- ]);
199
- const handleClick = React.useCallback(() => {
200
- onSelect(path);
201
- toggle();
202
- }, [
203
- onSelect,
204
- path,
205
- toggle
206
- ]);
207
- return /* @__PURE__ */ jsxs("li", {
208
- ref,
209
- role: "treeitem",
210
- "aria-expanded": isExpanded,
211
- "aria-selected": isSelected,
212
- className: cx("file-tree__folder", className),
213
- ...props,
214
- children: [/* @__PURE__ */ jsxs("button", {
215
- type: "button",
216
- className: "file-tree__node file-tree__node--folder",
217
- "data-focused": dataFlag(isFocused),
218
- "data-selected": dataFlag(isSelected),
219
- tabIndex: getFileTreeNodeTabIndex(focusedPath, path, level),
220
- onClick: handleClick,
221
- onFocus: () => onFocus(path),
222
- onKeyDown: (e) => handleKeyDown(e, path, "folder"),
223
- style: { paddingInlineStart: getFileTreeNodeIndent(level, .5) },
224
- children: [
225
- /* @__PURE__ */ jsx("span", {
226
- className: cx("file-tree__chevron", isExpanded && "file-tree__chevron--expanded"),
227
- "aria-hidden": "true",
228
- children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
229
- }),
230
- /* @__PURE__ */ jsx("span", {
231
- className: "file-tree__icon",
232
- "aria-hidden": "true",
233
- children: isExpanded ? /* @__PURE__ */ jsx(FolderOpenIcon, {}) : /* @__PURE__ */ jsx(FolderIcon, {})
234
- }),
235
- /* @__PURE__ */ jsx("span", {
236
- className: "file-tree__name",
237
- children: name
238
- })
239
- ]
240
- }), isExpanded ? /* @__PURE__ */ jsx("ul", {
241
- className: "file-tree__list",
242
- role: "group",
243
- children: React.Children.map(children, (child) => renderNestedFileTreeChild(child, level))
244
- }) : null]
245
- });
246
- }
247
- function FileTreeFile({ className, path, name, icon, level = 0, ref, ...props }) {
248
- const { selectedPath, focusedPath, onFocus, onSelect, register, handleKeyDown } = useFileTreeContext();
249
- const isSelected = selectedPath === path;
250
- const isFocused = focusedPath === path;
251
- register(path, "file", true);
252
- return /* @__PURE__ */ jsx("li", {
253
- ref,
254
- role: "treeitem",
255
- "aria-selected": isSelected,
256
- className: cx("file-tree__file", className),
257
- ...props,
258
- children: /* @__PURE__ */ jsxs("button", {
259
- type: "button",
260
- className: "file-tree__node file-tree__node--file",
261
- "data-selected": dataFlag(isSelected),
262
- "data-focused": dataFlag(isFocused),
263
- tabIndex: getFileTreeNodeTabIndex(focusedPath, path, level),
264
- onClick: () => onSelect(path),
265
- onFocus: () => onFocus(path),
266
- onKeyDown: (e) => handleKeyDown(e, path, "file"),
267
- style: { paddingInlineStart: getFileTreeNodeIndent(level, 1.5) },
268
- children: [/* @__PURE__ */ jsx("span", {
269
- className: "file-tree__icon",
270
- "aria-hidden": "true",
271
- children: icon ?? /* @__PURE__ */ jsx(FileIcon, {})
272
- }), /* @__PURE__ */ jsx("span", {
273
- className: "file-tree__name",
274
- children: name
275
- })]
276
- })
277
- });
278
- }
279
- function FileTreeIcon({ className, children, ref, ...props }) {
280
- return /* @__PURE__ */ jsx("span", {
281
- ref,
282
- className: cx("file-tree__icon", className),
283
- "aria-hidden": "true",
284
- ...props,
285
- children
286
- });
287
- }
288
- function FileTreeName({ className, children, ref, ...props }) {
289
- return /* @__PURE__ */ jsx("span", {
290
- ref,
291
- className: cx("file-tree__name", className),
292
- ...props,
293
- children
294
- });
295
- }
296
- function FileTreeActions({ className, children, onClick, ref, ...props }) {
297
- const handleClick = React.useCallback((e) => {
298
- e.stopPropagation();
299
- onClick?.(e);
300
- }, [onClick]);
301
- return /* @__PURE__ */ jsx("div", {
302
- ref,
303
- className: cx("file-tree__actions", className),
304
- onClick: handleClick,
305
- ...props,
306
- children
307
- });
308
- }
309
- //#endregion
1
+ import { a as FileTreeIcon, i as FileTreeFolder, n as FileTreeActions, o as FileTreeName, r as FileTreeFile, t as FileTree } from "../FileTree-D0c9Yj9U.js";
310
2
  export { FileTree, FileTreeActions, FileTreeFile, FileTreeFolder, FileTreeIcon, FileTreeName };
@@ -1,4 +1,4 @@
1
- import { d as DotIcon, l as ChevronRightIcon, o as CheckIcon } from "../icons-Bf7JMKk-.js";
1
+ import { d as DotIcon, l as ChevronRightIcon, o as CheckIcon } from "../icons-DQC4Zw5R.js";
2
2
  import "react";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  import { Menu } from "@base-ui/react/menu";
@@ -1,9 +1,10 @@
1
1
  import { r as ButtonProps } from "../Button-Ct5I6aTu.js";
2
2
  import * as React from "react";
3
+ import { FileUIPart, UIMessage } from "ai";
3
4
  import { StreamdownProps } from "streamdown";
4
5
 
5
6
  //#region src/components/Message.d.ts
6
- type MessageRole = "user" | "assistant" | "system" | "tool" | (string & {});
7
+ type MessageRole = UIMessage["role"] | (string & {});
7
8
  interface MessageProps extends React.HTMLAttributes<HTMLDivElement> {
8
9
  /**
9
10
  * The originating role of the message. Controls alignment and styling via
@@ -59,6 +60,20 @@ declare const MessageResponse: React.MemoExoticComponent<({
59
60
  className,
60
61
  ...props
61
62
  }: MessageResponseProps) => React.JSX.Element>;
63
+ interface MessageAttachmentProps extends Omit<React.HTMLAttributes<HTMLElement>, "part"> {
64
+ /** The AI SDK `file` part, taken whole. */
65
+ part: FileUIPart;
66
+ }
67
+ /**
68
+ * A `file` part inside a message: images render inline (click to zoom),
69
+ * anything else becomes a download chip. Covers both directions — files the
70
+ * user attached and files the agent emitted.
71
+ */
72
+ declare function MessageAttachment({
73
+ part,
74
+ className,
75
+ ...props
76
+ }: MessageAttachmentProps): React.JSX.Element;
62
77
  interface MessageActionsProps extends React.HTMLAttributes<HTMLDivElement> {}
63
78
  /**
64
79
  * Horizontal list of action buttons (copy, retry, thumbs-up, etc.) shown
@@ -213,4 +228,4 @@ declare function MessageBranchPage({
213
228
  ref?: React.Ref<HTMLSpanElement>;
214
229
  }): React.JSX.Element;
215
230
  //#endregion
216
- export { Message, MessageAction, MessageActionProps, MessageActions, MessageActionsProps, MessageBranch, MessageBranchContent, MessageBranchContentProps, MessageBranchNext, MessageBranchNextProps, MessageBranchPage, MessageBranchPageProps, MessageBranchPrevious, MessageBranchPreviousProps, MessageBranchProps, MessageBranchSelector, MessageBranchSelectorProps, MessageContent, MessageContentProps, MessageProps, MessageResponse, MessageResponseProps, MessageRole, MessageToolbar, MessageToolbarProps };
231
+ export { Message, MessageAction, MessageActionProps, MessageActions, MessageActionsProps, MessageAttachment, MessageAttachmentProps, MessageBranch, MessageBranchContent, MessageBranchContentProps, MessageBranchNext, MessageBranchNextProps, MessageBranchPage, MessageBranchPageProps, MessageBranchPrevious, MessageBranchPreviousProps, MessageBranchProps, MessageBranchSelector, MessageBranchSelectorProps, MessageContent, MessageContentProps, MessageProps, MessageResponse, MessageResponseProps, MessageRole, MessageToolbar, MessageToolbarProps };