import type { ReceivedChatMessage } from '@livekit/components-core'; import { tokenize, createDefaultGrammar } from '@livekit/components-core'; import * as React from 'react'; /** @public */ export type MessageFormatter = (message: string) => React.ReactNode; /** * ChatEntry composes the HTML div element under the hood, so you can pass all its props. * These are the props specific to the ChatEntry component: * @public */ export interface ChatEntryProps extends React.HTMLAttributes { /** The chat massage object to display. */ entry: ReceivedChatMessage; /** Hide sender name. Useful when displaying multiple consecutive chat messages from the same person. */ hideName?: boolean; /** Hide message timestamp. */ hideTimestamp?: boolean; /** An optional formatter for the message body. */ messageFormatter?: MessageFormatter; } /** * The `ChatEntry` component holds and displays one chat message. * * @example * ```tsx * * * * ``` * @see `Chat` * @public */ export const ChatEntry: ( props: ChatEntryProps & React.RefAttributes, ) => React.ReactNode = /* @__PURE__ */ React.forwardRef( function ChatEntry( { entry, hideName = false, hideTimestamp = false, messageFormatter, ...props }: ChatEntryProps, ref, ) { const formattedMessage = React.useMemo(() => { return messageFormatter ? messageFormatter(entry.message) : entry.message; }, [entry.message, messageFormatter]); const hasBeenEdited = !!entry.editTimestamp; const time = new Date(entry.timestamp); const locale = typeof navigator !== 'undefined' ? navigator.language : 'en-US'; const name = entry.from?.name ?? entry.from?.identity; return (
  • {(!hideTimestamp || !hideName || hasBeenEdited) && ( {!hideName && {name}} {(!hideTimestamp || hasBeenEdited) && ( {hasBeenEdited && 'edited '} {time.toLocaleTimeString(locale, { timeStyle: 'short' })} )} )} {formattedMessage} {entry.attachedFiles?.map( (file) => file.type.startsWith('image/') && ( {file.name} ), )}
  • ); }, ); /** @public */ export function formatChatMessageLinks(message: string): React.ReactNode { return tokenize(message, createDefaultGrammar()).map((tok, i) => { if (typeof tok === `string`) { return tok; } else { const content = tok.content.toString(); const href = tok.type === `url` ? /^http(s?):\/\//.test(content) ? content : `https://${content}` : `mailto:${content}`; return ( {content} ); } }); }