File tree Expand file tree Collapse file tree 9 files changed +51
-24
lines changed
tanstack-router/src/routes
tanstack-start/src/routes
frontend/react/web-base/src Expand file tree Collapse file tree 9 files changed +51
-24
lines changed Original file line number Diff line number Diff line change @@ -108,6 +108,7 @@ export const dependencyVersionMap = {
108
108
"@ai-sdk/vue" : "^2.0.9" ,
109
109
"@ai-sdk/svelte" : "^3.0.9" ,
110
110
"@ai-sdk/react" : "^2.0.9" ,
111
+ streamdown : "^1.1.6" ,
111
112
112
113
"@orpc/server" : "^1.8.4" ,
113
114
"@orpc/client" : "^1.8.4" ,
Original file line number Diff line number Diff line change @@ -43,7 +43,7 @@ export async function setupExamples(config: ProjectConfig) {
43
43
} else if ( hasSvelte ) {
44
44
dependencies . push ( "@ai-sdk/svelte" ) ;
45
45
} else if ( hasReactWeb ) {
46
- dependencies . push ( "@ai-sdk/react" ) ;
46
+ dependencies . push ( "@ai-sdk/react" , "streamdown" ) ;
47
47
}
48
48
await addPackageDependency ( {
49
49
dependencies,
Original file line number Diff line number Diff line change @@ -740,6 +740,19 @@ export async function setupExamplesTemplate(
740
740
if ( hasReactWeb ) {
741
741
const exampleWebSrc = path . join ( exampleBaseDir , "web/react" ) ;
742
742
if ( await fs . pathExists ( exampleWebSrc ) ) {
743
+ if ( example === "ai" ) {
744
+ const exampleWebBaseSrc = path . join ( exampleWebSrc , "base" ) ;
745
+ if ( await fs . pathExists ( exampleWebBaseSrc ) ) {
746
+ await processAndCopyFiles (
747
+ "**/*" ,
748
+ exampleWebBaseSrc ,
749
+ webAppDir ,
750
+ context ,
751
+ false ,
752
+ ) ;
753
+ }
754
+ }
755
+
743
756
const reactFramework = context . frontend . find ( ( f ) =>
744
757
[
745
758
"next" ,
Original file line number Diff line number Diff line change
1
+ "use client";
2
+
3
+ import { type ComponentProps, memo } from "react";
4
+ import { Streamdown } from "streamdown";
5
+ import { cn } from "@/lib/utils";
6
+
7
+ type ResponseProps = ComponentProps<typeof Streamdown>;
8
+
9
+ export const Response = memo(
10
+ ({ className, ...props }: ResponseProps) => (
11
+ <Streamdown
12
+ className = {cn(
13
+ " size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0" ,
14
+ className,
15
+ )}
16
+ {...props}
17
+ />
18
+ ),
19
+ (prevProps, nextProps) => prevProps.children === nextProps.children,
20
+ );
21
+
22
+ Response.displayName = "Response";
Original file line number Diff line number Diff line change 2
2
3
3
import { useChat } from "@ai-sdk/react";
4
4
import { DefaultChatTransport } from "ai";
5
- import { Input } from "@/components/ui/input";
6
- import { Button } from "@/components/ui/button";
7
5
import { Send } from "lucide-react";
8
- import { useRef, useEffect, useState } from "react";
6
+ import { useEffect, useRef, useState } from "react";
7
+ import { Response } from "@/components/response";
8
+ import { Button } from "@/components/ui/button";
9
+ import { Input } from "@/components/ui/input";
9
10
10
11
export default function AIPage() {
11
12
const [input, setInput] = useState("");
@@ -51,11 +52,7 @@ export default function AIPage() {
51
52
</p >
52
53
{message.parts?.map((part, index) => {
53
54
if (part.type === "text") {
54
- return (
55
- <div key = {index} className =" whitespace-pre-wrap" >
56
- {part.text}
57
- </div >
58
- );
55
+ return <Response key = {index}>{part.text}</Response >;
59
56
}
60
57
return null;
61
58
})}
Original file line number Diff line number Diff line change @@ -4,6 +4,7 @@ import { DefaultChatTransport } from "ai";
4
4
import { Input } from "@/components/ui/input";
5
5
import { Button } from "@/components/ui/button";
6
6
import { Send } from "lucide-react";
7
+ import { Response } from "@/components/response";
7
8
8
9
const AI: React.FC = () => {
9
10
const [input, setInput] = useState("");
@@ -49,11 +50,7 @@ const AI: React.FC = () => {
49
50
</p >
50
51
{message.parts?.map((part, index) => {
51
52
if (part.type === "text") {
52
- return (
53
- <div key = {index} className =" whitespace-pre-wrap" >
54
- {part.text}
55
- </div >
56
- );
53
+ return <Response key = {index}>{part.text}</Response >;
57
54
}
58
55
return null;
59
56
})}
Original file line number Diff line number Diff line change @@ -5,6 +5,7 @@ import { Input } from "@/components/ui/input";
5
5
import { Button } from "@/components/ui/button";
6
6
import { Send } from "lucide-react";
7
7
import { useRef, useEffect, useState } from "react";
8
+ import { Response } from "@/components/response";
8
9
9
10
export const Route = createFileRoute("/ai")({
10
11
component: RouteComponent,
@@ -54,11 +55,7 @@ function RouteComponent() {
54
55
</p >
55
56
{message.parts?.map((part, index) => {
56
57
if (part.type === "text") {
57
- return (
58
- <div key = {index} className =" whitespace-pre-wrap" >
59
- {part.text}
60
- </div >
61
- );
58
+ return <Response key = {index}>{part.text}</Response >;
62
59
}
63
60
return null;
64
61
})}
Original file line number Diff line number Diff line change @@ -5,6 +5,7 @@ import { Input } from "@/components/ui/input";
5
5
import { Button } from "@/components/ui/button";
6
6
import { Send } from "lucide-react";
7
7
import { useRef, useEffect, useState } from "react";
8
+ import { Response } from "@/components/response";
8
9
9
10
export const Route = createFileRoute("/ai")({
10
11
component: RouteComponent,
@@ -54,11 +55,7 @@ function RouteComponent() {
54
55
</p >
55
56
{message.parts?.map((part, index) => {
56
57
if (part.type === "text") {
57
- return (
58
- <div key = {index} className =" whitespace-pre-wrap" >
59
- {part.text}
60
- </div >
61
- );
58
+ return <Response key = {index}>{part.text}</Response >;
62
59
}
63
60
return null;
64
61
})}
Original file line number Diff line number Diff line change 1
1
@import "tailwindcss";
2
2
@import "tw-animate-css";
3
+ {{ #if (includes examples " ai" )}}
4
+ @source "../node_modules/streamdown/dist/index.js";
5
+ {{ /if }}
3
6
4
7
@custom-variant dark (& :where(.dark, .dark *));
5
8
You can’t perform that action at this time.
0 commit comments