@openconsole/shadcn 0.2.4 → 0.2.6

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 (117) hide show
  1. package/README.md +460 -380
  2. package/components/ai-elements/agent.tsx +141 -0
  3. package/components/ai-elements/artifact.tsx +148 -0
  4. package/components/ai-elements/attachments.tsx +426 -0
  5. package/components/ai-elements/audio-player.tsx +231 -0
  6. package/components/ai-elements/canvas.tsx +26 -0
  7. package/components/ai-elements/chain-of-thought.tsx +222 -0
  8. package/components/ai-elements/checkpoint.tsx +71 -0
  9. package/components/ai-elements/code-block.tsx +562 -0
  10. package/components/ai-elements/commit.tsx +458 -0
  11. package/components/ai-elements/confirmation.tsx +174 -0
  12. package/components/ai-elements/connection.tsx +28 -0
  13. package/components/ai-elements/context.tsx +409 -0
  14. package/components/ai-elements/controls.tsx +18 -0
  15. package/components/ai-elements/conversation.tsx +168 -0
  16. package/components/ai-elements/edge.tsx +143 -0
  17. package/components/ai-elements/environment-variables.tsx +324 -0
  18. package/components/ai-elements/file-tree.tsx +304 -0
  19. package/components/ai-elements/image.tsx +24 -0
  20. package/components/ai-elements/index.ts +51 -0
  21. package/components/ai-elements/inline-citation.tsx +296 -0
  22. package/components/ai-elements/jsx-preview.tsx +310 -0
  23. package/components/ai-elements/message.tsx +360 -0
  24. package/components/ai-elements/mic-selector.tsx +375 -0
  25. package/components/ai-elements/model-selector.tsx +213 -0
  26. package/components/ai-elements/node.tsx +71 -0
  27. package/components/ai-elements/open-in-chat.tsx +370 -0
  28. package/components/ai-elements/package-info.tsx +239 -0
  29. package/components/ai-elements/panel.tsx +15 -0
  30. package/components/ai-elements/persona.tsx +306 -0
  31. package/components/ai-elements/plan.tsx +147 -0
  32. package/components/ai-elements/prompt-input.tsx +1463 -0
  33. package/components/ai-elements/queue.tsx +274 -0
  34. package/components/ai-elements/reasoning.tsx +228 -0
  35. package/components/ai-elements/sandbox.tsx +132 -0
  36. package/components/ai-elements/schema-display.tsx +471 -0
  37. package/components/ai-elements/shimmer.tsx +77 -0
  38. package/components/ai-elements/snippet.tsx +145 -0
  39. package/components/ai-elements/sources.tsx +77 -0
  40. package/components/ai-elements/speech-input.tsx +323 -0
  41. package/components/ai-elements/stack-trace.tsx +528 -0
  42. package/components/ai-elements/suggestion.tsx +57 -0
  43. package/components/ai-elements/task.tsx +87 -0
  44. package/components/ai-elements/terminal.tsx +273 -0
  45. package/components/ai-elements/test-results.tsx +496 -0
  46. package/components/ai-elements/tool.tsx +173 -0
  47. package/components/ai-elements/toolbar.tsx +16 -0
  48. package/components/ai-elements/transcription.tsx +125 -0
  49. package/components/ai-elements/voice-selector.tsx +524 -0
  50. package/components/ai-elements/web-preview.tsx +281 -0
  51. package/components/index.ts +3 -0
  52. package/{accordion.tsx → components/ui/accordion.tsx} +66 -66
  53. package/{alert-dialog.tsx → components/ui/alert-dialog.tsx} +196 -196
  54. package/{alert.tsx → components/ui/alert.tsx} +66 -66
  55. package/{aspect-ratio.tsx → components/ui/aspect-ratio.tsx} +11 -11
  56. package/{avatar.tsx → components/ui/avatar.tsx} +53 -53
  57. package/{badge.tsx → components/ui/badge.tsx} +46 -46
  58. package/{breadcrumb.tsx → components/ui/breadcrumb.tsx} +109 -109
  59. package/{button-group.tsx → components/ui/button-group.tsx} +83 -83
  60. package/{button.tsx → components/ui/button.tsx} +60 -60
  61. package/{calendar.tsx → components/ui/calendar.tsx} +219 -219
  62. package/{card.tsx → components/ui/card.tsx} +92 -92
  63. package/{carousel.tsx → components/ui/carousel.tsx} +241 -241
  64. package/{chart.tsx → components/ui/chart.tsx} +374 -374
  65. package/{checkbox.tsx → components/ui/checkbox.tsx} +32 -32
  66. package/{collapsible.tsx → components/ui/collapsible.tsx} +33 -33
  67. package/{command.tsx → components/ui/command.tsx} +184 -184
  68. package/{context-menu.tsx → components/ui/context-menu.tsx} +252 -252
  69. package/{dialog.tsx → components/ui/dialog.tsx} +143 -143
  70. package/{direction.tsx → components/ui/direction.tsx} +22 -22
  71. package/{drawer.tsx → components/ui/drawer.tsx} +135 -135
  72. package/{dropdown-menu.tsx → components/ui/dropdown-menu.tsx} +257 -257
  73. package/{empty.tsx → components/ui/empty.tsx} +104 -104
  74. package/{field.tsx → components/ui/field.tsx} +248 -248
  75. package/{form.tsx → components/ui/form.tsx} +167 -167
  76. package/{hover-card.tsx → components/ui/hover-card.tsx} +44 -44
  77. package/{icon.tsx → components/ui/icon.tsx} +55 -55
  78. package/components/ui/index.ts +59 -0
  79. package/{input-group.tsx → components/ui/input-group.tsx} +170 -170
  80. package/{input-otp.tsx → components/ui/input-otp.tsx} +77 -77
  81. package/{input.tsx → components/ui/input.tsx} +21 -21
  82. package/{item.tsx → components/ui/item.tsx} +193 -193
  83. package/{kbd.tsx → components/ui/kbd.tsx} +28 -28
  84. package/{label.tsx → components/ui/label.tsx} +24 -24
  85. package/{menubar.tsx → components/ui/menubar.tsx} +276 -276
  86. package/{native-select.tsx → components/ui/native-select.tsx} +62 -62
  87. package/{navigation-menu.tsx → components/ui/navigation-menu.tsx} +168 -168
  88. package/{pagination.tsx → components/ui/pagination.tsx} +127 -127
  89. package/{popover.tsx → components/ui/popover.tsx} +89 -89
  90. package/{progress.tsx → components/ui/progress.tsx} +31 -31
  91. package/{radio-group.tsx → components/ui/radio-group.tsx} +45 -45
  92. package/{resizable.tsx → components/ui/resizable.tsx} +53 -53
  93. package/{scroll-area.tsx → components/ui/scroll-area.tsx} +58 -58
  94. package/{select.tsx → components/ui/select.tsx} +187 -187
  95. package/{separator.tsx → components/ui/separator.tsx} +28 -28
  96. package/{sheet.tsx → components/ui/sheet.tsx} +139 -139
  97. package/{sidebar.tsx → components/ui/sidebar.tsx} +724 -724
  98. package/{skeleton.tsx → components/ui/skeleton.tsx} +13 -13
  99. package/{slider.tsx → components/ui/slider.tsx} +63 -63
  100. package/{sonner.tsx → components/ui/sonner.tsx} +40 -40
  101. package/{spinner.tsx → components/ui/spinner.tsx} +16 -16
  102. package/{switch.tsx → components/ui/switch.tsx} +35 -35
  103. package/{table.tsx → components/ui/table.tsx} +116 -116
  104. package/{tabs.tsx → components/ui/tabs.tsx} +66 -66
  105. package/{textarea.tsx → components/ui/textarea.tsx} +18 -18
  106. package/{toggle-group.tsx → components/ui/toggle-group.tsx} +83 -83
  107. package/{toggle.tsx → components/ui/toggle.tsx} +47 -47
  108. package/{tooltip.tsx → components/ui/tooltip.tsx} +61 -61
  109. package/hooks/index.ts +1 -1
  110. package/hooks/use-mobile.ts +19 -19
  111. package/index.ts +3 -59
  112. package/lib/index.ts +1 -1
  113. package/lib/utils.ts +6 -6
  114. package/package.json +79 -1
  115. package/styles.css +124 -124
  116. package/tsconfig.json +0 -12
  117. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,231 @@
1
+ "use client";
2
+
3
+ import { Button } from "../ui/button";
4
+ import {
5
+ ButtonGroup,
6
+ ButtonGroupText,
7
+ } from "../ui/button-group";
8
+ import { cn } from "../../lib/utils";
9
+ import type { Experimental_SpeechResult as SpeechResult } from "ai";
10
+ import {
11
+ MediaControlBar,
12
+ MediaController,
13
+ MediaDurationDisplay,
14
+ MediaMuteButton,
15
+ MediaPlayButton,
16
+ MediaSeekBackwardButton,
17
+ MediaSeekForwardButton,
18
+ MediaTimeDisplay,
19
+ MediaTimeRange,
20
+ MediaVolumeRange,
21
+ } from "media-chrome/react";
22
+ import type { ComponentProps, CSSProperties } from "react";
23
+
24
+ export type AudioPlayerProps = Omit<
25
+ ComponentProps<typeof MediaController>,
26
+ "audio"
27
+ >;
28
+
29
+ export const AudioPlayer = ({
30
+ children,
31
+ style,
32
+ ...props
33
+ }: AudioPlayerProps) => (
34
+ <MediaController
35
+ audio
36
+ data-slot="audio-player"
37
+ style={
38
+ {
39
+ "--media-background-color": "transparent",
40
+ "--media-button-icon-height": "1rem",
41
+ "--media-button-icon-width": "1rem",
42
+ "--media-control-background": "transparent",
43
+ "--media-control-hover-background": "var(--color-accent)",
44
+ "--media-control-padding": "0",
45
+ "--media-font": "var(--font-sans)",
46
+ "--media-font-size": "10px",
47
+ "--media-icon-color": "currentColor",
48
+ "--media-preview-time-background": "var(--color-background)",
49
+ "--media-preview-time-border-radius": "var(--radius-md)",
50
+ "--media-preview-time-text-shadow": "none",
51
+ "--media-primary-color": "var(--color-primary)",
52
+ "--media-range-bar-color": "var(--color-primary)",
53
+ "--media-range-track-background": "var(--color-secondary)",
54
+ "--media-secondary-color": "var(--color-secondary)",
55
+ "--media-text-color": "var(--color-foreground)",
56
+ "--media-tooltip-arrow-display": "none",
57
+ "--media-tooltip-background": "var(--color-background)",
58
+ "--media-tooltip-border-radius": "var(--radius-md)",
59
+ ...style,
60
+ } as CSSProperties
61
+ }
62
+ {...props}
63
+ >
64
+ {children}
65
+ </MediaController>
66
+ );
67
+
68
+ export type AudioPlayerElementProps = Omit<ComponentProps<"audio">, "src"> &
69
+ (
70
+ | {
71
+ data: SpeechResult["audio"];
72
+ }
73
+ | {
74
+ src: string;
75
+ }
76
+ );
77
+
78
+ export const AudioPlayerElement = ({ ...props }: AudioPlayerElementProps) => (
79
+ // oxlint-disable-next-line eslint-plugin-jsx-a11y(media-has-caption) -- audio player captions are provided by consumer
80
+ <audio
81
+ data-slot="audio-player-element"
82
+ slot="media"
83
+ src={
84
+ "src" in props
85
+ ? props.src
86
+ : `data:${props.data.mediaType};base64,${props.data.base64}`
87
+ }
88
+ {...props}
89
+ />
90
+ );
91
+
92
+ export type AudioPlayerControlBarProps = ComponentProps<typeof MediaControlBar>;
93
+
94
+ export const AudioPlayerControlBar = ({
95
+ children,
96
+ ...props
97
+ }: AudioPlayerControlBarProps) => (
98
+ <MediaControlBar data-slot="audio-player-control-bar" {...props}>
99
+ <ButtonGroup orientation="horizontal">{children}</ButtonGroup>
100
+ </MediaControlBar>
101
+ );
102
+
103
+ export type AudioPlayerPlayButtonProps = ComponentProps<typeof MediaPlayButton>;
104
+
105
+ export const AudioPlayerPlayButton = ({
106
+ className,
107
+ ...props
108
+ }: AudioPlayerPlayButtonProps) => (
109
+ <Button asChild size="icon-sm" variant="outline">
110
+ <MediaPlayButton
111
+ className={cn("bg-transparent", className)}
112
+ data-slot="audio-player-play-button"
113
+ {...props}
114
+ />
115
+ </Button>
116
+ );
117
+
118
+ export type AudioPlayerSeekBackwardButtonProps = ComponentProps<
119
+ typeof MediaSeekBackwardButton
120
+ >;
121
+
122
+ export const AudioPlayerSeekBackwardButton = ({
123
+ seekOffset = 10,
124
+ ...props
125
+ }: AudioPlayerSeekBackwardButtonProps) => (
126
+ <Button asChild size="icon-sm" variant="outline">
127
+ <MediaSeekBackwardButton
128
+ data-slot="audio-player-seek-backward-button"
129
+ seekOffset={seekOffset}
130
+ {...props}
131
+ />
132
+ </Button>
133
+ );
134
+
135
+ export type AudioPlayerSeekForwardButtonProps = ComponentProps<
136
+ typeof MediaSeekForwardButton
137
+ >;
138
+
139
+ export const AudioPlayerSeekForwardButton = ({
140
+ seekOffset = 10,
141
+ ...props
142
+ }: AudioPlayerSeekForwardButtonProps) => (
143
+ <Button asChild size="icon-sm" variant="outline">
144
+ <MediaSeekForwardButton
145
+ data-slot="audio-player-seek-forward-button"
146
+ seekOffset={seekOffset}
147
+ {...props}
148
+ />
149
+ </Button>
150
+ );
151
+
152
+ export type AudioPlayerTimeDisplayProps = ComponentProps<
153
+ typeof MediaTimeDisplay
154
+ >;
155
+
156
+ export const AudioPlayerTimeDisplay = ({
157
+ className,
158
+ ...props
159
+ }: AudioPlayerTimeDisplayProps) => (
160
+ <ButtonGroupText asChild className="bg-transparent">
161
+ <MediaTimeDisplay
162
+ className={cn("tabular-nums", className)}
163
+ data-slot="audio-player-time-display"
164
+ {...props}
165
+ />
166
+ </ButtonGroupText>
167
+ );
168
+
169
+ export type AudioPlayerTimeRangeProps = ComponentProps<typeof MediaTimeRange>;
170
+
171
+ export const AudioPlayerTimeRange = ({
172
+ className,
173
+ ...props
174
+ }: AudioPlayerTimeRangeProps) => (
175
+ <ButtonGroupText asChild className="bg-transparent">
176
+ <MediaTimeRange
177
+ className={cn("", className)}
178
+ data-slot="audio-player-time-range"
179
+ {...props}
180
+ />
181
+ </ButtonGroupText>
182
+ );
183
+
184
+ export type AudioPlayerDurationDisplayProps = ComponentProps<
185
+ typeof MediaDurationDisplay
186
+ >;
187
+
188
+ export const AudioPlayerDurationDisplay = ({
189
+ className,
190
+ ...props
191
+ }: AudioPlayerDurationDisplayProps) => (
192
+ <ButtonGroupText asChild className="bg-transparent">
193
+ <MediaDurationDisplay
194
+ className={cn("tabular-nums", className)}
195
+ data-slot="audio-player-duration-display"
196
+ {...props}
197
+ />
198
+ </ButtonGroupText>
199
+ );
200
+
201
+ export type AudioPlayerMuteButtonProps = ComponentProps<typeof MediaMuteButton>;
202
+
203
+ export const AudioPlayerMuteButton = ({
204
+ className,
205
+ ...props
206
+ }: AudioPlayerMuteButtonProps) => (
207
+ <ButtonGroupText asChild className="bg-transparent">
208
+ <MediaMuteButton
209
+ className={cn("", className)}
210
+ data-slot="audio-player-mute-button"
211
+ {...props}
212
+ />
213
+ </ButtonGroupText>
214
+ );
215
+
216
+ export type AudioPlayerVolumeRangeProps = ComponentProps<
217
+ typeof MediaVolumeRange
218
+ >;
219
+
220
+ export const AudioPlayerVolumeRange = ({
221
+ className,
222
+ ...props
223
+ }: AudioPlayerVolumeRangeProps) => (
224
+ <ButtonGroupText asChild className="bg-transparent">
225
+ <MediaVolumeRange
226
+ className={cn("", className)}
227
+ data-slot="audio-player-volume-range"
228
+ {...props}
229
+ />
230
+ </ButtonGroupText>
231
+ );
@@ -0,0 +1,26 @@
1
+ import type { ReactFlowProps } from "@xyflow/react";
2
+ import { Background, ReactFlow } from "@xyflow/react";
3
+ import type { ReactNode } from "react";
4
+
5
+ import "@xyflow/react/dist/style.css";
6
+
7
+ type CanvasProps = ReactFlowProps & {
8
+ children?: ReactNode;
9
+ };
10
+
11
+ const deleteKeyCode = ["Backspace", "Delete"];
12
+
13
+ export const Canvas = ({ children, ...props }: CanvasProps) => (
14
+ <ReactFlow
15
+ deleteKeyCode={deleteKeyCode}
16
+ fitView
17
+ panOnDrag={false}
18
+ panOnScroll
19
+ selectionOnDrag={true}
20
+ zoomOnDoubleClick={false}
21
+ {...props}
22
+ >
23
+ <Background bgColor="var(--sidebar)" />
24
+ {children}
25
+ </ReactFlow>
26
+ );
@@ -0,0 +1,222 @@
1
+ "use client";
2
+
3
+ import { useControllableState } from "@radix-ui/react-use-controllable-state";
4
+ import { Badge } from "../ui/badge";
5
+ import {
6
+ Collapsible,
7
+ CollapsibleContent,
8
+ CollapsibleTrigger,
9
+ } from "../ui/collapsible";
10
+ import { cn } from "../../lib/utils";
11
+ import type { LucideIcon } from "lucide-react";
12
+ import { BrainIcon, ChevronDownIcon, DotIcon } from "lucide-react";
13
+ import type { ComponentProps, ReactNode } from "react";
14
+ import { createContext, memo, useContext, useMemo } from "react";
15
+
16
+ interface ChainOfThoughtContextValue {
17
+ isOpen: boolean;
18
+ setIsOpen: (open: boolean) => void;
19
+ }
20
+
21
+ const ChainOfThoughtContext = createContext<ChainOfThoughtContextValue | null>(
22
+ null
23
+ );
24
+
25
+ const useChainOfThought = () => {
26
+ const context = useContext(ChainOfThoughtContext);
27
+ if (!context) {
28
+ throw new Error(
29
+ "ChainOfThought components must be used within ChainOfThought"
30
+ );
31
+ }
32
+ return context;
33
+ };
34
+
35
+ export type ChainOfThoughtProps = ComponentProps<"div"> & {
36
+ open?: boolean;
37
+ defaultOpen?: boolean;
38
+ onOpenChange?: (open: boolean) => void;
39
+ };
40
+
41
+ export const ChainOfThought = memo(
42
+ ({
43
+ className,
44
+ open,
45
+ defaultOpen = false,
46
+ onOpenChange,
47
+ children,
48
+ ...props
49
+ }: ChainOfThoughtProps) => {
50
+ const [isOpen, setIsOpen] = useControllableState({
51
+ defaultProp: defaultOpen,
52
+ onChange: onOpenChange,
53
+ prop: open,
54
+ });
55
+
56
+ const chainOfThoughtContext = useMemo(
57
+ () => ({ isOpen, setIsOpen }),
58
+ [isOpen, setIsOpen]
59
+ );
60
+
61
+ return (
62
+ <ChainOfThoughtContext.Provider value={chainOfThoughtContext}>
63
+ <div className={cn("not-prose w-full space-y-4", className)} {...props}>
64
+ {children}
65
+ </div>
66
+ </ChainOfThoughtContext.Provider>
67
+ );
68
+ }
69
+ );
70
+
71
+ export type ChainOfThoughtHeaderProps = ComponentProps<
72
+ typeof CollapsibleTrigger
73
+ >;
74
+
75
+ export const ChainOfThoughtHeader = memo(
76
+ ({ className, children, ...props }: ChainOfThoughtHeaderProps) => {
77
+ const { isOpen, setIsOpen } = useChainOfThought();
78
+
79
+ return (
80
+ <Collapsible onOpenChange={setIsOpen} open={isOpen}>
81
+ <CollapsibleTrigger
82
+ className={cn(
83
+ "flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground",
84
+ className
85
+ )}
86
+ {...props}
87
+ >
88
+ <BrainIcon className="size-4" />
89
+ <span className="flex-1 text-left">
90
+ {children ?? "Chain of Thought"}
91
+ </span>
92
+ <ChevronDownIcon
93
+ className={cn(
94
+ "size-4 transition-transform",
95
+ isOpen ? "rotate-180" : "rotate-0"
96
+ )}
97
+ />
98
+ </CollapsibleTrigger>
99
+ </Collapsible>
100
+ );
101
+ }
102
+ );
103
+
104
+ export type ChainOfThoughtStepProps = ComponentProps<"div"> & {
105
+ icon?: LucideIcon;
106
+ label: ReactNode;
107
+ description?: ReactNode;
108
+ status?: "complete" | "active" | "pending";
109
+ };
110
+
111
+ const stepStatusStyles = {
112
+ active: "text-foreground",
113
+ complete: "text-muted-foreground",
114
+ pending: "text-muted-foreground/50",
115
+ };
116
+
117
+ export const ChainOfThoughtStep = memo(
118
+ ({
119
+ className,
120
+ icon: Icon = DotIcon,
121
+ label,
122
+ description,
123
+ status = "complete",
124
+ children,
125
+ ...props
126
+ }: ChainOfThoughtStepProps) => (
127
+ <div
128
+ className={cn(
129
+ "flex gap-2 text-sm",
130
+ stepStatusStyles[status],
131
+ "fade-in-0 slide-in-from-top-2 animate-in",
132
+ className
133
+ )}
134
+ {...props}
135
+ >
136
+ <div className="relative mt-0.5">
137
+ <Icon className="size-4" />
138
+ <div className="absolute top-7 bottom-0 left-1/2 -mx-px w-px bg-border" />
139
+ </div>
140
+ <div className="flex-1 space-y-2 overflow-hidden">
141
+ <div>{label}</div>
142
+ {description && (
143
+ <div className="text-muted-foreground text-xs">{description}</div>
144
+ )}
145
+ {children}
146
+ </div>
147
+ </div>
148
+ )
149
+ );
150
+
151
+ export type ChainOfThoughtSearchResultsProps = ComponentProps<"div">;
152
+
153
+ export const ChainOfThoughtSearchResults = memo(
154
+ ({ className, ...props }: ChainOfThoughtSearchResultsProps) => (
155
+ <div
156
+ className={cn("flex flex-wrap items-center gap-2", className)}
157
+ {...props}
158
+ />
159
+ )
160
+ );
161
+
162
+ export type ChainOfThoughtSearchResultProps = ComponentProps<typeof Badge>;
163
+
164
+ export const ChainOfThoughtSearchResult = memo(
165
+ ({ className, children, ...props }: ChainOfThoughtSearchResultProps) => (
166
+ <Badge
167
+ className={cn("gap-1 px-2 py-0.5 font-normal text-xs", className)}
168
+ variant="secondary"
169
+ {...props}
170
+ >
171
+ {children}
172
+ </Badge>
173
+ )
174
+ );
175
+
176
+ export type ChainOfThoughtContentProps = ComponentProps<
177
+ typeof CollapsibleContent
178
+ >;
179
+
180
+ export const ChainOfThoughtContent = memo(
181
+ ({ className, children, ...props }: ChainOfThoughtContentProps) => {
182
+ const { isOpen } = useChainOfThought();
183
+
184
+ return (
185
+ <Collapsible open={isOpen}>
186
+ <CollapsibleContent
187
+ className={cn(
188
+ "mt-2 space-y-3",
189
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-popover-foreground outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
190
+ className
191
+ )}
192
+ {...props}
193
+ >
194
+ {children}
195
+ </CollapsibleContent>
196
+ </Collapsible>
197
+ );
198
+ }
199
+ );
200
+
201
+ export type ChainOfThoughtImageProps = ComponentProps<"div"> & {
202
+ caption?: string;
203
+ };
204
+
205
+ export const ChainOfThoughtImage = memo(
206
+ ({ className, children, caption, ...props }: ChainOfThoughtImageProps) => (
207
+ <div className={cn("mt-2 space-y-2", className)} {...props}>
208
+ <div className="relative flex max-h-[22rem] items-center justify-center overflow-hidden rounded-lg bg-muted p-3">
209
+ {children}
210
+ </div>
211
+ {caption && <p className="text-muted-foreground text-xs">{caption}</p>}
212
+ </div>
213
+ )
214
+ );
215
+
216
+ ChainOfThought.displayName = "ChainOfThought";
217
+ ChainOfThoughtHeader.displayName = "ChainOfThoughtHeader";
218
+ ChainOfThoughtStep.displayName = "ChainOfThoughtStep";
219
+ ChainOfThoughtSearchResults.displayName = "ChainOfThoughtSearchResults";
220
+ ChainOfThoughtSearchResult.displayName = "ChainOfThoughtSearchResult";
221
+ ChainOfThoughtContent.displayName = "ChainOfThoughtContent";
222
+ ChainOfThoughtImage.displayName = "ChainOfThoughtImage";
@@ -0,0 +1,71 @@
1
+ "use client";
2
+
3
+ import { Button } from "../ui/button";
4
+ import { Separator } from "../ui/separator";
5
+ import {
6
+ Tooltip,
7
+ TooltipContent,
8
+ TooltipTrigger,
9
+ } from "../ui/tooltip";
10
+ import { cn } from "../../lib/utils";
11
+ import type { LucideProps } from "lucide-react";
12
+ import { BookmarkIcon } from "lucide-react";
13
+ import type { ComponentProps, HTMLAttributes } from "react";
14
+
15
+ export type CheckpointProps = HTMLAttributes<HTMLDivElement>;
16
+
17
+ export const Checkpoint = ({
18
+ className,
19
+ children,
20
+ ...props
21
+ }: CheckpointProps) => (
22
+ <div
23
+ className={cn(
24
+ "flex items-center gap-0.5 overflow-hidden text-muted-foreground",
25
+ className
26
+ )}
27
+ {...props}
28
+ >
29
+ {children}
30
+ <Separator />
31
+ </div>
32
+ );
33
+
34
+ export type CheckpointIconProps = LucideProps;
35
+
36
+ export const CheckpointIcon = ({
37
+ className,
38
+ children,
39
+ ...props
40
+ }: CheckpointIconProps) =>
41
+ children ?? (
42
+ <BookmarkIcon className={cn("size-4 shrink-0", className)} {...props} />
43
+ );
44
+
45
+ export type CheckpointTriggerProps = ComponentProps<typeof Button> & {
46
+ tooltip?: string;
47
+ };
48
+
49
+ export const CheckpointTrigger = ({
50
+ children,
51
+ variant = "ghost",
52
+ size = "sm",
53
+ tooltip,
54
+ ...props
55
+ }: CheckpointTriggerProps) =>
56
+ tooltip ? (
57
+ <Tooltip>
58
+ <TooltipTrigger asChild>
59
+ <Button size={size} type="button" variant={variant} {...props}>
60
+ {children}
61
+ </Button>
62
+ </TooltipTrigger>
63
+ <TooltipContent align="start" side="bottom">
64
+ {tooltip}
65
+ </TooltipContent>
66
+ </Tooltip>
67
+ ) : (
68
+ <Button size={size} type="button" variant={variant} {...props}>
69
+ {children}
70
+ </Button>
71
+ );