assistant-ui 0.0.120 → 0.0.122

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 (133) hide show
  1. package/README.md +60 -1
  2. package/dist/commands/add.d.ts.map +1 -1
  3. package/dist/commands/add.js +1 -2
  4. package/dist/commands/add.js.map +1 -1
  5. package/dist/commands/cloud.d.ts +25 -0
  6. package/dist/commands/cloud.d.ts.map +1 -0
  7. package/dist/commands/cloud.js +194 -0
  8. package/dist/commands/cloud.js.map +1 -0
  9. package/dist/commands/create.d.ts.map +1 -1
  10. package/dist/commands/create.js +10 -2
  11. package/dist/commands/create.js.map +1 -1
  12. package/dist/commands/info.js +2 -2
  13. package/dist/commands/init.d.ts.map +1 -1
  14. package/dist/commands/init.js +1 -2
  15. package/dist/commands/init.js.map +1 -1
  16. package/dist/commands/mcp.d.ts.map +1 -1
  17. package/dist/commands/mcp.js +95 -23
  18. package/dist/commands/mcp.js.map +1 -1
  19. package/dist/lib/agent-skill.d.ts +2 -2
  20. package/dist/lib/agent-skill.d.ts.map +1 -1
  21. package/dist/lib/agent-skill.js +10 -28
  22. package/dist/lib/agent-skill.js.map +1 -1
  23. package/dist/lib/cloud-abort.d.ts +2 -0
  24. package/dist/lib/cloud-abort.d.ts.map +1 -0
  25. package/dist/lib/cloud-abort.js +13 -0
  26. package/dist/lib/cloud-abort.js.map +1 -0
  27. package/dist/lib/cloud-auth.d.ts +28 -0
  28. package/dist/lib/cloud-auth.d.ts.map +1 -0
  29. package/dist/lib/cloud-auth.js +169 -0
  30. package/dist/lib/cloud-auth.js.map +1 -0
  31. package/dist/lib/cloud-config.d.ts +21 -0
  32. package/dist/lib/cloud-config.d.ts.map +1 -0
  33. package/dist/lib/cloud-config.js +76 -0
  34. package/dist/lib/cloud-config.js.map +1 -0
  35. package/dist/lib/cloud-provision.d.ts +20 -0
  36. package/dist/lib/cloud-provision.d.ts.map +1 -0
  37. package/dist/lib/cloud-provision.js +55 -0
  38. package/dist/lib/cloud-provision.js.map +1 -0
  39. package/dist/lib/cloud-setup-login.d.ts +9 -0
  40. package/dist/lib/cloud-setup-login.d.ts.map +1 -0
  41. package/dist/lib/cloud-setup-login.js +137 -0
  42. package/dist/lib/cloud-setup-login.js.map +1 -0
  43. package/dist/lib/cloud-url.d.ts +2 -0
  44. package/dist/lib/cloud-url.d.ts.map +1 -0
  45. package/dist/lib/cloud-url.js +14 -0
  46. package/dist/lib/cloud-url.js.map +1 -0
  47. package/dist/lib/create-project.d.ts +0 -9
  48. package/dist/lib/create-project.d.ts.map +1 -1
  49. package/dist/lib/create-project.js +15 -46
  50. package/dist/lib/create-project.js.map +1 -1
  51. package/dist/lib/transform.d.ts +0 -4
  52. package/dist/lib/transform.d.ts.map +1 -1
  53. package/dist/lib/transform.js +8 -17
  54. package/dist/lib/transform.js.map +1 -1
  55. package/dist/lib/utils/download.d.ts +5 -0
  56. package/dist/lib/utils/download.d.ts.map +1 -0
  57. package/dist/lib/utils/download.js +41 -0
  58. package/dist/lib/utils/download.js.map +1 -0
  59. package/dist/lib/utils/file-scanner.d.ts +0 -1
  60. package/dist/lib/utils/file-scanner.d.ts.map +1 -1
  61. package/dist/lib/utils/file-scanner.js +1 -16
  62. package/dist/lib/utils/file-scanner.js.map +1 -1
  63. package/dist/lib/utils/package-manager.d.ts +7 -0
  64. package/dist/lib/utils/package-manager.d.ts.map +1 -1
  65. package/dist/lib/utils/package-manager.js +15 -1
  66. package/dist/lib/utils/package-manager.js.map +1 -1
  67. package/dist/program.d.ts.map +1 -1
  68. package/dist/program.js +2 -1
  69. package/dist/program.js.map +1 -1
  70. package/package.json +12 -8
  71. package/src/commands/add.ts +2 -1
  72. package/src/commands/cloud.test.ts +238 -0
  73. package/src/commands/cloud.ts +455 -0
  74. package/src/commands/create.ts +13 -3
  75. package/src/commands/init.ts +5 -2
  76. package/src/commands/mcp.ts +223 -56
  77. package/src/lib/agent-skill.ts +18 -44
  78. package/src/lib/cloud-abort.ts +12 -0
  79. package/src/lib/cloud-auth.test.ts +500 -0
  80. package/src/lib/cloud-auth.ts +273 -0
  81. package/src/lib/cloud-config.test.ts +82 -0
  82. package/src/lib/cloud-config.ts +138 -0
  83. package/src/lib/cloud-provision.test.ts +132 -0
  84. package/src/lib/cloud-provision.ts +93 -0
  85. package/src/lib/cloud-setup-login.test.ts +361 -0
  86. package/src/lib/cloud-setup-login.ts +240 -0
  87. package/src/lib/cloud-url.ts +19 -0
  88. package/src/lib/create-project.test.ts +0 -17
  89. package/src/lib/create-project.ts +33 -98
  90. package/src/lib/transform-files.test.ts +1 -3
  91. package/src/lib/transform.ts +6 -20
  92. package/src/lib/utils/download.ts +57 -0
  93. package/src/lib/utils/file-scanner.ts +0 -26
  94. package/src/lib/utils/package-manager.ts +26 -0
  95. package/src/lib/utils/registry.test.ts +0 -6
  96. package/src/program.ts +2 -0
  97. package/templates/cloud-harness/.assistant-ui/template.json +3 -0
  98. package/templates/cloud-harness/.env.example +1 -0
  99. package/templates/cloud-harness/.gitignore +42 -0
  100. package/templates/cloud-harness/README.md +28 -0
  101. package/templates/cloud-harness/app/api/chat/route.ts +14 -0
  102. package/templates/cloud-harness/app/api/credential/route.ts +14 -0
  103. package/templates/cloud-harness/app/assistant.tsx +83 -0
  104. package/templates/cloud-harness/app/favicon.ico +0 -0
  105. package/templates/cloud-harness/app/globals.css +139 -0
  106. package/templates/cloud-harness/app/layout.tsx +37 -0
  107. package/templates/cloud-harness/app/page.tsx +5 -0
  108. package/templates/cloud-harness/components/assistant-ui/elements/attachment.aui.tsx +279 -0
  109. package/templates/cloud-harness/components/assistant-ui/elements/collapsible-root.tsx +19 -0
  110. package/templates/cloud-harness/components/assistant-ui/elements/markdown-text.tsx +238 -0
  111. package/templates/cloud-harness/components/assistant-ui/elements/thread.aui.tsx +521 -0
  112. package/templates/cloud-harness/components/assistant-ui/elements/tool-fallback.aui.tsx +1321 -0
  113. package/templates/cloud-harness/components/assistant-ui/elements/tooltip-icon-button.tsx +49 -0
  114. package/templates/cloud-harness/components/ui/avatar.tsx +109 -0
  115. package/templates/cloud-harness/components/ui/button.tsx +58 -0
  116. package/templates/cloud-harness/components/ui/collapsible.tsx +21 -0
  117. package/templates/cloud-harness/components/ui/dialog.tsx +159 -0
  118. package/templates/cloud-harness/components/ui/textarea.tsx +18 -0
  119. package/templates/cloud-harness/components/ui/tooltip.tsx +69 -0
  120. package/templates/cloud-harness/components.json +24 -0
  121. package/templates/cloud-harness/hooks/use-attachment-src.ts +46 -0
  122. package/templates/cloud-harness/hooks/use-copy-to-clipboard.ts +54 -0
  123. package/templates/cloud-harness/lib/utils.ts +1 -0
  124. package/templates/cloud-harness/next.config.ts +6 -0
  125. package/templates/cloud-harness/package.json +51 -0
  126. package/templates/cloud-harness/postcss.config.mjs +5 -0
  127. package/templates/cloud-harness/tsconfig.json +33 -0
  128. package/templates/cloud-harness/vendor/README.md +13 -0
  129. package/templates/cloud-harness/vendor/assistant-ui-react-harness-sdk-0.0.2.tgz +0 -0
  130. package/templates/cloud-harness/vendor/harness-sdk-0.3.1.tgz +0 -0
  131. package/templates/cloud-harness/vendor/provenance.json +38 -0
  132. package/templates/cloud-harness/vendor/statewire-0.19.3.tgz +0 -0
  133. /package/{LICENSE → templates/cloud-harness/vendor/LICENSE} +0 -0
@@ -0,0 +1,139 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+ @import "tw-shimmer";
4
+
5
+ @custom-variant data-open (&:where([data-state="open"], [data-open]:not([data-open="false"])));
6
+ @custom-variant data-closed (&:where([data-state="closed"], [data-closed]:not([data-closed="false"])));
7
+
8
+ @theme inline {
9
+ @keyframes collapsible-down {
10
+ from {
11
+ height: 0;
12
+ }
13
+ to {
14
+ height: var(
15
+ --radix-collapsible-content-height,
16
+ var(--collapsible-panel-height, auto)
17
+ );
18
+ }
19
+ }
20
+ @keyframes collapsible-up {
21
+ from {
22
+ height: var(
23
+ --radix-collapsible-content-height,
24
+ var(--collapsible-panel-height, auto)
25
+ );
26
+ }
27
+ to {
28
+ height: 0;
29
+ }
30
+ }
31
+ }
32
+
33
+ @custom-variant dark (&:is(.dark *));
34
+
35
+ @theme inline {
36
+ --color-background: var(--background);
37
+ --color-foreground: var(--foreground);
38
+ --font-sans: var(--font-inter);
39
+ --font-mono: var(--font-ibm-plex-mono);
40
+ --color-chart-5: var(--chart-5);
41
+ --color-chart-4: var(--chart-4);
42
+ --color-chart-3: var(--chart-3);
43
+ --color-chart-2: var(--chart-2);
44
+ --color-chart-1: var(--chart-1);
45
+ --color-ring: var(--ring);
46
+ --color-input: var(--input);
47
+ --color-border: var(--border);
48
+ --color-destructive: var(--destructive);
49
+ --color-accent-foreground: var(--accent-foreground);
50
+ --color-accent: var(--accent);
51
+ --color-muted-foreground: var(--muted-foreground);
52
+ --color-muted: var(--muted);
53
+ --color-secondary-foreground: var(--secondary-foreground);
54
+ --color-secondary: var(--secondary);
55
+ --color-primary-foreground: var(--primary-foreground);
56
+ --color-primary: var(--primary);
57
+ --color-popover-foreground: var(--popover-foreground);
58
+ --color-popover: var(--popover);
59
+ --color-card-foreground: var(--card-foreground);
60
+ --color-card: var(--card);
61
+ --radius-sm: calc(var(--radius) - 4px);
62
+ --radius-md: calc(var(--radius) - 2px);
63
+ --radius-lg: var(--radius);
64
+ --radius-xl: calc(var(--radius) + 4px);
65
+ --radius-2xl: calc(var(--radius) + 8px);
66
+ --radius-3xl: 1.5rem;
67
+ }
68
+
69
+ :root {
70
+ --radius: 0.625rem;
71
+ --background: oklch(1 0 0);
72
+ --foreground: oklch(0.141 0.005 285.823);
73
+ --card: oklch(1 0 0);
74
+ --card-foreground: oklch(0.141 0.005 285.823);
75
+ --popover: oklch(1 0 0);
76
+ --popover-foreground: oklch(0.141 0.005 285.823);
77
+ --primary: oklch(0.21 0.006 285.885);
78
+ --primary-foreground: oklch(0.985 0 0);
79
+ --secondary: oklch(0.967 0.001 286.375);
80
+ --secondary-foreground: oklch(0.21 0.006 285.885);
81
+ --muted: oklch(0.967 0.001 286.375);
82
+ --muted-foreground: oklch(0.552 0.016 285.938);
83
+ --accent: oklch(0.967 0.001 286.375);
84
+ --accent-foreground: oklch(0.21 0.006 285.885);
85
+ --destructive: oklch(0.577 0.245 27.325);
86
+ --border: oklch(0.92 0.004 286.32);
87
+ --input: oklch(0.92 0.004 286.32);
88
+ --ring: oklch(0.705 0.015 286.067);
89
+ --chart-1: oklch(0.646 0.222 41.116);
90
+ --chart-2: oklch(0.6 0.118 184.704);
91
+ --chart-3: oklch(0.398 0.07 227.392);
92
+ --chart-4: oklch(0.828 0.189 84.429);
93
+ --chart-5: oklch(0.769 0.188 70.08);
94
+ }
95
+
96
+ .dark {
97
+ --background: oklch(0.141 0.005 285.823);
98
+ --foreground: oklch(0.985 0 0);
99
+ --card: oklch(0.21 0.006 285.885);
100
+ --card-foreground: oklch(0.985 0 0);
101
+ --popover: oklch(0.21 0.006 285.885);
102
+ --popover-foreground: oklch(0.985 0 0);
103
+ --primary: oklch(0.92 0.004 286.32);
104
+ --primary-foreground: oklch(0.21 0.006 285.885);
105
+ --secondary: oklch(0.274 0.006 286.033);
106
+ --secondary-foreground: oklch(0.985 0 0);
107
+ --muted: oklch(0.274 0.006 286.033);
108
+ --muted-foreground: oklch(0.705 0.015 286.067);
109
+ --accent: oklch(0.274 0.006 286.033);
110
+ --accent-foreground: oklch(0.985 0 0);
111
+ --destructive: oklch(0.704 0.191 22.216);
112
+ --border: oklch(1 0 0 / 10%);
113
+ --input: oklch(1 0 0 / 15%);
114
+ --ring: oklch(0.552 0.016 285.938);
115
+ --chart-1: oklch(0.488 0.243 264.376);
116
+ --chart-2: oklch(0.696 0.17 162.48);
117
+ --chart-3: oklch(0.769 0.188 70.08);
118
+ --chart-4: oklch(0.627 0.265 303.9);
119
+ --chart-5: oklch(0.645 0.246 16.439);
120
+ }
121
+
122
+ @layer base {
123
+ * {
124
+ @apply border-border;
125
+ }
126
+
127
+ :root {
128
+ color-scheme: light;
129
+ }
130
+
131
+ :root.dark {
132
+ color-scheme: dark;
133
+ }
134
+
135
+ body {
136
+ @apply bg-background text-foreground;
137
+ font-optical-sizing: auto;
138
+ }
139
+ }
@@ -0,0 +1,37 @@
1
+ import type { Metadata } from "next";
2
+ import { IBM_Plex_Mono, Inter } from "next/font/google";
3
+ import { TooltipProvider } from "@/components/ui/tooltip";
4
+ import "./globals.css";
5
+
6
+ const inter = Inter({
7
+ variable: "--font-inter",
8
+ subsets: ["latin"],
9
+ axes: ["opsz"],
10
+ });
11
+
12
+ const ibmPlexMono = IBM_Plex_Mono({
13
+ variable: "--font-ibm-plex-mono",
14
+ subsets: ["latin"],
15
+ weight: ["400", "500", "600"],
16
+ });
17
+
18
+ export const metadata: Metadata = {
19
+ title: "Shared cloud chat",
20
+ description: "Generated by create-assistant-ui",
21
+ };
22
+
23
+ const RootLayout = ({
24
+ children,
25
+ }: Readonly<{
26
+ children: React.ReactNode;
27
+ }>) => {
28
+ return (
29
+ <html lang="en" className="dark">
30
+ <body className={`${inter.variable} ${ibmPlexMono.variable} antialiased`}>
31
+ <TooltipProvider>{children}</TooltipProvider>
32
+ </body>
33
+ </html>
34
+ );
35
+ };
36
+
37
+ export default RootLayout;
@@ -0,0 +1,5 @@
1
+ import { Assistant } from "./assistant";
2
+
3
+ const Home = () => <Assistant />;
4
+
5
+ export default Home;
@@ -0,0 +1,279 @@
1
+ "use client";
2
+
3
+ import {
4
+ type PropsWithChildren,
5
+ useState,
6
+ type FC,
7
+ isValidElement,
8
+ } from "react";
9
+ import {
10
+ XIcon,
11
+ PlusIcon,
12
+ FileText,
13
+ Loader2Icon,
14
+ AlertCircleIcon,
15
+ } from "lucide-react";
16
+ import {
17
+ AttachmentPrimitive,
18
+ ComposerPrimitive,
19
+ MessagePrimitive,
20
+ useAuiState,
21
+ useAui,
22
+ } from "@assistant-ui/react";
23
+ import {
24
+ Tooltip,
25
+ TooltipContent,
26
+ TooltipProvider,
27
+ TooltipTrigger,
28
+ } from "@/components/ui/tooltip";
29
+ import {
30
+ Dialog,
31
+ DialogTitle,
32
+ DialogContent,
33
+ DialogTrigger,
34
+ } from "@/components/ui/dialog";
35
+ import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
36
+ import { TooltipIconButton } from "@/components/assistant-ui/elements/tooltip-icon-button";
37
+ import { useAttachmentSrc } from "@/hooks/use-attachment-src";
38
+ import { cn } from "@/lib/utils";
39
+
40
+ type AttachmentPreviewProps = {
41
+ src: string;
42
+ name: string;
43
+ };
44
+
45
+ const AttachmentPreview: FC<AttachmentPreviewProps> = ({ src, name }) => {
46
+ const [isLoaded, setIsLoaded] = useState(false);
47
+ return (
48
+ <img
49
+ src={src}
50
+ alt={`Preview of ${name}`}
51
+ className={cn(
52
+ "block h-auto max-h-[80vh] w-auto max-w-full rounded-sm object-contain transition-opacity duration-300 motion-reduce:transition-none",
53
+ isLoaded
54
+ ? "aui-attachment-preview-image-loaded opacity-100"
55
+ : "aui-attachment-preview-image-loading opacity-0",
56
+ )}
57
+ onLoad={() => setIsLoaded(true)}
58
+ />
59
+ );
60
+ };
61
+
62
+ type AttachmentPreviewDialogProps = PropsWithChildren<{
63
+ src: string | undefined;
64
+ name: string;
65
+ }>;
66
+
67
+ const AttachmentPreviewDialog: FC<AttachmentPreviewDialogProps> = ({
68
+ children,
69
+ src,
70
+ name,
71
+ }) => {
72
+ if (!src) return children;
73
+
74
+ return (
75
+ <Dialog>
76
+ <DialogTrigger
77
+ nativeButton={false}
78
+ className="aui-attachment-preview-trigger cursor-zoom-in"
79
+ render={
80
+ isValidElement(children) ? (
81
+ children
82
+ ) : (
83
+ <button type="button">{children}</button>
84
+ )
85
+ }
86
+ />
87
+ <DialogContent className="aui-attachment-preview-dialog-content [&>button]:bg-foreground/60 [&>button]:hover:bg-foreground/80 [&_svg]:text-background p-2 sm:max-w-3xl [&>button]:rounded-full [&>button]:p-1 [&>button]:opacity-100 [&>button]:ring-0!">
88
+ <DialogTitle className="aui-sr-only sr-only">
89
+ Preview {name}
90
+ </DialogTitle>
91
+ <div className="aui-attachment-preview bg-background relative mx-auto flex max-h-[80dvh] w-full items-center justify-center overflow-hidden rounded-sm">
92
+ <AttachmentPreview src={src} name={name} />
93
+ </div>
94
+ </DialogContent>
95
+ </Dialog>
96
+ );
97
+ };
98
+
99
+ const AttachmentThumb: FC<{ src: string | undefined }> = ({ src }) => {
100
+ return (
101
+ <Avatar className="aui-attachment-tile-avatar h-full w-full rounded-none after:hidden">
102
+ <AvatarImage
103
+ src={src}
104
+ alt=""
105
+ className="aui-attachment-tile-image rounded-none object-cover"
106
+ />
107
+ <AvatarFallback>
108
+ <FileText className="aui-attachment-tile-fallback-icon text-muted-foreground/80 size-6 stroke-[1.5]" />
109
+ </AvatarFallback>
110
+ </Avatar>
111
+ );
112
+ };
113
+
114
+ const AttachmentUI: FC = () => {
115
+ const aui = useAui();
116
+ const isComposer = aui.attachment.source !== "message";
117
+ const src = useAttachmentSrc();
118
+
119
+ const isImage = useAuiState((s) => s.attachment.type === "image");
120
+ const name = useAuiState((s) => s.attachment.name);
121
+ const typeLabel = useAuiState((s) => {
122
+ const type = s.attachment.type;
123
+ switch (type) {
124
+ case "image":
125
+ return "Image";
126
+ case "document":
127
+ return "Document";
128
+ case "file":
129
+ return "File";
130
+ default:
131
+ return type;
132
+ }
133
+ });
134
+
135
+ // An attachment on a submission is still being prepared, whether or not the
136
+ // adapter reports progress while it uploads.
137
+ const uploadState = useAuiState((s) =>
138
+ s.attachment.status.type === "incomplete" &&
139
+ s.attachment.status.reason === "error"
140
+ ? "error"
141
+ : s.attachment.status.type === "running" ||
142
+ (s.optional.message?.submission !== undefined &&
143
+ s.attachment.status.type !== "complete")
144
+ ? "uploading"
145
+ : undefined,
146
+ );
147
+ const isUploading = uploadState === "uploading";
148
+ const isError = uploadState === "error";
149
+
150
+ const errorMessage = useAuiState((s) =>
151
+ s.attachment.status.type === "incomplete" &&
152
+ s.attachment.status.reason === "error"
153
+ ? (s.attachment.status.message ?? "Upload failed")
154
+ : undefined,
155
+ );
156
+
157
+ return (
158
+ <TooltipProvider>
159
+ <Tooltip>
160
+ <AttachmentPrimitive.Root
161
+ className={cn(
162
+ "aui-attachment-root relative",
163
+ isComposer &&
164
+ "animate-in fade-in-0 zoom-in-95 duration-200 motion-reduce:animate-none",
165
+ isImage &&
166
+ !isComposer &&
167
+ "aui-attachment-root-message only:*:first:size-24",
168
+ )}
169
+ >
170
+ <AttachmentPreviewDialog src={src} name={name}>
171
+ <TooltipTrigger
172
+ render={
173
+ <div
174
+ className={cn(
175
+ "aui-attachment-tile bg-muted hover:after:bg-foreground/10 focus-visible:ring-ring/50 relative size-14 overflow-hidden rounded-[calc(var(--composer-radius,1rem)-var(--composer-padding,8px))] transition-transform outline-none after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:ring-1 after:ring-black/10 after:transition-colors after:ring-inset focus-visible:ring-1 motion-reduce:transition-none dark:after:ring-white/10",
176
+ src
177
+ ? "cursor-zoom-in active:scale-[0.96]"
178
+ : "cursor-default",
179
+ isError &&
180
+ "after:ring-destructive/60 dark:after:ring-destructive/60",
181
+ )}
182
+ role={src ? "button" : "group"}
183
+ tabIndex={0}
184
+ aria-label={`${src ? `Preview ${name}` : `${typeLabel} attachment ${name}`}${
185
+ isError
186
+ ? ", upload failed"
187
+ : isUploading
188
+ ? ", uploading"
189
+ : ""
190
+ }`}
191
+ />
192
+ }
193
+ >
194
+ <AttachmentThumb src={src} />
195
+ {isUploading && (
196
+ <div
197
+ aria-hidden="true"
198
+ className="aui-attachment-tile-uploading bg-background/60 animate-in fade-in-0 absolute inset-0 flex items-center justify-center backdrop-blur-[2px] motion-reduce:animate-none"
199
+ >
200
+ <Loader2Icon className="text-muted-foreground size-4 animate-spin" />
201
+ </div>
202
+ )}
203
+ {isError && (
204
+ <div
205
+ aria-hidden="true"
206
+ className="aui-attachment-tile-error bg-background/70 animate-in fade-in-0 absolute inset-0 flex items-center justify-center backdrop-blur-[2px] motion-reduce:animate-none"
207
+ >
208
+ <AlertCircleIcon className="text-destructive size-4" />
209
+ </div>
210
+ )}
211
+ </TooltipTrigger>
212
+ </AttachmentPreviewDialog>
213
+ {isComposer && <AttachmentRemove name={name} />}
214
+ </AttachmentPrimitive.Root>
215
+ <TooltipContent side="top">
216
+ <AttachmentPrimitive.Name />
217
+ {errorMessage && (
218
+ <p className="aui-attachment-error-message">{errorMessage}</p>
219
+ )}
220
+ </TooltipContent>
221
+ </Tooltip>
222
+ </TooltipProvider>
223
+ );
224
+ };
225
+
226
+ const AttachmentRemove: FC<{ name: string }> = ({ name }) => {
227
+ return (
228
+ <AttachmentPrimitive.Remove
229
+ render={
230
+ <TooltipIconButton
231
+ tooltip={`Remove ${name}`}
232
+ className="aui-attachment-tile-remove absolute end-1 top-1 size-5 rounded-full bg-black/50! text-white after:absolute after:-inset-1.5 hover:bg-black/70! hover:text-white! active:scale-[0.96] motion-reduce:transition-none"
233
+ side="top"
234
+ />
235
+ }
236
+ >
237
+ <XIcon className="aui-attachment-remove-icon size-3 stroke-[2.5]" />
238
+ </AttachmentPrimitive.Remove>
239
+ );
240
+ };
241
+
242
+ export const UserMessageAttachments: FC = () => {
243
+ return (
244
+ <div className="aui-user-message-attachments-end col-span-full col-start-1 row-start-1 flex w-full flex-row justify-end gap-2 empty:hidden">
245
+ <MessagePrimitive.Attachments>
246
+ {() => <AttachmentUI />}
247
+ </MessagePrimitive.Attachments>
248
+ </div>
249
+ );
250
+ };
251
+
252
+ export const ComposerAttachments: FC = () => {
253
+ return (
254
+ <div className="aui-composer-attachments flex w-full flex-row items-center gap-2 overflow-x-auto empty:hidden">
255
+ <ComposerPrimitive.Attachments>
256
+ {() => <AttachmentUI />}
257
+ </ComposerPrimitive.Attachments>
258
+ </div>
259
+ );
260
+ };
261
+
262
+ export const ComposerAddAttachment: FC = () => {
263
+ return (
264
+ <ComposerPrimitive.AddAttachment
265
+ render={
266
+ <TooltipIconButton
267
+ tooltip="Add Attachment"
268
+ side="bottom"
269
+ variant="ghost"
270
+ size="icon"
271
+ className="aui-composer-add-attachment text-muted-foreground hover:text-foreground hover:bg-muted-foreground/15 dark:border-muted-foreground/15 dark:hover:bg-muted-foreground/30 size-7 rounded-full active:scale-[0.96] motion-reduce:transition-none"
272
+ aria-label="Add Attachment"
273
+ />
274
+ }
275
+ >
276
+ <PlusIcon className="aui-attachment-add-icon size-4" />
277
+ </ComposerPrimitive.AddAttachment>
278
+ );
279
+ };
@@ -0,0 +1,19 @@
1
+ "use client";
2
+
3
+ import { Collapsible } from "@base-ui/react/collapsible";
4
+ import { forwardRef } from "react";
5
+
6
+ export const CollapsibleRoot = forwardRef<
7
+ React.ComponentRef<typeof Collapsible.Root>,
8
+ React.ComponentPropsWithoutRef<typeof Collapsible.Root>
9
+ >(function CollapsibleRoot(props, ref) {
10
+ return <Collapsible.Root ref={ref} data-slot="collapsible" {...props} />;
11
+ });
12
+
13
+ export function CollapsibleTrigger({ ...props }: Collapsible.Trigger.Props) {
14
+ return <Collapsible.Trigger data-slot="collapsible-trigger" {...props} />;
15
+ }
16
+
17
+ export function CollapsibleContent({ ...props }: Collapsible.Panel.Props) {
18
+ return <Collapsible.Panel data-slot="collapsible-content" {...props} />;
19
+ }