UNPKG

@liveblocks/react-ui

Version:

A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.

1,559 lines (1,501 loc) 53.3 kB
import * as react from 'react'; import { ComponentType, ComponentPropsWithoutRef, ElementType, ReactNode, ComponentProps, FormEvent, RefAttributes, MouseEvent, PropsWithChildren } from 'react'; import { CommentAttachment, AiReasoningPart, AiRetrievalPart, Relax, WithNavigation, AiAssistantMessage, CopilotId, AiKnowledgeSource, AiOpaqueToolDefinition, AiToolTypePack, JsonObject, AiToolExecuteCallback, NoInfr, CommentBody, MentionData, BaseMetadata, DM, CommentData, HistoryVersion, InboxNotificationData, InboxNotificationThreadData, InboxNotificationTextMentionData, InboxNotificationCustomData, KDAD, ThreadData } from '@liveblocks/core'; import * as react_jsx_runtime from 'react/jsx-runtime'; interface GlobalComponents { Anchor: ComponentType<ComponentPropsWithoutRef<"a">> | "a"; } type Components = GlobalComponents; type Direction = "ltr" | "rtl"; type SlotProp = { /** * Replace the rendered element by the one passed as a child. */ asChild?: boolean; }; type ComponentPropsWithSlot<TElement extends ElementType<any>> = ComponentPropsWithoutRef<TElement> & SlotProp; type ComposerBodyText = { bold?: boolean; italic?: boolean; strikethrough?: boolean; code?: boolean; text: string; }; type ComposerBodyMark = keyof Omit<ComposerBodyText, "text">; type ComposerBodyMarks = { [K in ComposerBodyMark]: boolean; }; interface CommentAttachmentArgs { /** * The attachment. */ attachment: CommentAttachment; /** * A presigned URL for the attachment. */ url: string; } interface LocalizationOverrides { locale: string; dir: Direction; } interface GlobalOverrides { USER_SELF: string; USER_UNKNOWN: string; LIST_REMAINING: (count: number) => string; LIST_REMAINING_USERS: (count: number) => string; LIST_REMAINING_COMMENTS: (count: number) => string; EMOJI_PICKER_SEARCH_PLACEHOLDER: string; EMOJI_PICKER_EMPTY: ReactNode; EMOJI_PICKER_ERROR: (error: Error) => ReactNode; EMOJI_PICKER_CHANGE_SKIN_TONE: string; ATTACHMENT_TOO_LARGE: (maxSize?: string) => string; ATTACHMENT_ERROR: (error: Error) => string; COPY_TO_CLIPBOARD: string; } interface CommentOverrides { COMMENT_EDITED: ReactNode; COMMENT_DELETED: ReactNode; COMMENT_MORE: string; COMMENT_EDIT: string; COMMENT_EDIT_COMPOSER_PLACEHOLDER: string; COMMENT_EDIT_COMPOSER_CANCEL: string; COMMENT_EDIT_COMPOSER_SAVE: string; COMMENT_DELETE: string; COMMENT_DELETE_ATTACHMENT: string; COMMENT_ADD_REACTION: string; COMMENT_REACTION_LIST: (list: ReactNode, emoji: string, count: number) => ReactNode; COMMENT_REACTION_DESCRIPTION: (emoji: string, count: number) => string; } interface ComposerOverrides { COMPOSER_INSERT_MENTION: string; COMPOSER_INSERT_EMOJI: string; COMPOSER_ATTACH_FILES: string; COMPOSER_REMOVE_ATTACHMENT: string; COMPOSER_PLACEHOLDER: string; COMPOSER_SEND: string; COMPOSER_TOGGLE_MARK: (mark: ComposerBodyMark) => string; } interface AiToolConfirmationOverrides { AI_TOOL_CONFIRMATION_CONFIRM: string; AI_TOOL_CONFIRMATION_CANCEL: string; } interface AiComposerOverrides { AI_COMPOSER_PLACEHOLDER: string; AI_COMPOSER_SEND: string; AI_COMPOSER_ABORT: string; } interface AiChatMessageOverrides { AI_CHAT_MESSAGE_DELETED: string; AI_CHAT_MESSAGE_THINKING: ReactNode; AI_CHAT_MESSAGE_REASONING: (isStreaming: boolean, part: AiReasoningPart) => ReactNode; AI_CHAT_MESSAGE_RETRIEVAL: (isStreaming: boolean, part: AiRetrievalPart) => ReactNode; } interface AiChatOverrides { AI_CHAT_MESSAGES_ERROR: (error: Error) => ReactNode; } interface ThreadOverrides { THREAD_RESOLVE: string; THREAD_UNRESOLVE: string; THREAD_SUBSCRIBE: string; THREAD_UNSUBSCRIBE: string; THREAD_NEW_INDICATOR: string; THREAD_NEW_INDICATOR_DESCRIPTION: string; THREAD_SHOW_MORE_COMMENTS: (count: number) => string; THREAD_COMPOSER_PLACEHOLDER: string; THREAD_COMPOSER_SEND: string; } interface InboxNotificationOverrides { INBOX_NOTIFICATION_MORE: string; INBOX_NOTIFICATION_MARK_AS_READ: string; INBOX_NOTIFICATION_DELETE: string; INBOX_NOTIFICATION_THREAD_COMMENTS_LIST: (list: ReactNode, room: ReactNode | undefined, count: number) => ReactNode; INBOX_NOTIFICATION_THREAD_MENTION: (user: ReactNode, room: ReactNode | undefined) => ReactNode; INBOX_NOTIFICATION_TEXT_MENTION: (user: ReactNode, room: ReactNode | undefined) => ReactNode; } interface HistoryVersionPreviewOverrides { HISTORY_VERSION_PREVIEW_AUTHORS_LIST: (list: ReactNode) => ReactNode; HISTORY_VERSION_PREVIEW_RESTORE: string; HISTORY_VERSION_PREVIEW_EMPTY: ReactNode; HISTORY_VERSION_PREVIEW_ERROR: (error: Error) => ReactNode; } type Overrides = LocalizationOverrides & GlobalOverrides & ComposerOverrides & CommentOverrides & ThreadOverrides & InboxNotificationOverrides & HistoryVersionPreviewOverrides & AiComposerOverrides & AiChatMessageOverrides & AiChatOverrides & AiToolConfirmationOverrides; declare function useOverrides(overrides?: Partial<Overrides>): Overrides; type MarkdownComponents = { /** * The component used to render paragraphs. * * @example * ```md * A paragraph. * * Another paragraph. * ``` * ```tsx * <Markdown * components={{ * Paragraph: ({ children }) => <p className="...">{children}</p> * }} * /> * ``` */ Paragraph: ComponentType<MarkdownComponentsParagraphProps>; /** * The component used to render inline elements (bold, italic, strikethrough, and inline code). * * @example * ```md * **Bold**, _italic_, ~~strikethrough~~, and `inline code`. * ``` * ```tsx * <Markdown * components={{ * Inline: ({ type, children }) => { * const Component = type; * return <Component className="...">{children}</Component>; * } * }} * /> * ``` */ Inline: ComponentType<MarkdownComponentsInlineProps>; /** * The component used to render links. * * @example * ```md * A [link](https://liveblocks.io). * ``` * ```tsx * <Markdown * components={{ * Link: ({ href, children }) => <a href={href} className="...">{children}</a> * }} * /> * ``` */ Link: ComponentType<MarkdownComponentsLinkProps>; /** * The component used to render headings. * * @example * ```md * # Heading 1 * ## Heading 2 * ### Heading 3 * ``` * ```tsx * <Markdown * components={{ * Heading: ({ level, children }) => { * const Heading = `h${level}` as const; * return <Heading className="...">{children}</Heading>; * } * }} * /> * ``` */ Heading: ComponentType<MarkdownComponentsHeadingProps>; /** * The component used to render blockquotes. * * @example * ```md * > A blockquote. * ``` * ```tsx * <Markdown * components={{ * Blockquote: ({ children }) => <blockquote className="...">{children}</blockquote> * }} * /> * ``` */ Blockquote: ComponentType<MarkdownComponentsBlockquoteProps>; /** * The component used to render code blocks. * * @example * ```md * `⁠`⁠`javascript * const a = 1; * `⁠`⁠` * ``` * ```tsx * <Markdown * components={{ * CodeBlock: ({ language, code }) => ( * <pre data-language={language} className="..."> * <code className="...">{code}</code> * </pre> * ) * }} * /> * ``` */ CodeBlock: ComponentType<MarkdownComponentsCodeBlockProps>; /** * The component used to render images. * * @example * ```md * ![An image](https://liveblocks.io/logo.svg) * ``` * ```tsx * <Markdown * components={{ * Image: ({ src, alt }) => <img src={src} alt={alt} className="..."> * }} * /> * ``` */ Image: ComponentType<MarkdownComponentsImageProps>; /** * The component used to render lists. * * @example * ```md * 1. An ordered list item * - An unordered list item * - [x] A checked list item * ``` * ```tsx * <Markdown * components={{ * List: ({ type, items, start }) => { * const List = type === "ordered" ? "ol" : "ul"; * return ( * <List start={start}> * {items.map((item, index) => ( * <li key={index}> * {item.children} * </li> * ))} * </List> * ); * } * }} * /> * ``` */ List: ComponentType<MarkdownComponentsListProps>; /** * The component used to render tables. * * @example * ```md * | Heading 1 | Heading 2 | * |-----------|-----------| * | Cell 1 | Cell 2 | * | Cell 3 | Cell 4 | * ``` * ```tsx * <Markdown * components={{ * Table: ({ headings, rows }) => ( * <table> * <thead> * <tr> * {headings.map(({ children }, index) => ( * <th key={index}>{children}</th> * ))} * </tr> * </thead> * <tbody> * {rows.map((row, index) => ( * <tr key={index}> * {row.map(({ children }, index) => ( * <td key={index}>{children}</td> * ))} * </tr> * ))} * </tbody> * </table> * ) * }} * /> * ``` */ Table: ComponentType<MarkdownComponentsTableProps>; /** * The component used to render separators. * * @example * ```md * --- * ``` * ```tsx * <Markdown components={{ Separator: () => <hr className="..." /> }} /> * ``` */ Separator: ComponentType; }; interface MarkdownComponentsInlineProps { type: "strong" | "em" | "code" | "del"; children: ReactNode; } interface MarkdownComponentsParagraphProps { children: ReactNode; } interface MarkdownComponentsTableCell { align?: "left" | "center" | "right"; children: ReactNode; } interface MarkdownComponentsTableProps { headings: MarkdownComponentsTableCell[]; rows: MarkdownComponentsTableCell[][]; } interface MarkdownComponentsListItem { checked?: boolean; children: ReactNode; } type MarkdownComponentsListProps = Relax<MarkdownComponentsOrderedListProps | MarkdownComponentsUnorderedListProps>; interface MarkdownComponentsOrderedListProps { type: "ordered"; items: MarkdownComponentsListItem[]; start: number; } interface MarkdownComponentsUnorderedListProps { type: "unordered"; items: MarkdownComponentsListItem[]; } interface MarkdownComponentsBlockquoteProps { children: ReactNode; } interface MarkdownComponentsImageProps { src: string; alt: string; title?: string; } interface MarkdownComponentsHeadingProps { level: 1 | 2 | 3 | 4 | 5 | 6; children: ReactNode; } interface MarkdownComponentsLinkProps { href: string; title?: string; children: ReactNode; } interface MarkdownComponentsCodeBlockProps { code: string; language?: string; } type UiAssistantMessage = WithNavigation<AiAssistantMessage>; type AiChatAssistantMessageComponents = { /** * The components used to render Markdown content. */ markdown?: Partial<MarkdownComponents>; }; interface AiChatAssistantMessageProps extends ComponentProps<"div"> { /** * The message to display. */ message: UiAssistantMessage; /** * How to show or hide reasoning. */ showReasoning?: boolean | "during"; /** * How to show or hide retrievals. */ showRetrievals?: boolean | "during" | Record<AiRetrievalPart["kind"], boolean | "during">; /** * Whether to show sources. */ showSources?: boolean; /** * Override the component's strings. */ overrides?: Partial<GlobalOverrides & AiChatMessageOverrides>; /** * Override the component's components. */ components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>; } interface AiComposerSubmitMessage { /** * The submitted message text. */ text: string; } interface AiComposerFormProps extends ComponentPropsWithSlot<"form"> { /** * The ID of the chat the composer belongs to. */ chatId?: string; /** * The event handler called when the composer is submitted. */ onComposerSubmit?: (message: AiComposerSubmitMessage, event: FormEvent<HTMLFormElement>) => Promise<void> | void; /** * Whether the composer is disabled. */ disabled?: boolean; } interface AiComposerEditorProps extends Omit<ComponentPropsWithoutRef<"div">, "defaultValue" | "children"> { /** * The reading direction of the editor and related elements. */ dir?: Direction; /** * The editor's initial value. */ defaultValue?: string; /** * The text to display when the editor is empty. */ placeholder?: string; /** * Whether the editor is disabled. */ disabled?: boolean; /** * Whether to focus the editor on mount. */ autoFocus?: boolean; } interface AiComposerProps extends Omit<ComponentProps<"form">, "defaultValue"> { /** * The composer's initial value. */ defaultValue?: string; /** * The event handler called when the composer is submitted. */ onComposerSubmit?: (message: AiComposerSubmitMessage, event: FormEvent<HTMLFormElement>) => void; /** * Whether the composer is disabled. */ disabled?: AiComposerFormProps["disabled"]; /** * Whether to focus the composer on mount. */ autoFocus?: AiComposerEditorProps["autoFocus"]; /** * Override the component's strings. */ overrides?: Partial<GlobalOverrides & AiComposerOverrides>; /** * The ID of the chat the composer belongs to. */ chatId: string; /** * The ID of the copilot to use to send the message. */ copilotId?: CopilotId; /** * The time, in milliseconds, before an AI response will timeout. */ responseTimeout?: number; } type AiChatComponentsEmptyProps = { /** * The chat ID provided to the `AiChat` component. */ chatId: string; /** * The copilot ID provided to the `AiChat` component. */ copilotId?: string; }; type AiChatComponentsLoadingProps = Record<string, never>; type AiChatComponents = { /** * The component used to render the empty state of the chat. */ Empty: ComponentType<AiChatComponentsEmptyProps>; /** * The component used to render the loading state of the chat. */ Loading: ComponentType<AiChatComponentsLoadingProps>; /** * The components used to render Markdown content. */ markdown?: Partial<MarkdownComponents>; }; interface AiChatProps extends ComponentProps<"div"> { /** * The ID of the chat the composer belongs to. */ chatId: string; /** * Whether to focus the chat composer on mount. */ autoFocus?: boolean; /** * The ID of the copilot to use to send the message. */ copilotId?: string; /** * The contextual knowledge to include in the chat. May be used by the * assistant when generating responses. In addition to the knowledge passed * in via this prop, the AiChat instance will also have access to any * globally registered knowledge via <RegisterAiKnowledge />. */ knowledge?: AiKnowledgeSource[]; /** * Tool definitions to make available within this chat. May be used by the assistant when generating responses. */ tools?: Record<string, AiOpaqueToolDefinition>; /** * The event handler called when the composer is submitted. */ onComposerSubmit?: AiComposerProps["onComposerSubmit"]; /** * The layout of the chat and its composer. */ layout?: "inset" | "compact"; /** * How to show or hide reasoning. */ showReasoning?: AiChatAssistantMessageProps["showReasoning"]; /** * How to show or hide retrievals. */ showRetrievals?: AiChatAssistantMessageProps["showRetrievals"]; /** * Whether to show sources */ showSources?: AiChatAssistantMessageProps["showSources"]; /** * The time, in milliseconds, before an AI response will timeout. */ responseTimeout?: number; /** * Override the component's strings. */ overrides?: Partial<GlobalOverrides & AiComposerOverrides & AiChatMessageOverrides & AiChatOverrides>; /** * Override the component's components. */ components?: Partial<GlobalComponents & AiChatComponents>; } declare const AiChat: react.ForwardRefExoticComponent<Omit<AiChatProps, "ref"> & react.RefAttributes<HTMLDivElement>>; interface AiToolProps extends Omit<ComponentProps<"div">, "title" | "children"> { /** * The tool's title. * * By default, a human-readable version of the tool's name is used: * - `"showTodo"` → "Show todo" * - `"get_weather"` → "Get weather" */ title?: ReactNode; /** * An optional icon displayed next to the title. */ icon?: ReactNode; /** * The content shown in the tool. */ children?: ReactNode; /** * The visual appearance of the tool. */ variant?: "block" | "minimal"; /** * Whether the content is currently collapsed. * It is not a traditional controlled value, as in if you set it to `true` it would only stay expanded. * Instead, it is "semi-controlled", meaning that setting it to `true` will expand it, but it * can still be collapsed/expanded by clicking on it. */ collapsed?: boolean; /** * The event handler called when the content is collapsed or expanded by clicking on it. */ onCollapsedChange?: (collapsed: boolean) => void; /** * Whether the content can be collapsed/expanded. * If set to `false`, clicking on it will have no effect. * If there's no content, this prop has no effect. */ collapsible?: boolean; } type AiToolIconProps = ComponentProps<"div">; type AiToolInspectorProps = ComponentProps<"div">; interface AiToolConfirmationProps<A extends JsonObject, R extends JsonObject> extends ComponentProps<"div"> { /** * The callback invoked when the user clicks the confirm button. */ confirm: AiToolExecuteCallback<A, R>; /** * The callback invoked when the user clicks the cancel button. */ cancel?: AiToolExecuteCallback<A, R>; /** * The visual appearance. */ variant?: "default" | "destructive"; /** * Override the component's strings. */ overrides?: Partial<GlobalOverrides & AiToolConfirmationOverrides>; /** * The tool's result type, to be used with the `types` prop in the `render` method. * * @example * defineAiTool<{ value: number }>()({ * // ... * render: ({ types }) => ( * <AiTool.Confirmation * types={types} * confirm={() => { * return { * // Using `types` makes the result type-safe * // based on the tool's definition * data: { value: 123 }, * }; * }} * /> * ), * }) */ types?: NoInfr<AiToolTypePack<A, R>>; } declare function AiToolIcon({ className, ...props }: AiToolIconProps): react_jsx_runtime.JSX.Element; declare function AiToolInspector({ className, ...props }: AiToolInspectorProps): react_jsx_runtime.JSX.Element; declare function AiToolConfirmation<TPack extends AiToolTypePack, A extends JsonObject = TPack["A"], R extends JsonObject = TPack["R"]>({ children, variant, confirm, cancel, overrides, className, ...props }: AiToolConfirmationProps<A, R>): react_jsx_runtime.JSX.Element | null; /** * A pre-built component which displays a tool call. * * By default, a human-readable version of the tool's name is used as a title: * - `"showTodo"` → "Show todo" * - `"get_weather"` → "Get weather" * * @example * defineAiTool()({ * // ... * render: () => ( * <AiTool /> * ), * }) * * It can be customized in various ways: * - adding an icon * - customizing the title (even dynamically) * - adding custom content inside it * - collapsing it conditionally * - etc. * * @example * defineAiTool()({ * // ... * render: ({ stage, result }) => ( * <AiTool * icon="🔍" * * // Override the default title based on the tool's stage * title={stage === "executing" ? "Searching…" : "Search results"} * * // Start open and automatically collapse after it is executed * // The user can still expand/collapse it manually at any time * collapsed={stage === "executed"} * > * <SearchResults data={result.data} /> * </AiTool> * ), * }) * * It also comes with a few built-in sub-components: * - `AiTool.Confirmation` to display a human-in-the-loop confirmation step * which can be accepted or cancelled by the user. * - `AiTool.Inspector` to display the tool's arguments and result which can * be useful during development. * * @example * defineAiTool()({ * // ... * render: () => ( * <AiTool> * <AiTool.Confirmation * // Use a destructive visual appearance * variant="destructive" * * // The tool's arguments can be directly accessed like in `execute` * confirm={({ pageIds }) => { * const deletedPageTitles = pages * .filter((p) => pageIds.includes(p.id)) * .map((page) => page.title); * * deletePages(pageIds); * * // This result will be available as `result` in the tool's `render` props * return { data: { deletedPageTitles } }; * }} * * // If needed, `cancel={() => ...}` would work similarly * > * Do you want to delete these pages? * <PagesPreviews /> * </AiTool.Confirmation> * </AiTool> * ), * }) * * @example * defineAiTool()({ * // ... * render: () => ( * <AiTool> * <AiTool.Inspector /> * </AiTool> * ), * }) */ declare const AiTool: react.ForwardRefExoticComponent<Omit<AiToolProps, "ref"> & react.RefAttributes<HTMLDivElement>> & { /** * Display an icon in a container. * * @example * <AiTool * icon={ * <AiTool.Icon>🔍</AiTool.Icon> * } * /> */ Icon: typeof AiToolIcon; /** * Display the tool's arguments and result, which can be useful during * development. * * @example * <AiTool> * <AiTool.Inspector /> * </AiTool> */ Inspector: typeof AiToolInspector; /** * Display a human-in-the-loop confirmation step which can be accepted * or cancelled by the user. * * The `confirm` and `cancel` callbacks work like `execute` in tool definitions: they can * perform side-effects, be async if needed, and return a result. The tool call will stay * pending until either `confirm` or `cancel` is called. * * @example * <AiTool> * <AiTool.Confirmation * // Use a destructive visual appearance * variant="destructive" * * // The tool's arguments can be directly accessed like in `execute` * confirm={({ pageIds }) => { * const deletedPageTitles = pages * .filter((p) => pageIds.includes(p.id)) * .map((page) => page.title); * * deletePages(pageIds); * * // This result will be available as `result` in the tool's `render` props * return { data: { deletedPageTitles } }; * }} * * // If needed, `cancel={() => ...}` would work similarly * > * Do you want to delete these pages? * <PagesPreviews /> * </AiTool.Confirmation> * </AiTool> */ Confirmation: typeof AiToolConfirmation; }; interface ComposerEditorMentionProps { /** * Whether the mention is selected. */ isSelected: boolean; /** * The mention to display. */ mention: MentionData; } interface ComposerEditorLinkProps { /** * The link's absolute URL. * * @example "https://example.com" */ href: string; /** * The link's content. * * @example "www.example.com", "a link", etc. */ children: ReactNode; } type ComposerEditorMentionSuggestionsProps = { /** * The list of mention suggestions. */ mentions: MentionData[]; /** * The currently selected mention's ID. */ selectedMentionId?: string; }; type ComposerEditorFloatingToolbarProps = Record<string, never>; interface ComposerEditorComponents { /** * The component used to display mentions. */ Mention: ComponentType<ComposerEditorMentionProps>; /** * The component used to display mention suggestions. */ MentionSuggestions: ComponentType<ComposerEditorMentionSuggestionsProps>; /** * The component used to display links. */ Link: ComponentType<ComposerEditorLinkProps>; /** * The component used to display a floating toolbar attached to the selection. */ FloatingToolbar?: ComponentType<ComposerEditorFloatingToolbarProps>; } interface ComposerEditorProps extends Omit<ComponentPropsWithoutRef<"div">, "defaultValue" | "children"> { /** * The reading direction of the editor and related elements. */ dir?: Direction; /** * The editor's initial value. */ defaultValue?: CommentBody; /** * The text to display when the editor is empty. */ placeholder?: string; /** * Whether the editor is disabled. */ disabled?: boolean; /** * Whether to focus the editor on mount. */ autoFocus?: boolean; /** * The components displayed within the editor. */ components?: Partial<ComposerEditorComponents>; } interface ComposerFormProps extends ComponentPropsWithSlot<"form"> { /** * The event handler called when the form is submitted. */ onComposerSubmit?: (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => Promise<void> | void; /** * Whether the composer is disabled. */ disabled?: boolean; /** * The composer's initial attachments. */ defaultAttachments?: CommentAttachment[]; /** * Whether to create attachments when pasting files into the editor. */ pasteFilesAsAttachments?: boolean; /** * Whether to blur the editor when the form is submitted. */ blurOnSubmit?: boolean; /** * When `preventUnsavedChanges` is set on your Liveblocks client (or set on * <LiveblocksProvider>), then closing a browser tab will be prevented when * there are unsaved changes. * * By default, that will include draft texts or attachments that are (being) * uploaded via this composer, but not submitted yet. * * If you want to prevent unsaved changes with Liveblocks, but not for this * composer, you can opt-out this composer instance by setting this prop to * `false`. */ preventUnsavedChanges?: boolean; } interface ComposerSubmitComment { /** * The submitted comment's body. */ body: CommentBody; /** * The submitted comment's uploaded attachments. */ attachments: CommentAttachment[]; } type ComposerCreateThreadProps<M extends BaseMetadata> = { threadId?: never; commentId?: never; /** * The metadata of the thread to create. */ metadata?: M; }; type ComposerCreateCommentProps = { /** * The ID of the thread to reply to. */ threadId: string; commentId?: never; metadata?: never; }; type ComposerEditCommentProps = { /** * The ID of the thread to edit a comment in. */ threadId: string; /** * The ID of the comment to edit. */ commentId: string; metadata?: never; }; type ComposerProps<M extends BaseMetadata = DM> = Omit<ComponentPropsWithoutRef<"form">, "defaultValue"> & (ComposerCreateThreadProps<M> | ComposerCreateCommentProps | ComposerEditCommentProps) & { /** * The event handler called when the composer is submitted. */ onComposerSubmit?: (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => Promise<void> | void; /** * The composer's initial value. */ defaultValue?: ComposerEditorProps["defaultValue"]; /** * The composer's initial attachments. */ defaultAttachments?: CommentAttachment[]; /** * Whether the composer is collapsed. Setting a value will make the composer controlled. */ collapsed?: boolean; /** * The event handler called when the collapsed state of the composer changes. */ onCollapsedChange?: (collapsed: boolean) => void; /** * Whether the composer is initially collapsed. Setting a value will make the composer uncontrolled. */ defaultCollapsed?: boolean; /** * Whether to show and allow adding attachments. */ showAttachments?: boolean; /** * Whether to show formatting controls (e.g. a floating toolbar with formatting toggles when selecting text) */ showFormattingControls?: boolean; /** * Whether the composer is disabled. */ disabled?: ComposerFormProps["disabled"]; /** * Whether to focus the composer on mount. */ autoFocus?: ComposerEditorProps["autoFocus"]; /** * Whether to blur the composer editor when the composer is submitted. */ blurOnSubmit?: boolean; /** * Override the component's strings. */ overrides?: Partial<GlobalOverrides & ComposerOverrides>; }; /** * Displays a composer to create comments. * * @example * <Composer /> */ declare const Composer: <M extends BaseMetadata = DM>(props: ComposerProps<M> & RefAttributes<HTMLFormElement>) => JSX.Element; interface CommentProps extends ComponentPropsWithoutRef<"div"> { /** * The comment to display. */ comment: CommentData; /** * How to show or hide the actions. */ showActions?: boolean | "hover"; /** * Whether to show the comment if it was deleted. If set to `false`, it will render deleted comments as `null`. */ showDeleted?: boolean; /** * Whether to show reactions. */ showReactions?: boolean; /** * Whether to show attachments. */ showAttachments?: boolean; /** * Whether to show the composer's formatting controls when editing the comment. */ showComposerFormattingControls?: ComposerProps["showFormattingControls"]; /** * Whether to indent the comment's content. */ indentContent?: boolean; /** * The event handler called when the comment is edited. */ onCommentEdit?: (comment: CommentData) => void; /** * The event handler called when the comment is deleted. */ onCommentDelete?: (comment: CommentData) => void; /** * The event handler called when clicking on the author. */ onAuthorClick?: (userId: string, event: MouseEvent<HTMLElement>) => void; /** * The event handler called when clicking on a mention. */ onMentionClick?: (mention: MentionData, event: MouseEvent<HTMLElement>) => void; /** * The event handler called when clicking on a comment's attachment. */ onAttachmentClick?: (args: CommentAttachmentArgs, event: MouseEvent<HTMLElement>) => void; /** * Add (or change) items to display in the comment's dropdown. */ dropdownItems?: ReactNode | ((props: PropsWithChildren<{ comment: CommentData; }>) => ReactNode); /** * Override the component's strings. */ overrides?: Partial<GlobalOverrides & CommentOverrides & ComposerOverrides>; /** * Override the component's components. */ components?: Partial<GlobalComponents>; } interface CommentDropdownItemProps extends Omit<ComponentPropsWithoutRef<"div">, "onSelect"> { /** * An optional icon displayed in this dropdown item. */ icon?: ReactNode; /** * The event handler called when the dropdown item is selected. */ onSelect?: (event: Event) => void; } /** * Displays a single comment. * * @example * <> * {thread.comments.map((comment) => ( * <Comment key={comment.id} comment={comment} /> * ))} * </> */ declare const Comment: react.ForwardRefExoticComponent<CommentProps & react.RefAttributes<HTMLDivElement>> & { /** * Displays a dropdown item in the comment's dropdown. */ DropdownItem: react.ForwardRefExoticComponent<CommentDropdownItemProps & react.RefAttributes<HTMLDivElement>>; }; interface HistoryVersionSummaryProps extends ComponentPropsWithoutRef<"button"> { version: HistoryVersion; selected?: boolean; } /** * Displays some information about a version. * * @example * <HistoryVersionSummary version={version} /> */ declare const HistoryVersionSummary: react.ForwardRefExoticComponent<HistoryVersionSummaryProps & react.RefAttributes<HTMLButtonElement>>; type HistoryVersionSummaryListProps = ComponentPropsWithoutRef<"ol">; /** * Displays versions summaries as a list. * * @example * <HistoryVersionSummaryList> * {versions.map((version) => ( * <HistoryVersionSummary key={version.id} version={version} /> * ))} * </HistoryVersionSummaryList> */ declare const HistoryVersionSummaryList: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>, "ref"> & react.RefAttributes<HTMLOListElement>>; type ComponentTypeWithRef<T extends keyof JSX.IntrinsicElements, P> = ComponentType<P & Pick<ComponentProps<T>, "ref">>; type InboxNotificationKinds<KS extends KDAD = KDAD> = { [K in KS]: ComponentTypeWithRef<"a", InboxNotificationCustomKindProps<K>>; } & { thread: ComponentTypeWithRef<"a", InboxNotificationThreadKindProps>; textMention: ComponentTypeWithRef<"a", InboxNotificationTextMentionKindProps>; }; interface InboxNotificationSharedProps { /** * How to show or hide the actions. */ showActions?: boolean | "hover"; } interface InboxNotificationProps extends Omit<ComponentPropsWithoutRef<"a">, "title">, InboxNotificationSharedProps { /** * The inbox notification to display. */ inboxNotification: InboxNotificationData; /** * Override specific kinds of inbox notifications. */ kinds?: Partial<InboxNotificationKinds>; /** * Override the component's strings. */ overrides?: Partial<GlobalOverrides & InboxNotificationOverrides & ThreadOverrides & CommentOverrides>; /** * Override the component's components. */ components?: Partial<GlobalComponents>; } interface InboxNotificationThreadProps extends Omit<InboxNotificationProps, "kinds" | "children">, InboxNotificationSharedProps { /** * The inbox notification to display. */ inboxNotification: InboxNotificationThreadData; /** * Whether to show the room name in the title. */ showRoomName?: boolean; /** * Whether to show reactions. */ showReactions?: boolean; /** * Whether to show attachments. */ showAttachments?: boolean; } interface InboxNotificationTextMentionProps extends Omit<InboxNotificationProps, "kinds">, InboxNotificationSharedProps { /** * The inbox notification to display. */ inboxNotification: InboxNotificationTextMentionData; /** * Whether to show the room name in the title. */ showRoomName?: boolean; } interface InboxNotificationInspectorProps extends Omit<InboxNotificationProps, "kinds" | "children">, InboxNotificationSharedProps { /** * The inbox notification to display. */ inboxNotification: InboxNotificationData; } interface InboxNotificationCustomProps extends Omit<InboxNotificationProps, "kinds">, InboxNotificationSharedProps, SlotProp { /** * The inbox notification to display. */ inboxNotification: InboxNotificationCustomData; /** * The inbox notification's content. */ children: ReactNode; /** * The inbox notification's title. */ title: ReactNode; /** * The inbox notification's aside content. * Can be combined with `InboxNotification.Icon` or `InboxNotification.Avatar` to easily follow default styles. */ aside?: ReactNode; /** * Whether to mark the inbox notification as read when clicked. */ markAsReadOnClick?: boolean; } type InboxNotificationThreadKindProps = Omit<InboxNotificationProps, "kinds"> & { inboxNotification: InboxNotificationThreadData; }; type InboxNotificationTextMentionKindProps = Omit<InboxNotificationProps, "kinds"> & { inboxNotification: InboxNotificationTextMentionData; }; type InboxNotificationCustomKindProps<K extends KDAD = KDAD> = Omit<InboxNotificationProps, "kinds"> & { inboxNotification: InboxNotificationCustomData<K>; }; type InboxNotificationIconProps = ComponentProps<"div">; interface InboxNotificationAvatarProps extends ComponentProps<"div"> { /** * The user ID to display the avatar for. */ userId: string; } declare function InboxNotificationIcon({ className, ...props }: InboxNotificationIconProps): react_jsx_runtime.JSX.Element; declare function InboxNotificationAvatar({ className, ...props }: InboxNotificationAvatarProps): react_jsx_runtime.JSX.Element; /** * Displays a single inbox notification. * * @example * <> * {inboxNotifications.map((inboxNotification) => ( * <InboxNotification * key={inboxNotification.id} * inboxNotification={inboxNotification} * href={`/rooms/${inboxNotification.roomId}` * /> * ))} * </> */ declare const InboxNotification: react.ForwardRefExoticComponent<InboxNotificationProps & react.RefAttributes<HTMLAnchorElement>> & { /** * Displays a thread inbox notification kind. */ Thread: react.ForwardRefExoticComponent<InboxNotificationThreadProps & react.RefAttributes<HTMLAnchorElement>>; /** * Displays a text mention inbox notification kind. */ TextMention: react.ForwardRefExoticComponent<InboxNotificationTextMentionProps & react.RefAttributes<HTMLAnchorElement>>; /** * Displays a custom inbox notification kind. */ Custom: react.ForwardRefExoticComponent<InboxNotificationCustomProps & react.RefAttributes<HTMLAnchorElement>>; /** * Display the inbox notification's data, which can be useful during development. * * @example * <InboxNotification * inboxNotification={inboxNotification} * kinds={{ * $custom: InboxNotification.Inspector, * }} * /> */ Inspector: react.ForwardRefExoticComponent<InboxNotificationInspectorProps & react.RefAttributes<HTMLAnchorElement>>; Icon: typeof InboxNotificationIcon; Avatar: typeof InboxNotificationAvatar; }; interface InboxNotificationListProps extends ComponentPropsWithoutRef<"ol"> { /** * This API is *EXPERIMENTAL* and likely not going to be the final API. Do * not rely on it. * * @private */ onReachEnd?: () => void; } /** * Displays inbox notifications as a list. * * @example * <InboxNotificationList> * {inboxNotifications.map((inboxNotification) => ( * <InboxNotification key={inboxNotification.id} inboxNotification={inboxNotification} /> * ))} * </InboxNotificationList> */ declare const InboxNotificationList: react.ForwardRefExoticComponent<InboxNotificationListProps & react.RefAttributes<HTMLOListElement>>; interface ThreadProps<M extends BaseMetadata = DM> extends ComponentPropsWithoutRef<"div"> { /** * The thread to display. */ thread: ThreadData<M>; /** * How to show or hide the composer to reply to the thread. */ showComposer?: boolean | "collapsed"; /** * Whether to show the action to resolve the thread. */ showResolveAction?: boolean; /** * How to show or hide the actions. */ showActions?: CommentProps["showActions"]; /** * Whether to show reactions. */ showReactions?: CommentProps["showReactions"]; /** * Whether to show the composer's formatting controls. */ showComposerFormattingControls?: ComposerProps["showFormattingControls"]; /** * Add (or change) items to display in a comment's dropdown. */ commentDropdownItems?: ReactNode | ((props: PropsWithChildren<{ comment: CommentData; }>) => ReactNode); /** * The maximum number of comments to show. * * The first and last comments are always shown and by default if some comments * are hidden, only the first comment will be shown before the "show more" button * and after it will be shown all the newest comments to fit the limit set. * * It's possible to customize this by setting `maxVisibleComments` to an object: * * @example * // Only show the last comment, and all the older ones to fit the limit. * <Thread maxVisibleComments={{ max: 5, show: "oldest" }} /> * * @example * // Show as many old comments as new ones to fit the limit. * <Thread maxVisibleComments={{ max: 5, show: "both" }} /> */ maxVisibleComments?: number | { max: number; show: "oldest" | "both" | "newest"; }; /** * Whether to blur the composer editor when the composer is submitted. */ blurComposerOnSubmit?: ComposerProps["blurOnSubmit"]; /** * Whether to indent the comments' content. */ indentCommentContent?: CommentProps["indentContent"]; /** * Whether to show deleted comments. */ showDeletedComments?: CommentProps["showDeleted"]; /** * Whether to show attachments. */ showAttachments?: boolean; /** * The event handler called when changing the resolved status. */ onResolvedChange?: (resolved: boolean) => void; /** * The event handler called when a comment is edited. */ onCommentEdit?: CommentProps["onCommentEdit"]; /** * The event handler called when a comment is deleted. */ onCommentDelete?: CommentProps["onCommentDelete"]; /** * The event handler called when the thread is deleted. * A thread is deleted when all its comments are deleted. */ onThreadDelete?: (thread: ThreadData<M>) => void; /** * The event handler called when clicking on a comment's author. */ onAuthorClick?: CommentProps["onAuthorClick"]; /** * The event handler called when clicking on a mention. */ onMentionClick?: CommentProps["onMentionClick"]; /** * The event handler called when clicking on a comment's attachment. */ onAttachmentClick?: CommentProps["onAttachmentClick"]; /** * The event handler called when the composer is submitted. */ onComposerSubmit?: ComposerProps["onComposerSubmit"]; /** * Override the component's strings. */ overrides?: Partial<GlobalOverrides & ThreadOverrides & CommentOverrides & ComposerOverrides>; /** * Override the component's components. */ components?: Partial<GlobalComponents>; } /** * Displays a thread of comments, with a composer to reply * to it. * * @example * <> * {threads.map((thread) => ( * <Thread key={thread.id} thread={thread} /> * ))} * </> */ declare const Thread: <M extends BaseMetadata = DM>(props: ThreadProps<M> & RefAttributes<HTMLDivElement>) => JSX.Element; type LiveblocksUiConfigProps = PropsWithChildren<{ /** * Override the components' strings. */ overrides?: Partial<Overrides>; /** * Override the components' components. */ components?: Partial<Components>; /** * The container to render the portal into. */ portalContainer?: HTMLElement; /** * When `preventUnsavedChanges` is set on your Liveblocks client (or set on * <LiveblocksProvider>), then closing a browser tab will be prevented when * there are unsaved changes. * * By default, that will include draft texts or attachments that are (being) * uploaded via comments/threads composers, but not submitted yet. * * If you want to prevent unsaved changes with Liveblocks, but not for * composers, you can opt-out by setting this option to `false`. */ preventUnsavedComposerChanges?: boolean; /** * The Liveblocks emoji picker (visible when adding reactions in `Comment`) is built with * {@link https://github.com/liveblocks/frimousse | Frimousse}, which fetches its data from * {@link https://emojibase.dev/docs/datasets/ | Emojibase}. * * This option allows you to change the base URL of where the {@link https://www.npmjs.com/package/emojibase-data | `emojibase-data`} * files should be fetched from, used as follows: `${emojibaseUrl}/${locale}/${file}.json`. * (e.g. `${emojibaseUrl}/en/data.json`). * * @example "https://unpkg.com/emojibase-data" * * @example "https://example.com/self-hosted-emojibase-data" */ emojibaseUrl?: string; }>; /** * Set configuration options for all components. * * @example * <LiveblocksUiConfig overrides={{ locale: "fr", USER_UNKNOWN: "Anonyme", ... }}> * <App /> * </LiveblocksUiConfig> */ declare function LiveblocksUiConfig({ overrides, components, portalContainer, preventUnsavedComposerChanges, emojibaseUrl, children, }: LiveblocksUiConfigProps): react_jsx_runtime.JSX.Element; declare function ArrowCornerDownRightIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ArrowCornerUpRightIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ArrowDownIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ArrowUpIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function AttachmentIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function BellIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function BellCrossedIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function BlockquoteIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function BoldIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function CheckIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function CheckCircleIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ChevronDownIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ChevronLeftIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ChevronRightIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ChevronUpIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function CodeIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function CommentIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function CopyIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function CrossIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function EllipsisIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function EmojiIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function EmojiPlusIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function GlobeIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function H1Icon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function H2Icon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function H3Icon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ItalicIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function LengthenIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ListOrderedIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ListUnorderedIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function MentionIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function QuestionMarkIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function RedoIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function RetryIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function SearchIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function SendIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function ShortenIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function SparklesIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function SparklesTextIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element; declare function StopIcon(pro