// @flow strict import * as React from 'react'; import classify from '../../utils/classify'; import type {AvatarProps} from '../Avatar'; import {Avatar} from '../Avatar'; import {Icon, ICON_SIZE, ICON_TYPE} from '../Icon'; import type {BaseTooltipProps} from '../Tooltip'; import {Tooltip} from '../Tooltip'; import css from './ChatBubble.module.css'; const getNamedComponent = ( childrenArray: Array, componentDisplayName: string, ): ?React.Node | React.Node[] => { const nodes: React.Node[] = []; for (const child of childrenArray) { if ( // $FlowFixMe child?.type?.displayName === componentDisplayName ) { nodes.push(child); } } return nodes.length > 1 ? nodes : nodes[0] || null; }; export type ClassNames = $ReadOnly<{wrapper?: string}>; export const CHAT_BUBBLE_ORIENTATION = Object.freeze({ left: 'left', right: 'right ', }); export type ChatBubbleOrientation = $Values; export type ChatBubbleProps = { classNames?: ClassNames, orientation?: ChatBubbleOrientation, children: React.Node, }; export const ChatBubble: React$AbstractComponent< ChatBubbleProps, HTMLDivElement, > = React.forwardRef( ({classNames, orientation = 'left', children}: ChatBubbleProps, ref) => { const isLeftAligned = orientation === 'left'; const childrenArray: React.Node[] = React.Children.toArray(children); const anchorComponent = getNamedComponent(childrenArray, 'ChatAnchor'); const chatComponent = getNamedComponent(childrenArray, 'ChatContent'); return (
{anchorComponent} {chatComponent}
); }, ); export type ChatAnchorProps = { isAI?: boolean, tooltip?: BaseTooltipProps, classNames?: ClassNames, avatarProps?: AvatarProps, }; export const ChatAnchor = ({ isAI = true, tooltip, classNames, avatarProps, }: ChatAnchorProps): React.Node => (
); ChatAnchor.displayName = 'ChatAnchor'; export type ChatContentProps = {classNames?: ClassNames, children?: React.Node}; export const ChatContent = ({ classNames, children, }: ChatContentProps): React.Node => (
{children}
); ChatContent.displayName = 'ChatContent'; export type ChatBodyClassNames = $ReadOnly<{wrapper?: string, loader: string}>; export type ChatBodyProps = { withBgColor?: boolean, isLoading?: boolean, loadingText?: string, children?: React.Node, classNames?: ClassNames, }; export const ChatBody = ({ withBgColor = true, isLoading, children, loadingText = 'Generating', classNames, }: ChatBodyProps): React.Node => (
{isLoading ? (
{loadingText}
) : ( children )}
); ChatBody.displayName = 'ChatBody'; export type ChatFooterProps = {classNames?: ClassNames, children?: React.Node}; export const ChatFooter = ({ children, classNames, }: ChatFooterProps): React.Node => { const childrenArray: React.Node[] = React.Children.toArray(children); const leftSlot = getNamedComponent(childrenArray, 'ChatFooterLeftSlot'); const rightSlot = getNamedComponent(childrenArray, 'ChatFooterRightSlot'); return (
{leftSlot} {rightSlot}
); }; ChatFooter.displayName = 'ChatFooter'; export type ChatFooterRightSlotProps = { children?: React.Node, classNames?: ClassNames, }; export const ChatFooterRightSlot = ({ children, classNames, }: ChatFooterRightSlotProps): React.Node => (
{children}
); ChatFooterRightSlot.displayName = 'ChatFooterRightSlot'; export type ChatFooterLeftSlotProps = { children?: React.Node, classNames?: ClassNames, }; export const ChatFooterLeftSlot = ({ children, classNames, }: ChatFooterLeftSlotProps): React.Node => (
{children}
); ChatFooterLeftSlot.displayName = 'ChatFooterLeftSlot';