@openconsole/shadcn 0.2.5 → 0.2.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.
Files changed (113) hide show
  1. package/components/index.ts +1 -2
  2. package/components/ui/accordion.tsx +66 -66
  3. package/components/ui/alert-dialog.tsx +196 -196
  4. package/components/ui/alert.tsx +66 -66
  5. package/components/ui/aspect-ratio.tsx +11 -11
  6. package/components/ui/avatar.tsx +53 -53
  7. package/components/ui/badge.tsx +46 -46
  8. package/components/ui/breadcrumb.tsx +109 -109
  9. package/components/ui/button-group.tsx +83 -83
  10. package/components/ui/button.tsx +60 -60
  11. package/components/ui/calendar.tsx +219 -219
  12. package/components/ui/card.tsx +92 -92
  13. package/components/ui/carousel.tsx +241 -241
  14. package/components/ui/chart.tsx +374 -374
  15. package/components/ui/checkbox.tsx +32 -32
  16. package/components/ui/collapsible.tsx +33 -33
  17. package/components/ui/command.tsx +184 -184
  18. package/components/ui/context-menu.tsx +252 -252
  19. package/components/ui/dialog.tsx +143 -143
  20. package/components/ui/direction.tsx +22 -22
  21. package/components/ui/drawer.tsx +135 -135
  22. package/components/ui/dropdown-menu.tsx +257 -257
  23. package/components/ui/empty.tsx +104 -104
  24. package/components/ui/field.tsx +248 -248
  25. package/components/ui/form.tsx +167 -167
  26. package/components/ui/hover-card.tsx +44 -44
  27. package/components/ui/index.ts +59 -59
  28. package/components/ui/input-group.tsx +170 -170
  29. package/components/ui/input-otp.tsx +77 -77
  30. package/components/ui/input.tsx +21 -21
  31. package/components/ui/item.tsx +193 -193
  32. package/components/ui/kbd.tsx +28 -28
  33. package/components/ui/label.tsx +24 -24
  34. package/components/ui/menubar.tsx +276 -276
  35. package/components/ui/native-select.tsx +62 -62
  36. package/components/ui/navigation-menu.tsx +168 -168
  37. package/components/ui/pagination.tsx +127 -127
  38. package/components/ui/popover.tsx +89 -89
  39. package/components/ui/progress.tsx +31 -31
  40. package/components/ui/radio-group.tsx +45 -45
  41. package/components/ui/resizable.tsx +53 -53
  42. package/components/ui/scroll-area.tsx +58 -58
  43. package/components/ui/select.tsx +187 -187
  44. package/components/ui/separator.tsx +28 -28
  45. package/components/ui/sheet.tsx +139 -139
  46. package/components/ui/sidebar.tsx +724 -724
  47. package/components/ui/skeleton.tsx +13 -13
  48. package/components/ui/slider.tsx +63 -63
  49. package/components/ui/sonner.tsx +40 -40
  50. package/components/ui/spinner.tsx +16 -16
  51. package/components/ui/switch.tsx +35 -35
  52. package/components/ui/table.tsx +116 -116
  53. package/components/ui/tabs.tsx +66 -66
  54. package/components/ui/textarea.tsx +18 -18
  55. package/components/ui/toggle-group.tsx +83 -83
  56. package/components/ui/toggle.tsx +47 -47
  57. package/components/ui/tooltip.tsx +61 -61
  58. package/hooks/index.ts +1 -1
  59. package/hooks/use-mobile.ts +19 -19
  60. package/index.ts +3 -3
  61. package/lib/index.ts +1 -1
  62. package/lib/utils.ts +6 -6
  63. package/package.json +1 -1
  64. package/styles.css +124 -124
  65. package/components/ai-elements/agent.tsx +0 -141
  66. package/components/ai-elements/artifact.tsx +0 -148
  67. package/components/ai-elements/attachments.tsx +0 -426
  68. package/components/ai-elements/audio-player.tsx +0 -231
  69. package/components/ai-elements/canvas.tsx +0 -26
  70. package/components/ai-elements/chain-of-thought.tsx +0 -222
  71. package/components/ai-elements/checkpoint.tsx +0 -71
  72. package/components/ai-elements/code-block.tsx +0 -562
  73. package/components/ai-elements/commit.tsx +0 -458
  74. package/components/ai-elements/confirmation.tsx +0 -174
  75. package/components/ai-elements/connection.tsx +0 -28
  76. package/components/ai-elements/context.tsx +0 -409
  77. package/components/ai-elements/controls.tsx +0 -18
  78. package/components/ai-elements/conversation.tsx +0 -168
  79. package/components/ai-elements/edge.tsx +0 -143
  80. package/components/ai-elements/environment-variables.tsx +0 -324
  81. package/components/ai-elements/file-tree.tsx +0 -304
  82. package/components/ai-elements/image.tsx +0 -24
  83. package/components/ai-elements/index.ts +0 -51
  84. package/components/ai-elements/inline-citation.tsx +0 -296
  85. package/components/ai-elements/jsx-preview.tsx +0 -310
  86. package/components/ai-elements/message.tsx +0 -360
  87. package/components/ai-elements/mic-selector.tsx +0 -375
  88. package/components/ai-elements/model-selector.tsx +0 -213
  89. package/components/ai-elements/node.tsx +0 -71
  90. package/components/ai-elements/open-in-chat.tsx +0 -370
  91. package/components/ai-elements/package-info.tsx +0 -239
  92. package/components/ai-elements/panel.tsx +0 -15
  93. package/components/ai-elements/persona.tsx +0 -306
  94. package/components/ai-elements/plan.tsx +0 -147
  95. package/components/ai-elements/prompt-input.tsx +0 -1463
  96. package/components/ai-elements/queue.tsx +0 -274
  97. package/components/ai-elements/reasoning.tsx +0 -228
  98. package/components/ai-elements/sandbox.tsx +0 -132
  99. package/components/ai-elements/schema-display.tsx +0 -471
  100. package/components/ai-elements/shimmer.tsx +0 -77
  101. package/components/ai-elements/snippet.tsx +0 -145
  102. package/components/ai-elements/sources.tsx +0 -77
  103. package/components/ai-elements/speech-input.tsx +0 -323
  104. package/components/ai-elements/stack-trace.tsx +0 -528
  105. package/components/ai-elements/suggestion.tsx +0 -57
  106. package/components/ai-elements/task.tsx +0 -87
  107. package/components/ai-elements/terminal.tsx +0 -273
  108. package/components/ai-elements/test-results.tsx +0 -496
  109. package/components/ai-elements/tool.tsx +0 -173
  110. package/components/ai-elements/toolbar.tsx +0 -16
  111. package/components/ai-elements/transcription.tsx +0 -125
  112. package/components/ai-elements/voice-selector.tsx +0 -524
  113. package/components/ai-elements/web-preview.tsx +0 -281
@@ -1,304 +0,0 @@
1
- "use client";
2
-
3
- import {
4
- Collapsible,
5
- CollapsibleContent,
6
- CollapsibleTrigger,
7
- } from "../ui/collapsible";
8
- import { cn } from "../../lib/utils";
9
- import {
10
- ChevronRightIcon,
11
- FileIcon,
12
- FolderIcon,
13
- FolderOpenIcon,
14
- } from "lucide-react";
15
- import type { HTMLAttributes, ReactNode } from "react";
16
- import {
17
- createContext,
18
- useCallback,
19
- useContext,
20
- useMemo,
21
- useState,
22
- } from "react";
23
-
24
- interface FileTreeContextType {
25
- expandedPaths: Set<string>;
26
- togglePath: (path: string) => void;
27
- selectedPath?: string;
28
- onSelect?: (path: string) => void;
29
- }
30
-
31
- // Default noop for context default value
32
- // oxlint-disable-next-line eslint(no-empty-function)
33
- const noop = () => {};
34
-
35
- const FileTreeContext = createContext<FileTreeContextType>({
36
- // oxlint-disable-next-line eslint-plugin-unicorn(no-new-builtin)
37
- expandedPaths: new Set(),
38
- togglePath: noop,
39
- });
40
-
41
- export type FileTreeProps = Omit<HTMLAttributes<HTMLDivElement>, "onSelect"> & {
42
- expanded?: Set<string>;
43
- defaultExpanded?: Set<string>;
44
- selectedPath?: string;
45
- onSelect?: (path: string) => void;
46
- onExpandedChange?: (expanded: Set<string>) => void;
47
- };
48
-
49
- export const FileTree = ({
50
- expanded: controlledExpanded,
51
- defaultExpanded = new Set(),
52
- selectedPath,
53
- onSelect,
54
- onExpandedChange,
55
- className,
56
- children,
57
- ...props
58
- }: FileTreeProps) => {
59
- const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
60
- const expandedPaths = controlledExpanded ?? internalExpanded;
61
-
62
- const togglePath = useCallback(
63
- (path: string) => {
64
- const newExpanded = new Set(expandedPaths);
65
- if (newExpanded.has(path)) {
66
- newExpanded.delete(path);
67
- } else {
68
- newExpanded.add(path);
69
- }
70
- setInternalExpanded(newExpanded);
71
- onExpandedChange?.(newExpanded);
72
- },
73
- [expandedPaths, onExpandedChange]
74
- );
75
-
76
- const contextValue = useMemo(
77
- () => ({ expandedPaths, onSelect, selectedPath, togglePath }),
78
- [expandedPaths, onSelect, selectedPath, togglePath]
79
- );
80
-
81
- return (
82
- <FileTreeContext.Provider value={contextValue}>
83
- <div
84
- className={cn(
85
- "rounded-lg border bg-background font-mono text-sm",
86
- className
87
- )}
88
- role="tree"
89
- {...props}
90
- >
91
- <div className="p-2">{children}</div>
92
- </div>
93
- </FileTreeContext.Provider>
94
- );
95
- };
96
-
97
- export type FileTreeIconProps = HTMLAttributes<HTMLSpanElement>;
98
-
99
- export const FileTreeIcon = ({
100
- className,
101
- children,
102
- ...props
103
- }: FileTreeIconProps) => (
104
- <span className={cn("shrink-0", className)} {...props}>
105
- {children}
106
- </span>
107
- );
108
-
109
- export type FileTreeNameProps = HTMLAttributes<HTMLSpanElement>;
110
-
111
- export const FileTreeName = ({
112
- className,
113
- children,
114
- ...props
115
- }: FileTreeNameProps) => (
116
- <span className={cn("truncate", className)} {...props}>
117
- {children}
118
- </span>
119
- );
120
-
121
- interface FileTreeFolderContextType {
122
- path: string;
123
- name: string;
124
- isExpanded: boolean;
125
- }
126
-
127
- const FileTreeFolderContext = createContext<FileTreeFolderContextType>({
128
- isExpanded: false,
129
- name: "",
130
- path: "",
131
- });
132
-
133
- export type FileTreeFolderProps = HTMLAttributes<HTMLDivElement> & {
134
- path: string;
135
- name: string;
136
- };
137
-
138
- export const FileTreeFolder = ({
139
- path,
140
- name,
141
- className,
142
- children,
143
- ...props
144
- }: FileTreeFolderProps) => {
145
- const { expandedPaths, togglePath, selectedPath, onSelect } =
146
- useContext(FileTreeContext);
147
- const isExpanded = expandedPaths.has(path);
148
- const isSelected = selectedPath === path;
149
-
150
- const handleOpenChange = useCallback(() => {
151
- togglePath(path);
152
- }, [togglePath, path]);
153
-
154
- const handleSelect = useCallback(() => {
155
- onSelect?.(path);
156
- }, [onSelect, path]);
157
-
158
- const folderContextValue = useMemo(
159
- () => ({ isExpanded, name, path }),
160
- [isExpanded, name, path]
161
- );
162
-
163
- return (
164
- <FileTreeFolderContext.Provider value={folderContextValue}>
165
- <Collapsible onOpenChange={handleOpenChange} open={isExpanded}>
166
- <div
167
- className={cn("", className)}
168
- role="treeitem"
169
- tabIndex={0}
170
- {...props}
171
- >
172
- <div
173
- className={cn(
174
- "flex w-full items-center gap-1 rounded px-2 py-1 text-left transition-colors hover:bg-muted/50",
175
- isSelected && "bg-muted"
176
- )}
177
- >
178
- <CollapsibleTrigger asChild>
179
- <button
180
- className="flex shrink-0 cursor-pointer items-center border-none bg-transparent p-0"
181
- type="button"
182
- >
183
- <ChevronRightIcon
184
- className={cn(
185
- "size-4 shrink-0 text-muted-foreground transition-transform",
186
- isExpanded && "rotate-90"
187
- )}
188
- />
189
- </button>
190
- </CollapsibleTrigger>
191
- <button
192
- className="flex min-w-0 flex-1 cursor-pointer items-center gap-1 border-none bg-transparent p-0 text-left"
193
- onClick={handleSelect}
194
- type="button"
195
- >
196
- <FileTreeIcon>
197
- {isExpanded ? (
198
- <FolderOpenIcon className="size-4 text-blue-500" />
199
- ) : (
200
- <FolderIcon className="size-4 text-blue-500" />
201
- )}
202
- </FileTreeIcon>
203
- <FileTreeName>{name}</FileTreeName>
204
- </button>
205
- </div>
206
- <CollapsibleContent>
207
- <div className="ml-4 border-l pl-2">{children}</div>
208
- </CollapsibleContent>
209
- </div>
210
- </Collapsible>
211
- </FileTreeFolderContext.Provider>
212
- );
213
- };
214
-
215
- interface FileTreeFileContextType {
216
- path: string;
217
- name: string;
218
- }
219
-
220
- const FileTreeFileContext = createContext<FileTreeFileContextType>({
221
- name: "",
222
- path: "",
223
- });
224
-
225
- export type FileTreeFileProps = HTMLAttributes<HTMLDivElement> & {
226
- path: string;
227
- name: string;
228
- icon?: ReactNode;
229
- };
230
-
231
- export const FileTreeFile = ({
232
- path,
233
- name,
234
- icon,
235
- className,
236
- children,
237
- ...props
238
- }: FileTreeFileProps) => {
239
- const { selectedPath, onSelect } = useContext(FileTreeContext);
240
- const isSelected = selectedPath === path;
241
-
242
- const handleClick = useCallback(() => {
243
- onSelect?.(path);
244
- }, [onSelect, path]);
245
-
246
- const handleKeyDown = useCallback(
247
- (e: React.KeyboardEvent) => {
248
- if (e.key === "Enter" || e.key === " ") {
249
- onSelect?.(path);
250
- }
251
- },
252
- [onSelect, path]
253
- );
254
-
255
- const fileContextValue = useMemo(() => ({ name, path }), [name, path]);
256
-
257
- return (
258
- <FileTreeFileContext.Provider value={fileContextValue}>
259
- <div
260
- className={cn(
261
- "flex cursor-pointer items-center gap-1 rounded px-2 py-1 transition-colors hover:bg-muted/50",
262
- isSelected && "bg-muted",
263
- className
264
- )}
265
- onClick={handleClick}
266
- onKeyDown={handleKeyDown}
267
- role="treeitem"
268
- tabIndex={0}
269
- {...props}
270
- >
271
- {children ?? (
272
- <>
273
- {/* Spacer for alignment */}
274
- <span className="size-4 shrink-0" />
275
- <FileTreeIcon>
276
- {icon ?? <FileIcon className="size-4 text-muted-foreground" />}
277
- </FileTreeIcon>
278
- <FileTreeName>{name}</FileTreeName>
279
- </>
280
- )}
281
- </div>
282
- </FileTreeFileContext.Provider>
283
- );
284
- };
285
-
286
- export type FileTreeActionsProps = HTMLAttributes<HTMLDivElement>;
287
-
288
- const stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation();
289
-
290
- export const FileTreeActions = ({
291
- className,
292
- children,
293
- ...props
294
- }: FileTreeActionsProps) => (
295
- <div
296
- className={cn("ml-auto flex items-center gap-1", className)}
297
- onClick={stopPropagation}
298
- onKeyDown={stopPropagation}
299
- role="group"
300
- {...props}
301
- >
302
- {children}
303
- </div>
304
- );
@@ -1,24 +0,0 @@
1
- import { cn } from "../../lib/utils";
2
- import type { Experimental_GeneratedImage } from "ai";
3
-
4
- export type ImageProps = Experimental_GeneratedImage & {
5
- className?: string;
6
- alt?: string;
7
- };
8
-
9
- export const Image = ({
10
- base64,
11
- uint8Array: _uint8Array,
12
- mediaType,
13
- ...props
14
- }: ImageProps) => (
15
- <img
16
- {...props}
17
- alt={props.alt}
18
- className={cn(
19
- "h-auto max-w-full overflow-hidden rounded-md",
20
- props.className
21
- )}
22
- src={`data:${mediaType};base64,${base64}`}
23
- />
24
- );
@@ -1,51 +0,0 @@
1
- // Barrel — re-export every AI SDK Element in this directory.
2
- // Add a line when you add a component (keep sorted).
3
-
4
- export * from "./agent";
5
- export * from "./artifact";
6
- export * from "./attachments";
7
- export * from "./audio-player";
8
- export * from "./canvas";
9
- export * from "./chain-of-thought";
10
- export * from "./checkpoint";
11
- export * from "./code-block";
12
- export * from "./commit";
13
- export * from "./confirmation";
14
- export * from "./connection";
15
- export * from "./context";
16
- export * from "./controls";
17
- export * from "./conversation";
18
- export * from "./edge";
19
- export * from "./environment-variables";
20
- export * from "./file-tree";
21
- export * from "./image";
22
- export * from "./inline-citation";
23
- export * from "./jsx-preview";
24
- export * from "./message";
25
- export * from "./mic-selector";
26
- export * from "./model-selector";
27
- export * from "./node";
28
- export * from "./open-in-chat";
29
- export * from "./package-info";
30
- export * from "./panel";
31
- export * from "./persona";
32
- export * from "./plan";
33
- export * from "./prompt-input";
34
- export * from "./queue";
35
- export * from "./reasoning";
36
- export * from "./sandbox";
37
- export * from "./schema-display";
38
- export * from "./shimmer";
39
- export * from "./snippet";
40
- export * from "./sources";
41
- export * from "./speech-input";
42
- export * from "./stack-trace";
43
- export * from "./suggestion";
44
- export * from "./task";
45
- export * from "./terminal";
46
- export * from "./test-results";
47
- export * from "./tool";
48
- export * from "./toolbar";
49
- export * from "./transcription";
50
- export * from "./voice-selector";
51
- export * from "./web-preview";
@@ -1,296 +0,0 @@
1
- "use client";
2
-
3
- import { Badge } from "../ui/badge";
4
- import type { CarouselApi } from "../ui/carousel";
5
- import {
6
- Carousel,
7
- CarouselContent,
8
- CarouselItem,
9
- } from "../ui/carousel";
10
- import {
11
- HoverCard,
12
- HoverCardContent,
13
- HoverCardTrigger,
14
- } from "../ui/hover-card";
15
- import { cn } from "../../lib/utils";
16
- import { ArrowLeftIcon, ArrowRightIcon } from "lucide-react";
17
- import type { ComponentProps } from "react";
18
- import {
19
- createContext,
20
- useCallback,
21
- useContext,
22
- useEffect,
23
- useState,
24
- } from "react";
25
-
26
- export type InlineCitationProps = ComponentProps<"span">;
27
-
28
- export const InlineCitation = ({
29
- className,
30
- ...props
31
- }: InlineCitationProps) => (
32
- <span
33
- className={cn("group inline items-center gap-1", className)}
34
- {...props}
35
- />
36
- );
37
-
38
- export type InlineCitationTextProps = ComponentProps<"span">;
39
-
40
- export const InlineCitationText = ({
41
- className,
42
- ...props
43
- }: InlineCitationTextProps) => (
44
- <span
45
- className={cn("transition-colors group-hover:bg-accent", className)}
46
- {...props}
47
- />
48
- );
49
-
50
- export type InlineCitationCardProps = ComponentProps<typeof HoverCard>;
51
-
52
- export const InlineCitationCard = (props: InlineCitationCardProps) => (
53
- <HoverCard closeDelay={0} openDelay={0} {...props} />
54
- );
55
-
56
- export type InlineCitationCardTriggerProps = ComponentProps<typeof Badge> & {
57
- sources: string[];
58
- };
59
-
60
- export const InlineCitationCardTrigger = ({
61
- sources,
62
- className,
63
- ...props
64
- }: InlineCitationCardTriggerProps) => (
65
- <HoverCardTrigger asChild>
66
- <Badge
67
- className={cn("ml-1 rounded-full", className)}
68
- variant="secondary"
69
- {...props}
70
- >
71
- {sources[0] ? (
72
- <>
73
- {new URL(sources[0]).hostname}{" "}
74
- {sources.length > 1 && `+${sources.length - 1}`}
75
- </>
76
- ) : (
77
- "unknown"
78
- )}
79
- </Badge>
80
- </HoverCardTrigger>
81
- );
82
-
83
- export type InlineCitationCardBodyProps = ComponentProps<"div">;
84
-
85
- export const InlineCitationCardBody = ({
86
- className,
87
- ...props
88
- }: InlineCitationCardBodyProps) => (
89
- <HoverCardContent className={cn("relative w-80 p-0", className)} {...props} />
90
- );
91
-
92
- const CarouselApiContext = createContext<CarouselApi | undefined>(undefined);
93
-
94
- const useCarouselApi = () => {
95
- const context = useContext(CarouselApiContext);
96
- return context;
97
- };
98
-
99
- export type InlineCitationCarouselProps = ComponentProps<typeof Carousel>;
100
-
101
- export const InlineCitationCarousel = ({
102
- className,
103
- children,
104
- ...props
105
- }: InlineCitationCarouselProps) => {
106
- const [api, setApi] = useState<CarouselApi>();
107
-
108
- return (
109
- <CarouselApiContext.Provider value={api}>
110
- <Carousel className={cn("w-full", className)} setApi={setApi} {...props}>
111
- {children}
112
- </Carousel>
113
- </CarouselApiContext.Provider>
114
- );
115
- };
116
-
117
- export type InlineCitationCarouselContentProps = ComponentProps<"div">;
118
-
119
- export const InlineCitationCarouselContent = (
120
- props: InlineCitationCarouselContentProps
121
- ) => <CarouselContent {...props} />;
122
-
123
- export type InlineCitationCarouselItemProps = ComponentProps<"div">;
124
-
125
- export const InlineCitationCarouselItem = ({
126
- className,
127
- ...props
128
- }: InlineCitationCarouselItemProps) => (
129
- <CarouselItem
130
- className={cn("w-full space-y-2 p-4 pl-8", className)}
131
- {...props}
132
- />
133
- );
134
-
135
- export type InlineCitationCarouselHeaderProps = ComponentProps<"div">;
136
-
137
- export const InlineCitationCarouselHeader = ({
138
- className,
139
- ...props
140
- }: InlineCitationCarouselHeaderProps) => (
141
- <div
142
- className={cn(
143
- "flex items-center justify-between gap-2 rounded-t-md bg-secondary p-2",
144
- className
145
- )}
146
- {...props}
147
- />
148
- );
149
-
150
- export type InlineCitationCarouselIndexProps = ComponentProps<"div">;
151
-
152
- export const InlineCitationCarouselIndex = ({
153
- children,
154
- className,
155
- ...props
156
- }: InlineCitationCarouselIndexProps) => {
157
- const api = useCarouselApi();
158
- const [current, setCurrent] = useState(0);
159
- const [count, setCount] = useState(0);
160
-
161
- const syncState = useCallback(() => {
162
- if (!api) {
163
- return;
164
- }
165
- setCount(api.scrollSnapList().length);
166
- setCurrent(api.selectedScrollSnap() + 1);
167
- }, [api]);
168
-
169
- useEffect(() => {
170
- if (!api) {
171
- return;
172
- }
173
-
174
- syncState();
175
-
176
- api.on("select", syncState);
177
-
178
- return () => {
179
- api.off("select", syncState);
180
- };
181
- }, [api, syncState]);
182
-
183
- return (
184
- <div
185
- className={cn(
186
- "flex flex-1 items-center justify-end px-3 py-1 text-muted-foreground text-xs",
187
- className
188
- )}
189
- {...props}
190
- >
191
- {children ?? `${current}/${count}`}
192
- </div>
193
- );
194
- };
195
-
196
- export type InlineCitationCarouselPrevProps = ComponentProps<"button">;
197
-
198
- export const InlineCitationCarouselPrev = ({
199
- className,
200
- ...props
201
- }: InlineCitationCarouselPrevProps) => {
202
- const api = useCarouselApi();
203
-
204
- const handleClick = useCallback(() => {
205
- if (api) {
206
- api.scrollPrev();
207
- }
208
- }, [api]);
209
-
210
- return (
211
- <button
212
- aria-label="Previous"
213
- className={cn("shrink-0", className)}
214
- onClick={handleClick}
215
- type="button"
216
- {...props}
217
- >
218
- <ArrowLeftIcon className="size-4 text-muted-foreground" />
219
- </button>
220
- );
221
- };
222
-
223
- export type InlineCitationCarouselNextProps = ComponentProps<"button">;
224
-
225
- export const InlineCitationCarouselNext = ({
226
- className,
227
- ...props
228
- }: InlineCitationCarouselNextProps) => {
229
- const api = useCarouselApi();
230
-
231
- const handleClick = useCallback(() => {
232
- if (api) {
233
- api.scrollNext();
234
- }
235
- }, [api]);
236
-
237
- return (
238
- <button
239
- aria-label="Next"
240
- className={cn("shrink-0", className)}
241
- onClick={handleClick}
242
- type="button"
243
- {...props}
244
- >
245
- <ArrowRightIcon className="size-4 text-muted-foreground" />
246
- </button>
247
- );
248
- };
249
-
250
- export type InlineCitationSourceProps = ComponentProps<"div"> & {
251
- title?: string;
252
- url?: string;
253
- description?: string;
254
- };
255
-
256
- export const InlineCitationSource = ({
257
- title,
258
- url,
259
- description,
260
- className,
261
- children,
262
- ...props
263
- }: InlineCitationSourceProps) => (
264
- <div className={cn("space-y-1", className)} {...props}>
265
- {title && (
266
- <h4 className="truncate font-medium text-sm leading-tight">{title}</h4>
267
- )}
268
- {url && (
269
- <p className="truncate break-all text-muted-foreground text-xs">{url}</p>
270
- )}
271
- {description && (
272
- <p className="line-clamp-3 text-muted-foreground text-sm leading-relaxed">
273
- {description}
274
- </p>
275
- )}
276
- {children}
277
- </div>
278
- );
279
-
280
- export type InlineCitationQuoteProps = ComponentProps<"blockquote">;
281
-
282
- export const InlineCitationQuote = ({
283
- children,
284
- className,
285
- ...props
286
- }: InlineCitationQuoteProps) => (
287
- <blockquote
288
- className={cn(
289
- "border-muted border-l-2 pl-3 text-muted-foreground text-sm italic",
290
- className
291
- )}
292
- {...props}
293
- >
294
- {children}
295
- </blockquote>
296
- );