@liveblocks/react-ui 3.5.3 → 3.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_private/index.d.cts +0 -4
- package/dist/_private/index.d.ts +0 -4
- package/dist/components/Thread.cjs.map +1 -1
- package/dist/components/Thread.js.map +1 -1
- package/dist/components/internal/AiChatAssistantMessage.cjs +9 -29
- package/dist/components/internal/AiChatAssistantMessage.cjs.map +1 -1
- package/dist/components/internal/AiChatAssistantMessage.js +10 -30
- package/dist/components/internal/AiChatAssistantMessage.js.map +1 -1
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/overrides.cjs +1 -42
- package/dist/overrides.cjs.map +1 -1
- package/dist/overrides.js +1 -42
- package/dist/overrides.js.map +1 -1
- package/dist/primitives/AiMessage/index.cjs +1 -7
- package/dist/primitives/AiMessage/index.cjs.map +1 -1
- package/dist/primitives/AiMessage/index.js +1 -7
- package/dist/primitives/AiMessage/index.js.map +1 -1
- package/dist/primitives/AiMessage/tool-invocation.cjs.map +1 -1
- package/dist/primitives/AiMessage/tool-invocation.js.map +1 -1
- package/dist/primitives/Timestamp.cjs +3 -4
- package/dist/primitives/Timestamp.cjs.map +1 -1
- package/dist/primitives/Timestamp.js +4 -4
- package/dist/primitives/Timestamp.js.map +1 -1
- package/dist/primitives/index.cjs +0 -2
- package/dist/primitives/index.cjs.map +1 -1
- package/dist/primitives/index.d.cts +4 -59
- package/dist/primitives/index.d.ts +4 -59
- package/dist/primitives/index.js +0 -1
- package/dist/primitives/index.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
- package/src/styles/index.css +2 -20
- package/styles.css +1 -1
- package/styles.css.map +1 -1
- package/dist/primitives/Duration.cjs +0 -195
- package/dist/primitives/Duration.cjs.map +0 -1
- package/dist/primitives/Duration.js +0 -192
- package/dist/primitives/Duration.js.map +0 -1
|
@@ -620,10 +620,6 @@ interface AiMessageContentComponents {
|
|
|
620
620
|
* The component used to display reasoning parts.
|
|
621
621
|
*/
|
|
622
622
|
ReasoningPart: ComponentType<AiMessageContentReasoningPartProps>;
|
|
623
|
-
/**
|
|
624
|
-
* The component used to display knowledge retrieval parts.
|
|
625
|
-
*/
|
|
626
|
-
RetrievalPart: ComponentType<AiMessageContentRetrievalPartProps>;
|
|
627
623
|
}
|
|
628
624
|
interface AiMessageContentProps extends ComponentPropsWithSlot<"div"> {
|
|
629
625
|
/**
|
package/dist/_private/index.d.ts
CHANGED
|
@@ -620,10 +620,6 @@ interface AiMessageContentComponents {
|
|
|
620
620
|
* The component used to display reasoning parts.
|
|
621
621
|
*/
|
|
622
622
|
ReasoningPart: ComponentType<AiMessageContentReasoningPartProps>;
|
|
623
|
-
/**
|
|
624
|
-
* The component used to display knowledge retrieval parts.
|
|
625
|
-
*/
|
|
626
|
-
RetrievalPart: ComponentType<AiMessageContentRetrievalPartProps>;
|
|
627
623
|
}
|
|
628
624
|
interface AiMessageContentProps extends ComponentPropsWithSlot<"div"> {
|
|
629
625
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Thread.cjs","sources":["../../src/components/Thread.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type BaseMetadata,\n type CommentData,\n type DM,\n Permission,\n type ThreadData,\n} from \"@liveblocks/core\";\nimport { findLastIndex } from \"@liveblocks/core\";\nimport {\n useMarkRoomThreadAsResolved,\n useMarkRoomThreadAsUnresolved,\n useRoomPermissions,\n useRoomThreadSubscription,\n} from \"@liveblocks/react/_private\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport type {\n ComponentPropsWithoutRef,\n ForwardedRef,\n RefAttributes,\n SyntheticEvent,\n} from \"react\";\nimport {\n forwardRef,\n Fragment,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { ArrowDownIcon } from \"../icons/ArrowDown\";\nimport { BellIcon } from \"../icons/Bell\";\nimport { BellCrossedIcon } from \"../icons/BellCrossed\";\nimport { CheckCircleIcon } from \"../icons/CheckCircle\";\nimport { CheckCircleFillIcon } from \"../icons/CheckCircleFill\";\nimport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n ThreadOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { cn } from \"../utils/cn\";\nimport type { CommentProps } from \"./Comment\";\nimport { Comment } from \"./Comment\";\nimport type { ComposerProps } from \"./Composer\";\nimport { Composer } from \"./Composer\";\nimport { Button } from \"./internal/Button\";\nimport { DropdownItem } from \"./internal/Dropdown\";\nimport { Tooltip, TooltipProvider } from \"./internal/Tooltip\";\n\nexport interface ThreadProps<M extends BaseMetadata = DM>\n extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The thread to display.\n */\n thread: ThreadData<M>;\n\n /**\n * How to show or hide the composer to reply to the thread.\n */\n showComposer?: boolean | \"collapsed\";\n\n /**\n * Whether to show the action to resolve the thread.\n */\n showResolveAction?: boolean;\n\n /**\n * How to show or hide the actions.\n */\n showActions?: CommentProps[\"showActions\"];\n\n /**\n * Whether to show reactions.\n */\n showReactions?: CommentProps[\"showReactions\"];\n\n /**\n * Whether to show the composer's formatting controls.\n */\n showComposerFormattingControls?: ComposerProps[\"showFormattingControls\"];\n\n /**\n * The maximum number of comments to show.\n *\n * The first and last comments are always shown and by default if some comments\n * are hidden, only the first comment will be shown before the \"show more\" button\n * and after it will be shown all the newest comments to fit the limit set.\n *\n * It's possible to customize this by setting `maxVisibleComments` to an object:\n *\n * @example\n * // Only show the last comment, and all the older ones to fit the limit.\n * <Thread maxVisibleComments={{ max: 5, show: \"oldest\" }} />\n *\n * @example\n * // Show as many old comments as new ones to fit the limit.\n * <Thread maxVisibleComments={{ max: 5, show: \"both\" }} />\n */\n maxVisibleComments?:\n | number\n | { max: number; show: \"oldest\" | \"both\" | \"newest\" };\n\n /**\n * Whether to blur the composer editor when the composer is submitted.\n */\n blurComposerOnSubmit?: ComposerProps[\"blurOnSubmit\"];\n\n /**\n * Whether to indent the comments' content.\n */\n indentCommentContent?: CommentProps[\"indentContent\"];\n\n /**\n * Whether to show deleted comments.\n */\n showDeletedComments?: CommentProps[\"showDeleted\"];\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n\n /**\n * The event handler called when changing the resolved status.\n */\n onResolvedChange?: (resolved: boolean) => void;\n\n /**\n * The event handler called when a comment is edited.\n */\n onCommentEdit?: CommentProps[\"onCommentEdit\"];\n\n /**\n * The event handler called when a comment is deleted.\n */\n onCommentDelete?: CommentProps[\"onCommentDelete\"];\n\n /**\n * The event handler called when the thread is deleted.\n * A thread is deleted when all its comments are deleted.\n */\n onThreadDelete?: (thread: ThreadData<M>) => void;\n\n /**\n * The event handler called when clicking on a comment's author.\n */\n onAuthorClick?: CommentProps[\"onAuthorClick\"];\n\n /**\n * The event handler called when clicking on a mention.\n */\n onMentionClick?: CommentProps[\"onMentionClick\"];\n\n /**\n * The event handler called when clicking on a comment's attachment.\n */\n onAttachmentClick?: CommentProps[\"onAttachmentClick\"];\n\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: ComposerProps[\"onComposerSubmit\"];\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides & ThreadOverrides & CommentOverrides & ComposerOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\n/**\n * Displays a thread of comments, with a composer to reply\n * to it.\n *\n * @example\n * <>\n * {threads.map((thread) => (\n * <Thread key={thread.id} thread={thread} />\n * ))}\n * </>\n */\nexport const Thread = forwardRef(\n <M extends BaseMetadata = DM>(\n {\n thread,\n indentCommentContent = true,\n showActions = \"hover\",\n showDeletedComments,\n showResolveAction = true,\n showReactions = true,\n showComposer = \"collapsed\",\n showAttachments = true,\n showComposerFormattingControls = true,\n maxVisibleComments,\n onResolvedChange,\n onCommentEdit,\n onCommentDelete,\n onThreadDelete,\n onAuthorClick,\n onMentionClick,\n onAttachmentClick,\n onComposerSubmit,\n blurComposerOnSubmit,\n overrides,\n components,\n className,\n ...props\n }: ThreadProps<M>,\n forwardedRef: ForwardedRef<HTMLDivElement>\n ) => {\n const markThreadAsResolved = useMarkRoomThreadAsResolved(thread.roomId);\n const markThreadAsUnresolved = useMarkRoomThreadAsUnresolved(thread.roomId);\n const $ = useOverrides(overrides);\n const [showAllComments, setShowAllComments] = useState(false);\n const firstCommentIndex = useMemo(() => {\n return showDeletedComments\n ? 0\n : thread.comments.findIndex((comment) => comment.body);\n }, [showDeletedComments, thread.comments]);\n const lastCommentIndex = useMemo(() => {\n return showDeletedComments\n ? thread.comments.length - 1\n : findLastIndex(thread.comments, (comment) => Boolean(comment.body));\n }, [showDeletedComments, thread.comments]);\n const hiddenComments = useMemo(() => {\n const maxVisibleCommentsCount =\n typeof maxVisibleComments === \"number\"\n ? maxVisibleComments\n : maxVisibleComments?.max;\n const visibleCommentsShow =\n (typeof maxVisibleComments === \"object\"\n ? maxVisibleComments?.show\n : undefined) ?? \"newest\";\n\n // If we explicitly want to show all comments or there's no limit set,\n // no need to hide any comments.\n if (showAllComments || maxVisibleCommentsCount === undefined) {\n return;\n }\n\n const comments = thread.comments\n .map((comment, index) => ({ comment, index }))\n .filter(({ comment }) => showDeletedComments || comment.body);\n\n // There aren't enough comments so no need to hide any.\n if (comments.length <= Math.max(maxVisibleCommentsCount, 2)) {\n return;\n }\n\n const firstVisibleComment = comments[0]!;\n const lastVisibleComment = comments[comments.length - 1]!;\n\n // Always show the first and last comments even if the limit is set to lower than 2.\n if (maxVisibleCommentsCount <= 2) {\n const firstHiddenCommentIndex =\n comments[1]?.index ?? firstVisibleComment.index;\n const lastHiddenCommentIndex =\n comments[comments.length - 2]?.index ?? lastVisibleComment.index;\n\n return {\n firstIndex: firstHiddenCommentIndex,\n lastIndex: lastHiddenCommentIndex,\n count: comments.slice(1, comments.length - 1).length,\n };\n }\n\n const remainingVisibleCommentsCount = maxVisibleCommentsCount - 2;\n\n // Split the remaining visible comments before, after, or equally.\n const beforeVisibleCommentsCount =\n visibleCommentsShow === \"oldest\"\n ? remainingVisibleCommentsCount\n : visibleCommentsShow === \"newest\"\n ? 0\n : Math.floor(remainingVisibleCommentsCount / 2);\n const afterVisibleCommentsCount =\n visibleCommentsShow === \"oldest\"\n ? 0\n : visibleCommentsShow === \"newest\"\n ? remainingVisibleCommentsCount\n : Math.ceil(remainingVisibleCommentsCount / 2);\n\n // The first comment is always visible so `+ 1` to skip it.\n const firstHiddenComment = comments[1 + beforeVisibleCommentsCount];\n // The last comment is always visible so `- 2` to skip it.\n const lastHiddenComment =\n comments[comments.length - 2 - afterVisibleCommentsCount];\n\n // There aren't any comments to hide besides the first and last ones.\n if (\n !firstHiddenComment ||\n !lastHiddenComment ||\n firstHiddenComment.index > lastHiddenComment.index\n ) {\n return;\n }\n\n return {\n firstIndex: firstHiddenComment.index,\n lastIndex: lastHiddenComment.index,\n count: thread.comments\n .slice(firstHiddenComment.index, lastHiddenComment.index + 1)\n .filter((comment) => showDeletedComments || comment.body).length,\n };\n }, [\n maxVisibleComments,\n showAllComments,\n showDeletedComments,\n thread.comments,\n ]);\n const {\n status: subscriptionStatus,\n unreadSince,\n subscribe,\n unsubscribe,\n } = useRoomThreadSubscription(thread.roomId, thread.id);\n const unreadIndex = useMemo(() => {\n // The user is not subscribed to this thread.\n if (subscriptionStatus !== \"subscribed\") {\n return;\n }\n\n // The user hasn't read the thread yet, so all comments are unread.\n if (unreadSince === null) {\n return firstCommentIndex;\n }\n\n // The user has read the thread, so we find the first unread comment.\n const unreadIndex = thread.comments.findIndex(\n (comment) =>\n (showDeletedComments ? true : comment.body) &&\n comment.createdAt > unreadSince\n );\n\n return unreadIndex >= 0 && unreadIndex < thread.comments.length\n ? unreadIndex\n : undefined;\n }, [\n firstCommentIndex,\n showDeletedComments,\n subscriptionStatus,\n thread.comments,\n unreadSince,\n ]);\n const [newIndex, setNewIndex] = useState<number>();\n const newIndicatorIndex = newIndex === undefined ? unreadIndex : newIndex;\n\n useEffect(() => {\n if (unreadIndex) {\n // Keep the \"new\" indicator at the lowest unread index.\n setNewIndex((persistedUnreadIndex) =>\n Math.min(persistedUnreadIndex ?? Infinity, unreadIndex)\n );\n }\n }, [unreadIndex]);\n\n const permissions = useRoomPermissions(thread.roomId);\n const canComment =\n permissions.size > 0\n ? permissions.has(Permission.CommentsWrite) ||\n permissions.has(Permission.Write)\n : true;\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const handleResolvedChange = useCallback(\n (resolved: boolean) => {\n onResolvedChange?.(resolved);\n\n if (resolved) {\n markThreadAsResolved(thread.id);\n } else {\n markThreadAsUnresolved(thread.id);\n }\n },\n [\n markThreadAsResolved,\n markThreadAsUnresolved,\n onResolvedChange,\n thread.id,\n ]\n );\n\n const handleCommentDelete = useCallback(\n (comment: CommentData) => {\n onCommentDelete?.(comment);\n\n const filteredComments = thread.comments.filter(\n (comment) => comment.body\n );\n\n if (filteredComments.length <= 1) {\n onThreadDelete?.(thread);\n }\n },\n [onCommentDelete, onThreadDelete, thread]\n );\n\n const handleSubscribeChange = useCallback(() => {\n if (subscriptionStatus === \"subscribed\") {\n unsubscribe();\n } else {\n subscribe();\n }\n }, [subscriptionStatus, subscribe, unsubscribe]);\n\n return (\n <TooltipProvider>\n <div\n className={cn(\n \"lb-root lb-thread\",\n showActions === \"hover\" && \"lb-thread:show-actions-hover\",\n className\n )}\n data-resolved={thread.resolved ? \"\" : undefined}\n data-unread={unreadIndex !== undefined ? \"\" : undefined}\n dir={$.dir}\n {...props}\n ref={forwardedRef}\n >\n <div className=\"lb-thread-comments\">\n {thread.comments.map((comment, index) => {\n const isFirstComment = index === firstCommentIndex;\n const isUnread =\n unreadIndex !== undefined && index >= unreadIndex;\n const isHidden =\n hiddenComments &&\n index >= hiddenComments.firstIndex &&\n index <= hiddenComments.lastIndex;\n const isFirstHiddenComment =\n isHidden && index === hiddenComments.firstIndex;\n\n if (isFirstHiddenComment) {\n return (\n <div\n key={`${comment.id}-show-more`}\n className=\"lb-thread-show-more\"\n >\n <Button\n variant=\"ghost\"\n className=\"lb-thread-show-more-button\"\n onClick={() => setShowAllComments(true)}\n >\n {$.THREAD_SHOW_MORE_COMMENTS(hiddenComments.count)}\n </Button>\n </div>\n );\n }\n\n if (isHidden) {\n return null;\n }\n\n const children = (\n <Comment\n key={comment.id}\n overrides={overrides}\n className=\"lb-thread-comment\"\n data-unread={isUnread ? \"\" : undefined}\n comment={comment}\n indentContent={indentCommentContent}\n showDeleted={showDeletedComments}\n showActions={showActions}\n showReactions={showReactions}\n showAttachments={showAttachments}\n showComposerFormattingControls={\n showComposerFormattingControls\n }\n onCommentEdit={onCommentEdit}\n onCommentDelete={handleCommentDelete}\n onAuthorClick={onAuthorClick}\n onMentionClick={onMentionClick}\n onAttachmentClick={onAttachmentClick}\n components={components}\n autoMarkReadThreadId={\n index === lastCommentIndex && isUnread\n ? thread.id\n : undefined\n }\n additionalActionsClassName={\n isFirstComment ? \"lb-thread-actions\" : undefined\n }\n additionalActions={\n isFirstComment && showResolveAction ? (\n <Tooltip\n content={\n thread.resolved\n ? $.THREAD_UNRESOLVE\n : $.THREAD_RESOLVE\n }\n >\n <TogglePrimitive.Root\n pressed={thread.resolved}\n onPressedChange={handleResolvedChange}\n asChild\n >\n <Button\n className=\"lb-comment-action\"\n onClick={stopPropagation}\n aria-label={\n thread.resolved\n ? $.THREAD_UNRESOLVE\n : $.THREAD_RESOLVE\n }\n icon={\n thread.resolved ? (\n <CheckCircleFillIcon />\n ) : (\n <CheckCircleIcon />\n )\n }\n disabled={!canComment}\n />\n </TogglePrimitive.Root>\n </Tooltip>\n ) : null\n }\n additionalDropdownItemsBefore={\n isFirstComment ? (\n <DropdownItem\n onSelect={handleSubscribeChange}\n onClick={stopPropagation}\n icon={\n subscriptionStatus === \"subscribed\" ? (\n <BellCrossedIcon />\n ) : (\n <BellIcon />\n )\n }\n >\n {subscriptionStatus === \"subscribed\"\n ? $.THREAD_UNSUBSCRIBE\n : $.THREAD_SUBSCRIBE}\n </DropdownItem>\n ) : null\n }\n />\n );\n\n return index === newIndicatorIndex &&\n newIndicatorIndex !== firstCommentIndex &&\n newIndicatorIndex <= lastCommentIndex ? (\n <Fragment key={comment.id}>\n <div\n className=\"lb-thread-new-indicator\"\n aria-label={$.THREAD_NEW_INDICATOR_DESCRIPTION}\n >\n <span className=\"lb-thread-new-indicator-label\">\n <ArrowDownIcon className=\"lb-thread-new-indicator-label-icon\" />\n {$.THREAD_NEW_INDICATOR}\n </span>\n </div>\n {children}\n </Fragment>\n ) : (\n children\n );\n })}\n </div>\n {showComposer && (\n <Composer\n className=\"lb-thread-composer\"\n threadId={thread.id}\n defaultCollapsed={showComposer === \"collapsed\" ? true : undefined}\n showAttachments={showAttachments}\n showFormattingControls={showComposerFormattingControls}\n onComposerSubmit={onComposerSubmit}\n blurOnSubmit={blurComposerOnSubmit}\n overrides={{\n COMPOSER_PLACEHOLDER: $.THREAD_COMPOSER_PLACEHOLDER,\n COMPOSER_SEND: $.THREAD_COMPOSER_SEND,\n ...overrides,\n }}\n roomId={thread.roomId}\n />\n )}\n </div>\n </TooltipProvider>\n );\n }\n) as <M extends BaseMetadata = DM>(\n props: ThreadProps<M> & RefAttributes<HTMLDivElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgMO;AAAe;AAElB;AACE;AACuB;AACT;AACd;AACoB;AACJ;AACD;AACG;AACe;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACE;AAEuD;AAEzD;AACE;AAEqE;AAEvE;AACE;AAIA;AAOA;AACE;AAAA;AAGF;AAKA;AACE;AAAA;AAGF;AACA;AAGA;AACE;AAEA;AAGA;AAAO;AACO;AACD;AACmC;AAChD;AAGF;AAGA;AAMA;AAQA;AAEA;AAIA;AAKE;AAAA;AAGF;AAAO;AAC0B;AACF;AAG+B;AAC9D;AACC;AACD;AACA;AACA;AACO;AAET;AAAM;AACI;AACR;AACA;AACA;AAEF;AAEE;AACE;AAAA;AAIF;AACE;AAAO;AAIT;AAAoC;AAGZ;AAGxB;AAEI;AACH;AACD;AACA;AACA;AACO;AACP;AAEF;AACA;AAEA;AACE;AAEE;AAAA;AACwD;AACxD;AACF;AAGF;AACA;AAMA;AACE;AAAsB;AAGxB;AAA6B;AAEzB;AAEA;AACE;AAA8B;AAE9B;AAAgC;AAClC;AACF;AACA;AACE;AACA;AACA;AACO;AACT;AAGF;AAA4B;AAExB;AAEA;AAAyC;AAClB;AAGvB;AACE;AAAuB;AACzB;AACF;AACwC;AAG1C;AACE;AACE;AAAY;AAEZ;AAAU;AACZ;AAGF;AACG;AACE;AACY;AACT;AAC2B;AAC3B;AACF;AACsC;AACQ;AACvC;AACH;AACC;AAEL;AAAC;AAAc;AAEX;AACA;AAEA;AAIA;AAGA;AACE;AACG;AAEW;AAET;AACS;AACE;AAC4B;AAEW;AACnD;AACF;AAIJ;AACE;AAAO;AAGT;AACG;AAEC;AACU;AACmB;AAC7B;AACe;AACF;AACb;AACA;AACA;AACA;AAGA;AACiB;AACjB;AACA;AACA;AACA;AAIM;AAGmC;AAIpC;AAIS;AAGP;AACiB;AACC;AACV;AAEN;AACW;AACD;AAID;AAMa;AAGV;AACb;AACF;AAEA;AAID;AACW;AACD;AAKK;AAMR;AAEN;AAKV;AAGG;AACC;AAAC;AACW;AACI;AAEb;AAAe;AACd;AAAC;AAAwB;AAAqC;AAC3D;AAAA;AACL;AACF;AACC;AAAA;AAGH;AAEH;AACH;AAEG;AACW;AACO;AACuC;AACxD;AACwB;AACxB;AACc;AACH;AACe;AACP;AACd;AACL;AACe;AACjB;AAAA;AAEJ;AACF;AAGN;;"}
|
|
1
|
+
{"version":3,"file":"Thread.cjs","sources":["../../src/components/Thread.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type BaseMetadata,\n type CommentData,\n type DM,\n Permission,\n type ThreadData,\n} from \"@liveblocks/core\";\nimport {\n useMarkRoomThreadAsResolved,\n useMarkRoomThreadAsUnresolved,\n useRoomPermissions,\n useRoomThreadSubscription,\n} from \"@liveblocks/react/_private\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport type {\n ComponentPropsWithoutRef,\n ForwardedRef,\n RefAttributes,\n SyntheticEvent,\n} from \"react\";\nimport {\n forwardRef,\n Fragment,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { ArrowDownIcon } from \"../icons/ArrowDown\";\nimport { BellIcon } from \"../icons/Bell\";\nimport { BellCrossedIcon } from \"../icons/BellCrossed\";\nimport { CheckCircleIcon } from \"../icons/CheckCircle\";\nimport { CheckCircleFillIcon } from \"../icons/CheckCircleFill\";\nimport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n ThreadOverrides,\n} from \"../overrides\";\nimport { findLastIndex } from \"@liveblocks/core\";\n\nimport { useOverrides } from \"../overrides\";\nimport { cn } from \"../utils/cn\";\nimport type { CommentProps } from \"./Comment\";\nimport { Comment } from \"./Comment\";\nimport type { ComposerProps } from \"./Composer\";\nimport { Composer } from \"./Composer\";\nimport { Button } from \"./internal/Button\";\nimport { DropdownItem } from \"./internal/Dropdown\";\nimport { Tooltip, TooltipProvider } from \"./internal/Tooltip\";\n\nexport interface ThreadProps<M extends BaseMetadata = DM>\n extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The thread to display.\n */\n thread: ThreadData<M>;\n\n /**\n * How to show or hide the composer to reply to the thread.\n */\n showComposer?: boolean | \"collapsed\";\n\n /**\n * Whether to show the action to resolve the thread.\n */\n showResolveAction?: boolean;\n\n /**\n * How to show or hide the actions.\n */\n showActions?: CommentProps[\"showActions\"];\n\n /**\n * Whether to show reactions.\n */\n showReactions?: CommentProps[\"showReactions\"];\n\n /**\n * Whether to show the composer's formatting controls.\n */\n showComposerFormattingControls?: ComposerProps[\"showFormattingControls\"];\n\n /**\n * The maximum number of comments to show.\n *\n * The first and last comments are always shown and by default if some comments\n * are hidden, only the first comment will be shown before the \"show more\" button\n * and after it will be shown all the newest comments to fit the limit set.\n *\n * It's possible to customize this by setting `maxVisibleComments` to an object:\n *\n * @example\n * // Only show the last comment, and all the older ones to fit the limit.\n * <Thread maxVisibleComments={{ max: 5, show: \"oldest\" }} />\n *\n * @example\n * // Show as many old comments as new ones to fit the limit.\n * <Thread maxVisibleComments={{ max: 5, show: \"both\" }} />\n */\n maxVisibleComments?:\n | number\n | { max: number; show: \"oldest\" | \"both\" | \"newest\" };\n\n /**\n * Whether to blur the composer editor when the composer is submitted.\n */\n blurComposerOnSubmit?: ComposerProps[\"blurOnSubmit\"];\n\n /**\n * Whether to indent the comments' content.\n */\n indentCommentContent?: CommentProps[\"indentContent\"];\n\n /**\n * Whether to show deleted comments.\n */\n showDeletedComments?: CommentProps[\"showDeleted\"];\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n\n /**\n * The event handler called when changing the resolved status.\n */\n onResolvedChange?: (resolved: boolean) => void;\n\n /**\n * The event handler called when a comment is edited.\n */\n onCommentEdit?: CommentProps[\"onCommentEdit\"];\n\n /**\n * The event handler called when a comment is deleted.\n */\n onCommentDelete?: CommentProps[\"onCommentDelete\"];\n\n /**\n * The event handler called when the thread is deleted.\n * A thread is deleted when all its comments are deleted.\n */\n onThreadDelete?: (thread: ThreadData<M>) => void;\n\n /**\n * The event handler called when clicking on a comment's author.\n */\n onAuthorClick?: CommentProps[\"onAuthorClick\"];\n\n /**\n * The event handler called when clicking on a mention.\n */\n onMentionClick?: CommentProps[\"onMentionClick\"];\n\n /**\n * The event handler called when clicking on a comment's attachment.\n */\n onAttachmentClick?: CommentProps[\"onAttachmentClick\"];\n\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: ComposerProps[\"onComposerSubmit\"];\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides & ThreadOverrides & CommentOverrides & ComposerOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\n/**\n * Displays a thread of comments, with a composer to reply\n * to it.\n *\n * @example\n * <>\n * {threads.map((thread) => (\n * <Thread key={thread.id} thread={thread} />\n * ))}\n * </>\n */\nexport const Thread = forwardRef(\n <M extends BaseMetadata = DM>(\n {\n thread,\n indentCommentContent = true,\n showActions = \"hover\",\n showDeletedComments,\n showResolveAction = true,\n showReactions = true,\n showComposer = \"collapsed\",\n showAttachments = true,\n showComposerFormattingControls = true,\n maxVisibleComments,\n onResolvedChange,\n onCommentEdit,\n onCommentDelete,\n onThreadDelete,\n onAuthorClick,\n onMentionClick,\n onAttachmentClick,\n onComposerSubmit,\n blurComposerOnSubmit,\n overrides,\n components,\n className,\n ...props\n }: ThreadProps<M>,\n forwardedRef: ForwardedRef<HTMLDivElement>\n ) => {\n const markThreadAsResolved = useMarkRoomThreadAsResolved(thread.roomId);\n const markThreadAsUnresolved = useMarkRoomThreadAsUnresolved(thread.roomId);\n const $ = useOverrides(overrides);\n const [showAllComments, setShowAllComments] = useState(false);\n const firstCommentIndex = useMemo(() => {\n return showDeletedComments\n ? 0\n : thread.comments.findIndex((comment) => comment.body);\n }, [showDeletedComments, thread.comments]);\n const lastCommentIndex = useMemo(() => {\n return showDeletedComments\n ? thread.comments.length - 1\n : findLastIndex(thread.comments, (comment) => Boolean(comment.body));\n }, [showDeletedComments, thread.comments]);\n const hiddenComments = useMemo(() => {\n const maxVisibleCommentsCount =\n typeof maxVisibleComments === \"number\"\n ? maxVisibleComments\n : maxVisibleComments?.max;\n const visibleCommentsShow =\n (typeof maxVisibleComments === \"object\"\n ? maxVisibleComments?.show\n : undefined) ?? \"newest\";\n\n // If we explicitly want to show all comments or there's no limit set,\n // no need to hide any comments.\n if (showAllComments || maxVisibleCommentsCount === undefined) {\n return;\n }\n\n const comments = thread.comments\n .map((comment, index) => ({ comment, index }))\n .filter(({ comment }) => showDeletedComments || comment.body);\n\n // There aren't enough comments so no need to hide any.\n if (comments.length <= Math.max(maxVisibleCommentsCount, 2)) {\n return;\n }\n\n const firstVisibleComment = comments[0]!;\n const lastVisibleComment = comments[comments.length - 1]!;\n\n // Always show the first and last comments even if the limit is set to lower than 2.\n if (maxVisibleCommentsCount <= 2) {\n const firstHiddenCommentIndex =\n comments[1]?.index ?? firstVisibleComment.index;\n const lastHiddenCommentIndex =\n comments[comments.length - 2]?.index ?? lastVisibleComment.index;\n\n return {\n firstIndex: firstHiddenCommentIndex,\n lastIndex: lastHiddenCommentIndex,\n count: comments.slice(1, comments.length - 1).length,\n };\n }\n\n const remainingVisibleCommentsCount = maxVisibleCommentsCount - 2;\n\n // Split the remaining visible comments before, after, or equally.\n const beforeVisibleCommentsCount =\n visibleCommentsShow === \"oldest\"\n ? remainingVisibleCommentsCount\n : visibleCommentsShow === \"newest\"\n ? 0\n : Math.floor(remainingVisibleCommentsCount / 2);\n const afterVisibleCommentsCount =\n visibleCommentsShow === \"oldest\"\n ? 0\n : visibleCommentsShow === \"newest\"\n ? remainingVisibleCommentsCount\n : Math.ceil(remainingVisibleCommentsCount / 2);\n\n // The first comment is always visible so `+ 1` to skip it.\n const firstHiddenComment = comments[1 + beforeVisibleCommentsCount];\n // The last comment is always visible so `- 2` to skip it.\n const lastHiddenComment =\n comments[comments.length - 2 - afterVisibleCommentsCount];\n\n // There aren't any comments to hide besides the first and last ones.\n if (\n !firstHiddenComment ||\n !lastHiddenComment ||\n firstHiddenComment.index > lastHiddenComment.index\n ) {\n return;\n }\n\n return {\n firstIndex: firstHiddenComment.index,\n lastIndex: lastHiddenComment.index,\n count: thread.comments\n .slice(firstHiddenComment.index, lastHiddenComment.index + 1)\n .filter((comment) => showDeletedComments || comment.body).length,\n };\n }, [\n maxVisibleComments,\n showAllComments,\n showDeletedComments,\n thread.comments,\n ]);\n const {\n status: subscriptionStatus,\n unreadSince,\n subscribe,\n unsubscribe,\n } = useRoomThreadSubscription(thread.roomId, thread.id);\n const unreadIndex = useMemo(() => {\n // The user is not subscribed to this thread.\n if (subscriptionStatus !== \"subscribed\") {\n return;\n }\n\n // The user hasn't read the thread yet, so all comments are unread.\n if (unreadSince === null) {\n return firstCommentIndex;\n }\n\n // The user has read the thread, so we find the first unread comment.\n const unreadIndex = thread.comments.findIndex(\n (comment) =>\n (showDeletedComments ? true : comment.body) &&\n comment.createdAt > unreadSince\n );\n\n return unreadIndex >= 0 && unreadIndex < thread.comments.length\n ? unreadIndex\n : undefined;\n }, [\n firstCommentIndex,\n showDeletedComments,\n subscriptionStatus,\n thread.comments,\n unreadSince,\n ]);\n const [newIndex, setNewIndex] = useState<number>();\n const newIndicatorIndex = newIndex === undefined ? unreadIndex : newIndex;\n\n useEffect(() => {\n if (unreadIndex) {\n // Keep the \"new\" indicator at the lowest unread index.\n setNewIndex((persistedUnreadIndex) =>\n Math.min(persistedUnreadIndex ?? Infinity, unreadIndex)\n );\n }\n }, [unreadIndex]);\n\n const permissions = useRoomPermissions(thread.roomId);\n const canComment =\n permissions.size > 0\n ? permissions.has(Permission.CommentsWrite) ||\n permissions.has(Permission.Write)\n : true;\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const handleResolvedChange = useCallback(\n (resolved: boolean) => {\n onResolvedChange?.(resolved);\n\n if (resolved) {\n markThreadAsResolved(thread.id);\n } else {\n markThreadAsUnresolved(thread.id);\n }\n },\n [\n markThreadAsResolved,\n markThreadAsUnresolved,\n onResolvedChange,\n thread.id,\n ]\n );\n\n const handleCommentDelete = useCallback(\n (comment: CommentData) => {\n onCommentDelete?.(comment);\n\n const filteredComments = thread.comments.filter(\n (comment) => comment.body\n );\n\n if (filteredComments.length <= 1) {\n onThreadDelete?.(thread);\n }\n },\n [onCommentDelete, onThreadDelete, thread]\n );\n\n const handleSubscribeChange = useCallback(() => {\n if (subscriptionStatus === \"subscribed\") {\n unsubscribe();\n } else {\n subscribe();\n }\n }, [subscriptionStatus, subscribe, unsubscribe]);\n\n return (\n <TooltipProvider>\n <div\n className={cn(\n \"lb-root lb-thread\",\n showActions === \"hover\" && \"lb-thread:show-actions-hover\",\n className\n )}\n data-resolved={thread.resolved ? \"\" : undefined}\n data-unread={unreadIndex !== undefined ? \"\" : undefined}\n dir={$.dir}\n {...props}\n ref={forwardedRef}\n >\n <div className=\"lb-thread-comments\">\n {thread.comments.map((comment, index) => {\n const isFirstComment = index === firstCommentIndex;\n const isUnread =\n unreadIndex !== undefined && index >= unreadIndex;\n const isHidden =\n hiddenComments &&\n index >= hiddenComments.firstIndex &&\n index <= hiddenComments.lastIndex;\n const isFirstHiddenComment =\n isHidden && index === hiddenComments.firstIndex;\n\n if (isFirstHiddenComment) {\n return (\n <div\n key={`${comment.id}-show-more`}\n className=\"lb-thread-show-more\"\n >\n <Button\n variant=\"ghost\"\n className=\"lb-thread-show-more-button\"\n onClick={() => setShowAllComments(true)}\n >\n {$.THREAD_SHOW_MORE_COMMENTS(hiddenComments.count)}\n </Button>\n </div>\n );\n }\n\n if (isHidden) {\n return null;\n }\n\n const children = (\n <Comment\n key={comment.id}\n overrides={overrides}\n className=\"lb-thread-comment\"\n data-unread={isUnread ? \"\" : undefined}\n comment={comment}\n indentContent={indentCommentContent}\n showDeleted={showDeletedComments}\n showActions={showActions}\n showReactions={showReactions}\n showAttachments={showAttachments}\n showComposerFormattingControls={\n showComposerFormattingControls\n }\n onCommentEdit={onCommentEdit}\n onCommentDelete={handleCommentDelete}\n onAuthorClick={onAuthorClick}\n onMentionClick={onMentionClick}\n onAttachmentClick={onAttachmentClick}\n components={components}\n autoMarkReadThreadId={\n index === lastCommentIndex && isUnread\n ? thread.id\n : undefined\n }\n additionalActionsClassName={\n isFirstComment ? \"lb-thread-actions\" : undefined\n }\n additionalActions={\n isFirstComment && showResolveAction ? (\n <Tooltip\n content={\n thread.resolved\n ? $.THREAD_UNRESOLVE\n : $.THREAD_RESOLVE\n }\n >\n <TogglePrimitive.Root\n pressed={thread.resolved}\n onPressedChange={handleResolvedChange}\n asChild\n >\n <Button\n className=\"lb-comment-action\"\n onClick={stopPropagation}\n aria-label={\n thread.resolved\n ? $.THREAD_UNRESOLVE\n : $.THREAD_RESOLVE\n }\n icon={\n thread.resolved ? (\n <CheckCircleFillIcon />\n ) : (\n <CheckCircleIcon />\n )\n }\n disabled={!canComment}\n />\n </TogglePrimitive.Root>\n </Tooltip>\n ) : null\n }\n additionalDropdownItemsBefore={\n isFirstComment ? (\n <DropdownItem\n onSelect={handleSubscribeChange}\n onClick={stopPropagation}\n icon={\n subscriptionStatus === \"subscribed\" ? (\n <BellCrossedIcon />\n ) : (\n <BellIcon />\n )\n }\n >\n {subscriptionStatus === \"subscribed\"\n ? $.THREAD_UNSUBSCRIBE\n : $.THREAD_SUBSCRIBE}\n </DropdownItem>\n ) : null\n }\n />\n );\n\n return index === newIndicatorIndex &&\n newIndicatorIndex !== firstCommentIndex &&\n newIndicatorIndex <= lastCommentIndex ? (\n <Fragment key={comment.id}>\n <div\n className=\"lb-thread-new-indicator\"\n aria-label={$.THREAD_NEW_INDICATOR_DESCRIPTION}\n >\n <span className=\"lb-thread-new-indicator-label\">\n <ArrowDownIcon className=\"lb-thread-new-indicator-label-icon\" />\n {$.THREAD_NEW_INDICATOR}\n </span>\n </div>\n {children}\n </Fragment>\n ) : (\n children\n );\n })}\n </div>\n {showComposer && (\n <Composer\n className=\"lb-thread-composer\"\n threadId={thread.id}\n defaultCollapsed={showComposer === \"collapsed\" ? true : undefined}\n showAttachments={showAttachments}\n showFormattingControls={showComposerFormattingControls}\n onComposerSubmit={onComposerSubmit}\n blurOnSubmit={blurComposerOnSubmit}\n overrides={{\n COMPOSER_PLACEHOLDER: $.THREAD_COMPOSER_PLACEHOLDER,\n COMPOSER_SEND: $.THREAD_COMPOSER_SEND,\n ...overrides,\n }}\n roomId={thread.roomId}\n />\n )}\n </div>\n </TooltipProvider>\n );\n }\n) as <M extends BaseMetadata = DM>(\n props: ThreadProps<M> & RefAttributes<HTMLDivElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiMO;AAAe;AAElB;AACE;AACuB;AACT;AACd;AACoB;AACJ;AACD;AACG;AACe;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACE;AAEuD;AAEzD;AACE;AAEqE;AAEvE;AACE;AAIA;AAOA;AACE;AAAA;AAGF;AAKA;AACE;AAAA;AAGF;AACA;AAGA;AACE;AAEA;AAGA;AAAO;AACO;AACD;AACmC;AAChD;AAGF;AAGA;AAMA;AAQA;AAEA;AAIA;AAKE;AAAA;AAGF;AAAO;AAC0B;AACF;AAG+B;AAC9D;AACC;AACD;AACA;AACA;AACO;AAET;AAAM;AACI;AACR;AACA;AACA;AAEF;AAEE;AACE;AAAA;AAIF;AACE;AAAO;AAIT;AAAoC;AAGZ;AAGxB;AAEI;AACH;AACD;AACA;AACA;AACO;AACP;AAEF;AACA;AAEA;AACE;AAEE;AAAA;AACwD;AACxD;AACF;AAGF;AACA;AAMA;AACE;AAAsB;AAGxB;AAA6B;AAEzB;AAEA;AACE;AAA8B;AAE9B;AAAgC;AAClC;AACF;AACA;AACE;AACA;AACA;AACO;AACT;AAGF;AAA4B;AAExB;AAEA;AAAyC;AAClB;AAGvB;AACE;AAAuB;AACzB;AACF;AACwC;AAG1C;AACE;AACE;AAAY;AAEZ;AAAU;AACZ;AAGF;AACG;AACE;AACY;AACT;AAC2B;AAC3B;AACF;AACsC;AACQ;AACvC;AACH;AACC;AAEL;AAAC;AAAc;AAEX;AACA;AAEA;AAIA;AAGA;AACE;AACG;AAEW;AAET;AACS;AACE;AAC4B;AAEW;AACnD;AACF;AAIJ;AACE;AAAO;AAGT;AACG;AAEC;AACU;AACmB;AAC7B;AACe;AACF;AACb;AACA;AACA;AACA;AAGA;AACiB;AACjB;AACA;AACA;AACA;AAIM;AAGmC;AAIpC;AAIS;AAGP;AACiB;AACC;AACV;AAEN;AACW;AACD;AAID;AAMa;AAGV;AACb;AACF;AAEA;AAID;AACW;AACD;AAKK;AAMR;AAEN;AAKV;AAGG;AACC;AAAC;AACW;AACI;AAEb;AAAe;AACd;AAAC;AAAwB;AAAqC;AAC3D;AAAA;AACL;AACF;AACC;AAAA;AAGH;AAEH;AACH;AAEG;AACW;AACO;AACuC;AACxD;AACwB;AACxB;AACc;AACH;AACe;AACP;AACd;AACL;AACe;AACjB;AAAA;AAEJ;AACF;AAGN;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Thread.js","sources":["../../src/components/Thread.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type BaseMetadata,\n type CommentData,\n type DM,\n Permission,\n type ThreadData,\n} from \"@liveblocks/core\";\nimport { findLastIndex } from \"@liveblocks/core\";\nimport {\n useMarkRoomThreadAsResolved,\n useMarkRoomThreadAsUnresolved,\n useRoomPermissions,\n useRoomThreadSubscription,\n} from \"@liveblocks/react/_private\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport type {\n ComponentPropsWithoutRef,\n ForwardedRef,\n RefAttributes,\n SyntheticEvent,\n} from \"react\";\nimport {\n forwardRef,\n Fragment,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { ArrowDownIcon } from \"../icons/ArrowDown\";\nimport { BellIcon } from \"../icons/Bell\";\nimport { BellCrossedIcon } from \"../icons/BellCrossed\";\nimport { CheckCircleIcon } from \"../icons/CheckCircle\";\nimport { CheckCircleFillIcon } from \"../icons/CheckCircleFill\";\nimport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n ThreadOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { cn } from \"../utils/cn\";\nimport type { CommentProps } from \"./Comment\";\nimport { Comment } from \"./Comment\";\nimport type { ComposerProps } from \"./Composer\";\nimport { Composer } from \"./Composer\";\nimport { Button } from \"./internal/Button\";\nimport { DropdownItem } from \"./internal/Dropdown\";\nimport { Tooltip, TooltipProvider } from \"./internal/Tooltip\";\n\nexport interface ThreadProps<M extends BaseMetadata = DM>\n extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The thread to display.\n */\n thread: ThreadData<M>;\n\n /**\n * How to show or hide the composer to reply to the thread.\n */\n showComposer?: boolean | \"collapsed\";\n\n /**\n * Whether to show the action to resolve the thread.\n */\n showResolveAction?: boolean;\n\n /**\n * How to show or hide the actions.\n */\n showActions?: CommentProps[\"showActions\"];\n\n /**\n * Whether to show reactions.\n */\n showReactions?: CommentProps[\"showReactions\"];\n\n /**\n * Whether to show the composer's formatting controls.\n */\n showComposerFormattingControls?: ComposerProps[\"showFormattingControls\"];\n\n /**\n * The maximum number of comments to show.\n *\n * The first and last comments are always shown and by default if some comments\n * are hidden, only the first comment will be shown before the \"show more\" button\n * and after it will be shown all the newest comments to fit the limit set.\n *\n * It's possible to customize this by setting `maxVisibleComments` to an object:\n *\n * @example\n * // Only show the last comment, and all the older ones to fit the limit.\n * <Thread maxVisibleComments={{ max: 5, show: \"oldest\" }} />\n *\n * @example\n * // Show as many old comments as new ones to fit the limit.\n * <Thread maxVisibleComments={{ max: 5, show: \"both\" }} />\n */\n maxVisibleComments?:\n | number\n | { max: number; show: \"oldest\" | \"both\" | \"newest\" };\n\n /**\n * Whether to blur the composer editor when the composer is submitted.\n */\n blurComposerOnSubmit?: ComposerProps[\"blurOnSubmit\"];\n\n /**\n * Whether to indent the comments' content.\n */\n indentCommentContent?: CommentProps[\"indentContent\"];\n\n /**\n * Whether to show deleted comments.\n */\n showDeletedComments?: CommentProps[\"showDeleted\"];\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n\n /**\n * The event handler called when changing the resolved status.\n */\n onResolvedChange?: (resolved: boolean) => void;\n\n /**\n * The event handler called when a comment is edited.\n */\n onCommentEdit?: CommentProps[\"onCommentEdit\"];\n\n /**\n * The event handler called when a comment is deleted.\n */\n onCommentDelete?: CommentProps[\"onCommentDelete\"];\n\n /**\n * The event handler called when the thread is deleted.\n * A thread is deleted when all its comments are deleted.\n */\n onThreadDelete?: (thread: ThreadData<M>) => void;\n\n /**\n * The event handler called when clicking on a comment's author.\n */\n onAuthorClick?: CommentProps[\"onAuthorClick\"];\n\n /**\n * The event handler called when clicking on a mention.\n */\n onMentionClick?: CommentProps[\"onMentionClick\"];\n\n /**\n * The event handler called when clicking on a comment's attachment.\n */\n onAttachmentClick?: CommentProps[\"onAttachmentClick\"];\n\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: ComposerProps[\"onComposerSubmit\"];\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides & ThreadOverrides & CommentOverrides & ComposerOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\n/**\n * Displays a thread of comments, with a composer to reply\n * to it.\n *\n * @example\n * <>\n * {threads.map((thread) => (\n * <Thread key={thread.id} thread={thread} />\n * ))}\n * </>\n */\nexport const Thread = forwardRef(\n <M extends BaseMetadata = DM>(\n {\n thread,\n indentCommentContent = true,\n showActions = \"hover\",\n showDeletedComments,\n showResolveAction = true,\n showReactions = true,\n showComposer = \"collapsed\",\n showAttachments = true,\n showComposerFormattingControls = true,\n maxVisibleComments,\n onResolvedChange,\n onCommentEdit,\n onCommentDelete,\n onThreadDelete,\n onAuthorClick,\n onMentionClick,\n onAttachmentClick,\n onComposerSubmit,\n blurComposerOnSubmit,\n overrides,\n components,\n className,\n ...props\n }: ThreadProps<M>,\n forwardedRef: ForwardedRef<HTMLDivElement>\n ) => {\n const markThreadAsResolved = useMarkRoomThreadAsResolved(thread.roomId);\n const markThreadAsUnresolved = useMarkRoomThreadAsUnresolved(thread.roomId);\n const $ = useOverrides(overrides);\n const [showAllComments, setShowAllComments] = useState(false);\n const firstCommentIndex = useMemo(() => {\n return showDeletedComments\n ? 0\n : thread.comments.findIndex((comment) => comment.body);\n }, [showDeletedComments, thread.comments]);\n const lastCommentIndex = useMemo(() => {\n return showDeletedComments\n ? thread.comments.length - 1\n : findLastIndex(thread.comments, (comment) => Boolean(comment.body));\n }, [showDeletedComments, thread.comments]);\n const hiddenComments = useMemo(() => {\n const maxVisibleCommentsCount =\n typeof maxVisibleComments === \"number\"\n ? maxVisibleComments\n : maxVisibleComments?.max;\n const visibleCommentsShow =\n (typeof maxVisibleComments === \"object\"\n ? maxVisibleComments?.show\n : undefined) ?? \"newest\";\n\n // If we explicitly want to show all comments or there's no limit set,\n // no need to hide any comments.\n if (showAllComments || maxVisibleCommentsCount === undefined) {\n return;\n }\n\n const comments = thread.comments\n .map((comment, index) => ({ comment, index }))\n .filter(({ comment }) => showDeletedComments || comment.body);\n\n // There aren't enough comments so no need to hide any.\n if (comments.length <= Math.max(maxVisibleCommentsCount, 2)) {\n return;\n }\n\n const firstVisibleComment = comments[0]!;\n const lastVisibleComment = comments[comments.length - 1]!;\n\n // Always show the first and last comments even if the limit is set to lower than 2.\n if (maxVisibleCommentsCount <= 2) {\n const firstHiddenCommentIndex =\n comments[1]?.index ?? firstVisibleComment.index;\n const lastHiddenCommentIndex =\n comments[comments.length - 2]?.index ?? lastVisibleComment.index;\n\n return {\n firstIndex: firstHiddenCommentIndex,\n lastIndex: lastHiddenCommentIndex,\n count: comments.slice(1, comments.length - 1).length,\n };\n }\n\n const remainingVisibleCommentsCount = maxVisibleCommentsCount - 2;\n\n // Split the remaining visible comments before, after, or equally.\n const beforeVisibleCommentsCount =\n visibleCommentsShow === \"oldest\"\n ? remainingVisibleCommentsCount\n : visibleCommentsShow === \"newest\"\n ? 0\n : Math.floor(remainingVisibleCommentsCount / 2);\n const afterVisibleCommentsCount =\n visibleCommentsShow === \"oldest\"\n ? 0\n : visibleCommentsShow === \"newest\"\n ? remainingVisibleCommentsCount\n : Math.ceil(remainingVisibleCommentsCount / 2);\n\n // The first comment is always visible so `+ 1` to skip it.\n const firstHiddenComment = comments[1 + beforeVisibleCommentsCount];\n // The last comment is always visible so `- 2` to skip it.\n const lastHiddenComment =\n comments[comments.length - 2 - afterVisibleCommentsCount];\n\n // There aren't any comments to hide besides the first and last ones.\n if (\n !firstHiddenComment ||\n !lastHiddenComment ||\n firstHiddenComment.index > lastHiddenComment.index\n ) {\n return;\n }\n\n return {\n firstIndex: firstHiddenComment.index,\n lastIndex: lastHiddenComment.index,\n count: thread.comments\n .slice(firstHiddenComment.index, lastHiddenComment.index + 1)\n .filter((comment) => showDeletedComments || comment.body).length,\n };\n }, [\n maxVisibleComments,\n showAllComments,\n showDeletedComments,\n thread.comments,\n ]);\n const {\n status: subscriptionStatus,\n unreadSince,\n subscribe,\n unsubscribe,\n } = useRoomThreadSubscription(thread.roomId, thread.id);\n const unreadIndex = useMemo(() => {\n // The user is not subscribed to this thread.\n if (subscriptionStatus !== \"subscribed\") {\n return;\n }\n\n // The user hasn't read the thread yet, so all comments are unread.\n if (unreadSince === null) {\n return firstCommentIndex;\n }\n\n // The user has read the thread, so we find the first unread comment.\n const unreadIndex = thread.comments.findIndex(\n (comment) =>\n (showDeletedComments ? true : comment.body) &&\n comment.createdAt > unreadSince\n );\n\n return unreadIndex >= 0 && unreadIndex < thread.comments.length\n ? unreadIndex\n : undefined;\n }, [\n firstCommentIndex,\n showDeletedComments,\n subscriptionStatus,\n thread.comments,\n unreadSince,\n ]);\n const [newIndex, setNewIndex] = useState<number>();\n const newIndicatorIndex = newIndex === undefined ? unreadIndex : newIndex;\n\n useEffect(() => {\n if (unreadIndex) {\n // Keep the \"new\" indicator at the lowest unread index.\n setNewIndex((persistedUnreadIndex) =>\n Math.min(persistedUnreadIndex ?? Infinity, unreadIndex)\n );\n }\n }, [unreadIndex]);\n\n const permissions = useRoomPermissions(thread.roomId);\n const canComment =\n permissions.size > 0\n ? permissions.has(Permission.CommentsWrite) ||\n permissions.has(Permission.Write)\n : true;\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const handleResolvedChange = useCallback(\n (resolved: boolean) => {\n onResolvedChange?.(resolved);\n\n if (resolved) {\n markThreadAsResolved(thread.id);\n } else {\n markThreadAsUnresolved(thread.id);\n }\n },\n [\n markThreadAsResolved,\n markThreadAsUnresolved,\n onResolvedChange,\n thread.id,\n ]\n );\n\n const handleCommentDelete = useCallback(\n (comment: CommentData) => {\n onCommentDelete?.(comment);\n\n const filteredComments = thread.comments.filter(\n (comment) => comment.body\n );\n\n if (filteredComments.length <= 1) {\n onThreadDelete?.(thread);\n }\n },\n [onCommentDelete, onThreadDelete, thread]\n );\n\n const handleSubscribeChange = useCallback(() => {\n if (subscriptionStatus === \"subscribed\") {\n unsubscribe();\n } else {\n subscribe();\n }\n }, [subscriptionStatus, subscribe, unsubscribe]);\n\n return (\n <TooltipProvider>\n <div\n className={cn(\n \"lb-root lb-thread\",\n showActions === \"hover\" && \"lb-thread:show-actions-hover\",\n className\n )}\n data-resolved={thread.resolved ? \"\" : undefined}\n data-unread={unreadIndex !== undefined ? \"\" : undefined}\n dir={$.dir}\n {...props}\n ref={forwardedRef}\n >\n <div className=\"lb-thread-comments\">\n {thread.comments.map((comment, index) => {\n const isFirstComment = index === firstCommentIndex;\n const isUnread =\n unreadIndex !== undefined && index >= unreadIndex;\n const isHidden =\n hiddenComments &&\n index >= hiddenComments.firstIndex &&\n index <= hiddenComments.lastIndex;\n const isFirstHiddenComment =\n isHidden && index === hiddenComments.firstIndex;\n\n if (isFirstHiddenComment) {\n return (\n <div\n key={`${comment.id}-show-more`}\n className=\"lb-thread-show-more\"\n >\n <Button\n variant=\"ghost\"\n className=\"lb-thread-show-more-button\"\n onClick={() => setShowAllComments(true)}\n >\n {$.THREAD_SHOW_MORE_COMMENTS(hiddenComments.count)}\n </Button>\n </div>\n );\n }\n\n if (isHidden) {\n return null;\n }\n\n const children = (\n <Comment\n key={comment.id}\n overrides={overrides}\n className=\"lb-thread-comment\"\n data-unread={isUnread ? \"\" : undefined}\n comment={comment}\n indentContent={indentCommentContent}\n showDeleted={showDeletedComments}\n showActions={showActions}\n showReactions={showReactions}\n showAttachments={showAttachments}\n showComposerFormattingControls={\n showComposerFormattingControls\n }\n onCommentEdit={onCommentEdit}\n onCommentDelete={handleCommentDelete}\n onAuthorClick={onAuthorClick}\n onMentionClick={onMentionClick}\n onAttachmentClick={onAttachmentClick}\n components={components}\n autoMarkReadThreadId={\n index === lastCommentIndex && isUnread\n ? thread.id\n : undefined\n }\n additionalActionsClassName={\n isFirstComment ? \"lb-thread-actions\" : undefined\n }\n additionalActions={\n isFirstComment && showResolveAction ? (\n <Tooltip\n content={\n thread.resolved\n ? $.THREAD_UNRESOLVE\n : $.THREAD_RESOLVE\n }\n >\n <TogglePrimitive.Root\n pressed={thread.resolved}\n onPressedChange={handleResolvedChange}\n asChild\n >\n <Button\n className=\"lb-comment-action\"\n onClick={stopPropagation}\n aria-label={\n thread.resolved\n ? $.THREAD_UNRESOLVE\n : $.THREAD_RESOLVE\n }\n icon={\n thread.resolved ? (\n <CheckCircleFillIcon />\n ) : (\n <CheckCircleIcon />\n )\n }\n disabled={!canComment}\n />\n </TogglePrimitive.Root>\n </Tooltip>\n ) : null\n }\n additionalDropdownItemsBefore={\n isFirstComment ? (\n <DropdownItem\n onSelect={handleSubscribeChange}\n onClick={stopPropagation}\n icon={\n subscriptionStatus === \"subscribed\" ? (\n <BellCrossedIcon />\n ) : (\n <BellIcon />\n )\n }\n >\n {subscriptionStatus === \"subscribed\"\n ? $.THREAD_UNSUBSCRIBE\n : $.THREAD_SUBSCRIBE}\n </DropdownItem>\n ) : null\n }\n />\n );\n\n return index === newIndicatorIndex &&\n newIndicatorIndex !== firstCommentIndex &&\n newIndicatorIndex <= lastCommentIndex ? (\n <Fragment key={comment.id}>\n <div\n className=\"lb-thread-new-indicator\"\n aria-label={$.THREAD_NEW_INDICATOR_DESCRIPTION}\n >\n <span className=\"lb-thread-new-indicator-label\">\n <ArrowDownIcon className=\"lb-thread-new-indicator-label-icon\" />\n {$.THREAD_NEW_INDICATOR}\n </span>\n </div>\n {children}\n </Fragment>\n ) : (\n children\n );\n })}\n </div>\n {showComposer && (\n <Composer\n className=\"lb-thread-composer\"\n threadId={thread.id}\n defaultCollapsed={showComposer === \"collapsed\" ? true : undefined}\n showAttachments={showAttachments}\n showFormattingControls={showComposerFormattingControls}\n onComposerSubmit={onComposerSubmit}\n blurOnSubmit={blurComposerOnSubmit}\n overrides={{\n COMPOSER_PLACEHOLDER: $.THREAD_COMPOSER_PLACEHOLDER,\n COMPOSER_SEND: $.THREAD_COMPOSER_SEND,\n ...overrides,\n }}\n roomId={thread.roomId}\n />\n )}\n </div>\n </TooltipProvider>\n );\n }\n) as <M extends BaseMetadata = DM>(\n props: ThreadProps<M> & RefAttributes<HTMLDivElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgMO;AAAe;AAElB;AACE;AACuB;AACT;AACd;AACoB;AACJ;AACD;AACG;AACe;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACE;AAEuD;AAEzD;AACE;AAEqE;AAEvE;AACE;AAIA;AAOA;AACE;AAAA;AAGF;AAKA;AACE;AAAA;AAGF;AACA;AAGA;AACE;AAEA;AAGA;AAAO;AACO;AACD;AACmC;AAChD;AAGF;AAGA;AAMA;AAQA;AAEA;AAIA;AAKE;AAAA;AAGF;AAAO;AAC0B;AACF;AAG+B;AAC9D;AACC;AACD;AACA;AACA;AACO;AAET;AAAM;AACI;AACR;AACA;AACA;AAEF;AAEE;AACE;AAAA;AAIF;AACE;AAAO;AAIT;AAAoC;AAGZ;AAGxB;AAEI;AACH;AACD;AACA;AACA;AACO;AACP;AAEF;AACA;AAEA;AACE;AAEE;AAAA;AACwD;AACxD;AACF;AAGF;AACA;AAMA;AACE;AAAsB;AAGxB;AAA6B;AAEzB;AAEA;AACE;AAA8B;AAE9B;AAAgC;AAClC;AACF;AACA;AACE;AACA;AACA;AACO;AACT;AAGF;AAA4B;AAExB;AAEA;AAAyC;AAClB;AAGvB;AACE;AAAuB;AACzB;AACF;AACwC;AAG1C;AACE;AACE;AAAY;AAEZ;AAAU;AACZ;AAGF;AACG;AACE;AACY;AACT;AAC2B;AAC3B;AACF;AACsC;AACQ;AACvC;AACH;AACC;AAEL;AAAC;AAAc;AAEX;AACA;AAEA;AAIA;AAGA;AACE;AACG;AAEW;AAET;AACS;AACE;AAC4B;AAEW;AACnD;AACF;AAIJ;AACE;AAAO;AAGT;AACG;AAEC;AACU;AACmB;AAC7B;AACe;AACF;AACb;AACA;AACA;AACA;AAGA;AACiB;AACjB;AACA;AACA;AACA;AAIM;AAGmC;AAIpC;AAIS;AAGP;AACiB;AACC;AACV;AAEN;AACW;AACD;AAID;AAMa;AAGV;AACb;AACF;AAEA;AAID;AACW;AACD;AAKK;AAMR;AAEN;AAKV;AAGG;AACC;AAAC;AACW;AACI;AAEb;AAAe;AACd;AAAC;AAAwB;AAAqC;AAC3D;AAAA;AACL;AACF;AACC;AAAA;AAGH;AAEH;AACH;AAEG;AACW;AACO;AACuC;AACxD;AACwB;AACxB;AACc;AACH;AACe;AACP;AACd;AACL;AACe;AACjB;AAAA;AAEJ;AACF;AAGN;;"}
|
|
1
|
+
{"version":3,"file":"Thread.js","sources":["../../src/components/Thread.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type BaseMetadata,\n type CommentData,\n type DM,\n Permission,\n type ThreadData,\n} from \"@liveblocks/core\";\nimport {\n useMarkRoomThreadAsResolved,\n useMarkRoomThreadAsUnresolved,\n useRoomPermissions,\n useRoomThreadSubscription,\n} from \"@liveblocks/react/_private\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport type {\n ComponentPropsWithoutRef,\n ForwardedRef,\n RefAttributes,\n SyntheticEvent,\n} from \"react\";\nimport {\n forwardRef,\n Fragment,\n useCallback,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { ArrowDownIcon } from \"../icons/ArrowDown\";\nimport { BellIcon } from \"../icons/Bell\";\nimport { BellCrossedIcon } from \"../icons/BellCrossed\";\nimport { CheckCircleIcon } from \"../icons/CheckCircle\";\nimport { CheckCircleFillIcon } from \"../icons/CheckCircleFill\";\nimport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n ThreadOverrides,\n} from \"../overrides\";\nimport { findLastIndex } from \"@liveblocks/core\";\n\nimport { useOverrides } from \"../overrides\";\nimport { cn } from \"../utils/cn\";\nimport type { CommentProps } from \"./Comment\";\nimport { Comment } from \"./Comment\";\nimport type { ComposerProps } from \"./Composer\";\nimport { Composer } from \"./Composer\";\nimport { Button } from \"./internal/Button\";\nimport { DropdownItem } from \"./internal/Dropdown\";\nimport { Tooltip, TooltipProvider } from \"./internal/Tooltip\";\n\nexport interface ThreadProps<M extends BaseMetadata = DM>\n extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The thread to display.\n */\n thread: ThreadData<M>;\n\n /**\n * How to show or hide the composer to reply to the thread.\n */\n showComposer?: boolean | \"collapsed\";\n\n /**\n * Whether to show the action to resolve the thread.\n */\n showResolveAction?: boolean;\n\n /**\n * How to show or hide the actions.\n */\n showActions?: CommentProps[\"showActions\"];\n\n /**\n * Whether to show reactions.\n */\n showReactions?: CommentProps[\"showReactions\"];\n\n /**\n * Whether to show the composer's formatting controls.\n */\n showComposerFormattingControls?: ComposerProps[\"showFormattingControls\"];\n\n /**\n * The maximum number of comments to show.\n *\n * The first and last comments are always shown and by default if some comments\n * are hidden, only the first comment will be shown before the \"show more\" button\n * and after it will be shown all the newest comments to fit the limit set.\n *\n * It's possible to customize this by setting `maxVisibleComments` to an object:\n *\n * @example\n * // Only show the last comment, and all the older ones to fit the limit.\n * <Thread maxVisibleComments={{ max: 5, show: \"oldest\" }} />\n *\n * @example\n * // Show as many old comments as new ones to fit the limit.\n * <Thread maxVisibleComments={{ max: 5, show: \"both\" }} />\n */\n maxVisibleComments?:\n | number\n | { max: number; show: \"oldest\" | \"both\" | \"newest\" };\n\n /**\n * Whether to blur the composer editor when the composer is submitted.\n */\n blurComposerOnSubmit?: ComposerProps[\"blurOnSubmit\"];\n\n /**\n * Whether to indent the comments' content.\n */\n indentCommentContent?: CommentProps[\"indentContent\"];\n\n /**\n * Whether to show deleted comments.\n */\n showDeletedComments?: CommentProps[\"showDeleted\"];\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n\n /**\n * The event handler called when changing the resolved status.\n */\n onResolvedChange?: (resolved: boolean) => void;\n\n /**\n * The event handler called when a comment is edited.\n */\n onCommentEdit?: CommentProps[\"onCommentEdit\"];\n\n /**\n * The event handler called when a comment is deleted.\n */\n onCommentDelete?: CommentProps[\"onCommentDelete\"];\n\n /**\n * The event handler called when the thread is deleted.\n * A thread is deleted when all its comments are deleted.\n */\n onThreadDelete?: (thread: ThreadData<M>) => void;\n\n /**\n * The event handler called when clicking on a comment's author.\n */\n onAuthorClick?: CommentProps[\"onAuthorClick\"];\n\n /**\n * The event handler called when clicking on a mention.\n */\n onMentionClick?: CommentProps[\"onMentionClick\"];\n\n /**\n * The event handler called when clicking on a comment's attachment.\n */\n onAttachmentClick?: CommentProps[\"onAttachmentClick\"];\n\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: ComposerProps[\"onComposerSubmit\"];\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides & ThreadOverrides & CommentOverrides & ComposerOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\n/**\n * Displays a thread of comments, with a composer to reply\n * to it.\n *\n * @example\n * <>\n * {threads.map((thread) => (\n * <Thread key={thread.id} thread={thread} />\n * ))}\n * </>\n */\nexport const Thread = forwardRef(\n <M extends BaseMetadata = DM>(\n {\n thread,\n indentCommentContent = true,\n showActions = \"hover\",\n showDeletedComments,\n showResolveAction = true,\n showReactions = true,\n showComposer = \"collapsed\",\n showAttachments = true,\n showComposerFormattingControls = true,\n maxVisibleComments,\n onResolvedChange,\n onCommentEdit,\n onCommentDelete,\n onThreadDelete,\n onAuthorClick,\n onMentionClick,\n onAttachmentClick,\n onComposerSubmit,\n blurComposerOnSubmit,\n overrides,\n components,\n className,\n ...props\n }: ThreadProps<M>,\n forwardedRef: ForwardedRef<HTMLDivElement>\n ) => {\n const markThreadAsResolved = useMarkRoomThreadAsResolved(thread.roomId);\n const markThreadAsUnresolved = useMarkRoomThreadAsUnresolved(thread.roomId);\n const $ = useOverrides(overrides);\n const [showAllComments, setShowAllComments] = useState(false);\n const firstCommentIndex = useMemo(() => {\n return showDeletedComments\n ? 0\n : thread.comments.findIndex((comment) => comment.body);\n }, [showDeletedComments, thread.comments]);\n const lastCommentIndex = useMemo(() => {\n return showDeletedComments\n ? thread.comments.length - 1\n : findLastIndex(thread.comments, (comment) => Boolean(comment.body));\n }, [showDeletedComments, thread.comments]);\n const hiddenComments = useMemo(() => {\n const maxVisibleCommentsCount =\n typeof maxVisibleComments === \"number\"\n ? maxVisibleComments\n : maxVisibleComments?.max;\n const visibleCommentsShow =\n (typeof maxVisibleComments === \"object\"\n ? maxVisibleComments?.show\n : undefined) ?? \"newest\";\n\n // If we explicitly want to show all comments or there's no limit set,\n // no need to hide any comments.\n if (showAllComments || maxVisibleCommentsCount === undefined) {\n return;\n }\n\n const comments = thread.comments\n .map((comment, index) => ({ comment, index }))\n .filter(({ comment }) => showDeletedComments || comment.body);\n\n // There aren't enough comments so no need to hide any.\n if (comments.length <= Math.max(maxVisibleCommentsCount, 2)) {\n return;\n }\n\n const firstVisibleComment = comments[0]!;\n const lastVisibleComment = comments[comments.length - 1]!;\n\n // Always show the first and last comments even if the limit is set to lower than 2.\n if (maxVisibleCommentsCount <= 2) {\n const firstHiddenCommentIndex =\n comments[1]?.index ?? firstVisibleComment.index;\n const lastHiddenCommentIndex =\n comments[comments.length - 2]?.index ?? lastVisibleComment.index;\n\n return {\n firstIndex: firstHiddenCommentIndex,\n lastIndex: lastHiddenCommentIndex,\n count: comments.slice(1, comments.length - 1).length,\n };\n }\n\n const remainingVisibleCommentsCount = maxVisibleCommentsCount - 2;\n\n // Split the remaining visible comments before, after, or equally.\n const beforeVisibleCommentsCount =\n visibleCommentsShow === \"oldest\"\n ? remainingVisibleCommentsCount\n : visibleCommentsShow === \"newest\"\n ? 0\n : Math.floor(remainingVisibleCommentsCount / 2);\n const afterVisibleCommentsCount =\n visibleCommentsShow === \"oldest\"\n ? 0\n : visibleCommentsShow === \"newest\"\n ? remainingVisibleCommentsCount\n : Math.ceil(remainingVisibleCommentsCount / 2);\n\n // The first comment is always visible so `+ 1` to skip it.\n const firstHiddenComment = comments[1 + beforeVisibleCommentsCount];\n // The last comment is always visible so `- 2` to skip it.\n const lastHiddenComment =\n comments[comments.length - 2 - afterVisibleCommentsCount];\n\n // There aren't any comments to hide besides the first and last ones.\n if (\n !firstHiddenComment ||\n !lastHiddenComment ||\n firstHiddenComment.index > lastHiddenComment.index\n ) {\n return;\n }\n\n return {\n firstIndex: firstHiddenComment.index,\n lastIndex: lastHiddenComment.index,\n count: thread.comments\n .slice(firstHiddenComment.index, lastHiddenComment.index + 1)\n .filter((comment) => showDeletedComments || comment.body).length,\n };\n }, [\n maxVisibleComments,\n showAllComments,\n showDeletedComments,\n thread.comments,\n ]);\n const {\n status: subscriptionStatus,\n unreadSince,\n subscribe,\n unsubscribe,\n } = useRoomThreadSubscription(thread.roomId, thread.id);\n const unreadIndex = useMemo(() => {\n // The user is not subscribed to this thread.\n if (subscriptionStatus !== \"subscribed\") {\n return;\n }\n\n // The user hasn't read the thread yet, so all comments are unread.\n if (unreadSince === null) {\n return firstCommentIndex;\n }\n\n // The user has read the thread, so we find the first unread comment.\n const unreadIndex = thread.comments.findIndex(\n (comment) =>\n (showDeletedComments ? true : comment.body) &&\n comment.createdAt > unreadSince\n );\n\n return unreadIndex >= 0 && unreadIndex < thread.comments.length\n ? unreadIndex\n : undefined;\n }, [\n firstCommentIndex,\n showDeletedComments,\n subscriptionStatus,\n thread.comments,\n unreadSince,\n ]);\n const [newIndex, setNewIndex] = useState<number>();\n const newIndicatorIndex = newIndex === undefined ? unreadIndex : newIndex;\n\n useEffect(() => {\n if (unreadIndex) {\n // Keep the \"new\" indicator at the lowest unread index.\n setNewIndex((persistedUnreadIndex) =>\n Math.min(persistedUnreadIndex ?? Infinity, unreadIndex)\n );\n }\n }, [unreadIndex]);\n\n const permissions = useRoomPermissions(thread.roomId);\n const canComment =\n permissions.size > 0\n ? permissions.has(Permission.CommentsWrite) ||\n permissions.has(Permission.Write)\n : true;\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const handleResolvedChange = useCallback(\n (resolved: boolean) => {\n onResolvedChange?.(resolved);\n\n if (resolved) {\n markThreadAsResolved(thread.id);\n } else {\n markThreadAsUnresolved(thread.id);\n }\n },\n [\n markThreadAsResolved,\n markThreadAsUnresolved,\n onResolvedChange,\n thread.id,\n ]\n );\n\n const handleCommentDelete = useCallback(\n (comment: CommentData) => {\n onCommentDelete?.(comment);\n\n const filteredComments = thread.comments.filter(\n (comment) => comment.body\n );\n\n if (filteredComments.length <= 1) {\n onThreadDelete?.(thread);\n }\n },\n [onCommentDelete, onThreadDelete, thread]\n );\n\n const handleSubscribeChange = useCallback(() => {\n if (subscriptionStatus === \"subscribed\") {\n unsubscribe();\n } else {\n subscribe();\n }\n }, [subscriptionStatus, subscribe, unsubscribe]);\n\n return (\n <TooltipProvider>\n <div\n className={cn(\n \"lb-root lb-thread\",\n showActions === \"hover\" && \"lb-thread:show-actions-hover\",\n className\n )}\n data-resolved={thread.resolved ? \"\" : undefined}\n data-unread={unreadIndex !== undefined ? \"\" : undefined}\n dir={$.dir}\n {...props}\n ref={forwardedRef}\n >\n <div className=\"lb-thread-comments\">\n {thread.comments.map((comment, index) => {\n const isFirstComment = index === firstCommentIndex;\n const isUnread =\n unreadIndex !== undefined && index >= unreadIndex;\n const isHidden =\n hiddenComments &&\n index >= hiddenComments.firstIndex &&\n index <= hiddenComments.lastIndex;\n const isFirstHiddenComment =\n isHidden && index === hiddenComments.firstIndex;\n\n if (isFirstHiddenComment) {\n return (\n <div\n key={`${comment.id}-show-more`}\n className=\"lb-thread-show-more\"\n >\n <Button\n variant=\"ghost\"\n className=\"lb-thread-show-more-button\"\n onClick={() => setShowAllComments(true)}\n >\n {$.THREAD_SHOW_MORE_COMMENTS(hiddenComments.count)}\n </Button>\n </div>\n );\n }\n\n if (isHidden) {\n return null;\n }\n\n const children = (\n <Comment\n key={comment.id}\n overrides={overrides}\n className=\"lb-thread-comment\"\n data-unread={isUnread ? \"\" : undefined}\n comment={comment}\n indentContent={indentCommentContent}\n showDeleted={showDeletedComments}\n showActions={showActions}\n showReactions={showReactions}\n showAttachments={showAttachments}\n showComposerFormattingControls={\n showComposerFormattingControls\n }\n onCommentEdit={onCommentEdit}\n onCommentDelete={handleCommentDelete}\n onAuthorClick={onAuthorClick}\n onMentionClick={onMentionClick}\n onAttachmentClick={onAttachmentClick}\n components={components}\n autoMarkReadThreadId={\n index === lastCommentIndex && isUnread\n ? thread.id\n : undefined\n }\n additionalActionsClassName={\n isFirstComment ? \"lb-thread-actions\" : undefined\n }\n additionalActions={\n isFirstComment && showResolveAction ? (\n <Tooltip\n content={\n thread.resolved\n ? $.THREAD_UNRESOLVE\n : $.THREAD_RESOLVE\n }\n >\n <TogglePrimitive.Root\n pressed={thread.resolved}\n onPressedChange={handleResolvedChange}\n asChild\n >\n <Button\n className=\"lb-comment-action\"\n onClick={stopPropagation}\n aria-label={\n thread.resolved\n ? $.THREAD_UNRESOLVE\n : $.THREAD_RESOLVE\n }\n icon={\n thread.resolved ? (\n <CheckCircleFillIcon />\n ) : (\n <CheckCircleIcon />\n )\n }\n disabled={!canComment}\n />\n </TogglePrimitive.Root>\n </Tooltip>\n ) : null\n }\n additionalDropdownItemsBefore={\n isFirstComment ? (\n <DropdownItem\n onSelect={handleSubscribeChange}\n onClick={stopPropagation}\n icon={\n subscriptionStatus === \"subscribed\" ? (\n <BellCrossedIcon />\n ) : (\n <BellIcon />\n )\n }\n >\n {subscriptionStatus === \"subscribed\"\n ? $.THREAD_UNSUBSCRIBE\n : $.THREAD_SUBSCRIBE}\n </DropdownItem>\n ) : null\n }\n />\n );\n\n return index === newIndicatorIndex &&\n newIndicatorIndex !== firstCommentIndex &&\n newIndicatorIndex <= lastCommentIndex ? (\n <Fragment key={comment.id}>\n <div\n className=\"lb-thread-new-indicator\"\n aria-label={$.THREAD_NEW_INDICATOR_DESCRIPTION}\n >\n <span className=\"lb-thread-new-indicator-label\">\n <ArrowDownIcon className=\"lb-thread-new-indicator-label-icon\" />\n {$.THREAD_NEW_INDICATOR}\n </span>\n </div>\n {children}\n </Fragment>\n ) : (\n children\n );\n })}\n </div>\n {showComposer && (\n <Composer\n className=\"lb-thread-composer\"\n threadId={thread.id}\n defaultCollapsed={showComposer === \"collapsed\" ? true : undefined}\n showAttachments={showAttachments}\n showFormattingControls={showComposerFormattingControls}\n onComposerSubmit={onComposerSubmit}\n blurOnSubmit={blurComposerOnSubmit}\n overrides={{\n COMPOSER_PLACEHOLDER: $.THREAD_COMPOSER_PLACEHOLDER,\n COMPOSER_SEND: $.THREAD_COMPOSER_SEND,\n ...overrides,\n }}\n roomId={thread.roomId}\n />\n )}\n </div>\n </TooltipProvider>\n );\n }\n) as <M extends BaseMetadata = DM>(\n props: ThreadProps<M> & RefAttributes<HTMLDivElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAiMO;AAAe;AAElB;AACE;AACuB;AACT;AACd;AACoB;AACJ;AACD;AACG;AACe;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACE;AAEuD;AAEzD;AACE;AAEqE;AAEvE;AACE;AAIA;AAOA;AACE;AAAA;AAGF;AAKA;AACE;AAAA;AAGF;AACA;AAGA;AACE;AAEA;AAGA;AAAO;AACO;AACD;AACmC;AAChD;AAGF;AAGA;AAMA;AAQA;AAEA;AAIA;AAKE;AAAA;AAGF;AAAO;AAC0B;AACF;AAG+B;AAC9D;AACC;AACD;AACA;AACA;AACO;AAET;AAAM;AACI;AACR;AACA;AACA;AAEF;AAEE;AACE;AAAA;AAIF;AACE;AAAO;AAIT;AAAoC;AAGZ;AAGxB;AAEI;AACH;AACD;AACA;AACA;AACO;AACP;AAEF;AACA;AAEA;AACE;AAEE;AAAA;AACwD;AACxD;AACF;AAGF;AACA;AAMA;AACE;AAAsB;AAGxB;AAA6B;AAEzB;AAEA;AACE;AAA8B;AAE9B;AAAgC;AAClC;AACF;AACA;AACE;AACA;AACA;AACO;AACT;AAGF;AAA4B;AAExB;AAEA;AAAyC;AAClB;AAGvB;AACE;AAAuB;AACzB;AACF;AACwC;AAG1C;AACE;AACE;AAAY;AAEZ;AAAU;AACZ;AAGF;AACG;AACE;AACY;AACT;AAC2B;AAC3B;AACF;AACsC;AACQ;AACvC;AACH;AACC;AAEL;AAAC;AAAc;AAEX;AACA;AAEA;AAIA;AAGA;AACE;AACG;AAEW;AAET;AACS;AACE;AAC4B;AAEW;AACnD;AACF;AAIJ;AACE;AAAO;AAGT;AACG;AAEC;AACU;AACmB;AAC7B;AACe;AACF;AACb;AACA;AACA;AACA;AAGA;AACiB;AACjB;AACA;AACA;AACA;AAIM;AAGmC;AAIpC;AAIS;AAGP;AACiB;AACC;AACV;AAEN;AACW;AACD;AAID;AAMa;AAGV;AACb;AACF;AAEA;AAID;AACW;AACD;AAKK;AAMR;AAEN;AAKV;AAGG;AACC;AAAC;AACW;AACI;AAEb;AAAe;AACd;AAAC;AAAwB;AAAqC;AAC3D;AAAA;AACL;AACF;AACC;AAAA;AAGH;AAEH;AACH;AAEG;AACW;AACO;AACuC;AACxD;AACwB;AACxB;AACc;AACH;AACe;AACP;AACd;AACL;AACe;AACjB;AAAA;AAEJ;AACF;AAGN;;"}
|
|
@@ -85,27 +85,17 @@ function AssistantMessageContent({
|
|
|
85
85
|
message,
|
|
86
86
|
components
|
|
87
87
|
}) {
|
|
88
|
-
const ref = react.useRef(components);
|
|
89
|
-
const BoundTextPart = react.useMemo(
|
|
90
|
-
() => (props) => /* @__PURE__ */ jsxRuntime.jsx(TextPart, {
|
|
91
|
-
...props,
|
|
92
|
-
components: ref.current
|
|
93
|
-
}),
|
|
94
|
-
[]
|
|
95
|
-
);
|
|
96
|
-
const BoundReasoningPart = react.useMemo(
|
|
97
|
-
() => (props) => /* @__PURE__ */ jsxRuntime.jsx(ReasoningPart, {
|
|
98
|
-
...props,
|
|
99
|
-
components: ref.current
|
|
100
|
-
}),
|
|
101
|
-
[]
|
|
102
|
-
);
|
|
103
88
|
return /* @__PURE__ */ jsxRuntime.jsx(index.Content, {
|
|
104
89
|
message,
|
|
105
90
|
components: {
|
|
106
|
-
TextPart:
|
|
107
|
-
|
|
108
|
-
|
|
91
|
+
TextPart: (props) => /* @__PURE__ */ jsxRuntime.jsx(TextPart, {
|
|
92
|
+
...props,
|
|
93
|
+
components
|
|
94
|
+
}),
|
|
95
|
+
ReasoningPart: (props) => /* @__PURE__ */ jsxRuntime.jsx(ReasoningPart, {
|
|
96
|
+
...props,
|
|
97
|
+
components
|
|
98
|
+
}),
|
|
109
99
|
ToolInvocationPart
|
|
110
100
|
},
|
|
111
101
|
className: "lb-ai-chat-message-content"
|
|
@@ -138,7 +128,7 @@ function ReasoningPart({ part, isStreaming, components }) {
|
|
|
138
128
|
isStreaming && "lb-ai-chat-pending"
|
|
139
129
|
),
|
|
140
130
|
children: [
|
|
141
|
-
$.AI_CHAT_MESSAGE_REASONING(isStreaming
|
|
131
|
+
$.AI_CHAT_MESSAGE_REASONING(isStreaming),
|
|
142
132
|
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
143
133
|
className: "lb-collapsible-chevron lb-icon-container",
|
|
144
134
|
children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight.ChevronRightIcon, {})
|
|
@@ -156,16 +146,6 @@ function ReasoningPart({ part, isStreaming, components }) {
|
|
|
156
146
|
]
|
|
157
147
|
});
|
|
158
148
|
}
|
|
159
|
-
function RetrievalPart({ part, isStreaming }) {
|
|
160
|
-
const $ = overrides.useOverrides();
|
|
161
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
162
|
-
className: cn.cn(
|
|
163
|
-
"lb-ai-chat-message-retrieval",
|
|
164
|
-
isStreaming && "lb-ai-chat-pending"
|
|
165
|
-
),
|
|
166
|
-
children: $.AI_CHAT_MESSAGE_RETRIEVAL(isStreaming, part)
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
149
|
function ToolInvocationPart({
|
|
170
150
|
part,
|
|
171
151
|
message
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiChatAssistantMessage.cjs","sources":["../../../src/components/internal/AiChatAssistantMessage.tsx"],"sourcesContent":["import type { AiAssistantMessage, WithNavigation } from \"@liveblocks/core\";\nimport {\n type ComponentProps,\n forwardRef,\n memo,\n type ReactNode,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { type GlobalComponents } from \"../../components\";\nimport { ChevronRightIcon } from \"../../icons/ChevronRight\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport {\n type AiChatMessageOverrides,\n type GlobalOverrides,\n OverridesProvider,\n useOverrides,\n} from \"../../overrides\";\nimport * as AiMessage from \"../../primitives/AiMessage\";\nimport { AiMessageToolInvocation } from \"../../primitives/AiMessage/tool-invocation\";\nimport type {\n AiMessageContentReasoningPartProps,\n AiMessageContentRetrievalPartProps,\n AiMessageContentTextPartProps,\n AiMessageContentToolInvocationPartProps,\n} from \"../../primitives/AiMessage/types\";\nimport * as Collapsible from \"../../primitives/Collapsible\";\nimport type { MarkdownComponents } from \"../../primitives/Markdown\";\nimport { cn } from \"../../utils/cn\";\nimport { ErrorBoundary } from \"../../utils/ErrorBoundary\";\nimport { Prose } from \"./Prose\";\n\ntype UiAssistantMessage = WithNavigation<AiAssistantMessage>;\n\ntype AiChatAssistantMessageComponents = {\n /**\n * The components used to render Markdown content.\n */\n markdown?: Partial<MarkdownComponents>;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * AiChatAssistantMessage\n * -----------------------------------------------------------------------------------------------*/\nexport interface AiChatAssistantMessageProps extends ComponentProps<\"div\"> {\n /**\n * The message to display.\n */\n message: UiAssistantMessage;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & AiChatMessageOverrides>;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\ninterface TextPartProps extends AiMessageContentTextPartProps {\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\ninterface ReasoningPartProps extends AiMessageContentReasoningPartProps {\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\ninterface RetrievalPartProps extends AiMessageContentRetrievalPartProps {\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\nexport const AiChatAssistantMessage = memo(\n forwardRef<HTMLDivElement, AiChatAssistantMessageProps>(\n ({ message, className, overrides, components, ...props }, forwardedRef) => {\n const $ = useOverrides(overrides);\n\n let children: ReactNode = null;\n\n if (message.deletedAt !== undefined) {\n children = (\n <div className=\"lb-ai-chat-message-deleted\">\n {$.AI_CHAT_MESSAGE_DELETED}\n </div>\n );\n } else if (\n message.status === \"generating\" ||\n message.status === \"awaiting-tool\"\n ) {\n if (message.contentSoFar.length === 0) {\n children = (\n <div className=\"lb-ai-chat-message-thinking lb-ai-chat-pending\">\n {$.AI_CHAT_MESSAGE_THINKING}\n </div>\n );\n } else {\n children = (\n <AssistantMessageContent\n message={message}\n components={components}\n />\n );\n }\n } else if (message.status === \"completed\") {\n children = (\n <AssistantMessageContent message={message} components={components} />\n );\n } else if (message.status === \"failed\") {\n // Do not include the error message if the user aborted the request.\n if (message.errorReason === \"Aborted by user\") {\n children = (\n <AssistantMessageContent\n message={message}\n components={components}\n />\n );\n } else {\n children = (\n <>\n <AssistantMessageContent\n message={message}\n components={components}\n />\n\n <div className=\"lb-ai-chat-message-error\">\n <span className=\"lb-icon-container\">\n <WarningIcon />\n </span>\n {message.errorReason}\n </div>\n </>\n );\n }\n }\n\n return (\n <div\n className={cn(\n \"lb-ai-chat-message lb-ai-chat-assistant-message\",\n className\n )}\n {...props}\n ref={forwardedRef}\n >\n <OverridesProvider overrides={overrides}>\n {children}\n </OverridesProvider>\n </div>\n );\n }\n )\n);\n\nfunction AssistantMessageContent({\n message,\n components,\n}: {\n message: UiAssistantMessage;\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}) {\n const ref = useRef(components);\n const BoundTextPart = useMemo(\n () => (props: TextPartProps) => (\n <TextPart {...props} components={ref.current} />\n ),\n []\n );\n const BoundReasoningPart = useMemo(\n () => (props: ReasoningPartProps) => (\n <ReasoningPart {...props} components={ref.current} />\n ),\n []\n );\n return (\n <AiMessage.Content\n message={message}\n components={{\n TextPart: BoundTextPart,\n ReasoningPart: BoundReasoningPart,\n RetrievalPart,\n ToolInvocationPart,\n }}\n className=\"lb-ai-chat-message-content\"\n />\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * TextPart\n * -----------------------------------------------------------------------------------------------*/\nfunction TextPart({ part, components, isStreaming }: TextPartProps) {\n return (\n <Prose\n content={part.text}\n className=\"lb-ai-chat-message-text\"\n components={components}\n partial={isStreaming}\n />\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * ReasoningPart\n * -----------------------------------------------------------------------------------------------*/\nfunction ReasoningPart({ part, isStreaming, components }: ReasoningPartProps) {\n // Start collapsed if reasoning is already done.\n const [isOpen, setIsOpen] = useState(isStreaming);\n const $ = useOverrides();\n\n // Auto-collapse when reasoning is done, while still allowing the user to\n // open/collapse it manually during and after it's done.\n useEffect(() => {\n if (!isStreaming) {\n setIsOpen(false);\n }\n }, [isStreaming]);\n\n return (\n <Collapsible.Root\n className=\"lb-collapsible lb-ai-chat-message-reasoning\"\n open={isOpen}\n onOpenChange={setIsOpen}\n >\n <Collapsible.Trigger\n className={cn(\n \"lb-collapsible-trigger\",\n isStreaming && \"lb-ai-chat-pending\"\n )}\n >\n {$.AI_CHAT_MESSAGE_REASONING(isStreaming, part)}\n <span className=\"lb-collapsible-chevron lb-icon-container\">\n <ChevronRightIcon />\n </span>\n </Collapsible.Trigger>\n\n <Collapsible.Content className=\"lb-collapsible-content\">\n <Prose\n content={part.text}\n partial={isStreaming}\n components={components}\n />\n </Collapsible.Content>\n </Collapsible.Root>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * RetrievalPart\n * -----------------------------------------------------------------------------------------------*/\nfunction RetrievalPart({ part, isStreaming }: RetrievalPartProps) {\n const $ = useOverrides();\n\n return (\n <div\n className={cn(\n \"lb-ai-chat-message-retrieval\",\n isStreaming && \"lb-ai-chat-pending\"\n )}\n >\n {$.AI_CHAT_MESSAGE_RETRIEVAL(isStreaming, part)}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * ToolInvocationPart\n * -----------------------------------------------------------------------------------------------*/\nfunction ToolInvocationPart({\n part,\n message,\n}: AiMessageContentToolInvocationPartProps) {\n return (\n <div className=\"lb-ai-chat-message-tool-invocation\">\n <ErrorBoundary\n fallback={\n <div className=\"lb-ai-chat-message-error\">\n <span className=\"lb-icon-container\">\n <WarningIcon />\n </span>\n <p>\n Failed to render tool call result for <code>{part.name}</code>.\n See console for details.\n </p>\n </div>\n }\n >\n <AiMessageToolInvocation part={part} message={message} />\n </ErrorBoundary>\n </div>\n );\n}\n"],"names":["memo","forwardRef","overrides","useOverrides","jsx","jsxs","Fragment","WarningIcon","cn","OverridesProvider","useRef","useMemo","AiMessage.Content","Prose","useState","useEffect","Collapsible.Root","Collapsible.Trigger","ChevronRightIcon","Collapsible.Content","ErrorBoundary","AiMessageToolInvocation"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AiChatAssistantMessage.cjs","sources":["../../../src/components/internal/AiChatAssistantMessage.tsx"],"sourcesContent":["import type { AiAssistantMessage, WithNavigation } from \"@liveblocks/core\";\nimport {\n type ComponentProps,\n forwardRef,\n memo,\n type ReactNode,\n useEffect,\n useState,\n} from \"react\";\n\nimport { type GlobalComponents } from \"../../components\";\nimport { ChevronRightIcon } from \"../../icons/ChevronRight\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport {\n type AiChatMessageOverrides,\n type GlobalOverrides,\n OverridesProvider,\n useOverrides,\n} from \"../../overrides\";\nimport * as AiMessage from \"../../primitives/AiMessage\";\nimport { AiMessageToolInvocation } from \"../../primitives/AiMessage/tool-invocation\";\nimport type {\n AiMessageContentReasoningPartProps,\n AiMessageContentTextPartProps,\n AiMessageContentToolInvocationPartProps,\n} from \"../../primitives/AiMessage/types\";\nimport * as Collapsible from \"../../primitives/Collapsible\";\nimport type { MarkdownComponents } from \"../../primitives/Markdown\";\nimport { cn } from \"../../utils/cn\";\nimport { ErrorBoundary } from \"../../utils/ErrorBoundary\";\nimport { Prose } from \"./Prose\";\n\ntype UiAssistantMessage = WithNavigation<AiAssistantMessage>;\n\ntype AiChatAssistantMessageComponents = {\n /**\n * The components used to render Markdown content.\n */\n markdown?: Partial<MarkdownComponents>;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * AiChatAssistantMessage\n * -----------------------------------------------------------------------------------------------*/\nexport interface AiChatAssistantMessageProps extends ComponentProps<\"div\"> {\n /**\n * The message to display.\n */\n message: UiAssistantMessage;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & AiChatMessageOverrides>;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\ninterface TextPartProps extends AiMessageContentTextPartProps {\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\ninterface ReasoningPartProps extends AiMessageContentReasoningPartProps {\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\nexport const AiChatAssistantMessage = memo(\n forwardRef<HTMLDivElement, AiChatAssistantMessageProps>(\n ({ message, className, overrides, components, ...props }, forwardedRef) => {\n const $ = useOverrides(overrides);\n\n let children: ReactNode = null;\n\n if (message.deletedAt !== undefined) {\n children = (\n <div className=\"lb-ai-chat-message-deleted\">\n {$.AI_CHAT_MESSAGE_DELETED}\n </div>\n );\n } else if (\n message.status === \"generating\" ||\n message.status === \"awaiting-tool\"\n ) {\n if (message.contentSoFar.length === 0) {\n children = (\n <div className=\"lb-ai-chat-message-thinking lb-ai-chat-pending\">\n {$.AI_CHAT_MESSAGE_THINKING}\n </div>\n );\n } else {\n children = (\n <AssistantMessageContent\n message={message}\n components={components}\n />\n );\n }\n } else if (message.status === \"completed\") {\n children = (\n <AssistantMessageContent message={message} components={components} />\n );\n } else if (message.status === \"failed\") {\n // Do not include the error message if the user aborted the request.\n if (message.errorReason === \"Aborted by user\") {\n children = (\n <AssistantMessageContent\n message={message}\n components={components}\n />\n );\n } else {\n children = (\n <>\n <AssistantMessageContent\n message={message}\n components={components}\n />\n\n <div className=\"lb-ai-chat-message-error\">\n <span className=\"lb-icon-container\">\n <WarningIcon />\n </span>\n {message.errorReason}\n </div>\n </>\n );\n }\n }\n\n return (\n <div\n className={cn(\n \"lb-ai-chat-message lb-ai-chat-assistant-message\",\n className\n )}\n {...props}\n ref={forwardedRef}\n >\n <OverridesProvider overrides={overrides}>\n {children}\n </OverridesProvider>\n </div>\n );\n }\n )\n);\n\nfunction AssistantMessageContent({\n message,\n components,\n}: {\n message: UiAssistantMessage;\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}) {\n return (\n <AiMessage.Content\n message={message}\n components={{\n TextPart: (props) => <TextPart {...props} components={components} />,\n ReasoningPart: (props) => (\n <ReasoningPart {...props} components={components} />\n ),\n ToolInvocationPart,\n }}\n className=\"lb-ai-chat-message-content\"\n />\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * TextPart\n * -----------------------------------------------------------------------------------------------*/\nfunction TextPart({ part, components, isStreaming }: TextPartProps) {\n return (\n <Prose\n content={part.text}\n className=\"lb-ai-chat-message-text\"\n components={components}\n partial={isStreaming}\n />\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * ReasoningPart\n * -----------------------------------------------------------------------------------------------*/\nfunction ReasoningPart({ part, isStreaming, components }: ReasoningPartProps) {\n // Start collapsed if reasoning is already done.\n const [isOpen, setIsOpen] = useState(isStreaming);\n const $ = useOverrides();\n\n // Auto-collapse when reasoning is done, while still allowing the user to\n // open/collapse it manually during and after it's done.\n useEffect(() => {\n if (!isStreaming) {\n setIsOpen(false);\n }\n }, [isStreaming]);\n\n return (\n <Collapsible.Root\n className=\"lb-collapsible lb-ai-chat-message-reasoning\"\n open={isOpen}\n onOpenChange={setIsOpen}\n >\n <Collapsible.Trigger\n className={cn(\n \"lb-collapsible-trigger\",\n isStreaming && \"lb-ai-chat-pending\"\n )}\n >\n {/* TODO: Show duration as \"Reasoned for x seconds\"? */}\n {$.AI_CHAT_MESSAGE_REASONING(isStreaming)}\n <span className=\"lb-collapsible-chevron lb-icon-container\">\n <ChevronRightIcon />\n </span>\n </Collapsible.Trigger>\n\n <Collapsible.Content className=\"lb-collapsible-content\">\n <Prose\n content={part.text}\n partial={isStreaming}\n components={components}\n />\n </Collapsible.Content>\n </Collapsible.Root>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * ToolInvocationPart\n * -----------------------------------------------------------------------------------------------*/\nfunction ToolInvocationPart({\n part,\n message,\n}: AiMessageContentToolInvocationPartProps) {\n return (\n <div className=\"lb-ai-chat-message-tool-invocation\">\n <ErrorBoundary\n fallback={\n <div className=\"lb-ai-chat-message-error\">\n <span className=\"lb-icon-container\">\n <WarningIcon />\n </span>\n <p>\n Failed to render tool call result for <code>{part.name}</code>.\n See console for details.\n </p>\n </div>\n }\n >\n <AiMessageToolInvocation part={part} message={message} />\n </ErrorBoundary>\n </div>\n );\n}\n"],"names":["memo","forwardRef","overrides","useOverrides","jsx","jsxs","Fragment","WarningIcon","cn","OverridesProvider","AiMessage.Content","Prose","useState","useEffect","Collapsible.Root","Collapsible.Trigger","ChevronRightIcon","Collapsible.Content","ErrorBoundary","AiMessageToolInvocation"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { memo, forwardRef,
|
|
2
|
+
import { memo, forwardRef, useState, useEffect } from 'react';
|
|
3
3
|
import { ChevronRightIcon } from '../../icons/ChevronRight.js';
|
|
4
4
|
import { WarningIcon } from '../../icons/Warning.js';
|
|
5
5
|
import { useOverrides, OverridesProvider } from '../../overrides.js';
|
|
@@ -83,27 +83,17 @@ function AssistantMessageContent({
|
|
|
83
83
|
message,
|
|
84
84
|
components
|
|
85
85
|
}) {
|
|
86
|
-
const ref = useRef(components);
|
|
87
|
-
const BoundTextPart = useMemo(
|
|
88
|
-
() => (props) => /* @__PURE__ */ jsx(TextPart, {
|
|
89
|
-
...props,
|
|
90
|
-
components: ref.current
|
|
91
|
-
}),
|
|
92
|
-
[]
|
|
93
|
-
);
|
|
94
|
-
const BoundReasoningPart = useMemo(
|
|
95
|
-
() => (props) => /* @__PURE__ */ jsx(ReasoningPart, {
|
|
96
|
-
...props,
|
|
97
|
-
components: ref.current
|
|
98
|
-
}),
|
|
99
|
-
[]
|
|
100
|
-
);
|
|
101
86
|
return /* @__PURE__ */ jsx(AiMessageContent, {
|
|
102
87
|
message,
|
|
103
88
|
components: {
|
|
104
|
-
TextPart:
|
|
105
|
-
|
|
106
|
-
|
|
89
|
+
TextPart: (props) => /* @__PURE__ */ jsx(TextPart, {
|
|
90
|
+
...props,
|
|
91
|
+
components
|
|
92
|
+
}),
|
|
93
|
+
ReasoningPart: (props) => /* @__PURE__ */ jsx(ReasoningPart, {
|
|
94
|
+
...props,
|
|
95
|
+
components
|
|
96
|
+
}),
|
|
107
97
|
ToolInvocationPart
|
|
108
98
|
},
|
|
109
99
|
className: "lb-ai-chat-message-content"
|
|
@@ -136,7 +126,7 @@ function ReasoningPart({ part, isStreaming, components }) {
|
|
|
136
126
|
isStreaming && "lb-ai-chat-pending"
|
|
137
127
|
),
|
|
138
128
|
children: [
|
|
139
|
-
$.AI_CHAT_MESSAGE_REASONING(isStreaming
|
|
129
|
+
$.AI_CHAT_MESSAGE_REASONING(isStreaming),
|
|
140
130
|
/* @__PURE__ */ jsx("span", {
|
|
141
131
|
className: "lb-collapsible-chevron lb-icon-container",
|
|
142
132
|
children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
|
|
@@ -154,16 +144,6 @@ function ReasoningPart({ part, isStreaming, components }) {
|
|
|
154
144
|
]
|
|
155
145
|
});
|
|
156
146
|
}
|
|
157
|
-
function RetrievalPart({ part, isStreaming }) {
|
|
158
|
-
const $ = useOverrides();
|
|
159
|
-
return /* @__PURE__ */ jsx("div", {
|
|
160
|
-
className: cn(
|
|
161
|
-
"lb-ai-chat-message-retrieval",
|
|
162
|
-
isStreaming && "lb-ai-chat-pending"
|
|
163
|
-
),
|
|
164
|
-
children: $.AI_CHAT_MESSAGE_RETRIEVAL(isStreaming, part)
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
147
|
function ToolInvocationPart({
|
|
168
148
|
part,
|
|
169
149
|
message
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiChatAssistantMessage.js","sources":["../../../src/components/internal/AiChatAssistantMessage.tsx"],"sourcesContent":["import type { AiAssistantMessage, WithNavigation } from \"@liveblocks/core\";\nimport {\n type ComponentProps,\n forwardRef,\n memo,\n type ReactNode,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport { type GlobalComponents } from \"../../components\";\nimport { ChevronRightIcon } from \"../../icons/ChevronRight\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport {\n type AiChatMessageOverrides,\n type GlobalOverrides,\n OverridesProvider,\n useOverrides,\n} from \"../../overrides\";\nimport * as AiMessage from \"../../primitives/AiMessage\";\nimport { AiMessageToolInvocation } from \"../../primitives/AiMessage/tool-invocation\";\nimport type {\n AiMessageContentReasoningPartProps,\n AiMessageContentRetrievalPartProps,\n AiMessageContentTextPartProps,\n AiMessageContentToolInvocationPartProps,\n} from \"../../primitives/AiMessage/types\";\nimport * as Collapsible from \"../../primitives/Collapsible\";\nimport type { MarkdownComponents } from \"../../primitives/Markdown\";\nimport { cn } from \"../../utils/cn\";\nimport { ErrorBoundary } from \"../../utils/ErrorBoundary\";\nimport { Prose } from \"./Prose\";\n\ntype UiAssistantMessage = WithNavigation<AiAssistantMessage>;\n\ntype AiChatAssistantMessageComponents = {\n /**\n * The components used to render Markdown content.\n */\n markdown?: Partial<MarkdownComponents>;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * AiChatAssistantMessage\n * -----------------------------------------------------------------------------------------------*/\nexport interface AiChatAssistantMessageProps extends ComponentProps<\"div\"> {\n /**\n * The message to display.\n */\n message: UiAssistantMessage;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & AiChatMessageOverrides>;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\ninterface TextPartProps extends AiMessageContentTextPartProps {\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\ninterface ReasoningPartProps extends AiMessageContentReasoningPartProps {\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\ninterface RetrievalPartProps extends AiMessageContentRetrievalPartProps {\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\nexport const AiChatAssistantMessage = memo(\n forwardRef<HTMLDivElement, AiChatAssistantMessageProps>(\n ({ message, className, overrides, components, ...props }, forwardedRef) => {\n const $ = useOverrides(overrides);\n\n let children: ReactNode = null;\n\n if (message.deletedAt !== undefined) {\n children = (\n <div className=\"lb-ai-chat-message-deleted\">\n {$.AI_CHAT_MESSAGE_DELETED}\n </div>\n );\n } else if (\n message.status === \"generating\" ||\n message.status === \"awaiting-tool\"\n ) {\n if (message.contentSoFar.length === 0) {\n children = (\n <div className=\"lb-ai-chat-message-thinking lb-ai-chat-pending\">\n {$.AI_CHAT_MESSAGE_THINKING}\n </div>\n );\n } else {\n children = (\n <AssistantMessageContent\n message={message}\n components={components}\n />\n );\n }\n } else if (message.status === \"completed\") {\n children = (\n <AssistantMessageContent message={message} components={components} />\n );\n } else if (message.status === \"failed\") {\n // Do not include the error message if the user aborted the request.\n if (message.errorReason === \"Aborted by user\") {\n children = (\n <AssistantMessageContent\n message={message}\n components={components}\n />\n );\n } else {\n children = (\n <>\n <AssistantMessageContent\n message={message}\n components={components}\n />\n\n <div className=\"lb-ai-chat-message-error\">\n <span className=\"lb-icon-container\">\n <WarningIcon />\n </span>\n {message.errorReason}\n </div>\n </>\n );\n }\n }\n\n return (\n <div\n className={cn(\n \"lb-ai-chat-message lb-ai-chat-assistant-message\",\n className\n )}\n {...props}\n ref={forwardedRef}\n >\n <OverridesProvider overrides={overrides}>\n {children}\n </OverridesProvider>\n </div>\n );\n }\n )\n);\n\nfunction AssistantMessageContent({\n message,\n components,\n}: {\n message: UiAssistantMessage;\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}) {\n const ref = useRef(components);\n const BoundTextPart = useMemo(\n () => (props: TextPartProps) => (\n <TextPart {...props} components={ref.current} />\n ),\n []\n );\n const BoundReasoningPart = useMemo(\n () => (props: ReasoningPartProps) => (\n <ReasoningPart {...props} components={ref.current} />\n ),\n []\n );\n return (\n <AiMessage.Content\n message={message}\n components={{\n TextPart: BoundTextPart,\n ReasoningPart: BoundReasoningPart,\n RetrievalPart,\n ToolInvocationPart,\n }}\n className=\"lb-ai-chat-message-content\"\n />\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * TextPart\n * -----------------------------------------------------------------------------------------------*/\nfunction TextPart({ part, components, isStreaming }: TextPartProps) {\n return (\n <Prose\n content={part.text}\n className=\"lb-ai-chat-message-text\"\n components={components}\n partial={isStreaming}\n />\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * ReasoningPart\n * -----------------------------------------------------------------------------------------------*/\nfunction ReasoningPart({ part, isStreaming, components }: ReasoningPartProps) {\n // Start collapsed if reasoning is already done.\n const [isOpen, setIsOpen] = useState(isStreaming);\n const $ = useOverrides();\n\n // Auto-collapse when reasoning is done, while still allowing the user to\n // open/collapse it manually during and after it's done.\n useEffect(() => {\n if (!isStreaming) {\n setIsOpen(false);\n }\n }, [isStreaming]);\n\n return (\n <Collapsible.Root\n className=\"lb-collapsible lb-ai-chat-message-reasoning\"\n open={isOpen}\n onOpenChange={setIsOpen}\n >\n <Collapsible.Trigger\n className={cn(\n \"lb-collapsible-trigger\",\n isStreaming && \"lb-ai-chat-pending\"\n )}\n >\n {$.AI_CHAT_MESSAGE_REASONING(isStreaming, part)}\n <span className=\"lb-collapsible-chevron lb-icon-container\">\n <ChevronRightIcon />\n </span>\n </Collapsible.Trigger>\n\n <Collapsible.Content className=\"lb-collapsible-content\">\n <Prose\n content={part.text}\n partial={isStreaming}\n components={components}\n />\n </Collapsible.Content>\n </Collapsible.Root>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * RetrievalPart\n * -----------------------------------------------------------------------------------------------*/\nfunction RetrievalPart({ part, isStreaming }: RetrievalPartProps) {\n const $ = useOverrides();\n\n return (\n <div\n className={cn(\n \"lb-ai-chat-message-retrieval\",\n isStreaming && \"lb-ai-chat-pending\"\n )}\n >\n {$.AI_CHAT_MESSAGE_RETRIEVAL(isStreaming, part)}\n </div>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * ToolInvocationPart\n * -----------------------------------------------------------------------------------------------*/\nfunction ToolInvocationPart({\n part,\n message,\n}: AiMessageContentToolInvocationPartProps) {\n return (\n <div className=\"lb-ai-chat-message-tool-invocation\">\n <ErrorBoundary\n fallback={\n <div className=\"lb-ai-chat-message-error\">\n <span className=\"lb-icon-container\">\n <WarningIcon />\n </span>\n <p>\n Failed to render tool call result for <code>{part.name}</code>.\n See console for details.\n </p>\n </div>\n }\n >\n <AiMessageToolInvocation part={part} message={message} />\n </ErrorBoundary>\n </div>\n );\n}\n"],"names":["AiMessage.Content","Collapsible.Root","Collapsible.Trigger","Collapsible.Content"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AiChatAssistantMessage.js","sources":["../../../src/components/internal/AiChatAssistantMessage.tsx"],"sourcesContent":["import type { AiAssistantMessage, WithNavigation } from \"@liveblocks/core\";\nimport {\n type ComponentProps,\n forwardRef,\n memo,\n type ReactNode,\n useEffect,\n useState,\n} from \"react\";\n\nimport { type GlobalComponents } from \"../../components\";\nimport { ChevronRightIcon } from \"../../icons/ChevronRight\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport {\n type AiChatMessageOverrides,\n type GlobalOverrides,\n OverridesProvider,\n useOverrides,\n} from \"../../overrides\";\nimport * as AiMessage from \"../../primitives/AiMessage\";\nimport { AiMessageToolInvocation } from \"../../primitives/AiMessage/tool-invocation\";\nimport type {\n AiMessageContentReasoningPartProps,\n AiMessageContentTextPartProps,\n AiMessageContentToolInvocationPartProps,\n} from \"../../primitives/AiMessage/types\";\nimport * as Collapsible from \"../../primitives/Collapsible\";\nimport type { MarkdownComponents } from \"../../primitives/Markdown\";\nimport { cn } from \"../../utils/cn\";\nimport { ErrorBoundary } from \"../../utils/ErrorBoundary\";\nimport { Prose } from \"./Prose\";\n\ntype UiAssistantMessage = WithNavigation<AiAssistantMessage>;\n\ntype AiChatAssistantMessageComponents = {\n /**\n * The components used to render Markdown content.\n */\n markdown?: Partial<MarkdownComponents>;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * AiChatAssistantMessage\n * -----------------------------------------------------------------------------------------------*/\nexport interface AiChatAssistantMessageProps extends ComponentProps<\"div\"> {\n /**\n * The message to display.\n */\n message: UiAssistantMessage;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & AiChatMessageOverrides>;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\ninterface TextPartProps extends AiMessageContentTextPartProps {\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\ninterface ReasoningPartProps extends AiMessageContentReasoningPartProps {\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}\n\nexport const AiChatAssistantMessage = memo(\n forwardRef<HTMLDivElement, AiChatAssistantMessageProps>(\n ({ message, className, overrides, components, ...props }, forwardedRef) => {\n const $ = useOverrides(overrides);\n\n let children: ReactNode = null;\n\n if (message.deletedAt !== undefined) {\n children = (\n <div className=\"lb-ai-chat-message-deleted\">\n {$.AI_CHAT_MESSAGE_DELETED}\n </div>\n );\n } else if (\n message.status === \"generating\" ||\n message.status === \"awaiting-tool\"\n ) {\n if (message.contentSoFar.length === 0) {\n children = (\n <div className=\"lb-ai-chat-message-thinking lb-ai-chat-pending\">\n {$.AI_CHAT_MESSAGE_THINKING}\n </div>\n );\n } else {\n children = (\n <AssistantMessageContent\n message={message}\n components={components}\n />\n );\n }\n } else if (message.status === \"completed\") {\n children = (\n <AssistantMessageContent message={message} components={components} />\n );\n } else if (message.status === \"failed\") {\n // Do not include the error message if the user aborted the request.\n if (message.errorReason === \"Aborted by user\") {\n children = (\n <AssistantMessageContent\n message={message}\n components={components}\n />\n );\n } else {\n children = (\n <>\n <AssistantMessageContent\n message={message}\n components={components}\n />\n\n <div className=\"lb-ai-chat-message-error\">\n <span className=\"lb-icon-container\">\n <WarningIcon />\n </span>\n {message.errorReason}\n </div>\n </>\n );\n }\n }\n\n return (\n <div\n className={cn(\n \"lb-ai-chat-message lb-ai-chat-assistant-message\",\n className\n )}\n {...props}\n ref={forwardedRef}\n >\n <OverridesProvider overrides={overrides}>\n {children}\n </OverridesProvider>\n </div>\n );\n }\n )\n);\n\nfunction AssistantMessageContent({\n message,\n components,\n}: {\n message: UiAssistantMessage;\n components?: Partial<GlobalComponents & AiChatAssistantMessageComponents>;\n}) {\n return (\n <AiMessage.Content\n message={message}\n components={{\n TextPart: (props) => <TextPart {...props} components={components} />,\n ReasoningPart: (props) => (\n <ReasoningPart {...props} components={components} />\n ),\n ToolInvocationPart,\n }}\n className=\"lb-ai-chat-message-content\"\n />\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * TextPart\n * -----------------------------------------------------------------------------------------------*/\nfunction TextPart({ part, components, isStreaming }: TextPartProps) {\n return (\n <Prose\n content={part.text}\n className=\"lb-ai-chat-message-text\"\n components={components}\n partial={isStreaming}\n />\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * ReasoningPart\n * -----------------------------------------------------------------------------------------------*/\nfunction ReasoningPart({ part, isStreaming, components }: ReasoningPartProps) {\n // Start collapsed if reasoning is already done.\n const [isOpen, setIsOpen] = useState(isStreaming);\n const $ = useOverrides();\n\n // Auto-collapse when reasoning is done, while still allowing the user to\n // open/collapse it manually during and after it's done.\n useEffect(() => {\n if (!isStreaming) {\n setIsOpen(false);\n }\n }, [isStreaming]);\n\n return (\n <Collapsible.Root\n className=\"lb-collapsible lb-ai-chat-message-reasoning\"\n open={isOpen}\n onOpenChange={setIsOpen}\n >\n <Collapsible.Trigger\n className={cn(\n \"lb-collapsible-trigger\",\n isStreaming && \"lb-ai-chat-pending\"\n )}\n >\n {/* TODO: Show duration as \"Reasoned for x seconds\"? */}\n {$.AI_CHAT_MESSAGE_REASONING(isStreaming)}\n <span className=\"lb-collapsible-chevron lb-icon-container\">\n <ChevronRightIcon />\n </span>\n </Collapsible.Trigger>\n\n <Collapsible.Content className=\"lb-collapsible-content\">\n <Prose\n content={part.text}\n partial={isStreaming}\n components={components}\n />\n </Collapsible.Content>\n </Collapsible.Root>\n );\n}\n\n/* -------------------------------------------------------------------------------------------------\n * ToolInvocationPart\n * -----------------------------------------------------------------------------------------------*/\nfunction ToolInvocationPart({\n part,\n message,\n}: AiMessageContentToolInvocationPartProps) {\n return (\n <div className=\"lb-ai-chat-message-tool-invocation\">\n <ErrorBoundary\n fallback={\n <div className=\"lb-ai-chat-message-error\">\n <span className=\"lb-icon-container\">\n <WarningIcon />\n </span>\n <p>\n Failed to render tool call result for <code>{part.name}</code>.\n See console for details.\n </p>\n </div>\n }\n >\n <AiMessageToolInvocation part={part} message={message} />\n </ErrorBoundary>\n </div>\n );\n}\n"],"names":["AiMessage.Content","Collapsible.Root","Collapsible.Trigger","Collapsible.Content"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentType, ComponentPropsWithoutRef, ElementType, ReactNode, FormEvent, ComponentProps, RefAttributes, MouseEvent, PropsWithChildren } from 'react';
|
|
3
|
-
import { CommentAttachment,
|
|
3
|
+
import { CommentAttachment, Relax, CopilotId, AiKnowledgeSource, AiOpaqueToolDefinition, AiToolTypePack, JsonObject, AiToolExecuteCallback, NoInfr, CommentBody, MentionData, BaseMetadata, DM, CommentData, HistoryVersion, InboxNotificationData, InboxNotificationThreadData, InboxNotificationTextMentionData, InboxNotificationCustomData, KDAD, ThreadData } from '@liveblocks/core';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
6
|
interface GlobalComponents {
|
|
@@ -90,9 +90,8 @@ interface AiComposerOverrides {
|
|
|
90
90
|
}
|
|
91
91
|
interface AiChatMessageOverrides {
|
|
92
92
|
AI_CHAT_MESSAGE_DELETED: string;
|
|
93
|
-
AI_CHAT_MESSAGE_THINKING:
|
|
94
|
-
AI_CHAT_MESSAGE_REASONING: (isStreaming: boolean
|
|
95
|
-
AI_CHAT_MESSAGE_RETRIEVAL: (isStreaming: boolean, part: AiRetrievalPart) => ReactNode;
|
|
93
|
+
AI_CHAT_MESSAGE_THINKING: string;
|
|
94
|
+
AI_CHAT_MESSAGE_REASONING: (isStreaming: boolean) => string;
|
|
96
95
|
}
|
|
97
96
|
interface AiChatOverrides {
|
|
98
97
|
AI_CHAT_MESSAGES_ERROR: (error: Error) => ReactNode;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentType, ComponentPropsWithoutRef, ElementType, ReactNode, FormEvent, ComponentProps, RefAttributes, MouseEvent, PropsWithChildren } from 'react';
|
|
3
|
-
import { CommentAttachment,
|
|
3
|
+
import { CommentAttachment, Relax, CopilotId, AiKnowledgeSource, AiOpaqueToolDefinition, AiToolTypePack, JsonObject, AiToolExecuteCallback, NoInfr, CommentBody, MentionData, BaseMetadata, DM, CommentData, HistoryVersion, InboxNotificationData, InboxNotificationThreadData, InboxNotificationTextMentionData, InboxNotificationCustomData, KDAD, ThreadData } from '@liveblocks/core';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
6
|
interface GlobalComponents {
|
|
@@ -90,9 +90,8 @@ interface AiComposerOverrides {
|
|
|
90
90
|
}
|
|
91
91
|
interface AiChatMessageOverrides {
|
|
92
92
|
AI_CHAT_MESSAGE_DELETED: string;
|
|
93
|
-
AI_CHAT_MESSAGE_THINKING:
|
|
94
|
-
AI_CHAT_MESSAGE_REASONING: (isStreaming: boolean
|
|
95
|
-
AI_CHAT_MESSAGE_RETRIEVAL: (isStreaming: boolean, part: AiRetrievalPart) => ReactNode;
|
|
93
|
+
AI_CHAT_MESSAGE_THINKING: string;
|
|
94
|
+
AI_CHAT_MESSAGE_REASONING: (isStreaming: boolean) => string;
|
|
96
95
|
}
|
|
97
96
|
interface AiChatOverrides {
|
|
98
97
|
AI_CHAT_MESSAGES_ERROR: (error: Error) => ReactNode;
|
package/dist/overrides.cjs
CHANGED
|
@@ -5,7 +5,6 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
5
5
|
var core = require('@liveblocks/core');
|
|
6
6
|
var react = require('react');
|
|
7
7
|
var Emoji = require('./components/internal/Emoji.cjs');
|
|
8
|
-
var Duration = require('./primitives/Duration.cjs');
|
|
9
8
|
var pluralize = require('./utils/pluralize.cjs');
|
|
10
9
|
|
|
11
10
|
|
|
@@ -128,47 +127,7 @@ const defaultOverrides = {
|
|
|
128
127
|
AI_COMPOSER_ABORT: "Abort response",
|
|
129
128
|
AI_CHAT_MESSAGE_DELETED: "This message has been deleted.",
|
|
130
129
|
AI_CHAT_MESSAGE_THINKING: "Thinking\u2026",
|
|
131
|
-
AI_CHAT_MESSAGE_REASONING: (isStreaming
|
|
132
|
-
children: "Reasoning\u2026"
|
|
133
|
-
}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
134
|
-
children: [
|
|
135
|
-
"Reasoned for",
|
|
136
|
-
" ",
|
|
137
|
-
/* @__PURE__ */ jsxRuntime.jsx(Duration.Duration, {
|
|
138
|
-
className: "lb-duration lb-ai-chat-message-reasoning-duration",
|
|
139
|
-
from: part.startedAt,
|
|
140
|
-
to: part.endedAt
|
|
141
|
-
})
|
|
142
|
-
]
|
|
143
|
-
}),
|
|
144
|
-
AI_CHAT_MESSAGE_RETRIEVAL: (isStreaming, part) => isStreaming ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
145
|
-
children: [
|
|
146
|
-
"Searching",
|
|
147
|
-
" ",
|
|
148
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
149
|
-
className: "lb-ai-chat-message-retrieval-query",
|
|
150
|
-
children: part.query
|
|
151
|
-
}),
|
|
152
|
-
"\u2026"
|
|
153
|
-
]
|
|
154
|
-
}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
155
|
-
children: [
|
|
156
|
-
"Searched",
|
|
157
|
-
" ",
|
|
158
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
159
|
-
className: "lb-ai-chat-message-retrieval-query",
|
|
160
|
-
children: part.query
|
|
161
|
-
}),
|
|
162
|
-
" ",
|
|
163
|
-
"for",
|
|
164
|
-
" ",
|
|
165
|
-
/* @__PURE__ */ jsxRuntime.jsx(Duration.Duration, {
|
|
166
|
-
className: "lb-duration lb-ai-chat-message-retrieval-duration",
|
|
167
|
-
from: part.startedAt,
|
|
168
|
-
to: part.endedAt
|
|
169
|
-
})
|
|
170
|
-
]
|
|
171
|
-
}),
|
|
130
|
+
AI_CHAT_MESSAGE_REASONING: (isStreaming) => isStreaming ? "Reasoning\u2026" : "Reasoning",
|
|
172
131
|
AI_CHAT_MESSAGES_ERROR: () => "There was an error while getting the messages.",
|
|
173
132
|
AI_TOOL_CONFIRMATION_CONFIRM: "Confirm",
|
|
174
133
|
AI_TOOL_CONFIRMATION_CANCEL: "Cancel"
|