@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
TypeScript
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
* 
* ```
* ```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