@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,546 lines (1,480 loc) • 50.7 kB
text/typescript
import * as react from 'react';
import { ComponentType, ComponentPropsWithoutRef, ElementType, ReactNode, FormEvent, ComponentProps, RefAttributes, MouseEvent, PropsWithChildren } from 'react';
import { CommentAttachment, AiReasoningPart, AiRetrievalPart, Relax, 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
* 
* ```
* ```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;
}
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;
}
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";
/**
* 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?: string;
/**
* 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;
/**
* Override the component's strings.
*/
overrides?: Partial<GlobalOverrides & CommentOverrides & ComposerOverrides>;
/**
* Override the component's components.
*/
components?: Partial<GlobalComponents>;
}
/**
* Displays a single comment.
*
* @example
* <>
* {thread.comments.map((comment) => (
* <Comment key={comment.id} comment={comment} />
* ))}
* </>
*/
declare const Comment: react.ForwardRefExoticComponent<CommentProps & 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"];
/**
* 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 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(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
declare function StrikethroughIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
declare function TextIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
declare function TranslateIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
declare function UnderlineIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
declare function UndoIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
declare function UserIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
declare function UsersIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
declare function WarningIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
declare namespace icon {
export {
ArrowCornerDownRightIcon as ArrowCornerDownRight,
ArrowCornerUpRightIcon as ArrowCornerUpRight,
ArrowDownIcon as ArrowDown,
ArrowUpIcon as ArrowUp,
AttachmentIcon as Attachment,
BellIcon as Bell,
BellCrossedIcon as BellCrossed,
BlockquoteIcon as Blockquote,
BoldIcon as Bold,
CheckIcon as Check,
CheckCircleIcon as CheckCircle,
ChevronDownIcon as ChevronDown,
ChevronLeftIcon as ChevronLeft,
ChevronRightIcon as ChevronRight,
ChevronUpIcon as ChevronUp,
CodeIcon as Code,
CommentIcon as Comment,
CopyIcon as Copy,
CrossIcon as Cross,
EllipsisIcon as Ellipsis,
EmojiIcon as Emoji,
EmojiPlusIcon as EmojiPlus,
H1Icon as H1,
H2Icon as H2,
H3Icon as H3,
ItalicIcon as Italic,
LengthenIcon as Lengthen,
ListOrderedIcon as ListOrdered,
ListUnorderedIcon as ListUnordered,
MentionIcon as Mention,
QuestionMarkIcon as QuestionMark,
RedoIcon as Redo,
RetryIcon as Retry,
SearchIcon as Search,
SendIcon as Send,
ShortenIcon as Shorten,
SparklesIcon as Sparkles,
SparklesTextIcon as SparklesText,
StopIcon as Stop,
StrikethroughIcon as Strikethrough,
TextIcon as Text,
TranslateIcon as Translate,
UnderlineIcon as Underline,
UndoIcon as Undo,
UserIcon as User,
UsersIcon as Users,
WarningIcon as Warning,
};
}
export { AiChat, AiChatComponents, AiChatComponentsEmptyProps, AiChatComponentsLoadingProps, AiChatProps, AiComposerSubmitMessage, AiTool, AiToolIconProps, AiToolProps, Comment, CommentAttachmentArgs, CommentOverrides, CommentProps, Composer, ComposerBodyMark, ComposerBodyMarks, ComposerOverrides, ComposerProps, ComposerSubmitComment, GlobalOverrides, Histo