UNPKG

@liveblocks/react-ui

Version:

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

206 lines (202 loc) 7.96 kB
"use client"; import { jsx, jsxs } from 'react/jsx-runtime'; import { useThreadSubscription } from '@liveblocks/react'; import { useMarkRoomThreadAsResolved, useMarkRoomThreadAsUnresolved } from '@liveblocks/react/_private'; import * as TogglePrimitive from '@radix-ui/react-toggle'; import { forwardRef, useMemo, useState, useEffect, useCallback, Fragment } from 'react'; import { ArrowDownIcon } from '../icons/ArrowDown.js'; import { ResolveIcon } from '../icons/Resolve.js'; import { ResolvedIcon } from '../icons/Resolved.js'; import { useOverrides } from '../overrides.js'; import { classNames } from '../utils/class-names.js'; import { findLastIndex } from '../utils/find-last-index.js'; import { Comment } from './Comment.js'; import { Composer } from './Composer.js'; import { Button } from './internal/Button.js'; import { Tooltip } from './internal/Tooltip.js'; import { TooltipProvider } from '@radix-ui/react-tooltip'; const Thread = forwardRef( ({ thread, indentCommentContent = true, showActions = "hover", showDeletedComments, showResolveAction = true, showReactions = true, showComposer = "collapsed", showAttachments = true, showComposerFormattingControls = true, onResolvedChange, onCommentEdit, onCommentDelete, onThreadDelete, onAuthorClick, onMentionClick, onAttachmentClick, onComposerSubmit, overrides, className, ...props }, forwardedRef) => { const markThreadAsResolved = useMarkRoomThreadAsResolved(thread.roomId); const markThreadAsUnresolved = useMarkRoomThreadAsUnresolved(thread.roomId); const $ = useOverrides(overrides); const firstCommentIndex = useMemo(() => { return showDeletedComments ? 0 : thread.comments.findIndex((comment) => comment.body); }, [showDeletedComments, thread.comments]); const lastCommentIndex = useMemo(() => { return showDeletedComments ? thread.comments.length - 1 : findLastIndex(thread.comments, (comment) => comment.body); }, [showDeletedComments, thread.comments]); const { status: subscriptionStatus, unreadSince } = useThreadSubscription( thread.id ); const unreadIndex = useMemo(() => { if (subscriptionStatus !== "subscribed") { return; } if (unreadSince === null) { return firstCommentIndex; } const unreadIndex2 = thread.comments.findIndex( (comment) => (showDeletedComments ? true : comment.body) && comment.createdAt > unreadSince ); return unreadIndex2 >= 0 && unreadIndex2 < thread.comments.length ? unreadIndex2 : void 0; }, [ firstCommentIndex, showDeletedComments, subscriptionStatus, thread.comments, unreadSince ]); const [newIndex, setNewIndex] = useState(); const newIndicatorIndex = newIndex === void 0 ? unreadIndex : newIndex; useEffect(() => { if (unreadIndex) { setNewIndex( (persistedUnreadIndex) => Math.min(persistedUnreadIndex ?? Infinity, unreadIndex) ); } }, [unreadIndex]); const stopPropagation = useCallback((event) => { event.stopPropagation(); }, []); const handleResolvedChange = useCallback( (resolved) => { onResolvedChange?.(resolved); if (resolved) { markThreadAsResolved(thread.id); } else { markThreadAsUnresolved(thread.id); } }, [ markThreadAsResolved, markThreadAsUnresolved, onResolvedChange, thread.id ] ); const handleCommentDelete = useCallback( (comment) => { onCommentDelete?.(comment); const filteredComments = thread.comments.filter( (comment2) => comment2.body ); if (filteredComments.length <= 1) { onThreadDelete?.(thread); } }, [onCommentDelete, onThreadDelete, thread] ); return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs("div", { className: classNames( "lb-root lb-thread", showActions === "hover" && "lb-thread:show-actions-hover", className ), "data-resolved": thread.resolved ? "" : void 0, "data-unread": unreadIndex !== void 0 ? "" : void 0, dir: $.dir, ...props, ref: forwardedRef, children: [ /* @__PURE__ */ jsx("div", { className: "lb-thread-comments", children: thread.comments.map((comment, index) => { const isFirstComment = index === firstCommentIndex; const isUnread = unreadIndex !== void 0 && index >= unreadIndex; const children = /* @__PURE__ */ jsx(Comment, { overrides, className: "lb-thread-comment", "data-unread": isUnread ? "" : void 0, comment, indentContent: indentCommentContent, showDeleted: showDeletedComments, showActions, showReactions, showAttachments, showComposerFormattingControls, onCommentEdit, onCommentDelete: handleCommentDelete, onAuthorClick, onMentionClick, onAttachmentClick, autoMarkReadThreadId: index === lastCommentIndex && isUnread ? thread.id : void 0, additionalActionsClassName: isFirstComment ? "lb-thread-actions" : void 0, additionalActions: isFirstComment && showResolveAction ? /* @__PURE__ */ jsx(Tooltip, { content: thread.resolved ? $.THREAD_UNRESOLVE : $.THREAD_RESOLVE, children: /* @__PURE__ */ jsx(TogglePrimitive.Root, { pressed: thread.resolved, onPressedChange: handleResolvedChange, asChild: true, children: /* @__PURE__ */ jsx(Button, { className: "lb-comment-action", onClick: stopPropagation, "aria-label": thread.resolved ? $.THREAD_UNRESOLVE : $.THREAD_RESOLVE, icon: thread.resolved ? /* @__PURE__ */ jsx(ResolvedIcon, {}) : /* @__PURE__ */ jsx(ResolveIcon, {}) }) }) }) : null }, comment.id); return index === newIndicatorIndex && newIndicatorIndex !== firstCommentIndex && newIndicatorIndex <= lastCommentIndex ? /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx("div", { className: "lb-thread-new-indicator", "aria-label": $.THREAD_NEW_INDICATOR_DESCRIPTION, children: /* @__PURE__ */ jsxs("span", { className: "lb-thread-new-indicator-label", children: [ /* @__PURE__ */ jsx(ArrowDownIcon, { className: "lb-thread-new-indicator-label-icon" }), $.THREAD_NEW_INDICATOR ] }) }), children ] }, comment.id) : children; }) }), showComposer && /* @__PURE__ */ jsx(Composer, { className: "lb-thread-composer", threadId: thread.id, defaultCollapsed: showComposer === "collapsed" ? true : void 0, showAttachments, showFormattingControls: showComposerFormattingControls, onComposerSubmit, overrides: { COMPOSER_PLACEHOLDER: $.THREAD_COMPOSER_PLACEHOLDER, COMPOSER_SEND: $.THREAD_COMPOSER_SEND, ...overrides }, roomId: thread.roomId }) ] }) }); } ); export { Thread }; //# sourceMappingURL=Thread.js.map