@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.
- package/components/index.ts +1 -2
- package/components/ui/accordion.tsx +66 -66
- package/components/ui/alert-dialog.tsx +196 -196
- package/components/ui/alert.tsx +66 -66
- package/components/ui/aspect-ratio.tsx +11 -11
- package/components/ui/avatar.tsx +53 -53
- package/components/ui/badge.tsx +46 -46
- package/components/ui/breadcrumb.tsx +109 -109
- package/components/ui/button-group.tsx +83 -83
- package/components/ui/button.tsx +60 -60
- package/components/ui/calendar.tsx +219 -219
- package/components/ui/card.tsx +92 -92
- package/components/ui/carousel.tsx +241 -241
- package/components/ui/chart.tsx +374 -374
- package/components/ui/checkbox.tsx +32 -32
- package/components/ui/collapsible.tsx +33 -33
- package/components/ui/command.tsx +184 -184
- package/components/ui/context-menu.tsx +252 -252
- package/components/ui/dialog.tsx +143 -143
- package/components/ui/direction.tsx +22 -22
- package/components/ui/drawer.tsx +135 -135
- package/components/ui/dropdown-menu.tsx +257 -257
- package/components/ui/empty.tsx +104 -104
- package/components/ui/field.tsx +248 -248
- package/components/ui/form.tsx +167 -167
- package/components/ui/hover-card.tsx +44 -44
- package/components/ui/index.ts +59 -59
- package/components/ui/input-group.tsx +170 -170
- package/components/ui/input-otp.tsx +77 -77
- package/components/ui/input.tsx +21 -21
- package/components/ui/item.tsx +193 -193
- package/components/ui/kbd.tsx +28 -28
- package/components/ui/label.tsx +24 -24
- package/components/ui/menubar.tsx +276 -276
- package/components/ui/native-select.tsx +62 -62
- package/components/ui/navigation-menu.tsx +168 -168
- package/components/ui/pagination.tsx +127 -127
- package/components/ui/popover.tsx +89 -89
- package/components/ui/progress.tsx +31 -31
- package/components/ui/radio-group.tsx +45 -45
- package/components/ui/resizable.tsx +53 -53
- package/components/ui/scroll-area.tsx +58 -58
- package/components/ui/select.tsx +187 -187
- package/components/ui/separator.tsx +28 -28
- package/components/ui/sheet.tsx +139 -139
- package/components/ui/sidebar.tsx +724 -724
- package/components/ui/skeleton.tsx +13 -13
- package/components/ui/slider.tsx +63 -63
- package/components/ui/sonner.tsx +40 -40
- package/components/ui/spinner.tsx +16 -16
- package/components/ui/switch.tsx +35 -35
- package/components/ui/table.tsx +116 -116
- package/components/ui/tabs.tsx +66 -66
- package/components/ui/textarea.tsx +18 -18
- package/components/ui/toggle-group.tsx +83 -83
- package/components/ui/toggle.tsx +47 -47
- package/components/ui/tooltip.tsx +61 -61
- package/hooks/index.ts +1 -1
- package/hooks/use-mobile.ts +19 -19
- package/index.ts +3 -3
- package/lib/index.ts +1 -1
- package/lib/utils.ts +6 -6
- package/package.json +1 -1
- package/styles.css +124 -124
- package/components/ai-elements/agent.tsx +0 -141
- package/components/ai-elements/artifact.tsx +0 -148
- package/components/ai-elements/attachments.tsx +0 -426
- package/components/ai-elements/audio-player.tsx +0 -231
- package/components/ai-elements/canvas.tsx +0 -26
- package/components/ai-elements/chain-of-thought.tsx +0 -222
- package/components/ai-elements/checkpoint.tsx +0 -71
- package/components/ai-elements/code-block.tsx +0 -562
- package/components/ai-elements/commit.tsx +0 -458
- package/components/ai-elements/confirmation.tsx +0 -174
- package/components/ai-elements/connection.tsx +0 -28
- package/components/ai-elements/context.tsx +0 -409
- package/components/ai-elements/controls.tsx +0 -18
- package/components/ai-elements/conversation.tsx +0 -168
- package/components/ai-elements/edge.tsx +0 -143
- package/components/ai-elements/environment-variables.tsx +0 -324
- package/components/ai-elements/file-tree.tsx +0 -304
- package/components/ai-elements/image.tsx +0 -24
- package/components/ai-elements/index.ts +0 -51
- package/components/ai-elements/inline-citation.tsx +0 -296
- package/components/ai-elements/jsx-preview.tsx +0 -310
- package/components/ai-elements/message.tsx +0 -360
- package/components/ai-elements/mic-selector.tsx +0 -375
- package/components/ai-elements/model-selector.tsx +0 -213
- package/components/ai-elements/node.tsx +0 -71
- package/components/ai-elements/open-in-chat.tsx +0 -370
- package/components/ai-elements/package-info.tsx +0 -239
- package/components/ai-elements/panel.tsx +0 -15
- package/components/ai-elements/persona.tsx +0 -306
- package/components/ai-elements/plan.tsx +0 -147
- package/components/ai-elements/prompt-input.tsx +0 -1463
- package/components/ai-elements/queue.tsx +0 -274
- package/components/ai-elements/reasoning.tsx +0 -228
- package/components/ai-elements/sandbox.tsx +0 -132
- package/components/ai-elements/schema-display.tsx +0 -471
- package/components/ai-elements/shimmer.tsx +0 -77
- package/components/ai-elements/snippet.tsx +0 -145
- package/components/ai-elements/sources.tsx +0 -77
- package/components/ai-elements/speech-input.tsx +0 -323
- package/components/ai-elements/stack-trace.tsx +0 -528
- package/components/ai-elements/suggestion.tsx +0 -57
- package/components/ai-elements/task.tsx +0 -87
- package/components/ai-elements/terminal.tsx +0 -273
- package/components/ai-elements/test-results.tsx +0 -496
- package/components/ai-elements/tool.tsx +0 -173
- package/components/ai-elements/toolbar.tsx +0 -16
- package/components/ai-elements/transcription.tsx +0 -125
- package/components/ai-elements/voice-selector.tsx +0 -524
- package/components/ai-elements/web-preview.tsx +0 -281
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { cn } from "../../lib/utils";
|
|
4
|
-
import type { RiveParameters } from "@rive-app/react-webgl2";
|
|
5
|
-
import {
|
|
6
|
-
useRive,
|
|
7
|
-
useStateMachineInput,
|
|
8
|
-
useViewModel,
|
|
9
|
-
useViewModelInstance,
|
|
10
|
-
useViewModelInstanceColor,
|
|
11
|
-
} from "@rive-app/react-webgl2";
|
|
12
|
-
import type { FC, ReactNode } from "react";
|
|
13
|
-
import { memo, useEffect, useMemo, useRef, useState } from "react";
|
|
14
|
-
|
|
15
|
-
// Delays Rive initialization by one frame so that React Strict Mode's
|
|
16
|
-
// immediate unmount cycle never creates a WebGL2 context. Only the
|
|
17
|
-
// second (real) mount will initialise, avoiding context exhaustion.
|
|
18
|
-
const useStrictModeSafeInit = () => {
|
|
19
|
-
const [ready, setReady] = useState(false);
|
|
20
|
-
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
const id = requestAnimationFrame(() => setReady(true));
|
|
23
|
-
return () => {
|
|
24
|
-
cancelAnimationFrame(id);
|
|
25
|
-
setReady(false);
|
|
26
|
-
};
|
|
27
|
-
}, []);
|
|
28
|
-
|
|
29
|
-
return ready;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type PersonaState =
|
|
33
|
-
| "idle"
|
|
34
|
-
| "listening"
|
|
35
|
-
| "thinking"
|
|
36
|
-
| "speaking"
|
|
37
|
-
| "asleep";
|
|
38
|
-
|
|
39
|
-
interface PersonaProps {
|
|
40
|
-
state: PersonaState;
|
|
41
|
-
onLoad?: RiveParameters["onLoad"];
|
|
42
|
-
onLoadError?: RiveParameters["onLoadError"];
|
|
43
|
-
onReady?: () => void;
|
|
44
|
-
onPause?: RiveParameters["onPause"];
|
|
45
|
-
onPlay?: RiveParameters["onPlay"];
|
|
46
|
-
onStop?: RiveParameters["onStop"];
|
|
47
|
-
className?: string;
|
|
48
|
-
variant?: keyof typeof sources;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// The state machine name is always 'default' for Elements AI visuals
|
|
52
|
-
const stateMachine = "default";
|
|
53
|
-
|
|
54
|
-
const sources = {
|
|
55
|
-
command: {
|
|
56
|
-
dynamicColor: true,
|
|
57
|
-
hasModel: true,
|
|
58
|
-
source:
|
|
59
|
-
"https://ejiidnob33g9ap1r.public.blob.vercel-storage.com/command-2.0.riv",
|
|
60
|
-
},
|
|
61
|
-
glint: {
|
|
62
|
-
dynamicColor: true,
|
|
63
|
-
hasModel: true,
|
|
64
|
-
source:
|
|
65
|
-
"https://ejiidnob33g9ap1r.public.blob.vercel-storage.com/glint-2.0.riv",
|
|
66
|
-
},
|
|
67
|
-
halo: {
|
|
68
|
-
dynamicColor: true,
|
|
69
|
-
hasModel: true,
|
|
70
|
-
source:
|
|
71
|
-
"https://ejiidnob33g9ap1r.public.blob.vercel-storage.com/halo-2.0.riv",
|
|
72
|
-
},
|
|
73
|
-
mana: {
|
|
74
|
-
dynamicColor: false,
|
|
75
|
-
hasModel: true,
|
|
76
|
-
source:
|
|
77
|
-
"https://ejiidnob33g9ap1r.public.blob.vercel-storage.com/mana-2.0.riv",
|
|
78
|
-
},
|
|
79
|
-
obsidian: {
|
|
80
|
-
dynamicColor: true,
|
|
81
|
-
hasModel: true,
|
|
82
|
-
source:
|
|
83
|
-
"https://ejiidnob33g9ap1r.public.blob.vercel-storage.com/obsidian-2.0.riv",
|
|
84
|
-
},
|
|
85
|
-
opal: {
|
|
86
|
-
dynamicColor: false,
|
|
87
|
-
hasModel: false,
|
|
88
|
-
source:
|
|
89
|
-
"https://ejiidnob33g9ap1r.public.blob.vercel-storage.com/orb-1.2.riv",
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const getCurrentTheme = (): "light" | "dark" => {
|
|
94
|
-
if (typeof window !== "undefined") {
|
|
95
|
-
if (document.documentElement.classList.contains("dark")) {
|
|
96
|
-
return "dark";
|
|
97
|
-
}
|
|
98
|
-
if (window.matchMedia?.("(prefers-color-scheme: dark)").matches) {
|
|
99
|
-
return "dark";
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return "light";
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const useTheme = (enabled: boolean) => {
|
|
106
|
-
const [theme, setTheme] = useState<"light" | "dark">(getCurrentTheme);
|
|
107
|
-
|
|
108
|
-
useEffect(() => {
|
|
109
|
-
// Skip if not enabled (avoids unnecessary observers for non-dynamic-color variants)
|
|
110
|
-
if (!enabled) {
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Watch for classList changes
|
|
115
|
-
const observer = new MutationObserver(() => {
|
|
116
|
-
setTheme(getCurrentTheme());
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
observer.observe(document.documentElement, {
|
|
120
|
-
attributeFilter: ["class"],
|
|
121
|
-
attributes: true,
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
// Watch for OS-level theme changes
|
|
125
|
-
let mql: MediaQueryList | null = null;
|
|
126
|
-
const handleMediaChange = () => {
|
|
127
|
-
setTheme(getCurrentTheme());
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
if (window.matchMedia) {
|
|
131
|
-
mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
132
|
-
mql.addEventListener("change", handleMediaChange);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
return () => {
|
|
136
|
-
observer.disconnect();
|
|
137
|
-
if (mql) {
|
|
138
|
-
mql.removeEventListener("change", handleMediaChange);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
}, [enabled]);
|
|
142
|
-
|
|
143
|
-
return theme;
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
interface PersonaWithModelProps {
|
|
147
|
-
rive: ReturnType<typeof useRive>["rive"];
|
|
148
|
-
source: (typeof sources)[keyof typeof sources];
|
|
149
|
-
children: React.ReactNode;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const PersonaWithModel = memo(
|
|
153
|
-
({ rive, source, children }: PersonaWithModelProps) => {
|
|
154
|
-
const theme = useTheme(source.dynamicColor);
|
|
155
|
-
const viewModel = useViewModel(rive, { useDefault: true });
|
|
156
|
-
const viewModelInstance = useViewModelInstance(viewModel, {
|
|
157
|
-
rive,
|
|
158
|
-
useDefault: true,
|
|
159
|
-
});
|
|
160
|
-
const viewModelInstanceColor = useViewModelInstanceColor(
|
|
161
|
-
"color",
|
|
162
|
-
viewModelInstance
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
useEffect(() => {
|
|
166
|
-
if (!(viewModelInstanceColor && source.dynamicColor)) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const [r, g, b] = theme === "dark" ? [255, 255, 255] : [0, 0, 0];
|
|
171
|
-
viewModelInstanceColor.setRgb(r, g, b);
|
|
172
|
-
}, [viewModelInstanceColor, theme, source.dynamicColor]);
|
|
173
|
-
|
|
174
|
-
return children;
|
|
175
|
-
}
|
|
176
|
-
);
|
|
177
|
-
|
|
178
|
-
PersonaWithModel.displayName = "PersonaWithModel";
|
|
179
|
-
|
|
180
|
-
interface PersonaWithoutModelProps {
|
|
181
|
-
children: ReactNode;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const PersonaWithoutModel = memo(
|
|
185
|
-
({ children }: PersonaWithoutModelProps) => children
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
PersonaWithoutModel.displayName = "PersonaWithoutModel";
|
|
189
|
-
|
|
190
|
-
export const Persona: FC<PersonaProps> = memo(
|
|
191
|
-
({
|
|
192
|
-
variant = "obsidian",
|
|
193
|
-
state = "idle",
|
|
194
|
-
onLoad,
|
|
195
|
-
onLoadError,
|
|
196
|
-
onReady,
|
|
197
|
-
onPause,
|
|
198
|
-
onPlay,
|
|
199
|
-
onStop,
|
|
200
|
-
className,
|
|
201
|
-
}) => {
|
|
202
|
-
const source = sources[variant];
|
|
203
|
-
|
|
204
|
-
if (!source) {
|
|
205
|
-
throw new Error(`Invalid variant: ${variant}`);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Stabilize callbacks to prevent useRive from reinitializing
|
|
209
|
-
const callbacksRef = useRef({
|
|
210
|
-
onLoad,
|
|
211
|
-
onLoadError,
|
|
212
|
-
onPause,
|
|
213
|
-
onPlay,
|
|
214
|
-
onReady,
|
|
215
|
-
onStop,
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
useEffect(() => {
|
|
219
|
-
callbacksRef.current = {
|
|
220
|
-
onLoad,
|
|
221
|
-
onLoadError,
|
|
222
|
-
onPause,
|
|
223
|
-
onPlay,
|
|
224
|
-
onReady,
|
|
225
|
-
onStop,
|
|
226
|
-
};
|
|
227
|
-
}, [onLoad, onLoadError, onPause, onPlay, onReady, onStop]);
|
|
228
|
-
|
|
229
|
-
const stableCallbacks = useMemo(
|
|
230
|
-
() => ({
|
|
231
|
-
onLoad: ((loadedRive) =>
|
|
232
|
-
callbacksRef.current.onLoad?.(
|
|
233
|
-
loadedRive
|
|
234
|
-
)) as RiveParameters["onLoad"],
|
|
235
|
-
onLoadError: ((err) =>
|
|
236
|
-
callbacksRef.current.onLoadError?.(
|
|
237
|
-
err
|
|
238
|
-
)) as RiveParameters["onLoadError"],
|
|
239
|
-
onPause: ((event) =>
|
|
240
|
-
callbacksRef.current.onPause?.(event)) as RiveParameters["onPause"],
|
|
241
|
-
onPlay: ((event) =>
|
|
242
|
-
callbacksRef.current.onPlay?.(event)) as RiveParameters["onPlay"],
|
|
243
|
-
onReady: () => callbacksRef.current.onReady?.(),
|
|
244
|
-
onStop: ((event) =>
|
|
245
|
-
callbacksRef.current.onStop?.(event)) as RiveParameters["onStop"],
|
|
246
|
-
}),
|
|
247
|
-
[]
|
|
248
|
-
);
|
|
249
|
-
|
|
250
|
-
// Delay initialisation by one frame to avoid creating (and leaking)
|
|
251
|
-
// a WebGL2 context during React Strict Mode's first throw-away mount.
|
|
252
|
-
const ready = useStrictModeSafeInit();
|
|
253
|
-
|
|
254
|
-
const { rive, RiveComponent } = useRive(
|
|
255
|
-
ready
|
|
256
|
-
? {
|
|
257
|
-
autoplay: true,
|
|
258
|
-
onLoad: stableCallbacks.onLoad,
|
|
259
|
-
onLoadError: stableCallbacks.onLoadError,
|
|
260
|
-
onPause: stableCallbacks.onPause,
|
|
261
|
-
onPlay: stableCallbacks.onPlay,
|
|
262
|
-
onRiveReady: stableCallbacks.onReady,
|
|
263
|
-
onStop: stableCallbacks.onStop,
|
|
264
|
-
src: source.source,
|
|
265
|
-
stateMachines: stateMachine,
|
|
266
|
-
}
|
|
267
|
-
: null
|
|
268
|
-
);
|
|
269
|
-
|
|
270
|
-
const listeningInput = useStateMachineInput(
|
|
271
|
-
rive,
|
|
272
|
-
stateMachine,
|
|
273
|
-
"listening"
|
|
274
|
-
);
|
|
275
|
-
const thinkingInput = useStateMachineInput(rive, stateMachine, "thinking");
|
|
276
|
-
const speakingInput = useStateMachineInput(rive, stateMachine, "speaking");
|
|
277
|
-
const asleepInput = useStateMachineInput(rive, stateMachine, "asleep");
|
|
278
|
-
|
|
279
|
-
// Rive state machine inputs are mutable objects that must be set via direct
|
|
280
|
-
// property assignment — this is the intended Rive API, not a React anti-pattern.
|
|
281
|
-
useEffect(() => {
|
|
282
|
-
if (listeningInput) {
|
|
283
|
-
listeningInput.value = state === "listening";
|
|
284
|
-
}
|
|
285
|
-
if (thinkingInput) {
|
|
286
|
-
thinkingInput.value = state === "thinking";
|
|
287
|
-
}
|
|
288
|
-
if (speakingInput) {
|
|
289
|
-
speakingInput.value = state === "speaking";
|
|
290
|
-
}
|
|
291
|
-
if (asleepInput) {
|
|
292
|
-
asleepInput.value = state === "asleep";
|
|
293
|
-
}
|
|
294
|
-
}, [state, listeningInput, thinkingInput, speakingInput, asleepInput]);
|
|
295
|
-
|
|
296
|
-
const Component = source.hasModel ? PersonaWithModel : PersonaWithoutModel;
|
|
297
|
-
|
|
298
|
-
return (
|
|
299
|
-
<Component rive={rive} source={source}>
|
|
300
|
-
<RiveComponent className={cn("size-16 shrink-0", className)} />
|
|
301
|
-
</Component>
|
|
302
|
-
);
|
|
303
|
-
}
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
Persona.displayName = "Persona";
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Button } from "../ui/button";
|
|
4
|
-
import {
|
|
5
|
-
Card,
|
|
6
|
-
CardAction,
|
|
7
|
-
CardContent,
|
|
8
|
-
CardDescription,
|
|
9
|
-
CardFooter,
|
|
10
|
-
CardHeader,
|
|
11
|
-
CardTitle,
|
|
12
|
-
} from "../ui/card";
|
|
13
|
-
import {
|
|
14
|
-
Collapsible,
|
|
15
|
-
CollapsibleContent,
|
|
16
|
-
CollapsibleTrigger,
|
|
17
|
-
} from "../ui/collapsible";
|
|
18
|
-
import { cn } from "../../lib/utils";
|
|
19
|
-
import { ChevronsUpDownIcon } from "lucide-react";
|
|
20
|
-
import type { ComponentProps } from "react";
|
|
21
|
-
import { createContext, useContext, useMemo } from "react";
|
|
22
|
-
|
|
23
|
-
import { Shimmer } from "./shimmer";
|
|
24
|
-
|
|
25
|
-
interface PlanContextValue {
|
|
26
|
-
isStreaming: boolean;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const PlanContext = createContext<PlanContextValue | null>(null);
|
|
30
|
-
|
|
31
|
-
const usePlan = () => {
|
|
32
|
-
const context = useContext(PlanContext);
|
|
33
|
-
if (!context) {
|
|
34
|
-
throw new Error("Plan components must be used within Plan");
|
|
35
|
-
}
|
|
36
|
-
return context;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export type PlanProps = ComponentProps<typeof Collapsible> & {
|
|
40
|
-
isStreaming?: boolean;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const Plan = ({
|
|
44
|
-
className,
|
|
45
|
-
isStreaming = false,
|
|
46
|
-
children,
|
|
47
|
-
...props
|
|
48
|
-
}: PlanProps) => {
|
|
49
|
-
const contextValue = useMemo(() => ({ isStreaming }), [isStreaming]);
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<PlanContext.Provider value={contextValue}>
|
|
53
|
-
<Collapsible asChild data-slot="plan" {...props}>
|
|
54
|
-
<Card className={cn("shadow-none", className)}>{children}</Card>
|
|
55
|
-
</Collapsible>
|
|
56
|
-
</PlanContext.Provider>
|
|
57
|
-
);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export type PlanHeaderProps = ComponentProps<typeof CardHeader>;
|
|
61
|
-
|
|
62
|
-
export const PlanHeader = ({ className, ...props }: PlanHeaderProps) => (
|
|
63
|
-
<CardHeader
|
|
64
|
-
className={cn("flex items-start justify-between", className)}
|
|
65
|
-
data-slot="plan-header"
|
|
66
|
-
{...props}
|
|
67
|
-
/>
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
export type PlanTitleProps = Omit<
|
|
71
|
-
ComponentProps<typeof CardTitle>,
|
|
72
|
-
"children"
|
|
73
|
-
> & {
|
|
74
|
-
children: string;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
export const PlanTitle = ({ children, ...props }: PlanTitleProps) => {
|
|
78
|
-
const { isStreaming } = usePlan();
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<CardTitle data-slot="plan-title" {...props}>
|
|
82
|
-
{isStreaming ? <Shimmer>{children}</Shimmer> : children}
|
|
83
|
-
</CardTitle>
|
|
84
|
-
);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
export type PlanDescriptionProps = Omit<
|
|
88
|
-
ComponentProps<typeof CardDescription>,
|
|
89
|
-
"children"
|
|
90
|
-
> & {
|
|
91
|
-
children: string;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
export const PlanDescription = ({
|
|
95
|
-
className,
|
|
96
|
-
children,
|
|
97
|
-
...props
|
|
98
|
-
}: PlanDescriptionProps) => {
|
|
99
|
-
const { isStreaming } = usePlan();
|
|
100
|
-
|
|
101
|
-
return (
|
|
102
|
-
<CardDescription
|
|
103
|
-
className={cn("text-balance", className)}
|
|
104
|
-
data-slot="plan-description"
|
|
105
|
-
{...props}
|
|
106
|
-
>
|
|
107
|
-
{isStreaming ? <Shimmer>{children}</Shimmer> : children}
|
|
108
|
-
</CardDescription>
|
|
109
|
-
);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
export type PlanActionProps = ComponentProps<typeof CardAction>;
|
|
113
|
-
|
|
114
|
-
export const PlanAction = (props: PlanActionProps) => (
|
|
115
|
-
<CardAction data-slot="plan-action" {...props} />
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
export type PlanContentProps = ComponentProps<typeof CardContent>;
|
|
119
|
-
|
|
120
|
-
export const PlanContent = (props: PlanContentProps) => (
|
|
121
|
-
<CollapsibleContent asChild>
|
|
122
|
-
<CardContent data-slot="plan-content" {...props} />
|
|
123
|
-
</CollapsibleContent>
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
export type PlanFooterProps = ComponentProps<"div">;
|
|
127
|
-
|
|
128
|
-
export const PlanFooter = (props: PlanFooterProps) => (
|
|
129
|
-
<CardFooter data-slot="plan-footer" {...props} />
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
export type PlanTriggerProps = ComponentProps<typeof CollapsibleTrigger>;
|
|
133
|
-
|
|
134
|
-
export const PlanTrigger = ({ className, ...props }: PlanTriggerProps) => (
|
|
135
|
-
<CollapsibleTrigger asChild>
|
|
136
|
-
<Button
|
|
137
|
-
className={cn("size-8", className)}
|
|
138
|
-
data-slot="plan-trigger"
|
|
139
|
-
size="icon"
|
|
140
|
-
variant="ghost"
|
|
141
|
-
{...props}
|
|
142
|
-
>
|
|
143
|
-
<ChevronsUpDownIcon className="size-4" />
|
|
144
|
-
<span className="sr-only">Toggle plan</span>
|
|
145
|
-
</Button>
|
|
146
|
-
</CollapsibleTrigger>
|
|
147
|
-
);
|