| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- 'use client';
- import { Alert, AlertDescription } from '@/components/ui/alert';
- import { Button } from '@/components/ui/button';
- import { cn } from '@/lib/utils';
- import type { ToolUIPart } from 'ai';
- import { type ComponentProps, createContext, type ReactNode, useContext } from 'react';
- type ToolUIPartApproval =
- | {
- id: string;
- approved?: never;
- reason?: never;
- }
- | {
- id: string;
- approved: boolean;
- reason?: string;
- }
- | {
- id: string;
- approved: true;
- reason?: string;
- }
- | {
- id: string;
- approved: true;
- reason?: string;
- }
- | {
- id: string;
- approved: false;
- reason?: string;
- }
- | undefined;
- type ConfirmationContextValue = {
- approval: ToolUIPartApproval;
- state: ToolUIPart['state'];
- };
- const ConfirmationContext = createContext<ConfirmationContextValue | null>(null);
- const useConfirmation = () => {
- const context = useContext(ConfirmationContext);
- if (!context) {
- throw new Error('Confirmation components must be used within Confirmation');
- }
- return context;
- };
- export type ConfirmationProps = ComponentProps<typeof Alert> & {
- approval?: ToolUIPartApproval;
- state: ToolUIPart['state'];
- };
- export const Confirmation = ({ className, approval, state, ...props }: ConfirmationProps) => {
- if (!approval || state === 'input-streaming' || state === 'input-available') {
- return null;
- }
- return (
- <ConfirmationContext.Provider value={{ approval, state }}>
- <Alert className={cn('flex flex-col gap-2', className)} {...props} />
- </ConfirmationContext.Provider>
- );
- };
- export type ConfirmationTitleProps = ComponentProps<typeof AlertDescription>;
- export const ConfirmationTitle = ({ className, ...props }: ConfirmationTitleProps) => (
- <AlertDescription className={cn('inline', className)} {...props} />
- );
- export type ConfirmationRequestProps = {
- children?: ReactNode;
- };
- export const ConfirmationRequest = ({ children }: ConfirmationRequestProps) => {
- const { state } = useConfirmation();
- // Only show when approval is requested
- if (state !== 'approval-requested') {
- return null;
- }
- return children;
- };
- export type ConfirmationAcceptedProps = {
- children?: ReactNode;
- };
- export const ConfirmationAccepted = ({ children }: ConfirmationAcceptedProps) => {
- const { approval, state } = useConfirmation();
- // Only show when approved and in response states
- if (
- !approval?.approved ||
- (state !== 'approval-responded' && state !== 'output-denied' && state !== 'output-available')
- ) {
- return null;
- }
- return children;
- };
- export type ConfirmationRejectedProps = {
- children?: ReactNode;
- };
- export const ConfirmationRejected = ({ children }: ConfirmationRejectedProps) => {
- const { approval, state } = useConfirmation();
- // Only show when rejected and in response states
- if (
- approval?.approved !== false ||
- (state !== 'approval-responded' && state !== 'output-denied' && state !== 'output-available')
- ) {
- return null;
- }
- return children;
- };
- export type ConfirmationActionsProps = ComponentProps<'div'>;
- export const ConfirmationActions = ({ className, ...props }: ConfirmationActionsProps) => {
- const { state } = useConfirmation();
- // Only show when approval is requested
- if (state !== 'approval-requested') {
- return null;
- }
- return (
- <div className={cn('flex items-center justify-end gap-2 self-end', className)} {...props} />
- );
- };
- export type ConfirmationActionProps = ComponentProps<typeof Button>;
- export const ConfirmationAction = (props: ConfirmationActionProps) => (
- <Button className="h-8 px-3 text-sm" type="button" {...props} />
- );
|