@liveblocks/react-ui 2.15.0-debug1 → 2.15.1
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.js +1 -0
- package/dist/_private/index.js.map +1 -1
- package/dist/_private/index.mjs +1 -0
- package/dist/_private/index.mjs.map +1 -1
- package/dist/components/Comment.js +8 -6
- package/dist/components/Comment.js.map +1 -1
- package/dist/components/Comment.mjs +5 -3
- package/dist/components/Comment.mjs.map +1 -1
- package/dist/components/Composer.js +5 -2
- package/dist/components/Composer.js.map +1 -1
- package/dist/components/Composer.mjs +9 -7
- package/dist/components/Composer.mjs.map +1 -1
- package/dist/components/HistoryVersionSummary.js +4 -10
- package/dist/components/HistoryVersionSummary.js.map +1 -1
- package/dist/components/HistoryVersionSummary.mjs +4 -10
- package/dist/components/HistoryVersionSummary.mjs.map +1 -1
- package/dist/components/HistoryVersionSummaryList.js +2 -0
- package/dist/components/HistoryVersionSummaryList.js.map +1 -1
- package/dist/components/HistoryVersionSummaryList.mjs +2 -0
- package/dist/components/HistoryVersionSummaryList.mjs.map +1 -1
- package/dist/components/InboxNotification.js +2 -0
- package/dist/components/InboxNotification.js.map +1 -1
- package/dist/components/InboxNotification.mjs +2 -0
- package/dist/components/InboxNotification.mjs.map +1 -1
- package/dist/components/InboxNotificationList.js +2 -0
- package/dist/components/InboxNotificationList.js.map +1 -1
- package/dist/components/InboxNotificationList.mjs +4 -2
- package/dist/components/InboxNotificationList.mjs.map +1 -1
- package/dist/components/Thread.js +2 -0
- package/dist/components/Thread.js.map +1 -1
- package/dist/components/Thread.mjs +2 -0
- package/dist/components/Thread.mjs.map +1 -1
- package/dist/components/internal/Attachment.js +4 -6
- package/dist/components/internal/Attachment.js.map +1 -1
- package/dist/components/internal/Attachment.mjs +6 -8
- package/dist/components/internal/Attachment.mjs.map +1 -1
- package/dist/components/internal/Avatar.js +2 -0
- package/dist/components/internal/Avatar.js.map +1 -1
- package/dist/components/internal/Avatar.mjs +2 -0
- package/dist/components/internal/Avatar.mjs.map +1 -1
- package/dist/components/internal/Button.js +2 -0
- package/dist/components/internal/Button.js.map +1 -1
- package/dist/components/internal/Button.mjs +2 -0
- package/dist/components/internal/Button.mjs.map +1 -1
- package/dist/components/internal/Dropdown.js +2 -0
- package/dist/components/internal/Dropdown.js.map +1 -1
- package/dist/components/internal/Dropdown.mjs +3 -1
- package/dist/components/internal/Dropdown.mjs.map +1 -1
- package/dist/components/internal/EmojiPicker.mjs +2 -2
- package/dist/components/internal/Room.js +2 -0
- package/dist/components/internal/Room.js.map +1 -1
- package/dist/components/internal/Room.mjs +2 -0
- package/dist/components/internal/Room.mjs.map +1 -1
- package/dist/components/internal/Tooltip.js +2 -0
- package/dist/components/internal/Tooltip.js.map +1 -1
- package/dist/components/internal/Tooltip.mjs +2 -0
- package/dist/components/internal/Tooltip.mjs.map +1 -1
- package/dist/components/internal/User.js +2 -0
- package/dist/components/internal/User.js.map +1 -1
- package/dist/components/internal/User.mjs +2 -0
- package/dist/components/internal/User.mjs.map +1 -1
- package/dist/components.js +2 -0
- package/dist/components.js.map +1 -1
- package/dist/components.mjs +2 -0
- package/dist/components.mjs.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/config.mjs +2 -0
- package/dist/config.mjs.map +1 -1
- package/dist/icons/index.js +42 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/icons/index.mjs +19 -0
- package/dist/icons/index.mjs.map +1 -0
- package/dist/overrides.js +2 -0
- package/dist/overrides.js.map +1 -1
- package/dist/overrides.mjs +2 -0
- package/dist/overrides.mjs.map +1 -1
- package/dist/primitives/Composer/index.js +15 -13
- package/dist/primitives/Composer/index.js.map +1 -1
- package/dist/primitives/Composer/index.mjs +11 -9
- package/dist/primitives/Composer/index.mjs.map +1 -1
- package/dist/primitives/Composer/utils.js +2 -1
- package/dist/primitives/Composer/utils.js.map +1 -1
- package/dist/primitives/Composer/utils.mjs +4 -3
- package/dist/primitives/Composer/utils.mjs.map +1 -1
- package/dist/primitives/EmojiPicker/index.js +2 -0
- package/dist/primitives/EmojiPicker/index.js.map +1 -1
- package/dist/primitives/EmojiPicker/index.mjs +4 -2
- package/dist/primitives/EmojiPicker/index.mjs.map +1 -1
- package/dist/primitives/FileSize.js +2 -0
- package/dist/primitives/FileSize.js.map +1 -1
- package/dist/primitives/FileSize.mjs +2 -0
- package/dist/primitives/FileSize.mjs.map +1 -1
- package/dist/primitives/Timestamp.js +2 -0
- package/dist/primitives/Timestamp.js.map +1 -1
- package/dist/primitives/Timestamp.mjs +2 -0
- package/dist/primitives/Timestamp.mjs.map +1 -1
- package/dist/slate/plugins/auto-links.mjs +1 -1
- package/dist/slate/plugins/custom-links.mjs +1 -1
- package/dist/slate/plugins/mentions.mjs +1 -1
- package/dist/utils/Persist.js +2 -0
- package/dist/utils/Persist.js.map +1 -1
- package/dist/utils/Persist.mjs +3 -1
- package/dist/utils/Persist.mjs.map +1 -1
- package/dist/utils/Portal.js +2 -0
- package/dist/utils/Portal.js.map +1 -1
- package/dist/utils/Portal.mjs +2 -0
- package/dist/utils/Portal.mjs.map +1 -1
- package/dist/utils/use-visible.js +22 -0
- package/dist/utils/use-visible.js.map +1 -1
- package/dist/utils/use-visible.mjs +23 -2
- package/dist/utils/use-visible.mjs.map +1 -1
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/dist/version.mjs +2 -2
- package/dist/version.mjs.map +1 -1
- package/package.json +8 -21
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Thread.mjs","sources":["../../src/components/Thread.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n BaseMetadata,\n CommentData,\n DM,\n ThreadData,\n} from \"@liveblocks/core\";\nimport { useThreadSubscription } from \"@liveblocks/react\";\nimport {\n useMarkRoomThreadAsResolved,\n useMarkRoomThreadAsUnresolved,\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 { ArrowDownIcon } from \"../icons/ArrowDown\";\nimport { ResolveIcon } from \"../icons/Resolve\";\nimport { ResolvedIcon } from \"../icons/Resolved\";\nimport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n ThreadOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { classNames } from \"../utils/class-names\";\nimport { findLastIndex } from \"../utils/find-last-index\";\nimport type { CommentProps } from \"./Comment\";\nimport { Comment } from \"./Comment\";\nimport type { ComposerProps } from \"./Composer\";\nimport { Composer } from \"./Composer\";\nimport { Button } from \"./internal/Button\";\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 * 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/**\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 onResolvedChange,\n onCommentEdit,\n onCommentDelete,\n onThreadDelete,\n onAuthorClick,\n onMentionClick,\n onAttachmentClick,\n onComposerSubmit,\n overrides,\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 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) => comment.body);\n }, [showDeletedComments, thread.comments]);\n const { status: subscriptionStatus, unreadSince } = useThreadSubscription(\n thread.id\n );\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 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 return (\n <TooltipProvider>\n <div\n className={classNames(\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\n const children = (\n <Comment\n key={comment.id}\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 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 >\n {thread.resolved ? (\n <ResolvedIcon className=\"lb-button-icon\" />\n ) : (\n <ResolveIcon className=\"lb-button-icon\" />\n )}\n </Button>\n </TogglePrimitive.Root>\n </Tooltip>\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 overrides={{\n COMPOSER_PLACEHOLDER: $.THREAD_COMPOSER_PLACEHOLDER,\n COMPOSER_SEND: $.THREAD_COMPOSER_SEND,\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":["unreadIndex","comment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Thread.mjs","sources":["../../src/components/Thread.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n BaseMetadata,\n CommentData,\n DM,\n ThreadData,\n} from \"@liveblocks/core\";\nimport { useThreadSubscription } from \"@liveblocks/react\";\nimport {\n useMarkRoomThreadAsResolved,\n useMarkRoomThreadAsUnresolved,\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 { ArrowDownIcon } from \"../icons/ArrowDown\";\nimport { ResolveIcon } from \"../icons/Resolve\";\nimport { ResolvedIcon } from \"../icons/Resolved\";\nimport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n ThreadOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { classNames } from \"../utils/class-names\";\nimport { findLastIndex } from \"../utils/find-last-index\";\nimport type { CommentProps } from \"./Comment\";\nimport { Comment } from \"./Comment\";\nimport type { ComposerProps } from \"./Composer\";\nimport { Composer } from \"./Composer\";\nimport { Button } from \"./internal/Button\";\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 * 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/**\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 onResolvedChange,\n onCommentEdit,\n onCommentDelete,\n onThreadDelete,\n onAuthorClick,\n onMentionClick,\n onAttachmentClick,\n onComposerSubmit,\n overrides,\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 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) => comment.body);\n }, [showDeletedComments, thread.comments]);\n const { status: subscriptionStatus, unreadSince } = useThreadSubscription(\n thread.id\n );\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 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 return (\n <TooltipProvider>\n <div\n className={classNames(\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\n const children = (\n <Comment\n key={comment.id}\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 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 >\n {thread.resolved ? (\n <ResolvedIcon className=\"lb-button-icon\" />\n ) : (\n <ResolveIcon className=\"lb-button-icon\" />\n )}\n </Button>\n </TogglePrimitive.Root>\n </Tooltip>\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 overrides={{\n COMPOSER_PLACEHOLDER: $.THREAD_COMPOSER_PLACEHOLDER,\n COMPOSER_SEND: $.THREAD_COMPOSER_SEND,\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":";;;;;;;;;;;;;;;;;;AAAA;AA2JO;AAAe;AAElB;AACE;AACuB;AACT;AACd;AACoB;AACJ;AACD;AACG;AACe;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACE;AAEuD;AAEzD;AACE;AAE4D;AAE9D;AAAoD;AAC3C;AAET;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;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;AACG;AACE;AACY;AACT;AAC2B;AAC3B;AACF;AACsC;AACQ;AACvC;AACH;AACC;AAEL;AAAC;AAAc;AAEX;AACA;AAGA;AACG;AAEW;AACmB;AAC7B;AACe;AACF;AACb;AACA;AACA;AACA;AAGA;AACiB;AACjB;AACA;AACA;AAIM;AAGmC;AAIpC;AAIS;AAGP;AACiB;AACC;AACV;AAEN;AACW;AACD;AAID;AAIL;AAAuB;AAEvB;AAAsB;AAAiB;AAE5C;AACF;AAEA;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;AACW;AACe;AACP;AACnB;AACe;AACjB;AAAA;AAEJ;AACF;AAGN;;"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
'use strict';
|
|
2
3
|
|
|
3
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -7,16 +8,13 @@ var Cross = require('../../icons/Cross.js');
|
|
|
7
8
|
var Spinner = require('../../icons/Spinner.js');
|
|
8
9
|
var Warning = require('../../icons/Warning.js');
|
|
9
10
|
var overrides = require('../../overrides.js');
|
|
10
|
-
require('../../primitives/
|
|
11
|
-
require('../../primitives/Composer/index.js');
|
|
11
|
+
require('../../primitives/index.js');
|
|
12
12
|
var contexts = require('../../primitives/Composer/contexts.js');
|
|
13
|
-
var utils = require('../../primitives/Composer/utils.js');
|
|
14
|
-
require('../../primitives/EmojiPicker/index.js');
|
|
15
|
-
require('../../primitives/FileSize.js');
|
|
16
|
-
require('../../primitives/Timestamp.js');
|
|
17
13
|
var classNames = require('../../utils/class-names.js');
|
|
18
14
|
var formatFileSize = require('../../utils/format-file-size.js');
|
|
19
15
|
var Tooltip = require('./Tooltip.js');
|
|
16
|
+
var utils = require('../../primitives/Composer/utils.js');
|
|
17
|
+
|
|
20
18
|
|
|
21
19
|
const MAX_DISPLAYED_MEDIA_SIZE = 60 * 1024 * 1024;
|
|
22
20
|
const fileExtensionRegex = /^(.+?)(\.[^.]+)?$/;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Attachment.js","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { useRoomAttachmentUrl } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport { memo, useCallback, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { Overrides } from \"../../overrides\";\nimport { useOverrides } from \"../../overrides\";\nimport { AttachmentTooLargeError } from \"../../primitives\";\nimport { useComposerAttachmentsContextOrNull } from \"../../primitives/Composer/contexts\";\nimport { classNames } from \"../../utils/class-names\";\nimport { formatFileSize } from \"../../utils/format-file-size\";\nimport { Tooltip } from \"./Tooltip\";\n\nconst MAX_DISPLAYED_MEDIA_SIZE = 60 * 1024 * 1024; // 60 MB\n\ninterface AttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n roomId: string;\n overrides?: Partial<Overrides>;\n allowMediaPreview?: boolean;\n}\n\nconst fileExtensionRegex = /^(.+?)(\\.[^.]+)?$/;\n\nfunction splitFileName(name: string) {\n const match = name.match(fileExtensionRegex);\n\n return { base: match?.[1] ?? name, extension: match?.[2] };\n}\n\nfunction getAttachmentIconGlyph(mimeType: string) {\n if (\n mimeType === \"application/zip\" ||\n mimeType === \"application/gzip\" ||\n mimeType === \"application/vnd.rar\" ||\n mimeType === \"application/x-rar-compressed\" ||\n mimeType === \"application/x-7z-compressed\" ||\n mimeType === \"application/x-zip-compressed\" ||\n mimeType === \"application/x-tar\" ||\n mimeType === \"application/x-bzip\" ||\n mimeType === \"application/x-bzip2\"\n ) {\n return (\n <path d=\"M13 15h2v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1h1a.5.5 0 0 0 .5-.5V20h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 .5-.5V15a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2Z\" />\n );\n }\n\n if (\n mimeType.startsWith(\"text/\") ||\n mimeType.startsWith(\"font/\") ||\n mimeType.startsWith(\"application/\")\n ) {\n return (\n <path d=\"M10 16a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z\" />\n );\n }\n\n if (mimeType.startsWith(\"image/\")) {\n return (\n <path d=\"M12 16h6a1 1 0 0 1 1 1v3l-1.293-1.293a1 1 0 0 0-1.414 0L14.09 20.91l-.464-.386a1 1 0 0 0-1.265-.013l-1.231.985A.995.995 0 0 1 11 21v-4a1 1 0 0 1 1-1Zm-2 1a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-4Zm3 2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z\" />\n );\n }\n\n if (mimeType.startsWith(\"video/\")) {\n return (\n <path d=\"M12 15.71a1 1 0 0 1 1.49-.872l4.96 2.79a1 1 0 0 1 0 1.744l-4.96 2.79A1 1 0 0 1 12 21.29v-5.58Z\" />\n );\n }\n\n if (mimeType.startsWith(\"audio/\")) {\n return (\n <path d=\"M15 15a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 1 0v-7a.5.5 0 0 0-.5-.5Zm-2.5 2.5a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3Zm-2 1a.5.5 0 0 1 1 0v1a.5.5 0 0 1-1 0v-1Zm6-1a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3ZM19 16a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 1 0v-5a.5.5 0 0 0-.5-.5Z\" />\n );\n }\n\n return null;\n}\n\nconst AttachmentFileIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(() => getAttachmentIconGlyph(mimeType), [mimeType]);\n\n return (\n <svg\n className=\"lb-attachment-icon\"\n width={30}\n height={30}\n viewBox=\"0 0 30 30\"\n fill=\"currentColor\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-shadow\"\n />\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-background\"\n />\n <path\n d=\"M14.382 3.037a4 4 0 0 1 2.29 1.135l6.156 6.157a4 4 0 0 1 1.136 2.289A2 2 0 0 0 22 11h-4a2 2 0 0 1-2-2V5a2 2 0 0 0-1.618-1.963Z\"\n className=\"lb-attachment-icon-fold\"\n />\n\n {iconGlyph && <g className=\"lb-attachment-icon-glyph\">{iconGlyph}</g>}\n </svg>\n );\n});\n\nfunction AttachmentImagePreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img\n src={url}\n loading=\"lazy\"\n onLoad={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentVideoPreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <video\n src={url}\n onLoadedData={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentPreview({\n attachment,\n allowMediaPreview = true,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n allowMediaPreview?: boolean;\n roomId: string;\n}) {\n const [isUnsupportedPreview, setUnsupportedPreview] = useState(false);\n const isUploaded =\n attachment.type === \"attachment\" || attachment.status === \"uploaded\";\n\n function markPreviewAsUnsupported() {\n setUnsupportedPreview(true);\n }\n\n if (\n !isUnsupportedPreview &&\n allowMediaPreview &&\n isUploaded &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n if (attachment.mimeType.startsWith(\"image/\")) {\n return (\n <AttachmentImagePreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n\n if (attachment.mimeType.startsWith(\"video/\")) {\n return (\n <AttachmentVideoPreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n }\n\n return <AttachmentFileIcon mimeType={attachment.mimeType} />;\n}\n\nfunction AttachmentName({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n\n return (\n <span className=\"lb-attachment-name\" title={attachment.name}>\n <span className=\"lb-attachment-name-base\">{fileBaseName}</span>\n {fileExtension && (\n <span className=\"lb-attachment-name-extension\">{fileExtension}</span>\n )}\n </span>\n );\n}\n\nfunction useClickOnKeyDown(\n onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void\n) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n // Simulate a click event on Enter or Space because it's a div\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n\n const clickEvent = new MouseEvent(\"click\", {\n bubbles: true,\n cancelable: true,\n view: window,\n });\n event.target.dispatchEvent(clickEvent);\n }\n },\n [onKeyDown]\n );\n\n return handleKeyDown;\n}\n\nfunction useAttachmentContent(\n attachment: CommentMixedAttachment,\n overrides?: Partial<Overrides>\n) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n\n const status =\n attachment.type === \"localAttachment\" ? attachment.status : undefined;\n const isUploading = status === \"uploading\";\n const isError = status === \"error\";\n\n let description: string;\n\n if (attachment.type === \"localAttachment\" && attachment.status === \"error\") {\n if (attachment.error instanceof AttachmentTooLargeError) {\n if (attachment.error.origin === \"server\") {\n description = $.ATTACHMENT_TOO_LARGE();\n } else {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\n }\n } else {\n description = $.ATTACHMENT_ERROR(attachment.error);\n }\n } else {\n description = formatFileSize(attachment.size, $.locale);\n }\n\n const deleteLabel = isInComposer\n ? $.COMPOSER_REMOVE_ATTACHMENT\n : $.COMMENT_DELETE_ATTACHMENT;\n\n return {\n isUploading,\n isError,\n description,\n deleteLabel,\n };\n}\n\nexport function MediaAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-media-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-file-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n\nexport function separateMediaAttachments<T extends CommentMixedAttachment>(\n attachments: T[]\n) {\n const mediaAttachments: T[] = [];\n const fileAttachments: T[] = [];\n\n for (const attachment of attachments) {\n if (\n (attachment.mimeType.startsWith(\"image/\") ||\n attachment.mimeType.startsWith(\"video/\")) &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n mediaAttachments.push(attachment);\n } else {\n fileAttachments.push(attachment);\n }\n }\n\n return {\n mediaAttachments,\n fileAttachments,\n };\n}\n"],"names":["jsx","memo","useMemo","jsxs","useRoomAttachmentUrl","useState","useCallback","Fragment","SpinnerIcon","overrides","useOverrides","useComposerAttachmentsContextOrNull","AttachmentTooLargeError","formatFileSize","classNames","WarningIcon","Tooltip","CrossIcon"],"mappings":";;;;;;;;;;;;;;;;;;;;AAuBA,MAAM,wBAAA,GAA2B,KAAK,IAAO,GAAA,IAAA,CAAA;AAW7C,MAAM,kBAAqB,GAAA,mBAAA,CAAA;AAE3B,SAAS,cAAc,IAAc,EAAA;AACnC,EAAM,MAAA,KAAA,GAAQ,IAAK,CAAA,KAAA,CAAM,kBAAkB,CAAA,CAAA;AAE3C,EAAA,OAAO,EAAE,IAAM,EAAA,KAAA,GAAQ,MAAM,IAAM,EAAA,SAAA,EAAW,QAAQ,CAAG,CAAA,EAAA,CAAA;AAC3D,CAAA;AAEA,SAAS,uBAAuB,QAAkB,EAAA;AAChD,EAAA,IACE,aAAa,iBACb,IAAA,QAAA,KAAa,kBACb,IAAA,QAAA,KAAa,yBACb,QAAa,KAAA,8BAAA,IACb,QAAa,KAAA,6BAAA,IACb,aAAa,8BACb,IAAA,QAAA,KAAa,uBACb,QAAa,KAAA,oBAAA,IACb,aAAa,qBACb,EAAA;AACA,IAAA,uBACGA,cAAA,CAAA,MAAA,EAAA;AAAA,MAAK,CAAE,EAAA,mPAAA;AAAA,KAAoP,CAAA,CAAA;AAAA,GAEhQ;AAEA,EACE,IAAA,QAAA,CAAS,UAAW,CAAA,OAAO,CAC3B,IAAA,QAAA,CAAS,UAAW,CAAA,OAAO,CAC3B,IAAA,QAAA,CAAS,UAAW,CAAA,cAAc,CAClC,EAAA;AACA,IAAA,uBACGA,cAAA,CAAA,MAAA,EAAA;AAAA,MAAK,CAAE,EAAA,gPAAA;AAAA,KAAiP,CAAA,CAAA;AAAA,GAE7P;AAEA,EAAI,IAAA,QAAA,CAAS,UAAW,CAAA,QAAQ,CAAG,EAAA;AACjC,IAAA,uBACGA,cAAA,CAAA,MAAA,EAAA;AAAA,MAAK,CAAE,EAAA,gQAAA;AAAA,KAAiQ,CAAA,CAAA;AAAA,GAE7Q;AAEA,EAAI,IAAA,QAAA,CAAS,UAAW,CAAA,QAAQ,CAAG,EAAA;AACjC,IAAA,uBACGA,cAAA,CAAA,MAAA,EAAA;AAAA,MAAK,CAAE,EAAA,gGAAA;AAAA,KAAiG,CAAA,CAAA;AAAA,GAE7G;AAEA,EAAI,IAAA,QAAA,CAAS,UAAW,CAAA,QAAQ,CAAG,EAAA;AACjC,IAAA,uBACGA,cAAA,CAAA,MAAA,EAAA;AAAA,MAAK,CAAE,EAAA,wPAAA;AAAA,KAAyP,CAAA,CAAA;AAAA,GAErQ;AAEA,EAAO,OAAA,IAAA,CAAA;AACT,CAAA;AAEA,MAAM,kBAAqB,GAAAC,UAAA,CAAK,CAAC,EAAE,UAAqC,KAAA;AACtE,EAAM,MAAA,SAAA,GAAYC,cAAQ,MAAM,sBAAA,CAAuB,QAAQ,CAAG,EAAA,CAAC,QAAQ,CAAC,CAAA,CAAA;AAE5E,EAAA,uBACGC,eAAA,CAAA,KAAA,EAAA;AAAA,IACC,SAAU,EAAA,oBAAA;AAAA,IACV,KAAO,EAAA,EAAA;AAAA,IACP,MAAQ,EAAA,EAAA;AAAA,IACR,OAAQ,EAAA,WAAA;AAAA,IACR,IAAK,EAAA,cAAA;AAAA,IACL,QAAS,EAAA,SAAA;AAAA,IACT,QAAS,EAAA,SAAA;AAAA,IACT,KAAM,EAAA,4BAAA;AAAA,IAEN,QAAA,EAAA;AAAA,sBAACH,cAAA,CAAA,MAAA,EAAA;AAAA,QACC,CAAE,EAAA,oHAAA;AAAA,QACF,SAAU,EAAA,2BAAA;AAAA,OACZ,CAAA;AAAA,sBACCA,cAAA,CAAA,MAAA,EAAA;AAAA,QACC,CAAE,EAAA,oHAAA;AAAA,QACF,SAAU,EAAA,+BAAA;AAAA,OACZ,CAAA;AAAA,sBACCA,cAAA,CAAA,MAAA,EAAA;AAAA,QACC,CAAE,EAAA,gIAAA;AAAA,QACF,SAAU,EAAA,yBAAA;AAAA,OACZ,CAAA;AAAA,MAEC,6BAAcA,cAAA,CAAA,GAAA,EAAA;AAAA,QAAE,SAAU,EAAA,0BAAA;AAAA,QAA4B,QAAA,EAAA,SAAA;AAAA,OAAU,CAAA;AAAA,KAAA;AAAA,GACnE,CAAA,CAAA;AAEJ,CAAC,CAAA,CAAA;AAED,SAAS,sBAAuB,CAAA;AAAA,EAC9B,UAAA;AAAA,EACA,wBAAA;AAAA,EACA,MAAA;AACF,CAIG,EAAA;AACD,EAAA,MAAM,EAAE,GAAI,EAAA,GAAII,6BAAqB,CAAA,UAAA,CAAW,IAAI,MAAM,CAAA,CAAA;AAC1D,EAAA,MAAM,CAAC,QAAA,EAAU,SAAS,CAAA,GAAIC,eAAS,KAAK,CAAA,CAAA;AAE5C,EAAM,MAAA,UAAA,GAAaC,kBAAY,MAAM;AACnC,IAAA,SAAA,CAAU,IAAI,CAAA,CAAA;AAAA,GAChB,EAAG,EAAE,CAAA,CAAA;AAEL,EACE,uBAAAH,eAAA,CAAAI,mBAAA,EAAA;AAAA,IACG,QAAA,EAAA;AAAA,MAAC,CAAA,QAAA,mBAAYP,cAAA,CAAAQ,mBAAA,EAAA,EAAY,CAAK,GAAA,IAAA;AAAA,MAC9B,sBACER,cAAA,CAAA,KAAA,EAAA;AAAA,QACC,SAAU,EAAA,6BAAA;AAAA,QACV,aAAA,EAAa,CAAC,QAAA,GAAW,EAAK,GAAA,KAAA,CAAA;AAAA,QAE9B,QAAC,kBAAAA,cAAA,CAAA,KAAA,EAAA;AAAA,UACC,GAAK,EAAA,GAAA;AAAA,UACL,OAAQ,EAAA,MAAA;AAAA,UACR,MAAQ,EAAA,UAAA;AAAA,UACR,OAAS,EAAA,wBAAA;AAAA,SACX,CAAA;AAAA,OACF,CACE,GAAA,IAAA;AAAA,KAAA;AAAA,GACN,CAAA,CAAA;AAEJ,CAAA;AAEA,SAAS,sBAAuB,CAAA;AAAA,EAC9B,UAAA;AAAA,EACA,wBAAA;AAAA,EACA,MAAA;AACF,CAIG,EAAA;AACD,EAAA,MAAM,EAAE,GAAI,EAAA,GAAII,6BAAqB,CAAA,UAAA,CAAW,IAAI,MAAM,CAAA,CAAA;AAC1D,EAAA,MAAM,CAAC,QAAA,EAAU,SAAS,CAAA,GAAIC,eAAS,KAAK,CAAA,CAAA;AAE5C,EAAM,MAAA,UAAA,GAAaC,kBAAY,MAAM;AACnC,IAAA,SAAA,CAAU,IAAI,CAAA,CAAA;AAAA,GAChB,EAAG,EAAE,CAAA,CAAA;AAEL,EACE,uBAAAH,eAAA,CAAAI,mBAAA,EAAA;AAAA,IACG,QAAA,EAAA;AAAA,MAAC,CAAA,QAAA,mBAAYP,cAAA,CAAAQ,mBAAA,EAAA,EAAY,CAAK,GAAA,IAAA;AAAA,MAC9B,sBACER,cAAA,CAAA,KAAA,EAAA;AAAA,QACC,SAAU,EAAA,6BAAA;AAAA,QACV,aAAA,EAAa,CAAC,QAAA,GAAW,EAAK,GAAA,KAAA,CAAA;AAAA,QAE9B,QAAC,kBAAAA,cAAA,CAAA,OAAA,EAAA;AAAA,UACC,GAAK,EAAA,GAAA;AAAA,UACL,YAAc,EAAA,UAAA;AAAA,UACd,OAAS,EAAA,wBAAA;AAAA,SACX,CAAA;AAAA,OACF,CACE,GAAA,IAAA;AAAA,KAAA;AAAA,GACN,CAAA,CAAA;AAEJ,CAAA;AAEA,SAAS,iBAAkB,CAAA;AAAA,EACzB,UAAA;AAAA,EACA,iBAAoB,GAAA,IAAA;AAAA,EACpB,MAAA;AACF,CAIG,EAAA;AACD,EAAA,MAAM,CAAC,oBAAA,EAAsB,qBAAqB,CAAA,GAAIK,eAAS,KAAK,CAAA,CAAA;AACpE,EAAA,MAAM,UACJ,GAAA,UAAA,CAAW,IAAS,KAAA,YAAA,IAAgB,WAAW,MAAW,KAAA,UAAA,CAAA;AAE5D,EAAA,SAAS,wBAA2B,GAAA;AAClC,IAAA,qBAAA,CAAsB,IAAI,CAAA,CAAA;AAAA,GAC5B;AAEA,EAAA,IACE,CAAC,oBACD,IAAA,iBAAA,IACA,UACA,IAAA,UAAA,CAAW,QAAQ,wBACnB,EAAA;AACA,IAAA,IAAI,UAAW,CAAA,QAAA,CAAS,UAAW,CAAA,QAAQ,CAAG,EAAA;AAC5C,MAAA,uBACGL,cAAA,CAAA,sBAAA,EAAA;AAAA,QACC,UAAA;AAAA,QACA,wBAAA;AAAA,QACA,MAAA;AAAA,OACF,CAAA,CAAA;AAAA,KAEJ;AAEA,IAAA,IAAI,UAAW,CAAA,QAAA,CAAS,UAAW,CAAA,QAAQ,CAAG,EAAA;AAC5C,MAAA,uBACGA,cAAA,CAAA,sBAAA,EAAA;AAAA,QACC,UAAA;AAAA,QACA,wBAAA;AAAA,QACA,MAAA;AAAA,OACF,CAAA,CAAA;AAAA,KAEJ;AAAA,GACF;AAEA,EAAA,uBAAQA,cAAA,CAAA,kBAAA,EAAA;AAAA,IAAmB,UAAU,UAAW,CAAA,QAAA;AAAA,GAAU,CAAA,CAAA;AAC5D,CAAA;AAEA,SAAS,cAAe,CAAA;AAAA,EACtB,UAAA;AACF,CAEG,EAAA;AACD,EAAA,MAAM,EAAE,IAAM,EAAA,YAAA,EAAc,WAAW,aAAc,EAAA,GAAIE,cAAQ,MAAM;AACrE,IAAO,OAAA,aAAA,CAAc,WAAW,IAAI,CAAA,CAAA;AAAA,GACnC,EAAA,CAAC,UAAW,CAAA,IAAI,CAAC,CAAA,CAAA;AAEpB,EAAA,uBACGC,eAAA,CAAA,MAAA,EAAA;AAAA,IAAK,SAAU,EAAA,oBAAA;AAAA,IAAqB,OAAO,UAAW,CAAA,IAAA;AAAA,IACrD,QAAA,EAAA;AAAA,sBAACH,cAAA,CAAA,MAAA,EAAA;AAAA,QAAK,SAAU,EAAA,yBAAA;AAAA,QAA2B,QAAA,EAAA,YAAA;AAAA,OAAa,CAAA;AAAA,MACvD,iCACEA,cAAA,CAAA,MAAA,EAAA;AAAA,QAAK,SAAU,EAAA,8BAAA;AAAA,QAAgC,QAAA,EAAA,aAAA;AAAA,OAAc,CAAA;AAAA,KAAA;AAAA,GAElE,CAAA,CAAA;AAEJ,CAAA;AAEA,SAAS,kBACP,SACA,EAAA;AACA,EAAA,MAAM,aAAgB,GAAAM,iBAAA;AAAA,IACpB,CAAC,KAAyC,KAAA;AACxC,MAAA,SAAA,GAAY,KAAK,CAAA,CAAA;AAEjB,MAAI,IAAA,KAAA,CAAM,oBAAsB,EAAA;AAC9B,QAAA,OAAA;AAAA,OACF;AAGA,MAAA,IAAI,KAAM,CAAA,GAAA,KAAQ,OAAW,IAAA,KAAA,CAAM,QAAQ,GAAK,EAAA;AAC9C,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AAErB,QAAM,MAAA,UAAA,GAAa,IAAI,UAAA,CAAW,OAAS,EAAA;AAAA,UACzC,OAAS,EAAA,IAAA;AAAA,UACT,UAAY,EAAA,IAAA;AAAA,UACZ,IAAM,EAAA,MAAA;AAAA,SACP,CAAA,CAAA;AACD,QAAM,KAAA,CAAA,MAAA,CAAO,cAAc,UAAU,CAAA,CAAA;AAAA,OACvC;AAAA,KACF;AAAA,IACA,CAAC,SAAS,CAAA;AAAA,GACZ,CAAA;AAEA,EAAO,OAAA,aAAA,CAAA;AACT,CAAA;AAEA,SAAS,oBAAA,CACP,YACAG,WACA,EAAA;AACA,EAAM,MAAA,CAAA,GAAIC,uBAAaD,WAAS,CAAA,CAAA;AAChC,EAAA,MAAM,6BAA6BE,4CAAoC,EAAA,CAAA;AACvE,EAAM,MAAA,YAAA,GAAe,QAAQ,0BAA0B,CAAA,CAAA;AACvD,EAAA,MAAM,oBAAoB,0BAA4B,EAAA,iBAAA,CAAA;AAEtD,EAAA,MAAM,MACJ,GAAA,UAAA,CAAW,IAAS,KAAA,iBAAA,GAAoB,WAAW,MAAS,GAAA,KAAA,CAAA,CAAA;AAC9D,EAAA,MAAM,cAAc,MAAW,KAAA,WAAA,CAAA;AAC/B,EAAA,MAAM,UAAU,MAAW,KAAA,OAAA,CAAA;AAE3B,EAAI,IAAA,WAAA,CAAA;AAEJ,EAAA,IAAI,UAAW,CAAA,IAAA,KAAS,iBAAqB,IAAA,UAAA,CAAW,WAAW,OAAS,EAAA;AAC1E,IAAI,IAAA,UAAA,CAAW,iBAAiBC,6BAAyB,EAAA;AACvD,MAAI,IAAA,UAAA,CAAW,KAAM,CAAA,MAAA,KAAW,QAAU,EAAA;AACxC,QAAA,WAAA,GAAc,EAAE,oBAAqB,EAAA,CAAA;AAAA,OAChC,MAAA;AACL,QAAA,WAAA,GAAc,CAAE,CAAA,oBAAA;AAAA,UACd,iBACI,GAAAC,6BAAA,CAAe,iBAAmB,EAAA,CAAA,CAAE,MAAM,CAC1C,GAAA,KAAA,CAAA;AAAA,SACN,CAAA;AAAA,OACF;AAAA,KACK,MAAA;AACL,MAAc,WAAA,GAAA,CAAA,CAAE,gBAAiB,CAAA,UAAA,CAAW,KAAK,CAAA,CAAA;AAAA,KACnD;AAAA,GACK,MAAA;AACL,IAAA,WAAA,GAAcA,6BAAe,CAAA,UAAA,CAAW,IAAM,EAAA,CAAA,CAAE,MAAM,CAAA,CAAA;AAAA,GACxD;AAEA,EAAA,MAAM,WAAc,GAAA,YAAA,GAChB,CAAE,CAAA,0BAAA,GACF,CAAE,CAAA,yBAAA,CAAA;AAEN,EAAO,OAAA;AAAA,IACL,WAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,GACF,CAAA;AACF,CAAA;AAEO,SAAS,eAAgB,CAAA;AAAA,EAC9B,UAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,aAAA;AAAA,EACA,oBAAA;AAAA,EACA,iBAAoB,GAAA,IAAA;AAAA,EACpB,MAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACG,GAAA,KAAA;AACL,CAAoB,EAAA;AAClB,EAAM,MAAA,EAAE,aAAa,OAAS,EAAA,WAAA,EAAa,aACzC,GAAA,oBAAA,CAAqB,YAAY,SAAS,CAAA,CAAA;AAE5C,EAAA,MAAM,uBAA0B,GAAAP,iBAAA;AAAA,IAC9B,CAAC,KAA2C,KAAA;AAC1C,MAAA,IAAI,oBAAsB,EAAA;AACxB,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AAAA,OACvB;AAAA,KACF;AAAA,IACA,CAAC,oBAAoB,CAAA;AAAA,GACvB,CAAA;AAEA,EAAM,MAAA,aAAA,GAAgB,kBAAkB,SAAS,CAAA,CAAA;AAEjD,EAAA,uBACGH,eAAA,CAAA,KAAA,EAAA;AAAA,IACC,SAAA,EAAWW,qBAAW,CAAA,mCAAA,EAAqC,SAAS,CAAA;AAAA,IACpE,YAAA,EAAY,UAAU,EAAK,GAAA,KAAA,CAAA;AAAA,IAC1B,GAAG,KAAA;AAAA,IACJ,IAAA,EAAM,UAAU,QAAW,GAAA,KAAA,CAAA;AAAA,IAC3B,OAAA;AAAA,IACA,QAAA,EAAU,UAAU,CAAI,GAAA,CAAA,CAAA;AAAA,IACxB,SAAA,EAAW,UAAU,aAAgB,GAAA,KAAA,CAAA;AAAA,IAErC,QAAA,EAAA;AAAA,sBAACd,cAAA,CAAA,KAAA,EAAA;AAAA,QAAI,SAAU,EAAA,uBAAA;AAAA,QACZ,QAAA,EAAA,WAAA,kCACEQ,mBAAY,EAAA,EAAA,CAAA,GACX,0BACDR,cAAA,CAAAe,mBAAA,EAAA,EAAY,oBAEZf,cAAA,CAAA,iBAAA,EAAA;AAAA,UACC,UAAA;AAAA,UACA,iBAAA;AAAA,UACA,MAAA;AAAA,SACF,CAAA;AAAA,OAEJ,CAAA;AAAA,sBACCG,eAAA,CAAA,KAAA,EAAA;AAAA,QAAI,SAAU,EAAA,uBAAA;AAAA,QACb,QAAA,EAAA;AAAA,0BAACH,cAAA,CAAA,cAAA,EAAA;AAAA,YAAe,UAAA;AAAA,WAAwB,CAAA;AAAA,0BACvCA,cAAA,CAAA,MAAA,EAAA;AAAA,YAAK,SAAU,EAAA,2BAAA;AAAA,YAA4B,KAAO,EAAA,WAAA;AAAA,YAChD,QAAA,EAAA,WAAA;AAAA,WACH,CAAA;AAAA,SAAA;AAAA,OACF,CAAA;AAAA,MACC,iCACEA,cAAA,CAAAgB,eAAA,EAAA;AAAA,QAAQ,OAAS,EAAA,WAAA;AAAA,QAChB,QAAC,kBAAAhB,cAAA,CAAA,QAAA,EAAA;AAAA,UACC,IAAK,EAAA,QAAA;AAAA,UACL,SAAU,EAAA,sBAAA;AAAA,UACV,OAAS,EAAA,aAAA;AAAA,UACT,aAAe,EAAA,uBAAA;AAAA,UACf,YAAY,EAAA,WAAA;AAAA,UAEZ,yCAACiB,eAAU,EAAA,EAAA,CAAA;AAAA,SACb,CAAA;AAAA,OACF,CAAA;AAAA,KAAA;AAAA,GAEJ,CAAA,CAAA;AAEJ,CAAA;AAEO,SAAS,cAAe,CAAA;AAAA,EAC7B,UAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,aAAA;AAAA,EACA,oBAAA;AAAA,EACA,iBAAoB,GAAA,IAAA;AAAA,EACpB,MAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACG,GAAA,KAAA;AACL,CAAoB,EAAA;AAClB,EAAM,MAAA,EAAE,aAAa,OAAS,EAAA,WAAA,EAAa,aACzC,GAAA,oBAAA,CAAqB,YAAY,SAAS,CAAA,CAAA;AAE5C,EAAA,MAAM,uBAA0B,GAAAX,iBAAA;AAAA,IAC9B,CAAC,KAA2C,KAAA;AAC1C,MAAA,IAAI,oBAAsB,EAAA;AACxB,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AAAA,OACvB;AAAA,KACF;AAAA,IACA,CAAC,oBAAoB,CAAA;AAAA,GACvB,CAAA;AAEA,EAAM,MAAA,aAAA,GAAgB,kBAAkB,SAAS,CAAA,CAAA;AAEjD,EAAA,uBACGH,eAAA,CAAA,KAAA,EAAA;AAAA,IACC,SAAA,EAAWW,qBAAW,CAAA,kCAAA,EAAoC,SAAS,CAAA;AAAA,IACnE,YAAA,EAAY,UAAU,EAAK,GAAA,KAAA,CAAA;AAAA,IAC1B,GAAG,KAAA;AAAA,IACJ,IAAA,EAAM,UAAU,QAAW,GAAA,KAAA,CAAA;AAAA,IAC3B,OAAA;AAAA,IACA,QAAA,EAAU,UAAU,CAAI,GAAA,CAAA,CAAA;AAAA,IACxB,SAAA,EAAW,UAAU,aAAgB,GAAA,KAAA,CAAA;AAAA,IAErC,QAAA,EAAA;AAAA,sBAACd,cAAA,CAAA,KAAA,EAAA;AAAA,QAAI,SAAU,EAAA,uBAAA;AAAA,QACZ,QAAA,EAAA,WAAA,kCACEQ,mBAAY,EAAA,EAAA,CAAA,GACX,0BACDR,cAAA,CAAAe,mBAAA,EAAA,EAAY,oBAEZf,cAAA,CAAA,iBAAA,EAAA;AAAA,UACC,UAAA;AAAA,UACA,iBAAA;AAAA,UACA,MAAA;AAAA,SACF,CAAA;AAAA,OAEJ,CAAA;AAAA,sBACCG,eAAA,CAAA,KAAA,EAAA;AAAA,QAAI,SAAU,EAAA,uBAAA;AAAA,QACb,QAAA,EAAA;AAAA,0BAACH,cAAA,CAAA,cAAA,EAAA;AAAA,YAAe,UAAA;AAAA,WAAwB,CAAA;AAAA,0BACvCA,cAAA,CAAA,MAAA,EAAA;AAAA,YAAK,SAAU,EAAA,2BAAA;AAAA,YAA4B,KAAO,EAAA,WAAA;AAAA,YAChD,QAAA,EAAA,WAAA;AAAA,WACH,CAAA;AAAA,SAAA;AAAA,OACF,CAAA;AAAA,MACC,iCACEA,cAAA,CAAAgB,eAAA,EAAA;AAAA,QAAQ,OAAS,EAAA,WAAA;AAAA,QAChB,QAAC,kBAAAhB,cAAA,CAAA,QAAA,EAAA;AAAA,UACC,IAAK,EAAA,QAAA;AAAA,UACL,SAAU,EAAA,sBAAA;AAAA,UACV,OAAS,EAAA,aAAA;AAAA,UACT,aAAe,EAAA,uBAAA;AAAA,UACf,YAAY,EAAA,WAAA;AAAA,UAEZ,yCAACiB,eAAU,EAAA,EAAA,CAAA;AAAA,SACb,CAAA;AAAA,OACF,CAAA;AAAA,KAAA;AAAA,GAEJ,CAAA,CAAA;AAEJ,CAAA;AAEO,SAAS,yBACd,WACA,EAAA;AACA,EAAA,MAAM,mBAAwB,EAAC,CAAA;AAC/B,EAAA,MAAM,kBAAuB,EAAC,CAAA;AAE9B,EAAA,KAAA,MAAW,cAAc,WAAa,EAAA;AACpC,IAAA,IAAA,CACG,UAAW,CAAA,QAAA,CAAS,UAAW,CAAA,QAAQ,CACtC,IAAA,UAAA,CAAW,QAAS,CAAA,UAAA,CAAW,QAAQ,CAAA,KACzC,UAAW,CAAA,IAAA,IAAQ,wBACnB,EAAA;AACA,MAAA,gBAAA,CAAiB,KAAK,UAAU,CAAA,CAAA;AAAA,KAC3B,MAAA;AACL,MAAA,eAAA,CAAgB,KAAK,UAAU,CAAA,CAAA;AAAA,KACjC;AAAA,GACF;AAEA,EAAO,OAAA;AAAA,IACL,gBAAA;AAAA,IACA,eAAA;AAAA,GACF,CAAA;AACF;;;;;;"}
|
|
1
|
+
{"version":3,"file":"Attachment.js","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { useRoomAttachmentUrl } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport { memo, useCallback, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { Overrides } from \"../../overrides\";\nimport { useOverrides } from \"../../overrides\";\nimport { AttachmentTooLargeError } from \"../../primitives\";\nimport { useComposerAttachmentsContextOrNull } from \"../../primitives/Composer/contexts\";\nimport { classNames } from \"../../utils/class-names\";\nimport { formatFileSize } from \"../../utils/format-file-size\";\nimport { Tooltip } from \"./Tooltip\";\n\nconst MAX_DISPLAYED_MEDIA_SIZE = 60 * 1024 * 1024; // 60 MB\n\ninterface AttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n roomId: string;\n overrides?: Partial<Overrides>;\n allowMediaPreview?: boolean;\n}\n\nconst fileExtensionRegex = /^(.+?)(\\.[^.]+)?$/;\n\nfunction splitFileName(name: string) {\n const match = name.match(fileExtensionRegex);\n\n return { base: match?.[1] ?? name, extension: match?.[2] };\n}\n\nfunction getAttachmentIconGlyph(mimeType: string) {\n if (\n mimeType === \"application/zip\" ||\n mimeType === \"application/gzip\" ||\n mimeType === \"application/vnd.rar\" ||\n mimeType === \"application/x-rar-compressed\" ||\n mimeType === \"application/x-7z-compressed\" ||\n mimeType === \"application/x-zip-compressed\" ||\n mimeType === \"application/x-tar\" ||\n mimeType === \"application/x-bzip\" ||\n mimeType === \"application/x-bzip2\"\n ) {\n return (\n <path d=\"M13 15h2v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1h1a.5.5 0 0 0 .5-.5V20h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 .5-.5V15a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2Z\" />\n );\n }\n\n if (\n mimeType.startsWith(\"text/\") ||\n mimeType.startsWith(\"font/\") ||\n mimeType.startsWith(\"application/\")\n ) {\n return (\n <path d=\"M10 16a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z\" />\n );\n }\n\n if (mimeType.startsWith(\"image/\")) {\n return (\n <path d=\"M12 16h6a1 1 0 0 1 1 1v3l-1.293-1.293a1 1 0 0 0-1.414 0L14.09 20.91l-.464-.386a1 1 0 0 0-1.265-.013l-1.231.985A.995.995 0 0 1 11 21v-4a1 1 0 0 1 1-1Zm-2 1a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-4Zm3 2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z\" />\n );\n }\n\n if (mimeType.startsWith(\"video/\")) {\n return (\n <path d=\"M12 15.71a1 1 0 0 1 1.49-.872l4.96 2.79a1 1 0 0 1 0 1.744l-4.96 2.79A1 1 0 0 1 12 21.29v-5.58Z\" />\n );\n }\n\n if (mimeType.startsWith(\"audio/\")) {\n return (\n <path d=\"M15 15a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 1 0v-7a.5.5 0 0 0-.5-.5Zm-2.5 2.5a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3Zm-2 1a.5.5 0 0 1 1 0v1a.5.5 0 0 1-1 0v-1Zm6-1a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3ZM19 16a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 1 0v-5a.5.5 0 0 0-.5-.5Z\" />\n );\n }\n\n return null;\n}\n\nconst AttachmentFileIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(() => getAttachmentIconGlyph(mimeType), [mimeType]);\n\n return (\n <svg\n className=\"lb-attachment-icon\"\n width={30}\n height={30}\n viewBox=\"0 0 30 30\"\n fill=\"currentColor\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-shadow\"\n />\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-background\"\n />\n <path\n d=\"M14.382 3.037a4 4 0 0 1 2.29 1.135l6.156 6.157a4 4 0 0 1 1.136 2.289A2 2 0 0 0 22 11h-4a2 2 0 0 1-2-2V5a2 2 0 0 0-1.618-1.963Z\"\n className=\"lb-attachment-icon-fold\"\n />\n\n {iconGlyph && <g className=\"lb-attachment-icon-glyph\">{iconGlyph}</g>}\n </svg>\n );\n});\n\nfunction AttachmentImagePreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img\n src={url}\n loading=\"lazy\"\n onLoad={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentVideoPreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <video\n src={url}\n onLoadedData={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentPreview({\n attachment,\n allowMediaPreview = true,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n allowMediaPreview?: boolean;\n roomId: string;\n}) {\n const [isUnsupportedPreview, setUnsupportedPreview] = useState(false);\n const isUploaded =\n attachment.type === \"attachment\" || attachment.status === \"uploaded\";\n\n function markPreviewAsUnsupported() {\n setUnsupportedPreview(true);\n }\n\n if (\n !isUnsupportedPreview &&\n allowMediaPreview &&\n isUploaded &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n if (attachment.mimeType.startsWith(\"image/\")) {\n return (\n <AttachmentImagePreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n\n if (attachment.mimeType.startsWith(\"video/\")) {\n return (\n <AttachmentVideoPreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n }\n\n return <AttachmentFileIcon mimeType={attachment.mimeType} />;\n}\n\nfunction AttachmentName({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n\n return (\n <span className=\"lb-attachment-name\" title={attachment.name}>\n <span className=\"lb-attachment-name-base\">{fileBaseName}</span>\n {fileExtension && (\n <span className=\"lb-attachment-name-extension\">{fileExtension}</span>\n )}\n </span>\n );\n}\n\nfunction useClickOnKeyDown(\n onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void\n) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n // Simulate a click event on Enter or Space because it's a div\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n\n const clickEvent = new MouseEvent(\"click\", {\n bubbles: true,\n cancelable: true,\n view: window,\n });\n event.target.dispatchEvent(clickEvent);\n }\n },\n [onKeyDown]\n );\n\n return handleKeyDown;\n}\n\nfunction useAttachmentContent(\n attachment: CommentMixedAttachment,\n overrides?: Partial<Overrides>\n) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n\n const status =\n attachment.type === \"localAttachment\" ? attachment.status : undefined;\n const isUploading = status === \"uploading\";\n const isError = status === \"error\";\n\n let description: string;\n\n if (attachment.type === \"localAttachment\" && attachment.status === \"error\") {\n if (attachment.error instanceof AttachmentTooLargeError) {\n if (attachment.error.origin === \"server\") {\n description = $.ATTACHMENT_TOO_LARGE();\n } else {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\n }\n } else {\n description = $.ATTACHMENT_ERROR(attachment.error);\n }\n } else {\n description = formatFileSize(attachment.size, $.locale);\n }\n\n const deleteLabel = isInComposer\n ? $.COMPOSER_REMOVE_ATTACHMENT\n : $.COMMENT_DELETE_ATTACHMENT;\n\n return {\n isUploading,\n isError,\n description,\n deleteLabel,\n };\n}\n\nexport function MediaAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-media-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-file-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n\nexport function separateMediaAttachments<T extends CommentMixedAttachment>(\n attachments: T[]\n) {\n const mediaAttachments: T[] = [];\n const fileAttachments: T[] = [];\n\n for (const attachment of attachments) {\n if (\n (attachment.mimeType.startsWith(\"image/\") ||\n attachment.mimeType.startsWith(\"video/\")) &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n mediaAttachments.push(attachment);\n } else {\n fileAttachments.push(attachment);\n }\n }\n\n return {\n mediaAttachments,\n fileAttachments,\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA;AAuBA;AAWA;AAEA;AACE;AAEA;AACF;AAEA;AACE;AAWE;AACG;AAAO;AAAoP;AAIhQ;AAKE;AACG;AAAO;AAAiP;AAI7P;AACE;AACG;AAAO;AAAiQ;AAI7Q;AACE;AACG;AAAO;AAAiG;AAI7G;AACE;AACG;AAAO;AAAyP;AAIrQ;AACF;AAEA;AACE;AAEA;AACG;AACW;AACH;AACC;AACA;AACH;AACI;AACA;AACH;AAEN;AAAC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AAEe;AAAY;AAA4B;AAAU;AAAA;AAGvE;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACG;AACA;AACC;AACX;AAEA;AAAA;AAGV;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACS;AACL;AACX;AAEA;AAAA;AAGV;AAEA;AAA2B;AACzB;AACoB;AAEtB;AAKE;AACA;AAGA;AACE;AAA0B;AAG5B;AAME;AACE;AACG;AACC;AACA;AACA;AACF;AAIJ;AACE;AACG;AACC;AACA;AACA;AACF;AAEJ;AAGF;AAAQ;AAAwC;AAClD;AAEA;AAAwB;AAExB;AAGE;AACE;AAAoC;AAGtC;AACG;AAAe;AAAuC;AACrD;AAAC;AAAe;AAA2B;AAAa;AAErD;AAAe;AAAgC;AAAc;AAAA;AAItE;AAEA;AAGE;AAAsB;AAElB;AAEA;AACE;AAAA;AAIF;AACE;AAEA;AAA2C;AAChC;AACG;AACN;AAER;AAAqC;AACvC;AACF;AACU;AAGZ;AACF;AAEA;AAIE;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AACE;AACE;AACE;AAAqC;AAErC;AAAgB;AAGV;AACN;AACF;AAEA;AAAiD;AACnD;AAEA;AAAsD;AAGxD;AAIA;AAAO;AACL;AACA;AACA;AACA;AAEJ;AAEO;AAAyB;AAC9B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AACqE;AACzC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAAwB;AAC7B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AACoE;AACxC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAGL;AACA;AAEA;AACE;AAKE;AAAgC;AAEhC;AAA+B;AACjC;AAGF;AAAO;AACL;AACA;AAEJ;;;;"}
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
3
|
import { useRoomAttachmentUrl } from '@liveblocks/react/_private';
|
|
3
|
-
import { memo, useMemo,
|
|
4
|
+
import { memo, useMemo, useState, useCallback } from 'react';
|
|
4
5
|
import { CrossIcon } from '../../icons/Cross.mjs';
|
|
5
6
|
import { SpinnerIcon } from '../../icons/Spinner.mjs';
|
|
6
7
|
import { WarningIcon } from '../../icons/Warning.mjs';
|
|
7
8
|
import { useOverrides } from '../../overrides.mjs';
|
|
8
|
-
import '../../primitives/
|
|
9
|
-
import '../../primitives/Composer/index.mjs';
|
|
9
|
+
import '../../primitives/index.mjs';
|
|
10
10
|
import { useComposerAttachmentsContextOrNull } from '../../primitives/Composer/contexts.mjs';
|
|
11
|
-
import { AttachmentTooLargeError } from '../../primitives/Composer/utils.mjs';
|
|
12
|
-
import '../../primitives/EmojiPicker/index.mjs';
|
|
13
|
-
import '../../primitives/FileSize.mjs';
|
|
14
|
-
import '../../primitives/Timestamp.mjs';
|
|
15
11
|
import { classNames } from '../../utils/class-names.mjs';
|
|
16
12
|
import { formatFileSize } from '../../utils/format-file-size.mjs';
|
|
17
13
|
import { Tooltip } from './Tooltip.mjs';
|
|
14
|
+
import { AttachmentTooLargeError } from '../../primitives/Composer/utils.mjs';
|
|
15
|
+
|
|
18
16
|
|
|
19
17
|
const MAX_DISPLAYED_MEDIA_SIZE = 60 * 1024 * 1024;
|
|
20
18
|
const fileExtensionRegex = /^(.+?)(\.[^.]+)?$/;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Attachment.mjs","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { useRoomAttachmentUrl } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport { memo, useCallback, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { Overrides } from \"../../overrides\";\nimport { useOverrides } from \"../../overrides\";\nimport { AttachmentTooLargeError } from \"../../primitives\";\nimport { useComposerAttachmentsContextOrNull } from \"../../primitives/Composer/contexts\";\nimport { classNames } from \"../../utils/class-names\";\nimport { formatFileSize } from \"../../utils/format-file-size\";\nimport { Tooltip } from \"./Tooltip\";\n\nconst MAX_DISPLAYED_MEDIA_SIZE = 60 * 1024 * 1024; // 60 MB\n\ninterface AttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n roomId: string;\n overrides?: Partial<Overrides>;\n allowMediaPreview?: boolean;\n}\n\nconst fileExtensionRegex = /^(.+?)(\\.[^.]+)?$/;\n\nfunction splitFileName(name: string) {\n const match = name.match(fileExtensionRegex);\n\n return { base: match?.[1] ?? name, extension: match?.[2] };\n}\n\nfunction getAttachmentIconGlyph(mimeType: string) {\n if (\n mimeType === \"application/zip\" ||\n mimeType === \"application/gzip\" ||\n mimeType === \"application/vnd.rar\" ||\n mimeType === \"application/x-rar-compressed\" ||\n mimeType === \"application/x-7z-compressed\" ||\n mimeType === \"application/x-zip-compressed\" ||\n mimeType === \"application/x-tar\" ||\n mimeType === \"application/x-bzip\" ||\n mimeType === \"application/x-bzip2\"\n ) {\n return (\n <path d=\"M13 15h2v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1h1a.5.5 0 0 0 .5-.5V20h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 .5-.5V15a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2Z\" />\n );\n }\n\n if (\n mimeType.startsWith(\"text/\") ||\n mimeType.startsWith(\"font/\") ||\n mimeType.startsWith(\"application/\")\n ) {\n return (\n <path d=\"M10 16a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z\" />\n );\n }\n\n if (mimeType.startsWith(\"image/\")) {\n return (\n <path d=\"M12 16h6a1 1 0 0 1 1 1v3l-1.293-1.293a1 1 0 0 0-1.414 0L14.09 20.91l-.464-.386a1 1 0 0 0-1.265-.013l-1.231.985A.995.995 0 0 1 11 21v-4a1 1 0 0 1 1-1Zm-2 1a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-4Zm3 2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z\" />\n );\n }\n\n if (mimeType.startsWith(\"video/\")) {\n return (\n <path d=\"M12 15.71a1 1 0 0 1 1.49-.872l4.96 2.79a1 1 0 0 1 0 1.744l-4.96 2.79A1 1 0 0 1 12 21.29v-5.58Z\" />\n );\n }\n\n if (mimeType.startsWith(\"audio/\")) {\n return (\n <path d=\"M15 15a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 1 0v-7a.5.5 0 0 0-.5-.5Zm-2.5 2.5a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3Zm-2 1a.5.5 0 0 1 1 0v1a.5.5 0 0 1-1 0v-1Zm6-1a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3ZM19 16a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 1 0v-5a.5.5 0 0 0-.5-.5Z\" />\n );\n }\n\n return null;\n}\n\nconst AttachmentFileIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(() => getAttachmentIconGlyph(mimeType), [mimeType]);\n\n return (\n <svg\n className=\"lb-attachment-icon\"\n width={30}\n height={30}\n viewBox=\"0 0 30 30\"\n fill=\"currentColor\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-shadow\"\n />\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-background\"\n />\n <path\n d=\"M14.382 3.037a4 4 0 0 1 2.29 1.135l6.156 6.157a4 4 0 0 1 1.136 2.289A2 2 0 0 0 22 11h-4a2 2 0 0 1-2-2V5a2 2 0 0 0-1.618-1.963Z\"\n className=\"lb-attachment-icon-fold\"\n />\n\n {iconGlyph && <g className=\"lb-attachment-icon-glyph\">{iconGlyph}</g>}\n </svg>\n );\n});\n\nfunction AttachmentImagePreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img\n src={url}\n loading=\"lazy\"\n onLoad={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentVideoPreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <video\n src={url}\n onLoadedData={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentPreview({\n attachment,\n allowMediaPreview = true,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n allowMediaPreview?: boolean;\n roomId: string;\n}) {\n const [isUnsupportedPreview, setUnsupportedPreview] = useState(false);\n const isUploaded =\n attachment.type === \"attachment\" || attachment.status === \"uploaded\";\n\n function markPreviewAsUnsupported() {\n setUnsupportedPreview(true);\n }\n\n if (\n !isUnsupportedPreview &&\n allowMediaPreview &&\n isUploaded &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n if (attachment.mimeType.startsWith(\"image/\")) {\n return (\n <AttachmentImagePreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n\n if (attachment.mimeType.startsWith(\"video/\")) {\n return (\n <AttachmentVideoPreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n }\n\n return <AttachmentFileIcon mimeType={attachment.mimeType} />;\n}\n\nfunction AttachmentName({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n\n return (\n <span className=\"lb-attachment-name\" title={attachment.name}>\n <span className=\"lb-attachment-name-base\">{fileBaseName}</span>\n {fileExtension && (\n <span className=\"lb-attachment-name-extension\">{fileExtension}</span>\n )}\n </span>\n );\n}\n\nfunction useClickOnKeyDown(\n onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void\n) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n // Simulate a click event on Enter or Space because it's a div\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n\n const clickEvent = new MouseEvent(\"click\", {\n bubbles: true,\n cancelable: true,\n view: window,\n });\n event.target.dispatchEvent(clickEvent);\n }\n },\n [onKeyDown]\n );\n\n return handleKeyDown;\n}\n\nfunction useAttachmentContent(\n attachment: CommentMixedAttachment,\n overrides?: Partial<Overrides>\n) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n\n const status =\n attachment.type === \"localAttachment\" ? attachment.status : undefined;\n const isUploading = status === \"uploading\";\n const isError = status === \"error\";\n\n let description: string;\n\n if (attachment.type === \"localAttachment\" && attachment.status === \"error\") {\n if (attachment.error instanceof AttachmentTooLargeError) {\n if (attachment.error.origin === \"server\") {\n description = $.ATTACHMENT_TOO_LARGE();\n } else {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\n }\n } else {\n description = $.ATTACHMENT_ERROR(attachment.error);\n }\n } else {\n description = formatFileSize(attachment.size, $.locale);\n }\n\n const deleteLabel = isInComposer\n ? $.COMPOSER_REMOVE_ATTACHMENT\n : $.COMMENT_DELETE_ATTACHMENT;\n\n return {\n isUploading,\n isError,\n description,\n deleteLabel,\n };\n}\n\nexport function MediaAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-media-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-file-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n\nexport function separateMediaAttachments<T extends CommentMixedAttachment>(\n attachments: T[]\n) {\n const mediaAttachments: T[] = [];\n const fileAttachments: T[] = [];\n\n for (const attachment of attachments) {\n if (\n (attachment.mimeType.startsWith(\"image/\") ||\n attachment.mimeType.startsWith(\"video/\")) &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n mediaAttachments.push(attachment);\n } else {\n fileAttachments.push(attachment);\n }\n }\n\n return {\n mediaAttachments,\n fileAttachments,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Attachment.mjs","sources":["../../../src/components/internal/Attachment.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CommentMixedAttachment } from \"@liveblocks/core\";\nimport { useRoomAttachmentUrl } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n KeyboardEvent,\n MouseEventHandler,\n PointerEvent,\n} from \"react\";\nimport { memo, useCallback, useMemo, useState } from \"react\";\n\nimport { CrossIcon } from \"../../icons/Cross\";\nimport { SpinnerIcon } from \"../../icons/Spinner\";\nimport { WarningIcon } from \"../../icons/Warning\";\nimport type { Overrides } from \"../../overrides\";\nimport { useOverrides } from \"../../overrides\";\nimport { AttachmentTooLargeError } from \"../../primitives\";\nimport { useComposerAttachmentsContextOrNull } from \"../../primitives/Composer/contexts\";\nimport { classNames } from \"../../utils/class-names\";\nimport { formatFileSize } from \"../../utils/format-file-size\";\nimport { Tooltip } from \"./Tooltip\";\n\nconst MAX_DISPLAYED_MEDIA_SIZE = 60 * 1024 * 1024; // 60 MB\n\ninterface AttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n onDeleteClick?: MouseEventHandler<HTMLButtonElement>;\n preventFocusOnDelete?: boolean;\n roomId: string;\n overrides?: Partial<Overrides>;\n allowMediaPreview?: boolean;\n}\n\nconst fileExtensionRegex = /^(.+?)(\\.[^.]+)?$/;\n\nfunction splitFileName(name: string) {\n const match = name.match(fileExtensionRegex);\n\n return { base: match?.[1] ?? name, extension: match?.[2] };\n}\n\nfunction getAttachmentIconGlyph(mimeType: string) {\n if (\n mimeType === \"application/zip\" ||\n mimeType === \"application/gzip\" ||\n mimeType === \"application/vnd.rar\" ||\n mimeType === \"application/x-rar-compressed\" ||\n mimeType === \"application/x-7z-compressed\" ||\n mimeType === \"application/x-zip-compressed\" ||\n mimeType === \"application/x-tar\" ||\n mimeType === \"application/x-bzip\" ||\n mimeType === \"application/x-bzip2\"\n ) {\n return (\n <path d=\"M13 15h2v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1H15v1h-1.5a.5.5 0 0 0 0 1h1a.5.5 0 0 0 .5-.5V20h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 0-1H15v-1h1.5a.5.5 0 0 0 .5-.5V15a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2Z\" />\n );\n }\n\n if (\n mimeType.startsWith(\"text/\") ||\n mimeType.startsWith(\"font/\") ||\n mimeType.startsWith(\"application/\")\n ) {\n return (\n <path d=\"M10 16a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z\" />\n );\n }\n\n if (mimeType.startsWith(\"image/\")) {\n return (\n <path d=\"M12 16h6a1 1 0 0 1 1 1v3l-1.293-1.293a1 1 0 0 0-1.414 0L14.09 20.91l-.464-.386a1 1 0 0 0-1.265-.013l-1.231.985A.995.995 0 0 1 11 21v-4a1 1 0 0 1 1-1Zm-2 1a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-6a2 2 0 0 1-2-2v-4Zm3 2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z\" />\n );\n }\n\n if (mimeType.startsWith(\"video/\")) {\n return (\n <path d=\"M12 15.71a1 1 0 0 1 1.49-.872l4.96 2.79a1 1 0 0 1 0 1.744l-4.96 2.79A1 1 0 0 1 12 21.29v-5.58Z\" />\n );\n }\n\n if (mimeType.startsWith(\"audio/\")) {\n return (\n <path d=\"M15 15a.5.5 0 0 0-.5.5v7a.5.5 0 0 0 1 0v-7a.5.5 0 0 0-.5-.5Zm-2.5 2.5a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3Zm-2 1a.5.5 0 0 1 1 0v1a.5.5 0 0 1-1 0v-1Zm6-1a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0v-3ZM19 16a.5.5 0 0 0-.5.5v5a.5.5 0 0 0 1 0v-5a.5.5 0 0 0-.5-.5Z\" />\n );\n }\n\n return null;\n}\n\nconst AttachmentFileIcon = memo(({ mimeType }: { mimeType: string }) => {\n const iconGlyph = useMemo(() => getAttachmentIconGlyph(mimeType), [mimeType]);\n\n return (\n <svg\n className=\"lb-attachment-icon\"\n width={30}\n height={30}\n viewBox=\"0 0 30 30\"\n fill=\"currentColor\"\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-shadow\"\n />\n <path\n d=\"M6 5a2 2 0 0 1 2-2h5.843a4 4 0 0 1 2.829 1.172l6.156 6.156A4 4 0 0 1 24 13.157V25a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V5Z\"\n className=\"lb-attachment-icon-background\"\n />\n <path\n d=\"M14.382 3.037a4 4 0 0 1 2.29 1.135l6.156 6.157a4 4 0 0 1 1.136 2.289A2 2 0 0 0 22 11h-4a2 2 0 0 1-2-2V5a2 2 0 0 0-1.618-1.963Z\"\n className=\"lb-attachment-icon-fold\"\n />\n\n {iconGlyph && <g className=\"lb-attachment-icon-glyph\">{iconGlyph}</g>}\n </svg>\n );\n});\n\nfunction AttachmentImagePreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <img\n src={url}\n loading=\"lazy\"\n onLoad={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentVideoPreview({\n attachment,\n markPreviewAsUnsupported,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n markPreviewAsUnsupported: () => void;\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n const [isLoaded, setLoaded] = useState(false);\n\n const handleLoad = useCallback(() => {\n setLoaded(true);\n }, []);\n\n return (\n <>\n {!isLoaded ? <SpinnerIcon /> : null}\n {url ? (\n <div\n className=\"lb-attachment-preview-media\"\n data-hidden={!isLoaded ? \"\" : undefined}\n >\n <video\n src={url}\n onLoadedData={handleLoad}\n onError={markPreviewAsUnsupported}\n />\n </div>\n ) : null}\n </>\n );\n}\n\nfunction AttachmentPreview({\n attachment,\n allowMediaPreview = true,\n roomId,\n}: {\n attachment: CommentMixedAttachment;\n allowMediaPreview?: boolean;\n roomId: string;\n}) {\n const [isUnsupportedPreview, setUnsupportedPreview] = useState(false);\n const isUploaded =\n attachment.type === \"attachment\" || attachment.status === \"uploaded\";\n\n function markPreviewAsUnsupported() {\n setUnsupportedPreview(true);\n }\n\n if (\n !isUnsupportedPreview &&\n allowMediaPreview &&\n isUploaded &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n if (attachment.mimeType.startsWith(\"image/\")) {\n return (\n <AttachmentImagePreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n\n if (attachment.mimeType.startsWith(\"video/\")) {\n return (\n <AttachmentVideoPreview\n attachment={attachment}\n markPreviewAsUnsupported={markPreviewAsUnsupported}\n roomId={roomId}\n />\n );\n }\n }\n\n return <AttachmentFileIcon mimeType={attachment.mimeType} />;\n}\n\nfunction AttachmentName({\n attachment,\n}: {\n attachment: CommentMixedAttachment;\n}) {\n const { base: fileBaseName, extension: fileExtension } = useMemo(() => {\n return splitFileName(attachment.name);\n }, [attachment.name]);\n\n return (\n <span className=\"lb-attachment-name\" title={attachment.name}>\n <span className=\"lb-attachment-name-base\">{fileBaseName}</span>\n {fileExtension && (\n <span className=\"lb-attachment-name-extension\">{fileExtension}</span>\n )}\n </span>\n );\n}\n\nfunction useClickOnKeyDown(\n onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void\n) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n // Simulate a click event on Enter or Space because it's a div\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n\n const clickEvent = new MouseEvent(\"click\", {\n bubbles: true,\n cancelable: true,\n view: window,\n });\n event.target.dispatchEvent(clickEvent);\n }\n },\n [onKeyDown]\n );\n\n return handleKeyDown;\n}\n\nfunction useAttachmentContent(\n attachment: CommentMixedAttachment,\n overrides?: Partial<Overrides>\n) {\n const $ = useOverrides(overrides);\n const composerAttachmentsContext = useComposerAttachmentsContextOrNull();\n const isInComposer = Boolean(composerAttachmentsContext);\n const maxAttachmentSize = composerAttachmentsContext?.maxAttachmentSize;\n\n const status =\n attachment.type === \"localAttachment\" ? attachment.status : undefined;\n const isUploading = status === \"uploading\";\n const isError = status === \"error\";\n\n let description: string;\n\n if (attachment.type === \"localAttachment\" && attachment.status === \"error\") {\n if (attachment.error instanceof AttachmentTooLargeError) {\n if (attachment.error.origin === \"server\") {\n description = $.ATTACHMENT_TOO_LARGE();\n } else {\n description = $.ATTACHMENT_TOO_LARGE(\n maxAttachmentSize\n ? formatFileSize(maxAttachmentSize, $.locale)\n : undefined\n );\n }\n } else {\n description = $.ATTACHMENT_ERROR(attachment.error);\n }\n } else {\n description = formatFileSize(attachment.size, $.locale);\n }\n\n const deleteLabel = isInComposer\n ? $.COMPOSER_REMOVE_ATTACHMENT\n : $.COMMENT_DELETE_ATTACHMENT;\n\n return {\n isUploading,\n isError,\n description,\n deleteLabel,\n };\n}\n\nexport function MediaAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-media-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n\nexport function FileAttachment({\n attachment,\n overrides,\n onClick,\n onDeleteClick,\n preventFocusOnDelete,\n allowMediaPreview = true,\n roomId,\n className,\n onKeyDown,\n ...props\n}: AttachmentProps) {\n const { isUploading, isError, description, deleteLabel } =\n useAttachmentContent(attachment, overrides);\n\n const handleDeletePointerDown = useCallback(\n (event: PointerEvent<HTMLButtonElement>) => {\n if (preventFocusOnDelete) {\n event.preventDefault();\n }\n },\n [preventFocusOnDelete]\n );\n\n const handleKeyDown = useClickOnKeyDown(onKeyDown);\n\n return (\n <div\n className={classNames(\"lb-attachment lb-file-attachment\", className)}\n data-error={isError ? \"\" : undefined}\n {...props}\n role={onClick ? \"button\" : undefined}\n onClick={onClick}\n tabIndex={onClick ? 0 : -1}\n onKeyDown={onClick ? handleKeyDown : undefined}\n >\n <div className=\"lb-attachment-preview\">\n {isUploading ? (\n <SpinnerIcon />\n ) : isError ? (\n <WarningIcon />\n ) : (\n <AttachmentPreview\n attachment={attachment}\n allowMediaPreview={allowMediaPreview}\n roomId={roomId}\n />\n )}\n </div>\n <div className=\"lb-attachment-details\">\n <AttachmentName attachment={attachment} />\n <span className=\"lb-attachment-description\" title={description}>\n {description}\n </span>\n </div>\n {onDeleteClick && (\n <Tooltip content={deleteLabel}>\n <button\n type=\"button\"\n className=\"lb-attachment-delete\"\n onClick={onDeleteClick}\n onPointerDown={handleDeletePointerDown}\n aria-label={deleteLabel}\n >\n <CrossIcon />\n </button>\n </Tooltip>\n )}\n </div>\n );\n}\n\nexport function separateMediaAttachments<T extends CommentMixedAttachment>(\n attachments: T[]\n) {\n const mediaAttachments: T[] = [];\n const fileAttachments: T[] = [];\n\n for (const attachment of attachments) {\n if (\n (attachment.mimeType.startsWith(\"image/\") ||\n attachment.mimeType.startsWith(\"video/\")) &&\n attachment.size <= MAX_DISPLAYED_MEDIA_SIZE\n ) {\n mediaAttachments.push(attachment);\n } else {\n fileAttachments.push(attachment);\n }\n }\n\n return {\n mediaAttachments,\n fileAttachments,\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA;AAuBA;AAWA;AAEA;AACE;AAEA;AACF;AAEA;AACE;AAWE;AACG;AAAO;AAAoP;AAIhQ;AAKE;AACG;AAAO;AAAiP;AAI7P;AACE;AACG;AAAO;AAAiQ;AAI7Q;AACE;AACG;AAAO;AAAiG;AAI7G;AACE;AACG;AAAO;AAAyP;AAIrQ;AACF;AAEA;AACE;AAEA;AACG;AACW;AACH;AACC;AACA;AACH;AACI;AACA;AACH;AAEN;AAAC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AACC;AACG;AACQ;AACZ;AAEe;AAAY;AAA4B;AAAU;AAAA;AAGvE;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACG;AACA;AACC;AACX;AAEA;AAAA;AAGV;AAEA;AAAgC;AAC9B;AACA;AAEF;AAKE;AACA;AAEA;AACE;AAAc;AAGhB;AACE;AACG;AAA8B;AAE5B;AACW;AACoB;AAE7B;AACM;AACS;AACL;AACX;AAEA;AAAA;AAGV;AAEA;AAA2B;AACzB;AACoB;AAEtB;AAKE;AACA;AAGA;AACE;AAA0B;AAG5B;AAME;AACE;AACG;AACC;AACA;AACA;AACF;AAIJ;AACE;AACG;AACC;AACA;AACA;AACF;AAEJ;AAGF;AAAQ;AAAwC;AAClD;AAEA;AAAwB;AAExB;AAGE;AACE;AAAoC;AAGtC;AACG;AAAe;AAAuC;AACrD;AAAC;AAAe;AAA2B;AAAa;AAErD;AAAe;AAAgC;AAAc;AAAA;AAItE;AAEA;AAGE;AAAsB;AAElB;AAEA;AACE;AAAA;AAIF;AACE;AAEA;AAA2C;AAChC;AACG;AACN;AAER;AAAqC;AACvC;AACF;AACU;AAGZ;AACF;AAEA;AAIE;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AAEA;AACE;AACE;AACE;AAAqC;AAErC;AAAgB;AAGV;AACN;AACF;AAEA;AAAiD;AACnD;AAEA;AAAsD;AAGxD;AAIA;AAAO;AACL;AACA;AACA;AACA;AAEJ;AAEO;AAAyB;AAC9B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AACqE;AACzC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAAwB;AAC7B;AACA;AACA;AACA;AACA;AACoB;AACpB;AACA;AACA;AAEF;AACE;AAGA;AAAgC;AAE5B;AACE;AAAqB;AACvB;AACF;AACqB;AAGvB;AAEA;AACG;AACoE;AACxC;AACvB;AACuB;AAC3B;AACwB;AACa;AAErC;AAAC;AAAc;AAMV;AACC;AACA;AACA;AACF;AAEJ;AACC;AAAc;AACb;AAAC;AAAe;AAAwB;AACvC;AAAe;AAAmC;AAChD;AACH;AAAA;AACF;AAEG;AAAiB;AACf;AACM;AACK;AACD;AACM;AACH;AAED;AACb;AACF;AAAA;AAIR;AAEO;AAGL;AACA;AAEA;AACE;AAKE;AAAgC;AAEhC;AAA+B;AACjC;AAGF;AAAO;AACL;AACA;AAEJ;;"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
'use strict';
|
|
2
3
|
|
|
3
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -6,6 +7,7 @@ var react$1 = require('react');
|
|
|
6
7
|
var classNames = require('../../utils/class-names.js');
|
|
7
8
|
var getInitials = require('../../utils/get-initials.js');
|
|
8
9
|
|
|
10
|
+
|
|
9
11
|
function Avatar({ userId, className, ...props }) {
|
|
10
12
|
const { user, isLoading } = react.useUser(userId);
|
|
11
13
|
const resolvedUserName = react$1.useMemo(() => user?.name, [user]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Avatar.js","sources":["../../../src/components/internal/Avatar.tsx"],"sourcesContent":["\"use client\";\n\nimport { useUser } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\nimport { getInitials } from \"../../utils/get-initials\";\n\nexport interface AvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nexport function Avatar({ userId, className, ...props }: AvatarProps) {\n const { user, isLoading } = useUser(userId);\n const resolvedUserName = useMemo(() => user?.name, [user]);\n const resolvedUserAvatar = useMemo(() => user?.avatar, [user]);\n const resolvedUserInitials = useMemo(\n () => (resolvedUserName ? getInitials(resolvedUserName) : undefined),\n [resolvedUserName]\n );\n const resolvedUserIdInitials = useMemo(\n () => (!isLoading && !user ? getInitials(userId) : undefined),\n [isLoading, user, userId]\n );\n\n return (\n <div\n className={classNames(\"lb-avatar\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {resolvedUserAvatar && (\n <img\n className=\"lb-avatar-image\"\n src={resolvedUserAvatar}\n alt={resolvedUserName}\n />\n )}\n {resolvedUserInitials ? (\n <span className=\"lb-avatar-fallback\" aria-hidden>\n {resolvedUserInitials}\n </span>\n ) : resolvedUserIdInitials ? (\n <span className=\"lb-avatar-fallback\" aria-label={userId} title={userId}>\n {resolvedUserIdInitials}\n </span>\n ) : null}\n </div>\n );\n}\n"],"names":[
|
|
1
|
+
{"version":3,"file":"Avatar.js","sources":["../../../src/components/internal/Avatar.tsx"],"sourcesContent":["\"use client\";\n\nimport { useUser } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\nimport { getInitials } from \"../../utils/get-initials\";\n\nexport interface AvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nexport function Avatar({ userId, className, ...props }: AvatarProps) {\n const { user, isLoading } = useUser(userId);\n const resolvedUserName = useMemo(() => user?.name, [user]);\n const resolvedUserAvatar = useMemo(() => user?.avatar, [user]);\n const resolvedUserInitials = useMemo(\n () => (resolvedUserName ? getInitials(resolvedUserName) : undefined),\n [resolvedUserName]\n );\n const resolvedUserIdInitials = useMemo(\n () => (!isLoading && !user ? getInitials(userId) : undefined),\n [isLoading, user, userId]\n );\n\n return (\n <div\n className={classNames(\"lb-avatar\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {resolvedUserAvatar && (\n <img\n className=\"lb-avatar-image\"\n src={resolvedUserAvatar}\n alt={resolvedUserName}\n />\n )}\n {resolvedUserInitials ? (\n <span className=\"lb-avatar-fallback\" aria-hidden>\n {resolvedUserInitials}\n </span>\n ) : resolvedUserIdInitials ? (\n <span className=\"lb-avatar-fallback\" aria-label={userId} title={userId}>\n {resolvedUserIdInitials}\n </span>\n ) : null}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAAA;AAgBO;AACL;AACA;AACA;AACA;AAA6B;AAC+B;AACzC;AAEnB;AAA+B;AACsB;AAC3B;AAG1B;AACG;AAC6C;AACb;AAC3B;AAEH;AACE;AACW;AACL;AACA;AACP;AAGC;AAAe;AAAgC;AAC7C;AAGF;AAAe;AAAiC;AAAe;AAC7D;AAED;AAAA;AAGV;;"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
3
|
import { useUser } from '@liveblocks/react';
|
|
3
4
|
import { useMemo } from 'react';
|
|
4
5
|
import { classNames } from '../../utils/class-names.mjs';
|
|
5
6
|
import { getInitials } from '../../utils/get-initials.mjs';
|
|
6
7
|
|
|
8
|
+
|
|
7
9
|
function Avatar({ userId, className, ...props }) {
|
|
8
10
|
const { user, isLoading } = useUser(userId);
|
|
9
11
|
const resolvedUserName = useMemo(() => user?.name, [user]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Avatar.mjs","sources":["../../../src/components/internal/Avatar.tsx"],"sourcesContent":["\"use client\";\n\nimport { useUser } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\nimport { getInitials } from \"../../utils/get-initials\";\n\nexport interface AvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nexport function Avatar({ userId, className, ...props }: AvatarProps) {\n const { user, isLoading } = useUser(userId);\n const resolvedUserName = useMemo(() => user?.name, [user]);\n const resolvedUserAvatar = useMemo(() => user?.avatar, [user]);\n const resolvedUserInitials = useMemo(\n () => (resolvedUserName ? getInitials(resolvedUserName) : undefined),\n [resolvedUserName]\n );\n const resolvedUserIdInitials = useMemo(\n () => (!isLoading && !user ? getInitials(userId) : undefined),\n [isLoading, user, userId]\n );\n\n return (\n <div\n className={classNames(\"lb-avatar\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {resolvedUserAvatar && (\n <img\n className=\"lb-avatar-image\"\n src={resolvedUserAvatar}\n alt={resolvedUserName}\n />\n )}\n {resolvedUserInitials ? (\n <span className=\"lb-avatar-fallback\" aria-hidden>\n {resolvedUserInitials}\n </span>\n ) : resolvedUserIdInitials ? (\n <span className=\"lb-avatar-fallback\" aria-label={userId} title={userId}>\n {resolvedUserIdInitials}\n </span>\n ) : null}\n </div>\n );\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Avatar.mjs","sources":["../../../src/components/internal/Avatar.tsx"],"sourcesContent":["\"use client\";\n\nimport { useUser } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\nimport { getInitials } from \"../../utils/get-initials\";\n\nexport interface AvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nexport function Avatar({ userId, className, ...props }: AvatarProps) {\n const { user, isLoading } = useUser(userId);\n const resolvedUserName = useMemo(() => user?.name, [user]);\n const resolvedUserAvatar = useMemo(() => user?.avatar, [user]);\n const resolvedUserInitials = useMemo(\n () => (resolvedUserName ? getInitials(resolvedUserName) : undefined),\n [resolvedUserName]\n );\n const resolvedUserIdInitials = useMemo(\n () => (!isLoading && !user ? getInitials(userId) : undefined),\n [isLoading, user, userId]\n );\n\n return (\n <div\n className={classNames(\"lb-avatar\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {resolvedUserAvatar && (\n <img\n className=\"lb-avatar-image\"\n src={resolvedUserAvatar}\n alt={resolvedUserName}\n />\n )}\n {resolvedUserInitials ? (\n <span className=\"lb-avatar-fallback\" aria-hidden>\n {resolvedUserInitials}\n </span>\n ) : resolvedUserIdInitials ? (\n <span className=\"lb-avatar-fallback\" aria-label={userId} title={userId}>\n {resolvedUserIdInitials}\n </span>\n ) : null}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;;AAAA;AAgBO;AACL;AACA;AACA;AACA;AAA6B;AAC+B;AACzC;AAEnB;AAA+B;AACsB;AAC3B;AAG1B;AACG;AAC6C;AACb;AAC3B;AAEH;AACE;AACW;AACL;AACA;AACP;AAGC;AAAe;AAAgC;AAC7C;AAGF;AAAe;AAAiC;AAAe;AAC7D;AAED;AAAA;AAGV;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.js","sources":["../../../src/components/internal/Button.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface ButtonProps extends ComponentProps<\"button\"> {\n variant?: \"default\" | \"outline\" | \"toggle\" | \"primary\";\n size?: \"default\" | \"large\";\n disableable?: boolean;\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = \"default\",\n size = \"default\",\n disableable = true,\n className,\n ...props\n },\n forwardedRef\n ) => {\n return (\n <button\n type=\"button\"\n className={classNames(\n \"lb-button\",\n !disableable && \"lb-button:non-disableable\",\n className\n )}\n data-variant={variant}\n data-size={size}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n);\n"],"names":[
|
|
1
|
+
{"version":3,"file":"Button.js","sources":["../../../src/components/internal/Button.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface ButtonProps extends ComponentProps<\"button\"> {\n variant?: \"default\" | \"outline\" | \"toggle\" | \"primary\";\n size?: \"default\" | \"large\";\n disableable?: boolean;\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = \"default\",\n size = \"default\",\n disableable = true,\n className,\n ...props\n },\n forwardedRef\n ) => {\n return (\n <button\n type=\"button\"\n className={classNames(\n \"lb-button\",\n !disableable && \"lb-button:non-disableable\",\n className\n )}\n data-variant={variant}\n data-size={size}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;AAAA;AAaO;AAAe;AAElB;AACY;AACH;AACO;AACd;AACG;AAIL;AACG;AACM;AACM;AACT;AACgB;AAChB;AACF;AACc;AACH;AACP;AACC;AACP;AAGN;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.mjs","sources":["../../../src/components/internal/Button.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface ButtonProps extends ComponentProps<\"button\"> {\n variant?: \"default\" | \"outline\" | \"toggle\" | \"primary\";\n size?: \"default\" | \"large\";\n disableable?: boolean;\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = \"default\",\n size = \"default\",\n disableable = true,\n className,\n ...props\n },\n forwardedRef\n ) => {\n return (\n <button\n type=\"button\"\n className={classNames(\n \"lb-button\",\n !disableable && \"lb-button:non-disableable\",\n className\n )}\n data-variant={variant}\n data-size={size}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n);\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Button.mjs","sources":["../../../src/components/internal/Button.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface ButtonProps extends ComponentProps<\"button\"> {\n variant?: \"default\" | \"outline\" | \"toggle\" | \"primary\";\n size?: \"default\" | \"large\";\n disableable?: boolean;\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n variant = \"default\",\n size = \"default\",\n disableable = true,\n className,\n ...props\n },\n forwardedRef\n ) => {\n return (\n <button\n type=\"button\"\n className={classNames(\n \"lb-button\",\n !disableable && \"lb-button:non-disableable\",\n className\n )}\n data-variant={variant}\n data-size={size}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n);\n"],"names":[],"mappings":";;;;;AAAA;AAaO;AAAe;AAElB;AACY;AACH;AACO;AACd;AACG;AAIL;AACG;AACM;AACM;AACT;AACgB;AAChB;AACF;AACc;AACH;AACP;AACC;AACP;AAGN;;"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
'use strict';
|
|
2
3
|
|
|
3
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -27,6 +28,7 @@ function _interopNamespaceDefault(e) {
|
|
|
27
28
|
|
|
28
29
|
var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(DropdownMenuPrimitive);
|
|
29
30
|
|
|
31
|
+
|
|
30
32
|
function Dropdown({
|
|
31
33
|
children,
|
|
32
34
|
content,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.js","sources":["../../../src/components/internal/Dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport type { ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useLiveblocksUIConfig } from \"../../config\";\nimport {\n FLOATING_ELEMENT_COLLISION_PADDING,\n FLOATING_ELEMENT_SIDE_OFFSET,\n} from \"../../constants\";\nimport { useOverrides } from \"../../overrides\";\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface DropdownProps\n extends Pick<\n DropdownMenuPrimitive.DropdownMenuProps,\n \"defaultOpen\" | \"open\" | \"onOpenChange\"\n >,\n Pick<DropdownMenuPrimitive.DropdownMenuTriggerProps, \"children\">,\n Omit<DropdownMenuPrimitive.DropdownMenuContentProps, \"content\"> {\n content: ReactNode;\n}\n\nexport function Dropdown({\n children,\n content,\n defaultOpen,\n open,\n onOpenChange,\n className,\n ...props\n}: DropdownProps) {\n const $ = useOverrides();\n const { portalContainer } = useLiveblocksUIConfig();\n\n return (\n <DropdownMenuPrimitive.Root\n defaultOpen={defaultOpen}\n open={open}\n onOpenChange={onOpenChange}\n dir={$.dir}\n >\n {children}\n <DropdownMenuPrimitive.Portal container={portalContainer}>\n <DropdownMenuPrimitive.Content\n className={classNames(\n \"lb-root lb-portal lb-elevation lb-dropdown\",\n className\n )}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n {...props}\n >\n {content}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </DropdownMenuPrimitive.Root>\n );\n}\n\nexport const DropdownItem = forwardRef<\n HTMLDivElement,\n DropdownMenuPrimitive.DropdownMenuItemProps\n>(({ children, className, ...props }, forwardedRef) => {\n return (\n <DropdownMenuPrimitive.DropdownMenuItem\n className={classNames(\"lb-dropdown-item\", className)}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </DropdownMenuPrimitive.DropdownMenuItem>\n );\n});\n\nexport { DropdownMenuTrigger as DropdownTrigger } from \"@radix-ui/react-dropdown-menu\";\n"],"names":[
|
|
1
|
+
{"version":3,"file":"Dropdown.js","sources":["../../../src/components/internal/Dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport type { ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useLiveblocksUIConfig } from \"../../config\";\nimport {\n FLOATING_ELEMENT_COLLISION_PADDING,\n FLOATING_ELEMENT_SIDE_OFFSET,\n} from \"../../constants\";\nimport { useOverrides } from \"../../overrides\";\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface DropdownProps\n extends Pick<\n DropdownMenuPrimitive.DropdownMenuProps,\n \"defaultOpen\" | \"open\" | \"onOpenChange\"\n >,\n Pick<DropdownMenuPrimitive.DropdownMenuTriggerProps, \"children\">,\n Omit<DropdownMenuPrimitive.DropdownMenuContentProps, \"content\"> {\n content: ReactNode;\n}\n\nexport function Dropdown({\n children,\n content,\n defaultOpen,\n open,\n onOpenChange,\n className,\n ...props\n}: DropdownProps) {\n const $ = useOverrides();\n const { portalContainer } = useLiveblocksUIConfig();\n\n return (\n <DropdownMenuPrimitive.Root\n defaultOpen={defaultOpen}\n open={open}\n onOpenChange={onOpenChange}\n dir={$.dir}\n >\n {children}\n <DropdownMenuPrimitive.Portal container={portalContainer}>\n <DropdownMenuPrimitive.Content\n className={classNames(\n \"lb-root lb-portal lb-elevation lb-dropdown\",\n className\n )}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n {...props}\n >\n {content}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </DropdownMenuPrimitive.Root>\n );\n}\n\nexport const DropdownItem = forwardRef<\n HTMLDivElement,\n DropdownMenuPrimitive.DropdownMenuItemProps\n>(({ children, className, ...props }, forwardedRef) => {\n return (\n <DropdownMenuPrimitive.DropdownMenuItem\n className={classNames(\"lb-dropdown-item\", className)}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </DropdownMenuPrimitive.DropdownMenuItem>\n );\n});\n\nexport { DropdownMenuTrigger as DropdownTrigger } from \"@radix-ui/react-dropdown-menu\";\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAwBO;AAAkB;AACvB;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AAEA;AACG;AACC;AACA;AACA;AACO;AAEN;AAAA;AACA;AAAwC;AACtC;AACY;AACT;AACA;AACF;AACY;AACM;AACd;AAEH;AACH;AACF;AAAA;AAGN;AAEa;AAIX;AACG;AACoD;AAC/C;AACC;AAEJ;AAGP;;;;;;;"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
3
|
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
3
4
|
export { DropdownMenuTrigger as DropdownTrigger } from '@radix-ui/react-dropdown-menu';
|
|
4
5
|
import { forwardRef } from 'react';
|
|
@@ -7,6 +8,7 @@ import { FLOATING_ELEMENT_SIDE_OFFSET, FLOATING_ELEMENT_COLLISION_PADDING } from
|
|
|
7
8
|
import { useOverrides } from '../../overrides.mjs';
|
|
8
9
|
import { classNames } from '../../utils/class-names.mjs';
|
|
9
10
|
|
|
11
|
+
|
|
10
12
|
function Dropdown({
|
|
11
13
|
children,
|
|
12
14
|
content,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dropdown.mjs","sources":["../../../src/components/internal/Dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport type { ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useLiveblocksUIConfig } from \"../../config\";\nimport {\n FLOATING_ELEMENT_COLLISION_PADDING,\n FLOATING_ELEMENT_SIDE_OFFSET,\n} from \"../../constants\";\nimport { useOverrides } from \"../../overrides\";\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface DropdownProps\n extends Pick<\n DropdownMenuPrimitive.DropdownMenuProps,\n \"defaultOpen\" | \"open\" | \"onOpenChange\"\n >,\n Pick<DropdownMenuPrimitive.DropdownMenuTriggerProps, \"children\">,\n Omit<DropdownMenuPrimitive.DropdownMenuContentProps, \"content\"> {\n content: ReactNode;\n}\n\nexport function Dropdown({\n children,\n content,\n defaultOpen,\n open,\n onOpenChange,\n className,\n ...props\n}: DropdownProps) {\n const $ = useOverrides();\n const { portalContainer } = useLiveblocksUIConfig();\n\n return (\n <DropdownMenuPrimitive.Root\n defaultOpen={defaultOpen}\n open={open}\n onOpenChange={onOpenChange}\n dir={$.dir}\n >\n {children}\n <DropdownMenuPrimitive.Portal container={portalContainer}>\n <DropdownMenuPrimitive.Content\n className={classNames(\n \"lb-root lb-portal lb-elevation lb-dropdown\",\n className\n )}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n {...props}\n >\n {content}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </DropdownMenuPrimitive.Root>\n );\n}\n\nexport const DropdownItem = forwardRef<\n HTMLDivElement,\n DropdownMenuPrimitive.DropdownMenuItemProps\n>(({ children, className, ...props }, forwardedRef) => {\n return (\n <DropdownMenuPrimitive.DropdownMenuItem\n className={classNames(\"lb-dropdown-item\", className)}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </DropdownMenuPrimitive.DropdownMenuItem>\n );\n});\n\nexport { DropdownMenuTrigger as DropdownTrigger } from \"@radix-ui/react-dropdown-menu\";\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Dropdown.mjs","sources":["../../../src/components/internal/Dropdown.tsx"],"sourcesContent":["\"use client\";\n\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport type { ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useLiveblocksUIConfig } from \"../../config\";\nimport {\n FLOATING_ELEMENT_COLLISION_PADDING,\n FLOATING_ELEMENT_SIDE_OFFSET,\n} from \"../../constants\";\nimport { useOverrides } from \"../../overrides\";\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface DropdownProps\n extends Pick<\n DropdownMenuPrimitive.DropdownMenuProps,\n \"defaultOpen\" | \"open\" | \"onOpenChange\"\n >,\n Pick<DropdownMenuPrimitive.DropdownMenuTriggerProps, \"children\">,\n Omit<DropdownMenuPrimitive.DropdownMenuContentProps, \"content\"> {\n content: ReactNode;\n}\n\nexport function Dropdown({\n children,\n content,\n defaultOpen,\n open,\n onOpenChange,\n className,\n ...props\n}: DropdownProps) {\n const $ = useOverrides();\n const { portalContainer } = useLiveblocksUIConfig();\n\n return (\n <DropdownMenuPrimitive.Root\n defaultOpen={defaultOpen}\n open={open}\n onOpenChange={onOpenChange}\n dir={$.dir}\n >\n {children}\n <DropdownMenuPrimitive.Portal container={portalContainer}>\n <DropdownMenuPrimitive.Content\n className={classNames(\n \"lb-root lb-portal lb-elevation lb-dropdown\",\n className\n )}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n {...props}\n >\n {content}\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n </DropdownMenuPrimitive.Root>\n );\n}\n\nexport const DropdownItem = forwardRef<\n HTMLDivElement,\n DropdownMenuPrimitive.DropdownMenuItemProps\n>(({ children, className, ...props }, forwardedRef) => {\n return (\n <DropdownMenuPrimitive.DropdownMenuItem\n className={classNames(\"lb-dropdown-item\", className)}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </DropdownMenuPrimitive.DropdownMenuItem>\n );\n});\n\nexport { DropdownMenuTrigger as DropdownTrigger } from \"@radix-ui/react-dropdown-menu\";\n"],"names":[],"mappings":";;;;;;;;;;AAAA;AAwBO;AAAkB;AACvB;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AAEA;AACG;AACC;AACA;AACA;AACO;AAEN;AAAA;AACA;AAAwC;AACtC;AACY;AACT;AACA;AACF;AACY;AACM;AACd;AAEH;AACH;AACF;AAAA;AAGN;AAEa;AAIX;AACG;AACoD;AAC/C;AACC;AAEJ;AAGP;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
3
3
|
export { PopoverTrigger as EmojiPickerTrigger } from '@radix-ui/react-popover';
|
|
4
|
-
import { forwardRef, useState, useCallback
|
|
4
|
+
import { useMemo, forwardRef, useState, useCallback } from 'react';
|
|
5
5
|
import { useLiveblocksUIConfig } from '../../config.mjs';
|
|
6
6
|
import { FLOATING_ELEMENT_SIDE_OFFSET, FLOATING_ELEMENT_COLLISION_PADDING } from '../../constants.mjs';
|
|
7
7
|
import { SearchIcon } from '../../icons/Search.mjs';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
'use strict';
|
|
2
3
|
|
|
3
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -5,6 +6,7 @@ var react = require('@liveblocks/react');
|
|
|
5
6
|
var react$1 = require('react');
|
|
6
7
|
var classNames = require('../../utils/class-names.js');
|
|
7
8
|
|
|
9
|
+
|
|
8
10
|
function Room({ roomId, className, ...props }) {
|
|
9
11
|
const { info, isLoading } = react.useRoomInfo(roomId);
|
|
10
12
|
const resolvedRoomName = react$1.useMemo(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Room.js","sources":["../../../src/components/internal/Room.tsx"],"sourcesContent":["\"use client\";\n\nimport { useRoomInfo } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface RoomProps extends ComponentProps<\"span\"> {\n roomId: string;\n}\n\nexport function Room({ roomId, className, ...props }: RoomProps) {\n const { info, isLoading } = useRoomInfo(roomId);\n const resolvedRoomName = useMemo(() => {\n return info?.name ?? roomId;\n }, [info?.name, roomId]);\n\n return (\n <span\n className={classNames(\"lb-name lb-room\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {isLoading ? null : resolvedRoomName}\n </span>\n );\n}\n"],"names":[
|
|
1
|
+
{"version":3,"file":"Room.js","sources":["../../../src/components/internal/Room.tsx"],"sourcesContent":["\"use client\";\n\nimport { useRoomInfo } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { classNames } from \"../../utils/class-names\";\n\nexport interface RoomProps extends ComponentProps<\"span\"> {\n roomId: string;\n}\n\nexport function Room({ roomId, className, ...props }: RoomProps) {\n const { info, isLoading } = useRoomInfo(roomId);\n const resolvedRoomName = useMemo(() => {\n return info?.name ?? roomId;\n }, [info?.name, roomId]);\n\n return (\n <span\n className={classNames(\"lb-name lb-room\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {isLoading ? null : resolvedRoomName}\n </span>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AAAA;AAYO;AACL;AACA;AACE;AAAqB;AAGvB;AACG;AACmD;AACnB;AAC3B;AAEgB;AAG1B;;"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx } from 'react/jsx-runtime';
|
|
2
3
|
import { useRoomInfo } from '@liveblocks/react';
|
|
3
4
|
import { useMemo } from 'react';
|
|
4
5
|
import { classNames } from '../../utils/class-names.mjs';
|
|
5
6
|
|
|
7
|
+
|
|
6
8
|
function Room({ roomId, className, ...props }) {
|
|
7
9
|
const { info, isLoading } = useRoomInfo(roomId);
|
|
8
10
|
const resolvedRoomName = useMemo(() => {
|