@tangle-network/sandbox-ui 0.3.6 → 0.3.7

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.
@@ -3,6 +3,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import { S as SessionMessage, a as SessionPart } from './parts-CyGkM6Fp.js';
4
4
  import { A as AgentBranding } from './branding-DCi5VEik.js';
5
5
  import { C as CustomToolRenderer } from './tool-display-Ct9nFAzJ.js';
6
+ import { OpenUIAction } from './openui.js';
6
7
 
7
8
  /**
8
9
  * ChatInput — message input bar with file attach, send/cancel, model selector.
@@ -57,11 +58,15 @@ interface ChatContainerProps {
57
58
  onRemoveFile?: (id: string) => void;
58
59
  onAttach?: (files: FileList) => void;
59
60
  disabled?: boolean;
61
+ /** Callback when an OpenUI action button is pressed within inline OpenUI blocks. */
62
+ onOpenUIAction?: (action: OpenUIAction) => void;
63
+ /** Enable rendering OpenUI schemas inline in the chat timeline. Defaults to true. */
64
+ enableOpenUI?: boolean;
60
65
  }
61
66
  /**
62
67
  * Full chat container: message list + auto-scroll + input area.
63
68
  * Orchestrates useRunGroups, useRunCollapseState, and useAutoScroll.
64
69
  */
65
- declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, onSend, onCancel, branding, placeholder, className, hideInput, renderToolDetail, presentation, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, disabled, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
70
+ declare const ChatContainer: React.MemoExoticComponent<({ messages, partMap, isStreaming, onSend, onCancel, branding, placeholder, className, hideInput, renderToolDetail, presentation, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, disabled, onOpenUIAction, enableOpenUI, }: ChatContainerProps) => react_jsx_runtime.JSX.Element>;
66
71
 
67
72
  export { ChatContainer as C, type PendingFile as P, ChatInput as a, type ChatInputProps as b, type ChatContainerProps as c };
package/dist/chat.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { C as ChatContainer, c as ChatContainerProps, a as ChatInput, b as ChatInputProps, P as PendingFile } from './chat-container-C8eHLw8z.js';
1
+ export { C as ChatContainer, c as ChatContainerProps, a as ChatInput, b as ChatInputProps, P as PendingFile } from './chat-container-B34uj-J1.js';
2
2
  import * as React from 'react';
3
3
  import { ReactNode } from 'react';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
@@ -7,6 +7,7 @@ import { a as SessionPart, S as SessionMessage } from './parts-CyGkM6Fp.js';
7
7
  import { A as AgentBranding } from './branding-DCi5VEik.js';
8
8
  import { C as CustomToolRenderer } from './tool-display-Ct9nFAzJ.js';
9
9
  import { T as ToolCallData } from './tool-call-feed-D5Ume-Pt.js';
10
+ import './openui.js';
10
11
 
11
12
  type MessageRole = "user" | "assistant" | "system";
12
13
  interface ChatMessageProps {
package/dist/chat.js CHANGED
@@ -6,13 +6,17 @@ import {
6
6
  MessageList,
7
7
  ThinkingIndicator,
8
8
  UserMessage
9
- } from "./chunk-4F2GJRGU.js";
9
+ } from "./chunk-PXRPYAMM.js";
10
10
  import "./chunk-CNWVHQFY.js";
11
11
  import "./chunk-WUR652Y3.js";
12
12
  import "./chunk-HRMUF35V.js";
13
13
  import "./chunk-CJ2RYVZH.js";
14
14
  import "./chunk-BX6AQMUS.js";
15
+ import "./chunk-YDBXQQLC.js";
16
+ import "./chunk-TQN3VR4F.js";
15
17
  import "./chunk-LTFK464G.js";
18
+ import "./chunk-MXCSSOGH.js";
19
+ import "./chunk-HWLX5NME.js";
16
20
  import "./chunk-RQHJBTEU.js";
17
21
  export {
18
22
  AgentTimeline,
@@ -530,6 +530,155 @@ var TerminalInput = React6.forwardRef(
530
530
  );
531
531
  TerminalInput.displayName = "TerminalInput";
532
532
 
533
+ // src/primitives/drop-zone.tsx
534
+ import { useCallback as useCallback2, useRef as useRef2, useState as useState3 } from "react";
535
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
536
+ function DropZone({
537
+ onDrop,
538
+ accept,
539
+ disabled,
540
+ overlay,
541
+ title = "Drop files to upload",
542
+ description = "Your files will be securely stored in the workspace.",
543
+ icon = "cloud_upload",
544
+ children,
545
+ className
546
+ }) {
547
+ const [dragOver, setDragOver] = useState3(false);
548
+ const counter = useRef2(0);
549
+ const isAccepted = useCallback2(
550
+ (file) => {
551
+ if (!accept) return true;
552
+ const extensions = accept.split(",").map((ext) => ext.trim().toLowerCase());
553
+ const fileName = file.name.toLowerCase();
554
+ return extensions.some((ext) => fileName.endsWith(ext));
555
+ },
556
+ [accept]
557
+ );
558
+ const handleDragEnter = useCallback2(
559
+ (e) => {
560
+ e.preventDefault();
561
+ if (disabled) return;
562
+ counter.current++;
563
+ if (e.dataTransfer?.types.includes("Files")) setDragOver(true);
564
+ },
565
+ [disabled]
566
+ );
567
+ const handleDragLeave = useCallback2((e) => {
568
+ e.preventDefault();
569
+ counter.current--;
570
+ if (counter.current === 0) setDragOver(false);
571
+ }, []);
572
+ const handleDragOver = useCallback2(
573
+ (e) => {
574
+ e.preventDefault();
575
+ if (!disabled) e.dataTransfer.dropEffect = "copy";
576
+ },
577
+ [disabled]
578
+ );
579
+ const handleDrop = useCallback2(
580
+ (e) => {
581
+ e.preventDefault();
582
+ counter.current = 0;
583
+ setDragOver(false);
584
+ if (disabled) return;
585
+ const allFiles = Array.from(e.dataTransfer?.files || []);
586
+ const accepted = accept ? allFiles.filter(isAccepted) : allFiles;
587
+ if (accepted.length > 0) onDrop(accepted);
588
+ },
589
+ [disabled, accept, isAccepted, onDrop]
590
+ );
591
+ return /* @__PURE__ */ jsxs5(
592
+ "div",
593
+ {
594
+ onDragEnter: handleDragEnter,
595
+ onDragLeave: handleDragLeave,
596
+ onDragOver: handleDragOver,
597
+ onDrop: handleDrop,
598
+ className: cn("relative", className),
599
+ children: [
600
+ dragOver && (overlay || /* @__PURE__ */ jsx7("div", { className: "fixed inset-0 z-[100] flex items-center justify-center pointer-events-none bg-black/20 backdrop-blur-sm", children: /* @__PURE__ */ jsxs5("div", { className: "rounded-3xl border-2 border-dashed border-[hsl(var(--ring))] bg-[hsl(var(--card))] p-16 text-center shadow-2xl max-w-lg mx-auto", children: [
601
+ /* @__PURE__ */ jsx7("div", { className: "mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-2xl bg-[hsl(var(--primary))]/10", children: typeof icon === "string" ? /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-5xl text-[hsl(var(--primary))]", children: icon }) : icon }),
602
+ /* @__PURE__ */ jsx7("h2", { className: "text-2xl font-extrabold text-[hsl(var(--foreground))]", children: title }),
603
+ /* @__PURE__ */ jsx7("p", { className: "mt-2 text-[hsl(var(--muted-foreground))]", children: description })
604
+ ] }) })),
605
+ children
606
+ ]
607
+ }
608
+ );
609
+ }
610
+
611
+ // src/primitives/upload-progress.tsx
612
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
613
+ function formatSize(bytes) {
614
+ if (bytes < 1024) return `${bytes}B`;
615
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;
616
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
617
+ }
618
+ function UploadProgress({ files, onRemove, onRetry, className }) {
619
+ if (files.length === 0) return null;
620
+ return /* @__PURE__ */ jsx8("div", { className: cn("space-y-2", className), children: files.map((file) => /* @__PURE__ */ jsxs6(
621
+ "div",
622
+ {
623
+ className: cn(
624
+ "flex items-center gap-3 rounded-lg border px-3 py-2 text-sm",
625
+ file.status === "error" ? "border-[hsl(var(--destructive))]/20 bg-[hsl(var(--destructive))]/5" : file.status === "complete" ? "border-[hsl(var(--success))]/20 bg-[hsl(var(--success))]/5" : "border-[hsl(var(--border))] bg-[hsl(var(--card))]"
626
+ ),
627
+ children: [
628
+ /* @__PURE__ */ jsx8(
629
+ "span",
630
+ {
631
+ className: cn(
632
+ "material-symbols-outlined text-base shrink-0",
633
+ file.status === "complete" && "text-[hsl(var(--success))]",
634
+ file.status === "error" && "text-[hsl(var(--destructive))]",
635
+ file.status === "uploading" && "text-[hsl(var(--primary))] animate-pulse",
636
+ file.status === "pending" && "text-[hsl(var(--muted-foreground))]"
637
+ ),
638
+ style: file.status === "complete" ? { fontVariationSettings: "'FILL' 1" } : void 0,
639
+ children: file.status === "complete" ? "check_circle" : file.status === "error" ? "error" : file.status === "uploading" ? "progress_activity" : "description"
640
+ }
641
+ ),
642
+ /* @__PURE__ */ jsxs6("div", { className: "flex-1 min-w-0", children: [
643
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
644
+ /* @__PURE__ */ jsx8("span", { className: "truncate font-medium text-[hsl(var(--foreground))]", children: file.name }),
645
+ /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-xs text-[hsl(var(--muted-foreground))]", children: formatSize(file.size) })
646
+ ] }),
647
+ file.status === "uploading" && file.progress !== void 0 && /* @__PURE__ */ jsx8("div", { className: "mt-1 h-1 w-full rounded-full bg-[hsl(var(--muted))] overflow-hidden", children: /* @__PURE__ */ jsx8(
648
+ "div",
649
+ {
650
+ className: "h-full rounded-full bg-[hsl(var(--primary))] transition-all",
651
+ style: { width: `${file.progress}%` }
652
+ }
653
+ ) }),
654
+ file.status === "error" && file.error && /* @__PURE__ */ jsx8("p", { className: "mt-0.5 text-xs text-[hsl(var(--destructive))]", children: file.error })
655
+ ] }),
656
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1 shrink-0", children: [
657
+ file.status === "error" && onRetry && /* @__PURE__ */ jsx8(
658
+ "button",
659
+ {
660
+ type: "button",
661
+ onClick: () => onRetry(file.id),
662
+ className: "rounded p-1 text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] transition-colors",
663
+ children: /* @__PURE__ */ jsx8("span", { className: "material-symbols-outlined text-sm", children: "refresh" })
664
+ }
665
+ ),
666
+ onRemove && /* @__PURE__ */ jsx8(
667
+ "button",
668
+ {
669
+ type: "button",
670
+ onClick: () => onRemove(file.id),
671
+ className: "rounded p-1 text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--foreground))] transition-colors",
672
+ children: /* @__PURE__ */ jsx8("span", { className: "material-symbols-outlined text-sm", children: "close" })
673
+ }
674
+ )
675
+ ] })
676
+ ]
677
+ },
678
+ file.id
679
+ )) });
680
+ }
681
+
533
682
  export {
534
683
  Select,
535
684
  SelectGroup,
@@ -550,5 +699,7 @@ export {
550
699
  TerminalDisplay,
551
700
  TerminalLine,
552
701
  TerminalCursor,
553
- TerminalInput
702
+ TerminalInput,
703
+ DropZone,
704
+ UploadProgress
554
705
  };
@@ -14,6 +14,9 @@ import {
14
14
  import {
15
15
  getToolDisplayMetadata
16
16
  } from "./chunk-BX6AQMUS.js";
17
+ import {
18
+ OpenUIArtifactRenderer
19
+ } from "./chunk-YDBXQQLC.js";
17
20
  import {
18
21
  Markdown
19
22
  } from "./chunk-LTFK464G.js";
@@ -516,6 +519,52 @@ import {
516
519
  } from "react";
517
520
  import { ArrowDown } from "lucide-react";
518
521
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
522
+ var OPENUI_NODE_TYPES = /* @__PURE__ */ new Set([
523
+ "heading",
524
+ "text",
525
+ "badge",
526
+ "stat",
527
+ "key_value",
528
+ "code",
529
+ "markdown",
530
+ "table",
531
+ "actions",
532
+ "separator",
533
+ "stack",
534
+ "grid",
535
+ "card"
536
+ ]);
537
+ function isOpenUINode(value) {
538
+ return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string" && OPENUI_NODE_TYPES.has(value.type);
539
+ }
540
+ function extractOpenUISchema(output) {
541
+ if (output == null) return null;
542
+ if (isOpenUINode(output)) return [output];
543
+ if (Array.isArray(output) && output.length > 0 && output.every(isOpenUINode)) {
544
+ return output;
545
+ }
546
+ if (typeof output === "object" && !Array.isArray(output)) {
547
+ const obj = output;
548
+ for (const key of ["openui", "schema", "ui"]) {
549
+ if (obj[key]) {
550
+ const inner = obj[key];
551
+ if (isOpenUINode(inner)) return [inner];
552
+ if (Array.isArray(inner) && inner.length > 0 && inner.every(isOpenUINode)) {
553
+ return inner;
554
+ }
555
+ }
556
+ }
557
+ }
558
+ if (typeof output === "string") {
559
+ try {
560
+ const parsed = JSON.parse(output);
561
+ return extractOpenUISchema(parsed);
562
+ } catch {
563
+ return null;
564
+ }
565
+ }
566
+ return null;
567
+ }
519
568
  function formatUnknown(value) {
520
569
  if (value == null) return void 0;
521
570
  if (typeof value === "string") return value;
@@ -563,7 +612,7 @@ function mapToolPartToTimelineType(part) {
563
612
  return "unknown";
564
613
  }
565
614
  }
566
- function buildTimelineItems(messages, partMap, isStreaming) {
615
+ function buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enableOpenUI = true) {
567
616
  const items = [];
568
617
  const lastAssistantMessage = [...messages].reverse().find((message) => message.role === "assistant");
569
618
  const toToolCall = (part) => {
@@ -611,6 +660,18 @@ function buildTimelineItems(messages, partMap, isStreaming) {
611
660
  calls: toolBuffer.map((part) => toToolCall(part))
612
661
  });
613
662
  }
663
+ if (enableOpenUI) {
664
+ for (const part of toolBuffer) {
665
+ if (part.state.status !== "completed" || !part.state.output) continue;
666
+ const schema = extractOpenUISchema(part.state.output);
667
+ if (!schema) continue;
668
+ items.push({
669
+ id: `${message.id}-openui-${part.id}`,
670
+ kind: "custom",
671
+ content: /* @__PURE__ */ jsx7("div", { className: "my-2 rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--bg-card)] p-4 shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsx7(OpenUIArtifactRenderer, { schema, onAction: onOpenUIAction }) })
672
+ });
673
+ }
674
+ }
614
675
  toolBuffer.length = 0;
615
676
  };
616
677
  parts.forEach((part, index) => {
@@ -621,6 +682,40 @@ function buildTimelineItems(messages, partMap, isStreaming) {
621
682
  }
622
683
  flushToolBuffer(index);
623
684
  if (part.type === "text" && !part.synthetic && part.text.trim()) {
685
+ if (enableOpenUI) {
686
+ const jsonMatch = part.text.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
687
+ if (jsonMatch) {
688
+ const schema = extractOpenUISchema(jsonMatch[1]);
689
+ if (schema) {
690
+ const beforeJson = part.text.slice(0, part.text.indexOf("```")).trim();
691
+ if (beforeJson) {
692
+ items.push({
693
+ id: `${itemId}-text`,
694
+ kind: "message",
695
+ role: "assistant",
696
+ content: beforeJson,
697
+ timestamp: createdAtFromMessage(message)
698
+ });
699
+ }
700
+ items.push({
701
+ id: `${itemId}-openui`,
702
+ kind: "custom",
703
+ content: /* @__PURE__ */ jsx7("div", { className: "my-2 rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--bg-card)] p-4 shadow-[var(--shadow-card)]", children: /* @__PURE__ */ jsx7(OpenUIArtifactRenderer, { schema, onAction: onOpenUIAction }) })
704
+ });
705
+ const afterJson = part.text.slice(part.text.lastIndexOf("```") + 3).trim();
706
+ if (afterJson) {
707
+ items.push({
708
+ id: `${itemId}-after`,
709
+ kind: "message",
710
+ role: "assistant",
711
+ content: afterJson,
712
+ timestamp: createdAtFromMessage(message)
713
+ });
714
+ }
715
+ return;
716
+ }
717
+ }
718
+ }
624
719
  items.push({
625
720
  id: itemId,
626
721
  kind: "message",
@@ -665,7 +760,9 @@ var ChatContainer = memo3(
665
760
  pendingFiles,
666
761
  onRemoveFile,
667
762
  onAttach,
668
- disabled = false
763
+ disabled = false,
764
+ onOpenUIAction,
765
+ enableOpenUI = true
669
766
  }) => {
670
767
  const scrollRef = useRef2(null);
671
768
  const groups = useRunGroups({ messages, partMap, isStreaming });
@@ -677,8 +774,8 @@ var ChatContainer = memo3(
677
774
  isStreaming
678
775
  ]);
679
776
  const timeline = useMemo(
680
- () => buildTimelineItems(messages, partMap, isStreaming),
681
- [messages, partMap, isStreaming]
777
+ () => buildTimelineItems(messages, partMap, isStreaming, onOpenUIAction, enableOpenUI),
778
+ [messages, partMap, isStreaming, onOpenUIAction, enableOpenUI]
682
779
  );
683
780
  const handleSend = useCallback2(
684
781
  (text) => {
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-MUOL44AE.js";
5
5
  import {
6
6
  ChatContainer
7
- } from "./chunk-4F2GJRGU.js";
7
+ } from "./chunk-PXRPYAMM.js";
8
8
  import {
9
9
  OpenUIArtifactRenderer
10
10
  } from "./chunk-YDBXQQLC.js";
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { B as Button, a as ButtonProps, b as buttonVariants } from './button-CMQuQEW_.js';
2
- export { Avatar, AvatarFallback, AvatarImage, Badge, BadgeProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, EmptyStateProps, Input, InputProps, Label, Logo, LogoProps, Progress, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Skeleton, SkeletonCard, SkeletonTable, StatCard, StatCardProps, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TangleKnot, TerminalDisplay, TerminalCursor as TerminalDisplayCursor, TerminalInput as TerminalDisplayInput, TerminalLine as TerminalDisplayLine, Textarea, TextareaProps, Toast, ToastContainer, ToastProvider, badgeVariants, useToast } from './primitives.js';
2
+ export { Avatar, AvatarFallback, AvatarImage, Badge, BadgeProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, EmptyStateProps, Input, InputProps, Label, Logo, LogoProps, Progress, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Skeleton, SkeletonCard, SkeletonTable, StatCard, StatCardProps, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TangleKnot, TerminalDisplay, TerminalCursor as TerminalDisplayCursor, TerminalInput as TerminalDisplayInput, TerminalLine as TerminalDisplayLine, Textarea, TextareaProps, Toast, ToastContainer, ToastProvider, UploadFile, UploadProgress, UploadProgressProps, badgeVariants, useToast } from './primitives.js';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import * as React from 'react';
5
5
  import React__default from 'react';
@@ -7,7 +7,7 @@ export { AgentWorkbench, AuditCheck, AuditResults, AuditResultsProps, BannerType
7
7
  export { A as ArtifactPane, a as ArtifactPaneProps, F as FileNode, b as FileTabData, c as FileTabs, d as FileTabsProps, e as FileTree, f as FileTreeProps, g as FileTreeVisibilityOptions, h as filterFileTree } from './file-tabs-CmaoDVBI.js';
8
8
  export { OpenUIAction, OpenUIActionsNode, OpenUIArtifactRenderer, OpenUIArtifactRendererProps, OpenUIBadgeNode, OpenUICardNode, OpenUICodeNode, OpenUIComponentNode, OpenUIGridNode, OpenUIHeadingNode, OpenUIKeyValueNode, OpenUIMarkdownNode, OpenUIPrimitive, OpenUISeparatorNode, OpenUIStackNode, OpenUIStatNode, OpenUITableNode, OpenUITextNode } from './openui.js';
9
9
  export { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, ChatMessage, ChatMessageProps, MessageList, MessageRole, ThinkingIndicator, ThinkingIndicatorProps, UserMessage } from './chat.js';
10
- export { C as ChatContainer, a as ChatInput, b as ChatInputProps, P as PendingFile } from './chat-container-C8eHLw8z.js';
10
+ export { C as ChatContainer, a as ChatInput, b as ChatInputProps, P as PendingFile } from './chat-container-B34uj-J1.js';
11
11
  export { F as FeedSegment, T as ToolCallData, a as ToolCallFeed, b as ToolCallFeedProps, c as ToolCallGroup, d as ToolCallGroupProps, e as ToolCallStatus, f as ToolCallStep, g as ToolCallStepProps, h as ToolCallType, p as parseToolEvent } from './tool-call-feed-D5Ume-Pt.js';
12
12
  export { E as ExpandedToolDetail, I as InlineThinkingItem, c as InlineToolItem, R as RunGroup } from './expanded-tool-detail-BDi_h_dZ.js';
13
13
  import { b as ToolPart } from './parts-CyGkM6Fp.js';
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  useToolCallStream
26
26
  } from "./chunk-5LV6DZZF.js";
27
27
  import {
28
+ DropZone,
28
29
  Label,
29
30
  Select,
30
31
  SelectContent,
@@ -44,8 +45,9 @@ import {
44
45
  TerminalLine,
45
46
  ToastContainer,
46
47
  ToastProvider,
48
+ UploadProgress,
47
49
  useToast
48
- } from "./chunk-TXI4MZAZ.js";
50
+ } from "./chunk-CSIXZEKN.js";
49
51
  import {
50
52
  Avatar,
51
53
  AvatarFallback,
@@ -81,7 +83,7 @@ import {
81
83
  StatusBar,
82
84
  TerminalPanel,
83
85
  WorkspaceLayout
84
- } from "./chunk-QGI5E7JD.js";
86
+ } from "./chunk-ZSNOGOUX.js";
85
87
  import {
86
88
  EmptyState,
87
89
  Input,
@@ -95,7 +97,7 @@ import {
95
97
  MessageList,
96
98
  ThinkingIndicator,
97
99
  UserMessage
98
- } from "./chunk-4F2GJRGU.js";
100
+ } from "./chunk-PXRPYAMM.js";
99
101
  import {
100
102
  useAutoScroll,
101
103
  useRunCollapseState,
@@ -348,6 +350,7 @@ export {
348
350
  DialogTrigger,
349
351
  DiffPreview,
350
352
  DirectoryPane,
353
+ DropZone,
351
354
  DropdownMenu,
352
355
  DropdownMenuCheckboxItem,
353
356
  DropdownMenuContent,
@@ -440,6 +443,7 @@ export {
440
443
  ToolCallFeed,
441
444
  ToolCallGroup,
442
445
  ToolCallStep,
446
+ UploadProgress,
443
447
  UsageChart,
444
448
  UserMenu,
445
449
  UserMessage,
@@ -1,5 +1,6 @@
1
1
  export { B as Button, a as ButtonProps, b as buttonVariants } from './button-CMQuQEW_.js';
2
2
  import * as React$1 from 'react';
3
+ import { ReactNode } from 'react';
3
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
5
  import * as DialogPrimitive from '@radix-ui/react-dialog';
5
6
  import * as class_variance_authority_types from 'class-variance-authority/types';
@@ -230,4 +231,47 @@ interface TerminalInputProps extends Omit<React$1.InputHTMLAttributes<HTMLInputE
230
231
  }
231
232
  declare const TerminalInput: React$1.ForwardRefExoticComponent<TerminalInputProps & React$1.RefAttributes<HTMLInputElement>>;
232
233
 
233
- export { Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, Input, type InputProps, Label, Logo, type LogoProps, Progress, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Skeleton, SkeletonCard, SkeletonTable, StatCard, type StatCardProps, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TangleKnot, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, Textarea, type TextareaProps, type Toast, ToastContainer, ToastProvider, badgeVariants, useToast };
234
+ interface DropZoneProps {
235
+ /** Called with dropped files */
236
+ onDrop: (files: File[]) => void;
237
+ /** Accepted file types (e.g. ".pdf,.csv,.xlsx") */
238
+ accept?: string;
239
+ /** Whether drop zone is active */
240
+ disabled?: boolean;
241
+ /** Custom overlay content (replaces default) */
242
+ overlay?: ReactNode;
243
+ /** Overlay title */
244
+ title?: string;
245
+ /** Overlay description */
246
+ description?: string;
247
+ /** Overlay icon (Material Symbols name or ReactNode) */
248
+ icon?: string | ReactNode;
249
+ /** Children wrapped by the drop zone */
250
+ children: ReactNode;
251
+ className?: string;
252
+ }
253
+ declare function DropZone({ onDrop, accept, disabled, overlay, title, description, icon, children, className, }: DropZoneProps): react_jsx_runtime.JSX.Element;
254
+
255
+ /**
256
+ * UploadProgress — file upload status indicators.
257
+ *
258
+ * Shows a list of files being uploaded with progress bars,
259
+ * completion checkmarks, and error states.
260
+ */
261
+ interface UploadFile {
262
+ id: string;
263
+ name: string;
264
+ size: number;
265
+ status: "pending" | "uploading" | "complete" | "error";
266
+ progress?: number;
267
+ error?: string;
268
+ }
269
+ interface UploadProgressProps {
270
+ files: UploadFile[];
271
+ onRemove?: (id: string) => void;
272
+ onRetry?: (id: string) => void;
273
+ className?: string;
274
+ }
275
+ declare function UploadProgress({ files, onRemove, onRetry, className }: UploadProgressProps): react_jsx_runtime.JSX.Element | null;
276
+
277
+ export { Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropZone, type DropZoneProps, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, Input, type InputProps, Label, Logo, type LogoProps, Progress, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Skeleton, SkeletonCard, SkeletonTable, StatCard, type StatCardProps, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TangleKnot, TerminalCursor, TerminalDisplay, TerminalInput, TerminalLine, Textarea, type TextareaProps, type Toast, ToastContainer, ToastProvider, type UploadFile, UploadProgress, type UploadProgressProps, badgeVariants, useToast };
@@ -1,4 +1,5 @@
1
1
  import {
2
+ DropZone,
2
3
  Label,
3
4
  Select,
4
5
  SelectContent,
@@ -18,8 +19,9 @@ import {
18
19
  TerminalLine,
19
20
  ToastContainer,
20
21
  ToastProvider,
22
+ UploadProgress,
21
23
  useToast
22
- } from "./chunk-TXI4MZAZ.js";
24
+ } from "./chunk-CSIXZEKN.js";
23
25
  import {
24
26
  Avatar,
25
27
  AvatarFallback,
@@ -120,6 +122,7 @@ export {
120
122
  DialogPortal,
121
123
  DialogTitle,
122
124
  DialogTrigger,
125
+ DropZone,
123
126
  DropdownMenu,
124
127
  DropdownMenuCheckboxItem,
125
128
  DropdownMenuContent,
@@ -175,6 +178,7 @@ export {
175
178
  Textarea,
176
179
  ToastContainer,
177
180
  ToastProvider,
181
+ UploadProgress,
178
182
  badgeVariants,
179
183
  buttonVariants,
180
184
  useToast
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
3
  import { F as FileNode, g as FileTreeVisibilityOptions, b as FileTabData } from './file-tabs-CmaoDVBI.js';
4
4
  export { A as ArtifactPane, a as ArtifactPaneProps } from './file-tabs-CmaoDVBI.js';
5
- import { c as ChatContainerProps } from './chat-container-C8eHLw8z.js';
5
+ import { c as ChatContainerProps } from './chat-container-B34uj-J1.js';
6
6
  import { OpenUIComponentNode, OpenUIAction } from './openui.js';
7
7
  import './parts-CyGkM6Fp.js';
8
8
  import './branding-DCi5VEik.js';
package/dist/workspace.js CHANGED
@@ -8,9 +8,9 @@ import {
8
8
  StatusBar,
9
9
  TerminalPanel,
10
10
  WorkspaceLayout
11
- } from "./chunk-QGI5E7JD.js";
11
+ } from "./chunk-ZSNOGOUX.js";
12
12
  import "./chunk-MUOL44AE.js";
13
- import "./chunk-4F2GJRGU.js";
13
+ import "./chunk-PXRPYAMM.js";
14
14
  import "./chunk-CNWVHQFY.js";
15
15
  import "./chunk-WUR652Y3.js";
16
16
  import "./chunk-HRMUF35V.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Unified UI component library for Tangle Sandbox — primitives, chat, dashboard, terminal, editor, and workspace components",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",