@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.
754 lines (747 loc) • 28.2 kB
JavaScript
"use client";
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var core = require('@liveblocks/core');
var _private = require('@liveblocks/react/_private');
var TogglePrimitive = require('@radix-ui/react-toggle');
var react = require('react');
var components = require('../components.cjs');
var Check = require('../icons/Check.cjs');
var Cross = require('../icons/Cross.cjs');
var Delete = require('../icons/Delete.cjs');
var Edit = require('../icons/Edit.cjs');
var Ellipsis = require('../icons/Ellipsis.cjs');
var EmojiPlus = require('../icons/EmojiPlus.cjs');
var overrides = require('../overrides.cjs');
var index = require('../primitives/Comment/index.cjs');
var index$1 = require('../primitives/Composer/index.cjs');
var Timestamp = require('../primitives/Timestamp.cjs');
var shared = require('../shared.cjs');
var cn = require('../utils/cn.cjs');
var download = require('../utils/download.cjs');
var useGroupMention = require('../utils/use-group-mention.cjs');
var useRefs = require('../utils/use-refs.cjs');
var useVisible = require('../utils/use-visible.cjs');
var useWindowFocus = require('../utils/use-window-focus.cjs');
var Composer = require('./Composer.cjs');
var Attachment = require('./internal/Attachment.cjs');
var Avatar = require('./internal/Avatar.cjs');
var Button = require('./internal/Button.cjs');
var Dropdown = require('./internal/Dropdown.cjs');
var Emoji = require('./internal/Emoji.cjs');
var EmojiPicker = require('./internal/EmojiPicker.cjs');
var Group = require('./internal/Group.cjs');
var List = require('./internal/List.cjs');
var Tooltip = require('./internal/Tooltip.cjs');
var User = require('./internal/User.cjs');
var TooltipPrimitive = require('@radix-ui/react-tooltip');
var PopoverPrimitive = require('@radix-ui/react-popover');
var DropdownMenuPrimitive = require('@radix-ui/react-dropdown-menu');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var TogglePrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(TogglePrimitive);
const REACTIONS_TRUNCATE = 5;
function CommentUserMention({
mention,
className,
...props
}) {
const currentId = shared.useCurrentUserId();
return /* @__PURE__ */ jsxRuntime.jsxs(
index.Mention,
{
className: cn.cn("lb-mention lb-comment-mention", className),
"data-self": mention.id === currentId ? "" : void 0,
...props,
children: [
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "lb-mention-symbol", children: core.MENTION_CHARACTER }),
/* @__PURE__ */ jsxRuntime.jsx(User.User, { userId: mention.id })
]
}
);
}
function CommentGroupMention({
mention,
className,
...props
}) {
const isMember = useGroupMention.useIsGroupMentionMember(mention);
return /* @__PURE__ */ jsxRuntime.jsxs(
index.Mention,
{
className: cn.cn("lb-mention lb-comment-mention", className),
"data-self": isMember ? "" : void 0,
...props,
children: [
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "lb-mention-symbol", children: core.MENTION_CHARACTER }),
/* @__PURE__ */ jsxRuntime.jsx(Group.Group, { groupId: mention.id })
]
}
);
}
function CommentMention({ mention, ...props }) {
switch (mention.kind) {
case "user":
return /* @__PURE__ */ jsxRuntime.jsx(CommentUserMention, { mention, ...props });
case "group":
return /* @__PURE__ */ jsxRuntime.jsx(CommentGroupMention, { mention, ...props });
default:
return core.assertNever(mention, "Unhandled mention kind");
}
}
function CommentLink({
href,
children,
className,
...props
}) {
const { Anchor } = components.useComponents();
return /* @__PURE__ */ jsxRuntime.jsx(
index.Link,
{
className: cn.cn("lb-comment-link", className),
href,
...props,
asChild: true,
children: /* @__PURE__ */ jsxRuntime.jsx(Anchor, { ...props, children })
}
);
}
function CommentNonInteractiveLink({
href: _href,
children,
className,
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn.cn("lb-comment-link", className), ...props, children });
}
const CommentReactionButton = react.forwardRef(({ reaction, overrides: overrides$1, className, ...props }, forwardedRef) => {
const $ = overrides.useOverrides(overrides$1);
return /* @__PURE__ */ jsxRuntime.jsxs(
Button.CustomButton,
{
className: cn.cn("lb-comment-reaction", className),
variant: "outline",
"aria-label": $.COMMENT_REACTION_DESCRIPTION(
reaction.emoji,
reaction.users.length
),
...props,
ref: forwardedRef,
children: [
/* @__PURE__ */ jsxRuntime.jsx(Emoji.Emoji, { className: "lb-comment-reaction-emoji", emoji: reaction.emoji }),
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "lb-comment-reaction-count", children: reaction.users.length })
]
}
);
});
const CommentReaction = react.forwardRef(({ comment, reaction, overrides: overrides$1, disabled, ...props }, forwardedRef) => {
const addReaction = _private.useAddRoomCommentReaction(comment.roomId);
const removeReaction = _private.useRemoveRoomCommentReaction(comment.roomId);
const currentId = shared.useCurrentUserId();
const isActive = react.useMemo(() => {
return reaction.users.some((users) => users.id === currentId);
}, [currentId, reaction]);
const $ = overrides.useOverrides(overrides$1);
const tooltipContent = react.useMemo(
() => /* @__PURE__ */ jsxRuntime.jsx("span", { children: $.COMMENT_REACTION_LIST(
/* @__PURE__ */ jsxRuntime.jsx(
List.List,
{
values: reaction.users.map((users) => /* @__PURE__ */ jsxRuntime.jsx(User.User, { userId: users.id, replaceSelf: true }, users.id)),
formatRemaining: $.LIST_REMAINING_USERS,
truncate: REACTIONS_TRUNCATE,
locale: $.locale
}
),
reaction.emoji,
reaction.users.length
) }),
[$, reaction]
);
const stopPropagation = react.useCallback((event) => {
event.stopPropagation();
}, []);
const handlePressedChange = react.useCallback(
(isPressed) => {
if (isPressed) {
addReaction({
threadId: comment.threadId,
commentId: comment.id,
emoji: reaction.emoji
});
} else {
removeReaction({
threadId: comment.threadId,
commentId: comment.id,
emoji: reaction.emoji
});
}
},
[addReaction, comment.threadId, comment.id, reaction.emoji, removeReaction]
);
return /* @__PURE__ */ jsxRuntime.jsx(
Tooltip.Tooltip,
{
content: tooltipContent,
multiline: true,
className: "lb-comment-reaction-tooltip",
children: /* @__PURE__ */ jsxRuntime.jsx(
TogglePrimitive__namespace.Root,
{
asChild: true,
pressed: isActive,
onPressedChange: handlePressedChange,
onClick: stopPropagation,
disabled,
ref: forwardedRef,
children: /* @__PURE__ */ jsxRuntime.jsx(
CommentReactionButton,
{
"data-self": isActive ? "" : void 0,
reaction,
overrides: overrides$1,
...props
}
)
}
)
}
);
});
const CommentNonInteractiveReaction = react.forwardRef(({ reaction, overrides, ...props }, forwardedRef) => {
const currentId = shared.useCurrentUserId();
const isActive = react.useMemo(() => {
return reaction.users.some((users) => users.id === currentId);
}, [currentId, reaction]);
return /* @__PURE__ */ jsxRuntime.jsx(
CommentReactionButton,
{
disableable: false,
"data-self": isActive ? "" : void 0,
reaction,
overrides,
...props,
ref: forwardedRef
}
);
});
function openAttachment({ attachment, url }) {
if (attachment.mimeType === "application/pdf" || attachment.mimeType.startsWith("image/") || attachment.mimeType.startsWith("video/") || attachment.mimeType.startsWith("audio/")) {
window.open(url, "_blank");
} else {
download.download(url, attachment.name);
}
}
function CommentMediaAttachment({
attachment,
onAttachmentClick,
roomId,
className,
overrides,
...props
}) {
const { url } = _private.useRoomAttachmentUrl(attachment.id, roomId);
const handleClick = react.useCallback(
(event) => {
if (!url) {
return;
}
const args = { attachment, url };
onAttachmentClick?.(args, event);
if (event.isDefaultPrevented()) {
return;
}
openAttachment(args);
},
[attachment, onAttachmentClick, url]
);
return /* @__PURE__ */ jsxRuntime.jsx(
Attachment.MediaAttachment,
{
className: cn.cn("lb-comment-attachment", className),
...props,
attachment,
overrides,
onClick: url ? handleClick : void 0,
roomId
}
);
}
function CommentFileAttachment({
attachment,
onAttachmentClick,
roomId,
className,
overrides,
...props
}) {
const { url } = _private.useRoomAttachmentUrl(attachment.id, roomId);
const handleClick = react.useCallback(
(event) => {
if (!url) {
return;
}
const args = { attachment, url };
onAttachmentClick?.(args, event);
if (event.isDefaultPrevented()) {
return;
}
openAttachment(args);
},
[attachment, onAttachmentClick, url]
);
return /* @__PURE__ */ jsxRuntime.jsx(
Attachment.FileAttachment,
{
className: cn.cn("lb-comment-attachment", className),
...props,
attachment,
overrides,
onClick: url ? handleClick : void 0,
roomId
}
);
}
function CommentNonInteractiveFileAttachment({
className,
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsx(
Attachment.FileAttachment,
{
className: cn.cn("lb-comment-attachment", className),
allowMediaPreview: false,
...props
}
);
}
function AutoMarkReadThreadIdHandler({
threadId,
roomId,
commentRef
}) {
const markThreadAsRead = _private.useMarkRoomThreadAsRead(roomId);
const isWindowFocused = useWindowFocus.useWindowFocus();
useVisible.useIntersectionCallback(
commentRef,
(isIntersecting) => {
if (isIntersecting) {
markThreadAsRead(threadId);
}
},
{
// The underlying IntersectionObserver is only enabled when the window is focused
enabled: isWindowFocused
}
);
return null;
}
const CommentDropdownItem = react.forwardRef(({ children, icon, onSelect, onClick, ...props }, forwardedRef) => {
const handleClick = react.useCallback(
(event) => {
onClick?.(event);
if (!event.isDefaultPrevented()) {
event.stopPropagation();
}
},
[onClick]
);
return /* @__PURE__ */ jsxRuntime.jsx(
Dropdown.DropdownItem,
{
icon,
onSelect,
onClick: handleClick,
...props,
ref: forwardedRef,
children
}
);
});
const Comment = Object.assign(
react.forwardRef(
({
comment,
indentContent = true,
showDeleted,
showActions = "hover",
showReactions = true,
showAttachments = true,
showComposerFormattingControls = true,
onAuthorClick,
onMentionClick,
onAttachmentClick,
onCommentEdit,
onCommentDelete,
dropdownItems,
overrides: overrides$1,
components: components$1,
className,
actions,
actionsClassName,
autoMarkReadThreadId,
...props
}, forwardedRef) => {
const ref = react.useRef(null);
const mergedRefs = useRefs.useRefs(forwardedRef, ref);
const currentUserId = shared.useCurrentUserId();
const deleteComment = _private.useDeleteRoomComment(comment.roomId);
const editComment = _private.useEditRoomComment(comment.roomId);
const addReaction = _private.useAddRoomCommentReaction(comment.roomId);
const removeReaction = _private.useRemoveRoomCommentReaction(comment.roomId);
const $ = overrides.useOverrides(overrides$1);
const [isEditing, setEditing] = react.useState(false);
const [isTarget, setTarget] = react.useState(false);
const [isMoreActionOpen, setMoreActionOpen] = react.useState(false);
const [isReactionActionOpen, setReactionActionOpen] = react.useState(false);
const { mediaAttachments, fileAttachments } = react.useMemo(() => {
return Attachment.separateMediaAttachments(comment.attachments);
}, [comment.attachments]);
const permissions = _private.useRoomPermissions(comment.roomId);
const canComment = permissions.size > 0 ? permissions.has(core.Permission.CommentsWrite) || permissions.has(core.Permission.Write) : true;
const stopPropagation = react.useCallback((event) => {
event.stopPropagation();
}, []);
const handleEdit = react.useCallback(() => {
setEditing(true);
}, []);
const handleEditCancel = react.useCallback(
(event) => {
event.stopPropagation();
setEditing(false);
},
[]
);
const handleEditSubmit = react.useCallback(
({ body, attachments }, event) => {
onCommentEdit?.(comment);
if (event.isDefaultPrevented()) {
return;
}
event.stopPropagation();
event.preventDefault();
setEditing(false);
editComment({
commentId: comment.id,
threadId: comment.threadId,
body,
attachments
});
},
[comment, editComment, onCommentEdit]
);
const handleDelete = react.useCallback(() => {
onCommentDelete?.(comment);
deleteComment({
commentId: comment.id,
threadId: comment.threadId
});
}, [comment, deleteComment, onCommentDelete]);
const handleAuthorClick = react.useCallback(
(event) => {
onAuthorClick?.(comment.userId, event);
},
[comment.userId, onAuthorClick]
);
const handleReactionSelect = react.useCallback(
(emoji) => {
const reactionIndex = comment.reactions.findIndex(
(reaction) => reaction.emoji === emoji
);
if (reactionIndex >= 0 && currentUserId && comment.reactions[reactionIndex]?.users.some(
(user) => user.id === currentUserId
)) {
removeReaction({
threadId: comment.threadId,
commentId: comment.id,
emoji
});
} else {
addReaction({
threadId: comment.threadId,
commentId: comment.id,
emoji
});
}
},
[
addReaction,
comment.id,
comment.reactions,
comment.threadId,
removeReaction,
currentUserId
]
);
react.useEffect(() => {
const isWindowDefined = typeof window !== "undefined";
if (!isWindowDefined)
return;
const hash = window.location.hash;
const commentId = hash.slice(1);
if (commentId === comment.id) {
setTarget(true);
}
}, []);
if (!showDeleted && !comment.body) {
return null;
}
const defaultDropdownItems = comment.userId === currentUserId ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(CommentDropdownItem, { onSelect: handleEdit, icon: /* @__PURE__ */ jsxRuntime.jsx(Edit.EditIcon, {}), children: $.COMMENT_EDIT }),
/* @__PURE__ */ jsxRuntime.jsx(CommentDropdownItem, { onSelect: handleDelete, icon: /* @__PURE__ */ jsxRuntime.jsx(Delete.DeleteIcon, {}), children: $.COMMENT_DELETE })
] }) : null;
const dropdownContent = typeof dropdownItems === "function" ? dropdownItems({ children: defaultDropdownItems, comment }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
defaultDropdownItems,
dropdownItems
] });
return /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive.TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(components.ComponentsProvider, { components: components$1, children: [
autoMarkReadThreadId && /* @__PURE__ */ jsxRuntime.jsx(
AutoMarkReadThreadIdHandler,
{
commentRef: ref,
threadId: autoMarkReadThreadId,
roomId: comment.roomId
}
),
/* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
id: comment.id,
className: cn.cn(
"lb-root lb-comment",
indentContent && "lb-comment:indent-content",
showActions === "hover" && "lb-comment:show-actions-hover",
(isMoreActionOpen || isReactionActionOpen) && "lb-comment:action-open",
className
),
"data-deleted": !comment.body ? "" : void 0,
"data-editing": isEditing ? "" : void 0,
"data-target": isTarget ? "" : void 0,
dir: $.dir,
...props,
ref: mergedRefs,
children: [
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lb-comment-header", children: [
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lb-comment-details", children: [
/* @__PURE__ */ jsxRuntime.jsx(
Avatar.Avatar,
{
className: "lb-comment-avatar",
userId: comment.userId,
onClick: handleAuthorClick
}
),
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "lb-comment-details-labels", children: [
/* @__PURE__ */ jsxRuntime.jsx(
User.User,
{
className: "lb-comment-author",
userId: comment.userId,
onClick: handleAuthorClick
}
),
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "lb-comment-date", children: [
/* @__PURE__ */ jsxRuntime.jsx(
Timestamp.Timestamp,
{
locale: $.locale,
date: comment.createdAt,
className: "lb-date lb-comment-date-created"
}
),
comment.editedAt && comment.body && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
" ",
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "lb-comment-date-edited", children: $.COMMENT_EDITED })
] })
] })
] })
] }),
showActions && !isEditing && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn.cn("lb-comment-actions", actionsClassName), children: [
actions ?? null,
showReactions && canComment ? /* @__PURE__ */ jsxRuntime.jsx(
EmojiPicker.EmojiPicker,
{
onEmojiSelect: handleReactionSelect,
onOpenChange: setReactionActionOpen,
children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: $.COMMENT_ADD_REACTION, children: /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
Button.Button,
{
className: "lb-comment-action",
onClick: stopPropagation,
"aria-label": $.COMMENT_ADD_REACTION,
icon: /* @__PURE__ */ jsxRuntime.jsx(EmojiPlus.EmojiPlusIcon, {})
}
) }) })
}
) : null,
dropdownContent ? /* @__PURE__ */ jsxRuntime.jsx(
Dropdown.Dropdown,
{
open: isMoreActionOpen,
onOpenChange: setMoreActionOpen,
align: "end",
content: dropdownContent,
children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: $.COMMENT_MORE, children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
Button.Button,
{
className: "lb-comment-action",
disabled: !comment.body,
onClick: stopPropagation,
"aria-label": $.COMMENT_MORE,
icon: /* @__PURE__ */ jsxRuntime.jsx(Ellipsis.EllipsisIcon, {})
}
) }) })
}
) : null
] })
] }),
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "lb-comment-content", children: isEditing ? /* @__PURE__ */ jsxRuntime.jsx(
Composer.Composer,
{
className: "lb-comment-composer",
onComposerSubmit: handleEditSubmit,
defaultValue: comment.body,
defaultAttachments: comment.attachments,
autoFocus: true,
showAttribution: false,
showAttachments,
showFormattingControls: showComposerFormattingControls,
actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
Tooltip.Tooltip,
{
content: $.COMMENT_EDIT_COMPOSER_CANCEL,
"aria-label": $.COMMENT_EDIT_COMPOSER_CANCEL,
children: /* @__PURE__ */ jsxRuntime.jsx(
Button.Button,
{
className: "lb-composer-action",
onClick: handleEditCancel,
icon: /* @__PURE__ */ jsxRuntime.jsx(Cross.CrossIcon, {})
}
)
}
),
/* @__PURE__ */ jsxRuntime.jsx(
Tooltip.ShortcutTooltip,
{
content: $.COMMENT_EDIT_COMPOSER_SAVE,
shortcut: "Enter",
children: /* @__PURE__ */ jsxRuntime.jsx(index$1.Submit, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
Button.Button,
{
variant: "primary",
className: "lb-composer-action",
onClick: stopPropagation,
"aria-label": $.COMMENT_EDIT_COMPOSER_SAVE,
icon: /* @__PURE__ */ jsxRuntime.jsx(Check.CheckIcon, {})
}
) })
}
)
] }),
overrides: {
COMPOSER_PLACEHOLDER: $.COMMENT_EDIT_COMPOSER_PLACEHOLDER
},
roomId: comment.roomId
}
) : comment.body ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx(
index.Body,
{
className: "lb-comment-body",
body: comment.body,
components: {
Mention: ({ mention }) => /* @__PURE__ */ jsxRuntime.jsx(
CommentMention,
{
mention,
onClick: (event) => onMentionClick?.(mention, event),
overrides: overrides$1
}
),
Link: CommentLink
}
}
),
showAttachments && (mediaAttachments.length > 0 || fileAttachments.length > 0) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lb-comment-attachments", children: [
mediaAttachments.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "lb-attachments", children: mediaAttachments.map((attachment) => /* @__PURE__ */ jsxRuntime.jsx(
CommentMediaAttachment,
{
attachment,
overrides: overrides$1,
onAttachmentClick,
roomId: comment.roomId
},
attachment.id
)) }) : null,
fileAttachments.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "lb-attachments", children: fileAttachments.map((attachment) => /* @__PURE__ */ jsxRuntime.jsx(
CommentFileAttachment,
{
attachment,
overrides: overrides$1,
onAttachmentClick,
roomId: comment.roomId
},
attachment.id
)) }) : null
] }) : null,
showReactions && comment.reactions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lb-comment-reactions", children: [
comment.reactions.map((reaction) => /* @__PURE__ */ jsxRuntime.jsx(
CommentReaction,
{
comment,
reaction,
overrides: overrides$1,
disabled: !canComment
},
reaction.emoji
)),
canComment ? /* @__PURE__ */ jsxRuntime.jsx(EmojiPicker.EmojiPicker, { onEmojiSelect: handleReactionSelect, children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: $.COMMENT_ADD_REACTION, children: /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
Button.Button,
{
className: "lb-comment-reaction lb-comment-reaction-add",
variant: "outline",
onClick: stopPropagation,
"aria-label": $.COMMENT_ADD_REACTION,
icon: /* @__PURE__ */ jsxRuntime.jsx(EmojiPlus.EmojiPlusIcon, {})
}
) }) }) }) : null
] })
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "lb-comment-body", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lb-comment-deleted", children: $.COMMENT_DELETED }) }) })
]
}
)
] }) });
}
),
{
/**
* Displays a dropdown item in the comment's dropdown.
*/
DropdownItem: CommentDropdownItem
}
);
exports.Comment = Comment;
exports.CommentLink = CommentLink;
exports.CommentMention = CommentMention;
exports.CommentNonInteractiveFileAttachment = CommentNonInteractiveFileAttachment;
exports.CommentNonInteractiveLink = CommentNonInteractiveLink;
exports.CommentNonInteractiveReaction = CommentNonInteractiveReaction;
exports.CommentReaction = CommentReaction;
//# sourceMappingURL=Comment.cjs.map