| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- 'use client';
- import { Button } from '@/components/ui/button';
- import {
- Card,
- CardAction,
- CardContent,
- CardDescription,
- CardFooter,
- CardHeader,
- CardTitle,
- } from '@/components/ui/card';
- import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
- import { cn } from '@/lib/utils';
- import { ChevronsUpDownIcon } from 'lucide-react';
- import type { ComponentProps } from 'react';
- import { createContext, useContext } from 'react';
- import { Shimmer } from './shimmer';
- type PlanContextValue = {
- isStreaming: boolean;
- };
- const PlanContext = createContext<PlanContextValue | null>(null);
- const usePlan = () => {
- const context = useContext(PlanContext);
- if (!context) {
- throw new Error('Plan components must be used within Plan');
- }
- return context;
- };
- export type PlanProps = ComponentProps<typeof Collapsible> & {
- isStreaming?: boolean;
- };
- export const Plan = ({ className, isStreaming = false, children, ...props }: PlanProps) => (
- <PlanContext.Provider value={{ isStreaming }}>
- <Collapsible asChild data-slot="plan" {...props}>
- <Card className={cn('shadow-none', className)}>{children}</Card>
- </Collapsible>
- </PlanContext.Provider>
- );
- export type PlanHeaderProps = ComponentProps<typeof CardHeader>;
- export const PlanHeader = ({ className, ...props }: PlanHeaderProps) => (
- <CardHeader
- className={cn('flex items-start justify-between', className)}
- data-slot="plan-header"
- {...props}
- />
- );
- export type PlanTitleProps = Omit<ComponentProps<typeof CardTitle>, 'children'> & {
- children: string;
- };
- export const PlanTitle = ({ children, ...props }: PlanTitleProps) => {
- const { isStreaming } = usePlan();
- return (
- <CardTitle data-slot="plan-title" {...props}>
- {isStreaming ? <Shimmer>{children}</Shimmer> : children}
- </CardTitle>
- );
- };
- export type PlanDescriptionProps = Omit<ComponentProps<typeof CardDescription>, 'children'> & {
- children: string;
- };
- export const PlanDescription = ({ className, children, ...props }: PlanDescriptionProps) => {
- const { isStreaming } = usePlan();
- return (
- <CardDescription
- className={cn('text-balance', className)}
- data-slot="plan-description"
- {...props}
- >
- {isStreaming ? <Shimmer>{children}</Shimmer> : children}
- </CardDescription>
- );
- };
- export type PlanActionProps = ComponentProps<typeof CardAction>;
- export const PlanAction = (props: PlanActionProps) => (
- <CardAction data-slot="plan-action" {...props} />
- );
- export type PlanContentProps = ComponentProps<typeof CardContent>;
- export const PlanContent = (props: PlanContentProps) => (
- <CollapsibleContent asChild>
- <CardContent data-slot="plan-content" {...props} />
- </CollapsibleContent>
- );
- export type PlanFooterProps = ComponentProps<'div'>;
- export const PlanFooter = (props: PlanFooterProps) => (
- <CardFooter data-slot="plan-footer" {...props} />
- );
- export type PlanTriggerProps = ComponentProps<typeof CollapsibleTrigger>;
- export const PlanTrigger = ({ className, ...props }: PlanTriggerProps) => (
- <CollapsibleTrigger asChild>
- <Button
- className={cn('size-8', className)}
- data-slot="plan-trigger"
- size="icon"
- variant="ghost"
- {...props}
- >
- <ChevronsUpDownIcon className="size-4" />
- <span className="sr-only">Toggle plan</span>
- </Button>
- </CollapsibleTrigger>
- );
|