@liveblocks/react-ui 3.6.2 → 3.7.0
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.cjs +8 -0
- package/dist/_private/index.cjs.map +1 -1
- package/dist/_private/index.d.cts +34 -7
- package/dist/_private/index.d.ts +34 -7
- package/dist/_private/index.js +4 -0
- package/dist/_private/index.js.map +1 -1
- package/dist/components/Comment.cjs +51 -17
- package/dist/components/Comment.cjs.map +1 -1
- package/dist/components/Comment.js +52 -18
- package/dist/components/Comment.js.map +1 -1
- package/dist/components/Composer.cjs +77 -31
- package/dist/components/Composer.cjs.map +1 -1
- package/dist/components/Composer.js +79 -34
- package/dist/components/Composer.js.map +1 -1
- package/dist/components/InboxNotification.cjs +11 -12
- package/dist/components/InboxNotification.cjs.map +1 -1
- package/dist/components/InboxNotification.js +13 -14
- package/dist/components/InboxNotification.js.map +1 -1
- package/dist/components/internal/Avatar.cjs +41 -21
- package/dist/components/internal/Avatar.cjs.map +1 -1
- package/dist/components/internal/Avatar.js +40 -20
- package/dist/components/internal/Avatar.js.map +1 -1
- package/dist/components/internal/Group.cjs +23 -0
- package/dist/components/internal/Group.cjs.map +1 -0
- package/dist/components/internal/Group.js +21 -0
- package/dist/components/internal/Group.js.map +1 -0
- package/dist/components/internal/GroupDescription.cjs +23 -0
- package/dist/components/internal/GroupDescription.cjs.map +1 -0
- package/dist/components/internal/GroupDescription.js +21 -0
- package/dist/components/internal/GroupDescription.js.map +1 -0
- package/dist/components/internal/InboxNotificationThread.cjs +19 -8
- package/dist/components/internal/InboxNotificationThread.cjs.map +1 -1
- package/dist/components/internal/InboxNotificationThread.js +20 -9
- package/dist/components/internal/InboxNotificationThread.js.map +1 -1
- package/dist/components/internal/User.cjs +12 -3
- package/dist/components/internal/User.cjs.map +1 -1
- package/dist/components/internal/User.js +13 -4
- package/dist/components/internal/User.js.map +1 -1
- package/dist/constants.cjs +0 -2
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.js +1 -2
- package/dist/constants.js.map +1 -1
- package/dist/icon.cjs +4 -0
- package/dist/icon.cjs.map +1 -1
- package/dist/icon.js +2 -0
- package/dist/icon.js.map +1 -1
- package/dist/icons/User.cjs +16 -0
- package/dist/icons/User.cjs.map +1 -0
- package/dist/icons/User.js +14 -0
- package/dist/icons/User.js.map +1 -0
- package/dist/icons/Users.cjs +16 -0
- package/dist/icons/Users.cjs.map +1 -0
- package/dist/icons/Users.js +14 -0
- package/dist/icons/Users.js.map +1 -0
- package/dist/icons/index.cjs +4 -0
- package/dist/icons/index.cjs.map +1 -1
- package/dist/icons/index.js +2 -0
- package/dist/icons/index.js.map +1 -1
- package/dist/index.d.cts +12 -8
- package/dist/index.d.ts +12 -8
- package/dist/primitives/Comment/index.cjs +1 -2
- package/dist/primitives/Comment/index.cjs.map +1 -1
- package/dist/primitives/Comment/index.js +1 -2
- package/dist/primitives/Comment/index.js.map +1 -1
- package/dist/primitives/Composer/index.cjs +1 -2
- package/dist/primitives/Composer/index.cjs.map +1 -1
- package/dist/primitives/Composer/index.js +1 -2
- package/dist/primitives/Composer/index.js.map +1 -1
- package/dist/primitives/Composer/slate/plugins/mentions.cjs +5 -5
- package/dist/primitives/Composer/slate/plugins/mentions.cjs.map +1 -1
- package/dist/primitives/Composer/slate/plugins/mentions.js +1 -1
- package/dist/primitives/Composer/slate/plugins/mentions.js.map +1 -1
- package/dist/utils/use-group-mention.cjs +30 -0
- package/dist/utils/use-group-mention.cjs.map +1 -0
- package/dist/utils/use-group-mention.js +28 -0
- package/dist/utils/use-group-mention.js.map +1 -0
- package/dist/utils/use-user-or-group-info.cjs +49 -0
- package/dist/utils/use-user-or-group-info.cjs.map +1 -0
- package/dist/utils/use-user-or-group-info.js +46 -0
- package/dist/utils/use-user-or-group-info.js.map +1 -0
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
- package/src/styles/index.css +60 -35
- package/styles.css +1 -1
- package/styles.css.map +1 -1
package/dist/_private/index.cjs
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var Avatar = require('../components/internal/Avatar.cjs');
|
|
4
4
|
var Button = require('../components/internal/Button.cjs');
|
|
5
|
+
var Group = require('../components/internal/Group.cjs');
|
|
6
|
+
var GroupDescription = require('../components/internal/GroupDescription.cjs');
|
|
5
7
|
var List = require('../components/internal/List.cjs');
|
|
6
8
|
var Prose = require('../components/internal/Prose.cjs');
|
|
7
9
|
var Tooltip = require('../components/internal/Tooltip.cjs');
|
|
@@ -68,6 +70,8 @@ var Text = require('../icons/Text.cjs');
|
|
|
68
70
|
var Translate = require('../icons/Translate.cjs');
|
|
69
71
|
var Underline = require('../icons/Underline.cjs');
|
|
70
72
|
var Undo = require('../icons/Undo.cjs');
|
|
73
|
+
var User$1 = require('../icons/User.cjs');
|
|
74
|
+
var Users = require('../icons/Users.cjs');
|
|
71
75
|
var Warning = require('../icons/Warning.cjs');
|
|
72
76
|
|
|
73
77
|
|
|
@@ -75,6 +79,8 @@ var Warning = require('../icons/Warning.cjs');
|
|
|
75
79
|
exports.Avatar = Avatar.Avatar;
|
|
76
80
|
exports.Button = Button.Button;
|
|
77
81
|
exports.SelectButton = Button.SelectButton;
|
|
82
|
+
exports.Group = Group.Group;
|
|
83
|
+
exports.GroupDescription = GroupDescription.GroupDescription;
|
|
78
84
|
exports.List = List.List;
|
|
79
85
|
exports.Prose = Prose.Prose;
|
|
80
86
|
exports.ShortcutTooltip = Tooltip.ShortcutTooltip;
|
|
@@ -144,5 +150,7 @@ exports.TextIcon = Text.TextIcon;
|
|
|
144
150
|
exports.TranslateIcon = Translate.TranslateIcon;
|
|
145
151
|
exports.UnderlineIcon = Underline.UnderlineIcon;
|
|
146
152
|
exports.UndoIcon = Undo.UndoIcon;
|
|
153
|
+
exports.UserIcon = User$1.UserIcon;
|
|
154
|
+
exports.UsersIcon = Users.UsersIcon;
|
|
147
155
|
exports.WarningIcon = Warning.WarningIcon;
|
|
148
156
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import * as react from 'react';
|
|
3
|
-
import { ComponentProps, ReactNode, ElementType, ComponentPropsWithoutRef, ComponentType, Ref, RefCallback, FormEvent } from 'react';
|
|
4
2
|
import { Relax, AiTextPart, AiReasoningPart, AiChatMessage } from '@liveblocks/core';
|
|
3
|
+
import * as react from 'react';
|
|
4
|
+
import { ComponentProps, ReactNode, ComponentPropsWithoutRef, ElementType, ComponentType, Ref, RefCallback, FormEvent } from 'react';
|
|
5
5
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
6
6
|
export { TooltipProvider } from '@radix-ui/react-tooltip';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
type AvatarProps = ComponentProps<"div"> & {
|
|
9
|
+
icon?: ReactNode;
|
|
10
|
+
} & Relax<{
|
|
9
11
|
/**
|
|
10
12
|
* The user ID to display the avatar for.
|
|
11
13
|
*/
|
|
12
14
|
userId: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
+
} | {
|
|
16
|
+
/**
|
|
17
|
+
* The group ID to display the avatar for.
|
|
18
|
+
*/
|
|
19
|
+
groupId: string;
|
|
20
|
+
}>;
|
|
21
|
+
declare function Avatar({ userId, groupId, icon, ...props }: AvatarProps): react_jsx_runtime.JSX.Element;
|
|
15
22
|
|
|
16
23
|
interface ButtonProps extends ComponentProps<"button"> {
|
|
17
24
|
variant?: "default" | "toolbar" | "outline" | "ghost" | "primary" | "secondary" | "destructive";
|
|
@@ -22,6 +29,22 @@ interface ButtonProps extends ComponentProps<"button"> {
|
|
|
22
29
|
declare const Button: react.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
23
30
|
declare const SelectButton: react.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
24
31
|
|
|
32
|
+
interface GroupProps extends ComponentProps<"span"> {
|
|
33
|
+
/**
|
|
34
|
+
* The group ID to display the group name for.
|
|
35
|
+
*/
|
|
36
|
+
groupId: string;
|
|
37
|
+
}
|
|
38
|
+
declare function Group({ groupId, className, children, ...props }: GroupProps): react_jsx_runtime.JSX.Element;
|
|
39
|
+
|
|
40
|
+
interface GroupDescriptionProps extends ComponentPropsWithoutRef<"span"> {
|
|
41
|
+
/**
|
|
42
|
+
* The group ID to display the group description for.
|
|
43
|
+
*/
|
|
44
|
+
groupId: string;
|
|
45
|
+
}
|
|
46
|
+
declare function GroupDescription({ groupId, className, ...props }: GroupDescriptionProps): react_jsx_runtime.JSX.Element | null;
|
|
47
|
+
|
|
25
48
|
type Direction = "ltr" | "rtl";
|
|
26
49
|
type SlotProp = {
|
|
27
50
|
/**
|
|
@@ -342,7 +365,7 @@ interface UserProps extends ComponentProps<"span"> {
|
|
|
342
365
|
*/
|
|
343
366
|
replaceSelf?: boolean;
|
|
344
367
|
}
|
|
345
|
-
declare function User({ userId, replaceSelf, className, ...props }: UserProps): react_jsx_runtime.JSX.Element;
|
|
368
|
+
declare function User({ userId, replaceSelf, className, children, ...props }: UserProps): react_jsx_runtime.JSX.Element;
|
|
346
369
|
|
|
347
370
|
declare function ArrowCornerDownRightIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
|
|
348
371
|
|
|
@@ -446,6 +469,10 @@ declare function UnderlineIcon(props: ComponentProps<"svg">): react_jsx_runtime.
|
|
|
446
469
|
|
|
447
470
|
declare function UndoIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
|
|
448
471
|
|
|
472
|
+
declare function UserIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
|
|
473
|
+
|
|
474
|
+
declare function UsersIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
|
|
475
|
+
|
|
449
476
|
declare function WarningIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
|
|
450
477
|
|
|
451
478
|
declare function capitalize(string: string): string;
|
|
@@ -675,4 +702,4 @@ declare namespace index {
|
|
|
675
702
|
};
|
|
676
703
|
}
|
|
677
704
|
|
|
678
|
-
export { index$2 as AiComposer, AiComposerEditorProps, AiComposerFormProps, AiComposerSubmitProps, index$1 as AiMessage, AiMessageContentComponents, AiMessageContentProps, AiMessageContentReasoningPartProps, AiMessageContentTextPartProps, ArrowCornerDownRightIcon, ArrowCornerUpRightIcon, ArrowDownIcon, ArrowUpIcon, AttachmentIcon, Avatar, BellCrossedIcon, BellIcon, BlockquoteIcon, BoldIcon, Button, CheckCircleFillIcon, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, CodeIcon, index as Collapsible, CommentIcon, CopyIcon, CrossCircleFillIcon, CrossIcon, DeleteIcon, EditIcon, EllipsisIcon, EmojiIcon, EmojiPlusIcon, H1Icon, H2Icon, H3Icon, ItalicIcon, LengthenIcon, List, ListOrderedIcon, ListUnorderedIcon, Markdown, MarkdownComponents, MarkdownComponentsBlockquoteProps, MarkdownComponentsCodeBlockProps, MarkdownComponentsHeadingProps, MarkdownComponentsImageProps, MarkdownComponentsInlineProps, MarkdownComponentsLinkProps, MarkdownComponentsListProps, MarkdownComponentsParagraphProps, MarkdownComponentsTableProps, MarkdownProps, MentionIcon, MinusCircleIcon, Prose, QuestionMarkIcon, RedoIcon, RestoreIcon, RetryIcon, SearchIcon, SelectButton, SendIcon, ShortcutTooltip, ShortenIcon, SparklesIcon, SparklesTextIcon, SpinnerIcon, StopIcon, StrikethroughIcon, TextIcon, Tooltip, TranslateIcon, UnderlineIcon, UndoIcon, User, WarningIcon, capitalize, cn, useAiComposer, useInitial, useRefs };
|
|
705
|
+
export { index$2 as AiComposer, AiComposerEditorProps, AiComposerFormProps, AiComposerSubmitProps, index$1 as AiMessage, AiMessageContentComponents, AiMessageContentProps, AiMessageContentReasoningPartProps, AiMessageContentTextPartProps, ArrowCornerDownRightIcon, ArrowCornerUpRightIcon, ArrowDownIcon, ArrowUpIcon, AttachmentIcon, Avatar, BellCrossedIcon, BellIcon, BlockquoteIcon, BoldIcon, Button, CheckCircleFillIcon, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, CodeIcon, index as Collapsible, CommentIcon, CopyIcon, CrossCircleFillIcon, CrossIcon, DeleteIcon, EditIcon, EllipsisIcon, EmojiIcon, EmojiPlusIcon, Group, GroupDescription, H1Icon, H2Icon, H3Icon, ItalicIcon, LengthenIcon, List, ListOrderedIcon, ListUnorderedIcon, Markdown, MarkdownComponents, MarkdownComponentsBlockquoteProps, MarkdownComponentsCodeBlockProps, MarkdownComponentsHeadingProps, MarkdownComponentsImageProps, MarkdownComponentsInlineProps, MarkdownComponentsLinkProps, MarkdownComponentsListProps, MarkdownComponentsParagraphProps, MarkdownComponentsTableProps, MarkdownProps, MentionIcon, MinusCircleIcon, Prose, QuestionMarkIcon, RedoIcon, RestoreIcon, RetryIcon, SearchIcon, SelectButton, SendIcon, ShortcutTooltip, ShortenIcon, SparklesIcon, SparklesTextIcon, SpinnerIcon, StopIcon, StrikethroughIcon, TextIcon, Tooltip, TranslateIcon, UnderlineIcon, UndoIcon, User, UserIcon, UsersIcon, WarningIcon, capitalize, cn, useAiComposer, useInitial, useRefs };
|
package/dist/_private/index.d.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import * as react from 'react';
|
|
3
|
-
import { ComponentProps, ReactNode, ElementType, ComponentPropsWithoutRef, ComponentType, Ref, RefCallback, FormEvent } from 'react';
|
|
4
2
|
import { Relax, AiTextPart, AiReasoningPart, AiChatMessage } from '@liveblocks/core';
|
|
3
|
+
import * as react from 'react';
|
|
4
|
+
import { ComponentProps, ReactNode, ComponentPropsWithoutRef, ElementType, ComponentType, Ref, RefCallback, FormEvent } from 'react';
|
|
5
5
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
6
6
|
export { TooltipProvider } from '@radix-ui/react-tooltip';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
type AvatarProps = ComponentProps<"div"> & {
|
|
9
|
+
icon?: ReactNode;
|
|
10
|
+
} & Relax<{
|
|
9
11
|
/**
|
|
10
12
|
* The user ID to display the avatar for.
|
|
11
13
|
*/
|
|
12
14
|
userId: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
+
} | {
|
|
16
|
+
/**
|
|
17
|
+
* The group ID to display the avatar for.
|
|
18
|
+
*/
|
|
19
|
+
groupId: string;
|
|
20
|
+
}>;
|
|
21
|
+
declare function Avatar({ userId, groupId, icon, ...props }: AvatarProps): react_jsx_runtime.JSX.Element;
|
|
15
22
|
|
|
16
23
|
interface ButtonProps extends ComponentProps<"button"> {
|
|
17
24
|
variant?: "default" | "toolbar" | "outline" | "ghost" | "primary" | "secondary" | "destructive";
|
|
@@ -22,6 +29,22 @@ interface ButtonProps extends ComponentProps<"button"> {
|
|
|
22
29
|
declare const Button: react.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
23
30
|
declare const SelectButton: react.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
24
31
|
|
|
32
|
+
interface GroupProps extends ComponentProps<"span"> {
|
|
33
|
+
/**
|
|
34
|
+
* The group ID to display the group name for.
|
|
35
|
+
*/
|
|
36
|
+
groupId: string;
|
|
37
|
+
}
|
|
38
|
+
declare function Group({ groupId, className, children, ...props }: GroupProps): react_jsx_runtime.JSX.Element;
|
|
39
|
+
|
|
40
|
+
interface GroupDescriptionProps extends ComponentPropsWithoutRef<"span"> {
|
|
41
|
+
/**
|
|
42
|
+
* The group ID to display the group description for.
|
|
43
|
+
*/
|
|
44
|
+
groupId: string;
|
|
45
|
+
}
|
|
46
|
+
declare function GroupDescription({ groupId, className, ...props }: GroupDescriptionProps): react_jsx_runtime.JSX.Element | null;
|
|
47
|
+
|
|
25
48
|
type Direction = "ltr" | "rtl";
|
|
26
49
|
type SlotProp = {
|
|
27
50
|
/**
|
|
@@ -342,7 +365,7 @@ interface UserProps extends ComponentProps<"span"> {
|
|
|
342
365
|
*/
|
|
343
366
|
replaceSelf?: boolean;
|
|
344
367
|
}
|
|
345
|
-
declare function User({ userId, replaceSelf, className, ...props }: UserProps): react_jsx_runtime.JSX.Element;
|
|
368
|
+
declare function User({ userId, replaceSelf, className, children, ...props }: UserProps): react_jsx_runtime.JSX.Element;
|
|
346
369
|
|
|
347
370
|
declare function ArrowCornerDownRightIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
|
|
348
371
|
|
|
@@ -446,6 +469,10 @@ declare function UnderlineIcon(props: ComponentProps<"svg">): react_jsx_runtime.
|
|
|
446
469
|
|
|
447
470
|
declare function UndoIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
|
|
448
471
|
|
|
472
|
+
declare function UserIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
|
|
473
|
+
|
|
474
|
+
declare function UsersIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
|
|
475
|
+
|
|
449
476
|
declare function WarningIcon(props: ComponentProps<"svg">): react_jsx_runtime.JSX.Element;
|
|
450
477
|
|
|
451
478
|
declare function capitalize(string: string): string;
|
|
@@ -675,4 +702,4 @@ declare namespace index {
|
|
|
675
702
|
};
|
|
676
703
|
}
|
|
677
704
|
|
|
678
|
-
export { index$2 as AiComposer, AiComposerEditorProps, AiComposerFormProps, AiComposerSubmitProps, index$1 as AiMessage, AiMessageContentComponents, AiMessageContentProps, AiMessageContentReasoningPartProps, AiMessageContentTextPartProps, ArrowCornerDownRightIcon, ArrowCornerUpRightIcon, ArrowDownIcon, ArrowUpIcon, AttachmentIcon, Avatar, BellCrossedIcon, BellIcon, BlockquoteIcon, BoldIcon, Button, CheckCircleFillIcon, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, CodeIcon, index as Collapsible, CommentIcon, CopyIcon, CrossCircleFillIcon, CrossIcon, DeleteIcon, EditIcon, EllipsisIcon, EmojiIcon, EmojiPlusIcon, H1Icon, H2Icon, H3Icon, ItalicIcon, LengthenIcon, List, ListOrderedIcon, ListUnorderedIcon, Markdown, MarkdownComponents, MarkdownComponentsBlockquoteProps, MarkdownComponentsCodeBlockProps, MarkdownComponentsHeadingProps, MarkdownComponentsImageProps, MarkdownComponentsInlineProps, MarkdownComponentsLinkProps, MarkdownComponentsListProps, MarkdownComponentsParagraphProps, MarkdownComponentsTableProps, MarkdownProps, MentionIcon, MinusCircleIcon, Prose, QuestionMarkIcon, RedoIcon, RestoreIcon, RetryIcon, SearchIcon, SelectButton, SendIcon, ShortcutTooltip, ShortenIcon, SparklesIcon, SparklesTextIcon, SpinnerIcon, StopIcon, StrikethroughIcon, TextIcon, Tooltip, TranslateIcon, UnderlineIcon, UndoIcon, User, WarningIcon, capitalize, cn, useAiComposer, useInitial, useRefs };
|
|
705
|
+
export { index$2 as AiComposer, AiComposerEditorProps, AiComposerFormProps, AiComposerSubmitProps, index$1 as AiMessage, AiMessageContentComponents, AiMessageContentProps, AiMessageContentReasoningPartProps, AiMessageContentTextPartProps, ArrowCornerDownRightIcon, ArrowCornerUpRightIcon, ArrowDownIcon, ArrowUpIcon, AttachmentIcon, Avatar, BellCrossedIcon, BellIcon, BlockquoteIcon, BoldIcon, Button, CheckCircleFillIcon, CheckCircleIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, CodeIcon, index as Collapsible, CommentIcon, CopyIcon, CrossCircleFillIcon, CrossIcon, DeleteIcon, EditIcon, EllipsisIcon, EmojiIcon, EmojiPlusIcon, Group, GroupDescription, H1Icon, H2Icon, H3Icon, ItalicIcon, LengthenIcon, List, ListOrderedIcon, ListUnorderedIcon, Markdown, MarkdownComponents, MarkdownComponentsBlockquoteProps, MarkdownComponentsCodeBlockProps, MarkdownComponentsHeadingProps, MarkdownComponentsImageProps, MarkdownComponentsInlineProps, MarkdownComponentsLinkProps, MarkdownComponentsListProps, MarkdownComponentsParagraphProps, MarkdownComponentsTableProps, MarkdownProps, MentionIcon, MinusCircleIcon, Prose, QuestionMarkIcon, RedoIcon, RestoreIcon, RetryIcon, SearchIcon, SelectButton, SendIcon, ShortcutTooltip, ShortenIcon, SparklesIcon, SparklesTextIcon, SpinnerIcon, StopIcon, StrikethroughIcon, TextIcon, Tooltip, TranslateIcon, UnderlineIcon, UndoIcon, User, UserIcon, UsersIcon, WarningIcon, capitalize, cn, useAiComposer, useInitial, useRefs };
|
package/dist/_private/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { Avatar } from '../components/internal/Avatar.js';
|
|
2
2
|
export { Button, SelectButton } from '../components/internal/Button.js';
|
|
3
|
+
export { Group } from '../components/internal/Group.js';
|
|
4
|
+
export { GroupDescription } from '../components/internal/GroupDescription.js';
|
|
3
5
|
export { List } from '../components/internal/List.js';
|
|
4
6
|
export { Prose } from '../components/internal/Prose.js';
|
|
5
7
|
export { ShortcutTooltip, Tooltip } from '../components/internal/Tooltip.js';
|
|
@@ -69,5 +71,7 @@ export { TextIcon } from '../icons/Text.js';
|
|
|
69
71
|
export { TranslateIcon } from '../icons/Translate.js';
|
|
70
72
|
export { UnderlineIcon } from '../icons/Underline.js';
|
|
71
73
|
export { UndoIcon } from '../icons/Undo.js';
|
|
74
|
+
export { UserIcon } from '../icons/User.js';
|
|
75
|
+
export { UsersIcon } from '../icons/Users.js';
|
|
72
76
|
export { WarningIcon } from '../icons/Warning.js';
|
|
73
77
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -7,7 +7,6 @@ var _private = require('@liveblocks/react/_private');
|
|
|
7
7
|
var TogglePrimitive = require('@radix-ui/react-toggle');
|
|
8
8
|
var react = require('react');
|
|
9
9
|
var components = require('../components.cjs');
|
|
10
|
-
var constants = require('../constants.cjs');
|
|
11
10
|
var Check = require('../icons/Check.cjs');
|
|
12
11
|
var Cross = require('../icons/Cross.cjs');
|
|
13
12
|
var Delete = require('../icons/Delete.cjs');
|
|
@@ -21,6 +20,7 @@ var Timestamp = require('../primitives/Timestamp.cjs');
|
|
|
21
20
|
var shared = require('../shared.cjs');
|
|
22
21
|
var cn = require('../utils/cn.cjs');
|
|
23
22
|
var download = require('../utils/download.cjs');
|
|
23
|
+
var useGroupMention = require('../utils/use-group-mention.cjs');
|
|
24
24
|
var useRefs = require('../utils/use-refs.cjs');
|
|
25
25
|
var useVisible = require('../utils/use-visible.cjs');
|
|
26
26
|
var useWindowFocus = require('../utils/use-window-focus.cjs');
|
|
@@ -31,6 +31,7 @@ var Button = require('./internal/Button.cjs');
|
|
|
31
31
|
var Dropdown = require('./internal/Dropdown.cjs');
|
|
32
32
|
var Emoji = require('./internal/Emoji.cjs');
|
|
33
33
|
var EmojiPicker = require('./internal/EmojiPicker.cjs');
|
|
34
|
+
var Group = require('./internal/Group.cjs');
|
|
34
35
|
var List = require('./internal/List.cjs');
|
|
35
36
|
var Tooltip = require('./internal/Tooltip.cjs');
|
|
36
37
|
var User = require('./internal/User.cjs');
|
|
@@ -59,30 +60,62 @@ var TogglePrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(TogglePri
|
|
|
59
60
|
|
|
60
61
|
|
|
61
62
|
const REACTIONS_TRUNCATE = 5;
|
|
62
|
-
function
|
|
63
|
+
function CommentUserMention({
|
|
63
64
|
mention,
|
|
64
65
|
className,
|
|
65
66
|
...props
|
|
66
67
|
}) {
|
|
67
68
|
const currentId = shared.useCurrentUserId();
|
|
69
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(index.Mention, {
|
|
70
|
+
className: cn.cn("lb-mention lb-comment-mention", className),
|
|
71
|
+
"data-self": mention.id === currentId ? "" : void 0,
|
|
72
|
+
...props,
|
|
73
|
+
children: [
|
|
74
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
75
|
+
className: "lb-mention-symbol",
|
|
76
|
+
children: core.MENTION_CHARACTER
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ jsxRuntime.jsx(User.User, {
|
|
79
|
+
userId: mention.id
|
|
80
|
+
})
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function CommentGroupMention({
|
|
85
|
+
mention,
|
|
86
|
+
className,
|
|
87
|
+
...props
|
|
88
|
+
}) {
|
|
89
|
+
const isMember = useGroupMention.useIsGroupMentionMember(mention);
|
|
90
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(index.Mention, {
|
|
91
|
+
className: cn.cn("lb-mention lb-comment-mention", className),
|
|
92
|
+
"data-self": isMember ? "" : void 0,
|
|
93
|
+
...props,
|
|
94
|
+
children: [
|
|
95
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
96
|
+
className: "lb-mention-symbol",
|
|
97
|
+
children: core.MENTION_CHARACTER
|
|
98
|
+
}),
|
|
99
|
+
/* @__PURE__ */ jsxRuntime.jsx(Group.Group, {
|
|
100
|
+
groupId: mention.id
|
|
101
|
+
})
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function CommentMention({ mention, ...props }) {
|
|
68
106
|
switch (mention.kind) {
|
|
69
107
|
case "user":
|
|
70
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}),
|
|
79
|
-
/* @__PURE__ */ jsxRuntime.jsx(User.User, {
|
|
80
|
-
userId: mention.id
|
|
81
|
-
})
|
|
82
|
-
]
|
|
108
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CommentUserMention, {
|
|
109
|
+
mention,
|
|
110
|
+
...props
|
|
111
|
+
});
|
|
112
|
+
case "group":
|
|
113
|
+
return /* @__PURE__ */ jsxRuntime.jsx(CommentGroupMention, {
|
|
114
|
+
mention,
|
|
115
|
+
...props
|
|
83
116
|
});
|
|
84
117
|
default:
|
|
85
|
-
return core.assertNever(mention
|
|
118
|
+
return core.assertNever(mention, "Unhandled mention kind");
|
|
86
119
|
}
|
|
87
120
|
}
|
|
88
121
|
function CommentLink({
|
|
@@ -632,7 +665,8 @@ const Comment = react.forwardRef(
|
|
|
632
665
|
components: {
|
|
633
666
|
Mention: ({ mention }) => /* @__PURE__ */ jsxRuntime.jsx(CommentMention, {
|
|
634
667
|
mention,
|
|
635
|
-
onClick: (event) => onMentionClick?.(mention, event)
|
|
668
|
+
onClick: (event) => onMentionClick?.(mention, event),
|
|
669
|
+
overrides: overrides$1
|
|
636
670
|
}),
|
|
637
671
|
Link: CommentLink
|
|
638
672
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Comment.cjs","sources":["../../src/components/Comment.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n assertNever,\n type CommentAttachment,\n type CommentData,\n type CommentReaction as CommentReactionData,\n type MentionData,\n Permission,\n} from \"@liveblocks/core\";\nimport {\n useAddRoomCommentReaction,\n useDeleteRoomComment,\n useEditRoomComment,\n useMarkRoomThreadAsRead,\n useRemoveRoomCommentReaction,\n useRoomAttachmentUrl,\n useRoomPermissions,\n} from \"@liveblocks/react/_private\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport type {\n ComponentProps,\n ComponentPropsWithoutRef,\n FormEvent,\n MouseEvent,\n ReactNode,\n RefObject,\n SyntheticEvent,\n} from \"react\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport {\n ComponentsProvider,\n type GlobalComponents,\n useComponents,\n} from \"../components\";\nimport { MENTION_CHARACTER } from \"../constants\";\nimport { CheckIcon } from \"../icons/Check\";\nimport { CrossIcon } from \"../icons/Cross\";\nimport { DeleteIcon } from \"../icons/Delete\";\nimport { EditIcon } from \"../icons/Edit\";\nimport { EllipsisIcon } from \"../icons/Ellipsis\";\nimport { EmojiPlusIcon } from \"../icons/EmojiPlus\";\nimport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport type { ComposerSubmitComment } from \"../primitives\";\nimport * as CommentPrimitive from \"../primitives/Comment\";\nimport type {\n CommentBodyLinkProps,\n CommentBodyMentionProps,\n CommentLinkProps,\n CommentMentionProps,\n} from \"../primitives/Comment/types\";\nimport * as ComposerPrimitive from \"../primitives/Composer\";\nimport { Timestamp } from \"../primitives/Timestamp\";\nimport { useCurrentUserId } from \"../shared\";\nimport type { CommentAttachmentArgs } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { download } from \"../utils/download\";\nimport { useRefs } from \"../utils/use-refs\";\nimport { useIntersectionCallback } from \"../utils/use-visible\";\nimport { useWindowFocus } from \"../utils/use-window-focus\";\nimport type { ComposerProps } from \"./Composer\";\nimport { Composer } from \"./Composer\";\nimport {\n FileAttachment,\n MediaAttachment,\n separateMediaAttachments,\n} from \"./internal/Attachment\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button, CustomButton } from \"./internal/Button\";\nimport { Dropdown, DropdownItem, DropdownTrigger } from \"./internal/Dropdown\";\nimport { Emoji } from \"./internal/Emoji\";\nimport { EmojiPicker, EmojiPickerTrigger } from \"./internal/EmojiPicker\";\nimport { List } from \"./internal/List\";\nimport { ShortcutTooltip, Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\nconst REACTIONS_TRUNCATE = 5;\n\nexport interface CommentProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The comment to display.\n */\n comment: CommentData;\n\n /**\n * How to show or hide the actions.\n */\n showActions?: boolean | \"hover\";\n\n /**\n * Whether to show the comment if it was deleted. If set to `false`, it will render deleted comments as `null`.\n */\n showDeleted?: boolean;\n\n /**\n * Whether to show reactions.\n */\n showReactions?: boolean;\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n\n /**\n * Whether to show the composer's formatting controls when editing the comment.\n */\n showComposerFormattingControls?: ComposerProps[\"showFormattingControls\"];\n\n /**\n * Whether to indent the comment's content.\n */\n indentContent?: boolean;\n\n /**\n * The event handler called when the comment is edited.\n */\n onCommentEdit?: (comment: CommentData) => void;\n\n /**\n * The event handler called when the comment is deleted.\n */\n onCommentDelete?: (comment: CommentData) => void;\n\n /**\n * The event handler called when clicking on the author.\n */\n onAuthorClick?: (userId: string, event: MouseEvent<HTMLElement>) => void;\n\n /**\n * The event handler called when clicking on a mention.\n */\n onMentionClick?: (\n mention: MentionData,\n event: MouseEvent<HTMLElement>\n ) => void;\n\n /**\n * The event handler called when clicking on a comment's attachment.\n */\n onAttachmentClick?: (\n args: CommentAttachmentArgs,\n event: MouseEvent<HTMLElement>\n ) => void;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & CommentOverrides & ComposerOverrides>;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n\n /**\n * @internal\n */\n autoMarkReadThreadId?: string;\n\n /**\n * @internal\n */\n additionalActions?: ReactNode;\n\n /**\n * @internal\n */\n additionalDropdownItemsBefore?: ReactNode;\n\n /**\n * @internal\n */\n additionalDropdownItemsAfter?: ReactNode;\n\n /**\n * @internal\n */\n additionalActionsClassName?: string;\n}\n\ninterface CommentReactionButtonProps\n extends ComponentPropsWithoutRef<typeof Button> {\n reaction: CommentReactionData;\n overrides?: Partial<GlobalOverrides & CommentOverrides>;\n}\n\ninterface CommentReactionProps extends ComponentPropsWithoutRef<\"button\"> {\n comment: CommentData;\n reaction: CommentReactionData;\n overrides?: Partial<GlobalOverrides & CommentOverrides>;\n}\n\ntype CommentNonInteractiveReactionProps = Omit<CommentReactionProps, \"comment\">;\n\ninterface CommentAttachmentProps extends ComponentProps<typeof FileAttachment> {\n attachment: CommentAttachment;\n onAttachmentClick?: CommentProps[\"onAttachmentClick\"];\n}\n\nexport function CommentMention({\n mention,\n className,\n ...props\n}: CommentBodyMentionProps & CommentMentionProps) {\n const currentId = useCurrentUserId();\n\n switch (mention.kind) {\n case \"user\":\n return (\n <CommentPrimitive.Mention\n className={cn(\"lb-mention lb-comment-mention\", className)}\n data-self={mention.id === currentId ? \"\" : undefined}\n {...props}\n >\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <User userId={mention.id} />\n </CommentPrimitive.Mention>\n );\n\n default:\n return assertNever(mention.kind, \"Unhandled mention kind\");\n }\n}\n\nexport function CommentLink({\n href,\n children,\n className,\n ...props\n}: CommentBodyLinkProps & CommentLinkProps) {\n const { Anchor } = useComponents();\n\n return (\n <CommentPrimitive.Link\n className={cn(\"lb-comment-link\", className)}\n href={href}\n {...props}\n asChild\n >\n <Anchor {...props}>{children}</Anchor>\n </CommentPrimitive.Link>\n );\n}\n\nexport function CommentNonInteractiveLink({\n href: _href,\n children,\n className,\n ...props\n}: CommentBodyLinkProps & CommentLinkProps) {\n return (\n <span className={cn(\"lb-comment-link\", className)} {...props}>\n {children}\n </span>\n );\n}\n\nconst CommentReactionButton = forwardRef<\n HTMLButtonElement,\n CommentReactionButtonProps\n>(({ reaction, overrides, className, ...props }, forwardedRef) => {\n const $ = useOverrides(overrides);\n return (\n <CustomButton\n className={cn(\"lb-comment-reaction\", className)}\n variant=\"outline\"\n aria-label={$.COMMENT_REACTION_DESCRIPTION(\n reaction.emoji,\n reaction.users.length\n )}\n {...props}\n ref={forwardedRef}\n >\n <Emoji className=\"lb-comment-reaction-emoji\" emoji={reaction.emoji} />\n <span className=\"lb-comment-reaction-count\">{reaction.users.length}</span>\n </CustomButton>\n );\n});\n\nexport const CommentReaction = forwardRef<\n HTMLButtonElement,\n CommentReactionProps\n>(({ comment, reaction, overrides, disabled, ...props }, forwardedRef) => {\n const addReaction = useAddRoomCommentReaction(comment.roomId);\n const removeReaction = useRemoveRoomCommentReaction(comment.roomId);\n const currentId = useCurrentUserId();\n const isActive = useMemo(() => {\n return reaction.users.some((users) => users.id === currentId);\n }, [currentId, reaction]);\n const $ = useOverrides(overrides);\n const tooltipContent = useMemo(\n () => (\n <span>\n {$.COMMENT_REACTION_LIST(\n <List\n values={reaction.users.map((users) => (\n <User key={users.id} userId={users.id} replaceSelf />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={REACTIONS_TRUNCATE}\n locale={$.locale}\n />,\n reaction.emoji,\n reaction.users.length\n )}\n </span>\n ),\n [$, reaction]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const handlePressedChange = useCallback(\n (isPressed: boolean) => {\n if (isPressed) {\n addReaction({\n threadId: comment.threadId,\n commentId: comment.id,\n emoji: reaction.emoji,\n });\n } else {\n removeReaction({\n threadId: comment.threadId,\n commentId: comment.id,\n emoji: reaction.emoji,\n });\n }\n },\n [addReaction, comment.threadId, comment.id, reaction.emoji, removeReaction]\n );\n\n return (\n <Tooltip\n content={tooltipContent}\n multiline\n className=\"lb-comment-reaction-tooltip\"\n >\n <TogglePrimitive.Root\n asChild\n pressed={isActive}\n onPressedChange={handlePressedChange}\n onClick={stopPropagation}\n disabled={disabled}\n ref={forwardedRef}\n >\n <CommentReactionButton\n data-self={isActive ? \"\" : undefined}\n reaction={reaction}\n overrides={overrides}\n {...props}\n />\n </TogglePrimitive.Root>\n </Tooltip>\n );\n});\n\nexport const CommentNonInteractiveReaction = forwardRef<\n HTMLButtonElement,\n CommentNonInteractiveReactionProps\n>(({ reaction, overrides, ...props }, forwardedRef) => {\n const currentId = useCurrentUserId();\n const isActive = useMemo(() => {\n return reaction.users.some((users) => users.id === currentId);\n }, [currentId, reaction]);\n\n return (\n <CommentReactionButton\n disableable={false}\n data-self={isActive ? \"\" : undefined}\n reaction={reaction}\n overrides={overrides}\n {...props}\n ref={forwardedRef}\n />\n );\n});\n\nfunction openAttachment({ attachment, url }: CommentAttachmentArgs) {\n // Open the attachment in a new tab if the attachment is a PDF,\n // an image, a video, or audio. Otherwise, download it.\n if (\n attachment.mimeType === \"application/pdf\" ||\n attachment.mimeType.startsWith(\"image/\") ||\n attachment.mimeType.startsWith(\"video/\") ||\n attachment.mimeType.startsWith(\"audio/\")\n ) {\n window.open(url, \"_blank\");\n } else {\n download(url, attachment.name);\n }\n}\n\nfunction CommentMediaAttachment({\n attachment,\n onAttachmentClick,\n roomId,\n className,\n overrides,\n ...props\n}: CommentAttachmentProps & {\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLElement>) => {\n if (!url) {\n return;\n }\n\n const args: CommentAttachmentArgs = { attachment, url };\n\n onAttachmentClick?.(args, event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n openAttachment(args);\n },\n [attachment, onAttachmentClick, url]\n );\n\n return (\n <MediaAttachment\n className={cn(\"lb-comment-attachment\", className)}\n {...props}\n attachment={attachment}\n overrides={overrides}\n onClick={url ? handleClick : undefined}\n roomId={roomId}\n />\n );\n}\n\nfunction CommentFileAttachment({\n attachment,\n onAttachmentClick,\n roomId,\n className,\n overrides,\n ...props\n}: CommentAttachmentProps & {\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLElement>) => {\n if (!url) {\n return;\n }\n\n const args: CommentAttachmentArgs = { attachment, url };\n\n onAttachmentClick?.(args, event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n openAttachment(args);\n },\n [attachment, onAttachmentClick, url]\n );\n\n return (\n <FileAttachment\n className={cn(\"lb-comment-attachment\", className)}\n {...props}\n attachment={attachment}\n overrides={overrides}\n onClick={url ? handleClick : undefined}\n roomId={roomId}\n />\n );\n}\n\nexport function CommentNonInteractiveFileAttachment({\n className,\n ...props\n}: CommentAttachmentProps) {\n return (\n <FileAttachment\n className={cn(\"lb-comment-attachment\", className)}\n allowMediaPreview={false}\n {...props}\n />\n );\n}\n\n// A void component (which doesn't render anything) responsible for marking a thread\n// as read when the comment it's used in becomes visible.\n// Moving this logic into a separate component allows us to use the visibility\n// and focus hooks \"conditionally\" by conditionally rendering this component.\nfunction AutoMarkReadThreadIdHandler({\n threadId,\n roomId,\n commentRef,\n}: {\n threadId: string;\n roomId: string;\n commentRef: RefObject<HTMLElement>;\n}) {\n const markThreadAsRead = useMarkRoomThreadAsRead(roomId);\n const isWindowFocused = useWindowFocus();\n\n useIntersectionCallback(\n commentRef,\n (isIntersecting) => {\n if (isIntersecting) {\n markThreadAsRead(threadId);\n }\n },\n {\n // The underlying IntersectionObserver is only enabled when the window is focused\n enabled: isWindowFocused,\n }\n );\n\n return null;\n}\n\n/**\n * Displays a single comment.\n *\n * @example\n * <>\n * {thread.comments.map((comment) => (\n * <Comment key={comment.id} comment={comment} />\n * ))}\n * </>\n */\nexport const Comment = forwardRef<HTMLDivElement, CommentProps>(\n (\n {\n comment,\n indentContent = true,\n showDeleted,\n showActions = \"hover\",\n showReactions = true,\n showAttachments = true,\n showComposerFormattingControls = true,\n onAuthorClick,\n onMentionClick,\n onAttachmentClick,\n onCommentEdit,\n onCommentDelete,\n overrides,\n components,\n className,\n additionalActions,\n additionalActionsClassName,\n additionalDropdownItemsBefore,\n additionalDropdownItemsAfter,\n autoMarkReadThreadId,\n ...props\n },\n forwardedRef\n ) => {\n const ref = useRef<HTMLDivElement>(null);\n const mergedRefs = useRefs(forwardedRef, ref);\n const currentUserId = useCurrentUserId();\n const deleteComment = useDeleteRoomComment(comment.roomId);\n const editComment = useEditRoomComment(comment.roomId);\n const addReaction = useAddRoomCommentReaction(comment.roomId);\n const removeReaction = useRemoveRoomCommentReaction(comment.roomId);\n const $ = useOverrides(overrides);\n const [isEditing, setEditing] = useState(false);\n const [isTarget, setTarget] = useState(false);\n const [isMoreActionOpen, setMoreActionOpen] = useState(false);\n const [isReactionActionOpen, setReactionActionOpen] = useState(false);\n const { mediaAttachments, fileAttachments } = useMemo(() => {\n return separateMediaAttachments(comment.attachments);\n }, [comment.attachments]);\n\n const permissions = useRoomPermissions(comment.roomId);\n const canComment =\n permissions.size > 0\n ? permissions.has(Permission.CommentsWrite) ||\n permissions.has(Permission.Write)\n : true;\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const handleEdit = useCallback(() => {\n setEditing(true);\n }, []);\n\n const handleEditCancel = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n setEditing(false);\n },\n []\n );\n\n const handleEditSubmit = useCallback(\n (\n { body, attachments }: ComposerSubmitComment,\n event: FormEvent<HTMLFormElement>\n ) => {\n // TODO: Add a way to preventDefault from within this callback, to override the default behavior (e.g. showing a confirmation dialog)\n onCommentEdit?.(comment);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n event.stopPropagation();\n event.preventDefault();\n\n setEditing(false);\n editComment({\n commentId: comment.id,\n threadId: comment.threadId,\n body,\n attachments,\n });\n },\n [comment, editComment, onCommentEdit]\n );\n\n const handleDelete = useCallback(() => {\n // TODO: Add a way to preventDefault from within this callback, to override the default behavior (e.g. showing a confirmation dialog)\n onCommentDelete?.(comment);\n\n deleteComment({\n commentId: comment.id,\n threadId: comment.threadId,\n });\n }, [comment, deleteComment, onCommentDelete]);\n\n const handleAuthorClick = useCallback(\n (event: MouseEvent<HTMLElement>) => {\n onAuthorClick?.(comment.userId, event);\n },\n [comment.userId, onAuthorClick]\n );\n\n const handleReactionSelect = useCallback(\n (emoji: string) => {\n const reactionIndex = comment.reactions.findIndex(\n (reaction) => reaction.emoji === emoji\n );\n\n if (\n reactionIndex >= 0 &&\n currentUserId &&\n comment.reactions[reactionIndex]?.users.some(\n (user) => user.id === currentUserId\n )\n ) {\n removeReaction({\n threadId: comment.threadId,\n commentId: comment.id,\n emoji,\n });\n } else {\n addReaction({\n threadId: comment.threadId,\n commentId: comment.id,\n emoji,\n });\n }\n },\n [\n addReaction,\n comment.id,\n comment.reactions,\n comment.threadId,\n removeReaction,\n currentUserId,\n ]\n );\n\n useEffect(() => {\n const isWindowDefined = typeof window !== \"undefined\";\n if (!isWindowDefined) return;\n\n const hash = window.location.hash;\n const commentId = hash.slice(1);\n\n if (commentId === comment.id) {\n setTarget(true);\n }\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (!showDeleted && !comment.body) {\n return null;\n }\n\n return (\n <TooltipProvider>\n <ComponentsProvider components={components}>\n {autoMarkReadThreadId && (\n <AutoMarkReadThreadIdHandler\n commentRef={ref}\n threadId={autoMarkReadThreadId}\n roomId={comment.roomId}\n />\n )}\n <div\n id={comment.id}\n className={cn(\n \"lb-root lb-comment\",\n indentContent && \"lb-comment:indent-content\",\n showActions === \"hover\" && \"lb-comment:show-actions-hover\",\n (isMoreActionOpen || isReactionActionOpen) &&\n \"lb-comment:action-open\",\n className\n )}\n data-deleted={!comment.body ? \"\" : undefined}\n data-editing={isEditing ? \"\" : undefined}\n // In some cases, `:target` doesn't work as expected so we also define it manually.\n data-target={isTarget ? \"\" : undefined}\n dir={$.dir}\n {...props}\n ref={mergedRefs}\n >\n <div className=\"lb-comment-header\">\n <div className=\"lb-comment-details\">\n <Avatar\n className=\"lb-comment-avatar\"\n userId={comment.userId}\n onClick={handleAuthorClick}\n />\n <span className=\"lb-comment-details-labels\">\n <User\n className=\"lb-comment-author\"\n userId={comment.userId}\n onClick={handleAuthorClick}\n />\n <span className=\"lb-comment-date\">\n <Timestamp\n locale={$.locale}\n date={comment.createdAt}\n className=\"lb-date lb-comment-date-created\"\n />\n {comment.editedAt && comment.body && (\n <>\n {\" \"}\n <span className=\"lb-comment-date-edited\">\n {$.COMMENT_EDITED}\n </span>\n </>\n )}\n </span>\n </span>\n </div>\n {showActions && !isEditing && (\n <div\n className={cn(\n \"lb-comment-actions\",\n additionalActionsClassName\n )}\n >\n {additionalActions ?? null}\n {showReactions && canComment ? (\n <EmojiPicker\n onEmojiSelect={handleReactionSelect}\n onOpenChange={setReactionActionOpen}\n >\n <Tooltip content={$.COMMENT_ADD_REACTION}>\n <EmojiPickerTrigger asChild>\n <Button\n className=\"lb-comment-action\"\n onClick={stopPropagation}\n aria-label={$.COMMENT_ADD_REACTION}\n icon={<EmojiPlusIcon />}\n />\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n ) : null}\n {comment.userId === currentUserId ||\n additionalDropdownItemsBefore ||\n additionalDropdownItemsAfter ? (\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n {additionalDropdownItemsBefore}\n {comment.userId === currentUserId && (\n <>\n <DropdownItem\n onSelect={handleEdit}\n onClick={stopPropagation}\n icon={<EditIcon />}\n >\n {$.COMMENT_EDIT}\n </DropdownItem>\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n icon={<DeleteIcon />}\n >\n {$.COMMENT_DELETE}\n </DropdownItem>\n </>\n )}\n {additionalDropdownItemsAfter}\n </>\n }\n >\n <Tooltip content={$.COMMENT_MORE}>\n <DropdownTrigger asChild>\n <Button\n className=\"lb-comment-action\"\n disabled={!comment.body}\n onClick={stopPropagation}\n aria-label={$.COMMENT_MORE}\n icon={<EllipsisIcon />}\n />\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n ) : null}\n </div>\n )}\n </div>\n <div className=\"lb-comment-content\">\n {isEditing ? (\n <Composer\n className=\"lb-comment-composer\"\n onComposerSubmit={handleEditSubmit}\n defaultValue={comment.body}\n defaultAttachments={comment.attachments}\n autoFocus\n showAttribution={false}\n showAttachments={showAttachments}\n showFormattingControls={showComposerFormattingControls}\n actions={\n <>\n <Tooltip\n content={$.COMMENT_EDIT_COMPOSER_CANCEL}\n aria-label={$.COMMENT_EDIT_COMPOSER_CANCEL}\n >\n <Button\n className=\"lb-composer-action\"\n onClick={handleEditCancel}\n icon={<CrossIcon />}\n />\n </Tooltip>\n <ShortcutTooltip\n content={$.COMMENT_EDIT_COMPOSER_SAVE}\n shortcut=\"Enter\"\n >\n <ComposerPrimitive.Submit asChild>\n <Button\n variant=\"primary\"\n className=\"lb-composer-action\"\n onClick={stopPropagation}\n aria-label={$.COMMENT_EDIT_COMPOSER_SAVE}\n icon={<CheckIcon />}\n />\n </ComposerPrimitive.Submit>\n </ShortcutTooltip>\n </>\n }\n overrides={{\n COMPOSER_PLACEHOLDER: $.COMMENT_EDIT_COMPOSER_PLACEHOLDER,\n }}\n roomId={comment.roomId}\n />\n ) : comment.body ? (\n <>\n <CommentPrimitive.Body\n className=\"lb-comment-body\"\n body={comment.body}\n components={{\n Mention: ({ mention }) => (\n <CommentMention\n mention={mention}\n onClick={(event) => onMentionClick?.(mention, event)}\n />\n ),\n Link: CommentLink,\n }}\n />\n {showAttachments &&\n (mediaAttachments.length > 0 ||\n fileAttachments.length > 0) ? (\n <div className=\"lb-comment-attachments\">\n {mediaAttachments.length > 0 ? (\n <div className=\"lb-attachments\">\n {mediaAttachments.map((attachment) => (\n <CommentMediaAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n onAttachmentClick={onAttachmentClick}\n roomId={comment.roomId}\n />\n ))}\n </div>\n ) : null}\n {fileAttachments.length > 0 ? (\n <div className=\"lb-attachments\">\n {fileAttachments.map((attachment) => (\n <CommentFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n onAttachmentClick={onAttachmentClick}\n roomId={comment.roomId}\n />\n ))}\n </div>\n ) : null}\n </div>\n ) : null}\n {showReactions && comment.reactions.length > 0 && (\n <div className=\"lb-comment-reactions\">\n {comment.reactions.map((reaction) => (\n <CommentReaction\n key={reaction.emoji}\n comment={comment}\n reaction={reaction}\n overrides={overrides}\n disabled={!canComment}\n />\n ))}\n {canComment ? (\n <EmojiPicker onEmojiSelect={handleReactionSelect}>\n <Tooltip content={$.COMMENT_ADD_REACTION}>\n <EmojiPickerTrigger asChild>\n <Button\n className=\"lb-comment-reaction lb-comment-reaction-add\"\n variant=\"outline\"\n onClick={stopPropagation}\n aria-label={$.COMMENT_ADD_REACTION}\n icon={<EmojiPlusIcon />}\n />\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n ) : null}\n </div>\n )}\n </>\n ) : (\n <div className=\"lb-comment-body\">\n <p className=\"lb-comment-deleted\">{$.COMMENT_DELETED}</p>\n </div>\n )}\n </div>\n </div>\n </ComponentsProvider>\n </TooltipProvider>\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyFA;AA4HO;AAAwB;AAC7B;AACA;AAEF;AACE;AAEA;AAAsB;AAElB;AACG;AACyD;AACb;AACvC;AAEJ;AAAC;AAAe;AAAqB;AAAkB;AACtD;AAAqB;AAAI;AAAA;AAC5B;AAIF;AAAyD;AAE/D;AAEO;AAAqB;AAC1B;AACA;AACA;AAEF;AACE;AAEA;AACG;AAC2C;AAC1C;AACI;AACG;AAEN;AAAW;AAAQ;AAAS;AAGnC;AAEO;AAAmC;AAClC;AACN;AACA;AAEF;AACE;AACG;AAA+C;AAAO;AACpD;AAGP;AAEA;AAIE;AACA;AACG;AAC+C;AACtC;AACM;AACH;AACM;AACjB;AACI;AACC;AAEL;AAAC;AAAgB;AAA4C;AAAO;AACnE;AAAe;AAA4C;AAAO;AAAA;AAGzE;AAEa;AAIX;AACA;AACA;AACA;AACE;AAA4D;AAE9D;AACA;AAAuB;AAElB;AACI;AACA;AAEI;AAAkC;AAAe;AACnD;AACkB;AACT;AACA;AACZ;AACS;AACM;AACjB;AACF;AAEU;AAGd;AACE;AAAsB;AAGxB;AAA4B;AAExB;AACE;AAAY;AACQ;AACC;AACH;AACjB;AAED;AAAe;AACK;AACC;AACH;AACjB;AACH;AACF;AAC0E;AAG5E;AACG;AACU;AACA;AACC;AAET;AACQ;AACE;AACQ;AACR;AACT;AACK;AAEJ;AAC4B;AAC3B;AACA;AACI;AACN;AACF;AAGN;AAEa;AAIX;AACA;AACE;AAA4D;AAG9D;AACG;AACc;AACc;AAC3B;AACA;AACI;AACC;AAGX;AAEA;AAGE;AAME;AAAyB;AAEzB;AAA6B;AAEjC;AAEA;AAAgC;AAC9B;AACA;AACA;AACA;AACA;AAEF;AAGE;AAEA;AAAoB;AAEhB;AACE;AAAA;AAGF;AAEA;AAEA;AACE;AAAA;AAGF;AAAmB;AACrB;AACmC;AAGrC;AACG;AACiD;AAC5C;AACJ;AACA;AAC6B;AAC7B;AAGN;AAEA;AAA+B;AAC7B;AACA;AACA;AACA;AACA;AAEF;AAGE;AAEA;AAAoB;AAEhB;AACE;AAAA;AAGF;AAEA;AAEA;AACE;AAAA;AAGF;AAAmB;AACrB;AACmC;AAGrC;AACG;AACiD;AAC5C;AACJ;AACA;AAC6B;AAC7B;AAGN;AAEO;AAA6C;AAClD;AAEF;AACE;AACG;AACiD;AAC7B;AACf;AAGV;AAMA;AAAqC;AACnC;AACA;AAEF;AAKE;AACA;AAEA;AAAA;AACE;AAEE;AACE;AAAyB;AAC3B;AACF;AACA;AAEW;AACX;AAGF;AACF;AAYO;AAAgB;AAEnB;AACE;AACgB;AAChB;AACc;AACE;AACE;AACe;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACE;AAAmD;AAGrD;AACA;AAMA;AACE;AAAsB;AAGxB;AACE;AAAe;AAGjB;AAAyB;AAErB;AACA;AAAgB;AAClB;AACC;AAGH;AAAyB;AAMrB;AAEA;AACE;AAAA;AAGF;AACA;AAEA;AACA;AAAY;AACS;AACD;AAClB;AACA;AACD;AACH;AACoC;AAGtC;AAEE;AAEA;AAAc;AACO;AACD;AACnB;AAGH;AAA0B;AAEtB;AAAqC;AACvC;AAC8B;AAGhC;AAA6B;AAEzB;AAAwC;AACL;AAGnC;AAG0C;AAChB;AAGxB;AAAe;AACK;AACC;AACnB;AACD;AAED;AAAY;AACQ;AACC;AACnB;AACD;AACH;AACF;AACA;AACE;AACQ;AACA;AACA;AACR;AACA;AACF;AAGF;AACE;AACA;AAAsB;AAEtB;AACA;AAEA;AACE;AAAc;AAChB;AAGF;AACE;AAAO;AAGT;AACG;AACE;AAAmB;AACjB;AACE;AACa;AACF;AACM;AAClB;AAED;AACa;AACD;AACT;AACiB;AACU;AAEzB;AACF;AACF;AACmC;AACJ;AAEF;AACtB;AACH;AACC;AAEL;AAAC;AAAc;AACb;AAAC;AAAc;AACb;AAAC;AACW;AACM;AACP;AACX;AACC;AAAe;AACd;AAAC;AACW;AACM;AACP;AACX;AACC;AAAe;AACd;AAAC;AACW;AACI;AACJ;AACZ;AAEE;AACG;AAAA;AACA;AAAe;AACX;AACL;AAAA;AACF;AAAA;AAEJ;AAAA;AACF;AAAA;AACF;AAEG;AACY;AACT;AACA;AACF;AAEC;AAAqB;AAEnB;AACgB;AACD;AAEb;AAAmB;AACjB;AAA0B;AACxB;AACW;AACD;AACK;AACO;AACvB;AACF;AACF;AAEA;AAID;AACO;AACQ;AACR;AAEJ;AACG;AAAA;AAEC;AACE;AAAC;AACW;AACD;AACO;AAEb;AACL;AACC;AACW;AACD;AACS;AAEf;AACL;AAAA;AACF;AAED;AAAA;AACH;AAGD;AAAmB;AACjB;AAAuB;AACrB;AACW;AACS;AACV;AACK;AACM;AACtB;AACF;AACF;AAEA;AAAA;AACN;AAAA;AAEJ;AACC;AAAc;AAEV;AACW;AACQ;AACI;AACM;AACnB;AACQ;AACjB;AACwB;AAEtB;AACE;AAAC;AACY;AACG;AAEb;AACW;AACD;AACQ;AACnB;AACF;AACC;AACY;AACF;AAER;AAAgC;AAC9B;AACS;AACE;AACD;AACK;AACG;AACnB;AACF;AACF;AAAA;AACF;AAES;AACe;AAC1B;AACgB;AAGlB;AACE;AAAC;AACW;AACI;AACF;AAEP;AACC;AACmD;AACrD;AAEI;AACR;AACF;AAIG;AAAc;AACZ;AACE;AAAc;AAEV;AAEC;AACA;AACA;AACgB;AAEnB;AAED;AAED;AAAc;AAEV;AAEC;AACA;AACA;AACgB;AAEnB;AAED;AAAA;AAEJ;AAED;AAAc;AACZ;AACE;AAEC;AACA;AACA;AACW;AAEd;AAEE;AAA2B;AACzB;AAAmB;AACjB;AAA0B;AACxB;AACW;AACF;AACC;AACK;AACO;AACvB;AACF;AACF;AAEA;AAAA;AACN;AAAA;AAIH;AAAc;AACZ;AAAY;AAAwB;AAAgB;AACvD;AAEJ;AAAA;AACF;AAAA;AACF;AACF;AAGN;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"Comment.cjs","sources":["../../src/components/Comment.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n assertNever,\n type CommentAttachment,\n type CommentData,\n type CommentReaction as CommentReactionData,\n type GroupMentionData,\n MENTION_CHARACTER,\n type MentionData,\n Permission,\n} from \"@liveblocks/core\";\nimport {\n useAddRoomCommentReaction,\n useDeleteRoomComment,\n useEditRoomComment,\n useMarkRoomThreadAsRead,\n useRemoveRoomCommentReaction,\n useRoomAttachmentUrl,\n useRoomPermissions,\n} from \"@liveblocks/react/_private\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport type {\n ComponentProps,\n ComponentPropsWithoutRef,\n FormEvent,\n MouseEvent,\n ReactNode,\n RefObject,\n SyntheticEvent,\n} from \"react\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport {\n ComponentsProvider,\n type GlobalComponents,\n useComponents,\n} from \"../components\";\nimport { CheckIcon } from \"../icons/Check\";\nimport { CrossIcon } from \"../icons/Cross\";\nimport { DeleteIcon } from \"../icons/Delete\";\nimport { EditIcon } from \"../icons/Edit\";\nimport { EllipsisIcon } from \"../icons/Ellipsis\";\nimport { EmojiPlusIcon } from \"../icons/EmojiPlus\";\nimport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport type { ComposerSubmitComment } from \"../primitives\";\nimport * as CommentPrimitive from \"../primitives/Comment\";\nimport type {\n CommentBodyLinkProps,\n CommentBodyMentionProps,\n CommentLinkProps,\n CommentMentionProps as CommentPrimitiveMentionProps,\n} from \"../primitives/Comment/types\";\nimport * as ComposerPrimitive from \"../primitives/Composer\";\nimport { Timestamp } from \"../primitives/Timestamp\";\nimport { useCurrentUserId } from \"../shared\";\nimport type { CommentAttachmentArgs } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { download } from \"../utils/download\";\nimport { useIsGroupMentionMember } from \"../utils/use-group-mention\";\nimport { useRefs } from \"../utils/use-refs\";\nimport { useIntersectionCallback } from \"../utils/use-visible\";\nimport { useWindowFocus } from \"../utils/use-window-focus\";\nimport type { ComposerProps } from \"./Composer\";\nimport { Composer } from \"./Composer\";\nimport {\n FileAttachment,\n MediaAttachment,\n separateMediaAttachments,\n} from \"./internal/Attachment\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button, CustomButton } from \"./internal/Button\";\nimport { Dropdown, DropdownItem, DropdownTrigger } from \"./internal/Dropdown\";\nimport { Emoji } from \"./internal/Emoji\";\nimport { EmojiPicker, EmojiPickerTrigger } from \"./internal/EmojiPicker\";\nimport { Group } from \"./internal/Group\";\nimport { List } from \"./internal/List\";\nimport { ShortcutTooltip, Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\nconst REACTIONS_TRUNCATE = 5;\n\nexport interface CommentProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The comment to display.\n */\n comment: CommentData;\n\n /**\n * How to show or hide the actions.\n */\n showActions?: boolean | \"hover\";\n\n /**\n * Whether to show the comment if it was deleted. If set to `false`, it will render deleted comments as `null`.\n */\n showDeleted?: boolean;\n\n /**\n * Whether to show reactions.\n */\n showReactions?: boolean;\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n\n /**\n * Whether to show the composer's formatting controls when editing the comment.\n */\n showComposerFormattingControls?: ComposerProps[\"showFormattingControls\"];\n\n /**\n * Whether to indent the comment's content.\n */\n indentContent?: boolean;\n\n /**\n * The event handler called when the comment is edited.\n */\n onCommentEdit?: (comment: CommentData) => void;\n\n /**\n * The event handler called when the comment is deleted.\n */\n onCommentDelete?: (comment: CommentData) => void;\n\n /**\n * The event handler called when clicking on the author.\n */\n onAuthorClick?: (userId: string, event: MouseEvent<HTMLElement>) => void;\n\n /**\n * The event handler called when clicking on a mention.\n */\n onMentionClick?: (\n mention: MentionData,\n event: MouseEvent<HTMLElement>\n ) => void;\n\n /**\n * The event handler called when clicking on a comment's attachment.\n */\n onAttachmentClick?: (\n args: CommentAttachmentArgs,\n event: MouseEvent<HTMLElement>\n ) => void;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & CommentOverrides & ComposerOverrides>;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n\n /**\n * @internal\n */\n autoMarkReadThreadId?: string;\n\n /**\n * @internal\n */\n additionalActions?: ReactNode;\n\n /**\n * @internal\n */\n additionalDropdownItemsBefore?: ReactNode;\n\n /**\n * @internal\n */\n additionalDropdownItemsAfter?: ReactNode;\n\n /**\n * @internal\n */\n additionalActionsClassName?: string;\n}\n\ninterface CommentReactionButtonProps\n extends ComponentPropsWithoutRef<typeof Button> {\n reaction: CommentReactionData;\n overrides?: Partial<GlobalOverrides & CommentOverrides>;\n}\n\ninterface CommentReactionProps extends ComponentPropsWithoutRef<\"button\"> {\n comment: CommentData;\n reaction: CommentReactionData;\n overrides?: Partial<GlobalOverrides & CommentOverrides>;\n}\n\ntype CommentNonInteractiveReactionProps = Omit<CommentReactionProps, \"comment\">;\n\ninterface CommentAttachmentProps extends ComponentProps<typeof FileAttachment> {\n attachment: CommentAttachment;\n onAttachmentClick?: CommentProps[\"onAttachmentClick\"];\n}\n\ninterface CommentMentionProps\n extends CommentBodyMentionProps,\n CommentPrimitiveMentionProps {\n overrides?: CommentProps[\"overrides\"];\n}\n\nfunction CommentUserMention({\n mention,\n className,\n ...props\n}: CommentMentionProps) {\n const currentId = useCurrentUserId();\n\n return (\n <CommentPrimitive.Mention\n className={cn(\"lb-mention lb-comment-mention\", className)}\n data-self={mention.id === currentId ? \"\" : undefined}\n {...props}\n >\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <User userId={mention.id} />\n </CommentPrimitive.Mention>\n );\n}\n\nfunction CommentGroupMention({\n mention,\n className,\n ...props\n}: CommentMentionProps) {\n const isMember = useIsGroupMentionMember(mention as GroupMentionData);\n\n return (\n <CommentPrimitive.Mention\n className={cn(\"lb-mention lb-comment-mention\", className)}\n data-self={isMember ? \"\" : undefined}\n {...props}\n >\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <Group groupId={mention.id} />\n </CommentPrimitive.Mention>\n );\n}\n\nexport function CommentMention({ mention, ...props }: CommentMentionProps) {\n switch (mention.kind) {\n case \"user\":\n return <CommentUserMention mention={mention} {...props} />;\n\n case \"group\":\n return <CommentGroupMention mention={mention} {...props} />;\n\n default:\n return assertNever(mention, \"Unhandled mention kind\");\n }\n}\n\nexport function CommentLink({\n href,\n children,\n className,\n ...props\n}: CommentBodyLinkProps & CommentLinkProps) {\n const { Anchor } = useComponents();\n\n return (\n <CommentPrimitive.Link\n className={cn(\"lb-comment-link\", className)}\n href={href}\n {...props}\n asChild\n >\n <Anchor {...props}>{children}</Anchor>\n </CommentPrimitive.Link>\n );\n}\n\nexport function CommentNonInteractiveLink({\n href: _href,\n children,\n className,\n ...props\n}: CommentBodyLinkProps & CommentLinkProps) {\n return (\n <span className={cn(\"lb-comment-link\", className)} {...props}>\n {children}\n </span>\n );\n}\n\nconst CommentReactionButton = forwardRef<\n HTMLButtonElement,\n CommentReactionButtonProps\n>(({ reaction, overrides, className, ...props }, forwardedRef) => {\n const $ = useOverrides(overrides);\n return (\n <CustomButton\n className={cn(\"lb-comment-reaction\", className)}\n variant=\"outline\"\n aria-label={$.COMMENT_REACTION_DESCRIPTION(\n reaction.emoji,\n reaction.users.length\n )}\n {...props}\n ref={forwardedRef}\n >\n <Emoji className=\"lb-comment-reaction-emoji\" emoji={reaction.emoji} />\n <span className=\"lb-comment-reaction-count\">{reaction.users.length}</span>\n </CustomButton>\n );\n});\n\nexport const CommentReaction = forwardRef<\n HTMLButtonElement,\n CommentReactionProps\n>(({ comment, reaction, overrides, disabled, ...props }, forwardedRef) => {\n const addReaction = useAddRoomCommentReaction(comment.roomId);\n const removeReaction = useRemoveRoomCommentReaction(comment.roomId);\n const currentId = useCurrentUserId();\n const isActive = useMemo(() => {\n return reaction.users.some((users) => users.id === currentId);\n }, [currentId, reaction]);\n const $ = useOverrides(overrides);\n const tooltipContent = useMemo(\n () => (\n <span>\n {$.COMMENT_REACTION_LIST(\n <List\n values={reaction.users.map((users) => (\n <User key={users.id} userId={users.id} replaceSelf />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={REACTIONS_TRUNCATE}\n locale={$.locale}\n />,\n reaction.emoji,\n reaction.users.length\n )}\n </span>\n ),\n [$, reaction]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const handlePressedChange = useCallback(\n (isPressed: boolean) => {\n if (isPressed) {\n addReaction({\n threadId: comment.threadId,\n commentId: comment.id,\n emoji: reaction.emoji,\n });\n } else {\n removeReaction({\n threadId: comment.threadId,\n commentId: comment.id,\n emoji: reaction.emoji,\n });\n }\n },\n [addReaction, comment.threadId, comment.id, reaction.emoji, removeReaction]\n );\n\n return (\n <Tooltip\n content={tooltipContent}\n multiline\n className=\"lb-comment-reaction-tooltip\"\n >\n <TogglePrimitive.Root\n asChild\n pressed={isActive}\n onPressedChange={handlePressedChange}\n onClick={stopPropagation}\n disabled={disabled}\n ref={forwardedRef}\n >\n <CommentReactionButton\n data-self={isActive ? \"\" : undefined}\n reaction={reaction}\n overrides={overrides}\n {...props}\n />\n </TogglePrimitive.Root>\n </Tooltip>\n );\n});\n\nexport const CommentNonInteractiveReaction = forwardRef<\n HTMLButtonElement,\n CommentNonInteractiveReactionProps\n>(({ reaction, overrides, ...props }, forwardedRef) => {\n const currentId = useCurrentUserId();\n const isActive = useMemo(() => {\n return reaction.users.some((users) => users.id === currentId);\n }, [currentId, reaction]);\n\n return (\n <CommentReactionButton\n disableable={false}\n data-self={isActive ? \"\" : undefined}\n reaction={reaction}\n overrides={overrides}\n {...props}\n ref={forwardedRef}\n />\n );\n});\n\nfunction openAttachment({ attachment, url }: CommentAttachmentArgs) {\n // Open the attachment in a new tab if the attachment is a PDF,\n // an image, a video, or audio. Otherwise, download it.\n if (\n attachment.mimeType === \"application/pdf\" ||\n attachment.mimeType.startsWith(\"image/\") ||\n attachment.mimeType.startsWith(\"video/\") ||\n attachment.mimeType.startsWith(\"audio/\")\n ) {\n window.open(url, \"_blank\");\n } else {\n download(url, attachment.name);\n }\n}\n\nfunction CommentMediaAttachment({\n attachment,\n onAttachmentClick,\n roomId,\n className,\n overrides,\n ...props\n}: CommentAttachmentProps & {\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLElement>) => {\n if (!url) {\n return;\n }\n\n const args: CommentAttachmentArgs = { attachment, url };\n\n onAttachmentClick?.(args, event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n openAttachment(args);\n },\n [attachment, onAttachmentClick, url]\n );\n\n return (\n <MediaAttachment\n className={cn(\"lb-comment-attachment\", className)}\n {...props}\n attachment={attachment}\n overrides={overrides}\n onClick={url ? handleClick : undefined}\n roomId={roomId}\n />\n );\n}\n\nfunction CommentFileAttachment({\n attachment,\n onAttachmentClick,\n roomId,\n className,\n overrides,\n ...props\n}: CommentAttachmentProps & {\n roomId: string;\n}) {\n const { url } = useRoomAttachmentUrl(attachment.id, roomId);\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLElement>) => {\n if (!url) {\n return;\n }\n\n const args: CommentAttachmentArgs = { attachment, url };\n\n onAttachmentClick?.(args, event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n openAttachment(args);\n },\n [attachment, onAttachmentClick, url]\n );\n\n return (\n <FileAttachment\n className={cn(\"lb-comment-attachment\", className)}\n {...props}\n attachment={attachment}\n overrides={overrides}\n onClick={url ? handleClick : undefined}\n roomId={roomId}\n />\n );\n}\n\nexport function CommentNonInteractiveFileAttachment({\n className,\n ...props\n}: CommentAttachmentProps) {\n return (\n <FileAttachment\n className={cn(\"lb-comment-attachment\", className)}\n allowMediaPreview={false}\n {...props}\n />\n );\n}\n\n// A void component (which doesn't render anything) responsible for marking a thread\n// as read when the comment it's used in becomes visible.\n// Moving this logic into a separate component allows us to use the visibility\n// and focus hooks \"conditionally\" by conditionally rendering this component.\nfunction AutoMarkReadThreadIdHandler({\n threadId,\n roomId,\n commentRef,\n}: {\n threadId: string;\n roomId: string;\n commentRef: RefObject<HTMLElement>;\n}) {\n const markThreadAsRead = useMarkRoomThreadAsRead(roomId);\n const isWindowFocused = useWindowFocus();\n\n useIntersectionCallback(\n commentRef,\n (isIntersecting) => {\n if (isIntersecting) {\n markThreadAsRead(threadId);\n }\n },\n {\n // The underlying IntersectionObserver is only enabled when the window is focused\n enabled: isWindowFocused,\n }\n );\n\n return null;\n}\n\n/**\n * Displays a single comment.\n *\n * @example\n * <>\n * {thread.comments.map((comment) => (\n * <Comment key={comment.id} comment={comment} />\n * ))}\n * </>\n */\nexport const Comment = forwardRef<HTMLDivElement, CommentProps>(\n (\n {\n comment,\n indentContent = true,\n showDeleted,\n showActions = \"hover\",\n showReactions = true,\n showAttachments = true,\n showComposerFormattingControls = true,\n onAuthorClick,\n onMentionClick,\n onAttachmentClick,\n onCommentEdit,\n onCommentDelete,\n overrides,\n components,\n className,\n additionalActions,\n additionalActionsClassName,\n additionalDropdownItemsBefore,\n additionalDropdownItemsAfter,\n autoMarkReadThreadId,\n ...props\n },\n forwardedRef\n ) => {\n const ref = useRef<HTMLDivElement>(null);\n const mergedRefs = useRefs(forwardedRef, ref);\n const currentUserId = useCurrentUserId();\n const deleteComment = useDeleteRoomComment(comment.roomId);\n const editComment = useEditRoomComment(comment.roomId);\n const addReaction = useAddRoomCommentReaction(comment.roomId);\n const removeReaction = useRemoveRoomCommentReaction(comment.roomId);\n const $ = useOverrides(overrides);\n const [isEditing, setEditing] = useState(false);\n const [isTarget, setTarget] = useState(false);\n const [isMoreActionOpen, setMoreActionOpen] = useState(false);\n const [isReactionActionOpen, setReactionActionOpen] = useState(false);\n const { mediaAttachments, fileAttachments } = useMemo(() => {\n return separateMediaAttachments(comment.attachments);\n }, [comment.attachments]);\n\n const permissions = useRoomPermissions(comment.roomId);\n const canComment =\n permissions.size > 0\n ? permissions.has(Permission.CommentsWrite) ||\n permissions.has(Permission.Write)\n : true;\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const handleEdit = useCallback(() => {\n setEditing(true);\n }, []);\n\n const handleEditCancel = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n event.stopPropagation();\n setEditing(false);\n },\n []\n );\n\n const handleEditSubmit = useCallback(\n (\n { body, attachments }: ComposerSubmitComment,\n event: FormEvent<HTMLFormElement>\n ) => {\n // TODO: Add a way to preventDefault from within this callback, to override the default behavior (e.g. showing a confirmation dialog)\n onCommentEdit?.(comment);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n event.stopPropagation();\n event.preventDefault();\n\n setEditing(false);\n editComment({\n commentId: comment.id,\n threadId: comment.threadId,\n body,\n attachments,\n });\n },\n [comment, editComment, onCommentEdit]\n );\n\n const handleDelete = useCallback(() => {\n // TODO: Add a way to preventDefault from within this callback, to override the default behavior (e.g. showing a confirmation dialog)\n onCommentDelete?.(comment);\n\n deleteComment({\n commentId: comment.id,\n threadId: comment.threadId,\n });\n }, [comment, deleteComment, onCommentDelete]);\n\n const handleAuthorClick = useCallback(\n (event: MouseEvent<HTMLElement>) => {\n onAuthorClick?.(comment.userId, event);\n },\n [comment.userId, onAuthorClick]\n );\n\n const handleReactionSelect = useCallback(\n (emoji: string) => {\n const reactionIndex = comment.reactions.findIndex(\n (reaction) => reaction.emoji === emoji\n );\n\n if (\n reactionIndex >= 0 &&\n currentUserId &&\n comment.reactions[reactionIndex]?.users.some(\n (user) => user.id === currentUserId\n )\n ) {\n removeReaction({\n threadId: comment.threadId,\n commentId: comment.id,\n emoji,\n });\n } else {\n addReaction({\n threadId: comment.threadId,\n commentId: comment.id,\n emoji,\n });\n }\n },\n [\n addReaction,\n comment.id,\n comment.reactions,\n comment.threadId,\n removeReaction,\n currentUserId,\n ]\n );\n\n useEffect(() => {\n const isWindowDefined = typeof window !== \"undefined\";\n if (!isWindowDefined) return;\n\n const hash = window.location.hash;\n const commentId = hash.slice(1);\n\n if (commentId === comment.id) {\n setTarget(true);\n }\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n if (!showDeleted && !comment.body) {\n return null;\n }\n\n return (\n <TooltipProvider>\n <ComponentsProvider components={components}>\n {autoMarkReadThreadId && (\n <AutoMarkReadThreadIdHandler\n commentRef={ref}\n threadId={autoMarkReadThreadId}\n roomId={comment.roomId}\n />\n )}\n <div\n id={comment.id}\n className={cn(\n \"lb-root lb-comment\",\n indentContent && \"lb-comment:indent-content\",\n showActions === \"hover\" && \"lb-comment:show-actions-hover\",\n (isMoreActionOpen || isReactionActionOpen) &&\n \"lb-comment:action-open\",\n className\n )}\n data-deleted={!comment.body ? \"\" : undefined}\n data-editing={isEditing ? \"\" : undefined}\n // In some cases, `:target` doesn't work as expected so we also define it manually.\n data-target={isTarget ? \"\" : undefined}\n dir={$.dir}\n {...props}\n ref={mergedRefs}\n >\n <div className=\"lb-comment-header\">\n <div className=\"lb-comment-details\">\n <Avatar\n className=\"lb-comment-avatar\"\n userId={comment.userId}\n onClick={handleAuthorClick}\n />\n <span className=\"lb-comment-details-labels\">\n <User\n className=\"lb-comment-author\"\n userId={comment.userId}\n onClick={handleAuthorClick}\n />\n <span className=\"lb-comment-date\">\n <Timestamp\n locale={$.locale}\n date={comment.createdAt}\n className=\"lb-date lb-comment-date-created\"\n />\n {comment.editedAt && comment.body && (\n <>\n {\" \"}\n <span className=\"lb-comment-date-edited\">\n {$.COMMENT_EDITED}\n </span>\n </>\n )}\n </span>\n </span>\n </div>\n {showActions && !isEditing && (\n <div\n className={cn(\n \"lb-comment-actions\",\n additionalActionsClassName\n )}\n >\n {additionalActions ?? null}\n {showReactions && canComment ? (\n <EmojiPicker\n onEmojiSelect={handleReactionSelect}\n onOpenChange={setReactionActionOpen}\n >\n <Tooltip content={$.COMMENT_ADD_REACTION}>\n <EmojiPickerTrigger asChild>\n <Button\n className=\"lb-comment-action\"\n onClick={stopPropagation}\n aria-label={$.COMMENT_ADD_REACTION}\n icon={<EmojiPlusIcon />}\n />\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n ) : null}\n {comment.userId === currentUserId ||\n additionalDropdownItemsBefore ||\n additionalDropdownItemsAfter ? (\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n {additionalDropdownItemsBefore}\n {comment.userId === currentUserId && (\n <>\n <DropdownItem\n onSelect={handleEdit}\n onClick={stopPropagation}\n icon={<EditIcon />}\n >\n {$.COMMENT_EDIT}\n </DropdownItem>\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n icon={<DeleteIcon />}\n >\n {$.COMMENT_DELETE}\n </DropdownItem>\n </>\n )}\n {additionalDropdownItemsAfter}\n </>\n }\n >\n <Tooltip content={$.COMMENT_MORE}>\n <DropdownTrigger asChild>\n <Button\n className=\"lb-comment-action\"\n disabled={!comment.body}\n onClick={stopPropagation}\n aria-label={$.COMMENT_MORE}\n icon={<EllipsisIcon />}\n />\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n ) : null}\n </div>\n )}\n </div>\n <div className=\"lb-comment-content\">\n {isEditing ? (\n <Composer\n className=\"lb-comment-composer\"\n onComposerSubmit={handleEditSubmit}\n defaultValue={comment.body}\n defaultAttachments={comment.attachments}\n autoFocus\n showAttribution={false}\n showAttachments={showAttachments}\n showFormattingControls={showComposerFormattingControls}\n actions={\n <>\n <Tooltip\n content={$.COMMENT_EDIT_COMPOSER_CANCEL}\n aria-label={$.COMMENT_EDIT_COMPOSER_CANCEL}\n >\n <Button\n className=\"lb-composer-action\"\n onClick={handleEditCancel}\n icon={<CrossIcon />}\n />\n </Tooltip>\n <ShortcutTooltip\n content={$.COMMENT_EDIT_COMPOSER_SAVE}\n shortcut=\"Enter\"\n >\n <ComposerPrimitive.Submit asChild>\n <Button\n variant=\"primary\"\n className=\"lb-composer-action\"\n onClick={stopPropagation}\n aria-label={$.COMMENT_EDIT_COMPOSER_SAVE}\n icon={<CheckIcon />}\n />\n </ComposerPrimitive.Submit>\n </ShortcutTooltip>\n </>\n }\n overrides={{\n COMPOSER_PLACEHOLDER: $.COMMENT_EDIT_COMPOSER_PLACEHOLDER,\n }}\n roomId={comment.roomId}\n />\n ) : comment.body ? (\n <>\n <CommentPrimitive.Body\n className=\"lb-comment-body\"\n body={comment.body}\n components={{\n Mention: ({ mention }) => (\n <CommentMention\n mention={mention}\n onClick={(event) => onMentionClick?.(mention, event)}\n overrides={overrides}\n />\n ),\n Link: CommentLink,\n }}\n />\n {showAttachments &&\n (mediaAttachments.length > 0 ||\n fileAttachments.length > 0) ? (\n <div className=\"lb-comment-attachments\">\n {mediaAttachments.length > 0 ? (\n <div className=\"lb-attachments\">\n {mediaAttachments.map((attachment) => (\n <CommentMediaAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n onAttachmentClick={onAttachmentClick}\n roomId={comment.roomId}\n />\n ))}\n </div>\n ) : null}\n {fileAttachments.length > 0 ? (\n <div className=\"lb-attachments\">\n {fileAttachments.map((attachment) => (\n <CommentFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n onAttachmentClick={onAttachmentClick}\n roomId={comment.roomId}\n />\n ))}\n </div>\n ) : null}\n </div>\n ) : null}\n {showReactions && comment.reactions.length > 0 && (\n <div className=\"lb-comment-reactions\">\n {comment.reactions.map((reaction) => (\n <CommentReaction\n key={reaction.emoji}\n comment={comment}\n reaction={reaction}\n overrides={overrides}\n disabled={!canComment}\n />\n ))}\n {canComment ? (\n <EmojiPicker onEmojiSelect={handleReactionSelect}>\n <Tooltip content={$.COMMENT_ADD_REACTION}>\n <EmojiPickerTrigger asChild>\n <Button\n className=\"lb-comment-reaction lb-comment-reaction-add\"\n variant=\"outline\"\n onClick={stopPropagation}\n aria-label={$.COMMENT_ADD_REACTION}\n icon={<EmojiPlusIcon />}\n />\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n ) : null}\n </div>\n )}\n </>\n ) : (\n <div className=\"lb-comment-body\">\n <p className=\"lb-comment-deleted\">{$.COMMENT_DELETED}</p>\n </div>\n )}\n </div>\n </div>\n </ComponentsProvider>\n </TooltipProvider>\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4FA;AAkIA;AAA4B;AAC1B;AACA;AAEF;AACE;AAEA;AACG;AACyD;AACb;AACvC;AAEJ;AAAC;AAAe;AAAqB;AAAkB;AACtD;AAAqB;AAAI;AAAA;AAGhC;AAEA;AAA6B;AAC3B;AACA;AAEF;AACE;AAEA;AACG;AACyD;AAC7B;AACvB;AAEJ;AAAC;AAAe;AAAqB;AAAkB;AACtD;AAAuB;AAAI;AAAA;AAGlC;AAEO;AACL;AAAsB;AAElB;AAAQ;AAAmB;AAAsB;AAAO;AAGxD;AAAQ;AAAoB;AAAsB;AAAO;AAGzD;AAAoD;AAE1D;AAEO;AAAqB;AAC1B;AACA;AACA;AAEF;AACE;AAEA;AACG;AAC2C;AAC1C;AACI;AACG;AAEN;AAAW;AAAQ;AAAS;AAGnC;AAEO;AAAmC;AAClC;AACN;AACA;AAEF;AACE;AACG;AAA+C;AAAO;AACpD;AAGP;AAEA;AAIE;AACA;AACG;AAC+C;AACtC;AACM;AACH;AACM;AACjB;AACI;AACC;AAEL;AAAC;AAAgB;AAA4C;AAAO;AACnE;AAAe;AAA4C;AAAO;AAAA;AAGzE;AAEa;AAIX;AACA;AACA;AACA;AACE;AAA4D;AAE9D;AACA;AAAuB;AAElB;AACI;AACA;AAEI;AAAkC;AAAe;AACnD;AACkB;AACT;AACA;AACZ;AACS;AACM;AACjB;AACF;AAEU;AAGd;AACE;AAAsB;AAGxB;AAA4B;AAExB;AACE;AAAY;AACQ;AACC;AACH;AACjB;AAED;AAAe;AACK;AACC;AACH;AACjB;AACH;AACF;AAC0E;AAG5E;AACG;AACU;AACA;AACC;AAET;AACQ;AACE;AACQ;AACR;AACT;AACK;AAEJ;AAC4B;AAC3B;AACA;AACI;AACN;AACF;AAGN;AAEa;AAIX;AACA;AACE;AAA4D;AAG9D;AACG;AACc;AACc;AAC3B;AACA;AACI;AACC;AAGX;AAEA;AAGE;AAME;AAAyB;AAEzB;AAA6B;AAEjC;AAEA;AAAgC;AAC9B;AACA;AACA;AACA;AACA;AAEF;AAGE;AAEA;AAAoB;AAEhB;AACE;AAAA;AAGF;AAEA;AAEA;AACE;AAAA;AAGF;AAAmB;AACrB;AACmC;AAGrC;AACG;AACiD;AAC5C;AACJ;AACA;AAC6B;AAC7B;AAGN;AAEA;AAA+B;AAC7B;AACA;AACA;AACA;AACA;AAEF;AAGE;AAEA;AAAoB;AAEhB;AACE;AAAA;AAGF;AAEA;AAEA;AACE;AAAA;AAGF;AAAmB;AACrB;AACmC;AAGrC;AACG;AACiD;AAC5C;AACJ;AACA;AAC6B;AAC7B;AAGN;AAEO;AAA6C;AAClD;AAEF;AACE;AACG;AACiD;AAC7B;AACf;AAGV;AAMA;AAAqC;AACnC;AACA;AAEF;AAKE;AACA;AAEA;AAAA;AACE;AAEE;AACE;AAAyB;AAC3B;AACF;AACA;AAEW;AACX;AAGF;AACF;AAYO;AAAgB;AAEnB;AACE;AACgB;AAChB;AACc;AACE;AACE;AACe;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACE;AAAmD;AAGrD;AACA;AAMA;AACE;AAAsB;AAGxB;AACE;AAAe;AAGjB;AAAyB;AAErB;AACA;AAAgB;AAClB;AACC;AAGH;AAAyB;AAMrB;AAEA;AACE;AAAA;AAGF;AACA;AAEA;AACA;AAAY;AACS;AACD;AAClB;AACA;AACD;AACH;AACoC;AAGtC;AAEE;AAEA;AAAc;AACO;AACD;AACnB;AAGH;AAA0B;AAEtB;AAAqC;AACvC;AAC8B;AAGhC;AAA6B;AAEzB;AAAwC;AACL;AAGnC;AAG0C;AAChB;AAGxB;AAAe;AACK;AACC;AACnB;AACD;AAED;AAAY;AACQ;AACC;AACnB;AACD;AACH;AACF;AACA;AACE;AACQ;AACA;AACA;AACR;AACA;AACF;AAGF;AACE;AACA;AAAsB;AAEtB;AACA;AAEA;AACE;AAAc;AAChB;AAGF;AACE;AAAO;AAGT;AACG;AACE;AAAmB;AACjB;AACE;AACa;AACF;AACM;AAClB;AAED;AACa;AACD;AACT;AACiB;AACU;AAEzB;AACF;AACF;AACmC;AACJ;AAEF;AACtB;AACH;AACC;AAEL;AAAC;AAAc;AACb;AAAC;AAAc;AACb;AAAC;AACW;AACM;AACP;AACX;AACC;AAAe;AACd;AAAC;AACW;AACM;AACP;AACX;AACC;AAAe;AACd;AAAC;AACW;AACI;AACJ;AACZ;AAEE;AACG;AAAA;AACA;AAAe;AACX;AACL;AAAA;AACF;AAAA;AAEJ;AAAA;AACF;AAAA;AACF;AAEG;AACY;AACT;AACA;AACF;AAEC;AAAqB;AAEnB;AACgB;AACD;AAEb;AAAmB;AACjB;AAA0B;AACxB;AACW;AACD;AACK;AACO;AACvB;AACF;AACF;AAEA;AAID;AACO;AACQ;AACR;AAEJ;AACG;AAAA;AAEC;AACE;AAAC;AACW;AACD;AACO;AAEb;AACL;AACC;AACW;AACD;AACS;AAEf;AACL;AAAA;AACF;AAED;AAAA;AACH;AAGD;AAAmB;AACjB;AAAuB;AACrB;AACW;AACS;AACV;AACK;AACM;AACtB;AACF;AACF;AAEA;AAAA;AACN;AAAA;AAEJ;AACC;AAAc;AAEV;AACW;AACQ;AACI;AACM;AACnB;AACQ;AACjB;AACwB;AAEtB;AACE;AAAC;AACY;AACG;AAEb;AACW;AACD;AACQ;AACnB;AACF;AACC;AACY;AACF;AAER;AAAgC;AAC9B;AACS;AACE;AACD;AACK;AACG;AACnB;AACF;AACF;AAAA;AACF;AAES;AACe;AAC1B;AACgB;AAGlB;AACE;AAAC;AACW;AACI;AACF;AAEP;AACC;AACmD;AACnD;AACF;AAEI;AACR;AACF;AAIG;AAAc;AACZ;AACE;AAAc;AAEV;AAEC;AACA;AACA;AACgB;AAEnB;AAED;AAED;AAAc;AAEV;AAEC;AACA;AACA;AACgB;AAEnB;AAED;AAAA;AAEJ;AAED;AAAc;AACZ;AACE;AAEC;AACA;AACA;AACW;AAEd;AAEE;AAA2B;AACzB;AAAmB;AACjB;AAA0B;AACxB;AACW;AACF;AACC;AACK;AACO;AACvB;AACF;AACF;AAEA;AAAA;AACN;AAAA;AAIH;AAAc;AACZ;AAAY;AAAwB;AAAgB;AACvD;AAEJ;AAAA;AACF;AAAA;AACF;AACF;AAGN;;;;;;;;"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import { assertNever, Permission } from '@liveblocks/core';
|
|
3
|
+
import { MENTION_CHARACTER, assertNever, Permission } from '@liveblocks/core';
|
|
4
4
|
import { useAddRoomCommentReaction, useRemoveRoomCommentReaction, useRoomAttachmentUrl, useMarkRoomThreadAsRead, useDeleteRoomComment, useEditRoomComment, useRoomPermissions } from '@liveblocks/react/_private';
|
|
5
5
|
import * as TogglePrimitive from '@radix-ui/react-toggle';
|
|
6
6
|
import { forwardRef, useMemo, useCallback, useRef, useState, useEffect } from 'react';
|
|
7
7
|
import { useComponents, ComponentsProvider } from '../components.js';
|
|
8
|
-
import { MENTION_CHARACTER } from '../constants.js';
|
|
9
8
|
import { CheckIcon } from '../icons/Check.js';
|
|
10
9
|
import { CrossIcon } from '../icons/Cross.js';
|
|
11
10
|
import { DeleteIcon } from '../icons/Delete.js';
|
|
@@ -19,6 +18,7 @@ import { Timestamp } from '../primitives/Timestamp.js';
|
|
|
19
18
|
import { useCurrentUserId } from '../shared.js';
|
|
20
19
|
import { cn } from '../utils/cn.js';
|
|
21
20
|
import { download } from '../utils/download.js';
|
|
21
|
+
import { useIsGroupMentionMember } from '../utils/use-group-mention.js';
|
|
22
22
|
import { useRefs } from '../utils/use-refs.js';
|
|
23
23
|
import { useIntersectionCallback } from '../utils/use-visible.js';
|
|
24
24
|
import { useWindowFocus } from '../utils/use-window-focus.js';
|
|
@@ -29,6 +29,7 @@ import { CustomButton, Button } from './internal/Button.js';
|
|
|
29
29
|
import { Dropdown, DropdownItem } from './internal/Dropdown.js';
|
|
30
30
|
import { Emoji } from './internal/Emoji.js';
|
|
31
31
|
import { EmojiPicker } from './internal/EmojiPicker.js';
|
|
32
|
+
import { Group } from './internal/Group.js';
|
|
32
33
|
import { List } from './internal/List.js';
|
|
33
34
|
import { Tooltip, ShortcutTooltip } from './internal/Tooltip.js';
|
|
34
35
|
import { User } from './internal/User.js';
|
|
@@ -38,30 +39,62 @@ import { DropdownMenuTrigger } from '@radix-ui/react-dropdown-menu';
|
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
const REACTIONS_TRUNCATE = 5;
|
|
41
|
-
function
|
|
42
|
+
function CommentUserMention({
|
|
42
43
|
mention,
|
|
43
44
|
className,
|
|
44
45
|
...props
|
|
45
46
|
}) {
|
|
46
47
|
const currentId = useCurrentUserId();
|
|
48
|
+
return /* @__PURE__ */ jsxs(CommentMention$1, {
|
|
49
|
+
className: cn("lb-mention lb-comment-mention", className),
|
|
50
|
+
"data-self": mention.id === currentId ? "" : void 0,
|
|
51
|
+
...props,
|
|
52
|
+
children: [
|
|
53
|
+
/* @__PURE__ */ jsx("span", {
|
|
54
|
+
className: "lb-mention-symbol",
|
|
55
|
+
children: MENTION_CHARACTER
|
|
56
|
+
}),
|
|
57
|
+
/* @__PURE__ */ jsx(User, {
|
|
58
|
+
userId: mention.id
|
|
59
|
+
})
|
|
60
|
+
]
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function CommentGroupMention({
|
|
64
|
+
mention,
|
|
65
|
+
className,
|
|
66
|
+
...props
|
|
67
|
+
}) {
|
|
68
|
+
const isMember = useIsGroupMentionMember(mention);
|
|
69
|
+
return /* @__PURE__ */ jsxs(CommentMention$1, {
|
|
70
|
+
className: cn("lb-mention lb-comment-mention", className),
|
|
71
|
+
"data-self": isMember ? "" : void 0,
|
|
72
|
+
...props,
|
|
73
|
+
children: [
|
|
74
|
+
/* @__PURE__ */ jsx("span", {
|
|
75
|
+
className: "lb-mention-symbol",
|
|
76
|
+
children: MENTION_CHARACTER
|
|
77
|
+
}),
|
|
78
|
+
/* @__PURE__ */ jsx(Group, {
|
|
79
|
+
groupId: mention.id
|
|
80
|
+
})
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function CommentMention({ mention, ...props }) {
|
|
47
85
|
switch (mention.kind) {
|
|
48
86
|
case "user":
|
|
49
|
-
return /* @__PURE__ */
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}),
|
|
58
|
-
/* @__PURE__ */ jsx(User, {
|
|
59
|
-
userId: mention.id
|
|
60
|
-
})
|
|
61
|
-
]
|
|
87
|
+
return /* @__PURE__ */ jsx(CommentUserMention, {
|
|
88
|
+
mention,
|
|
89
|
+
...props
|
|
90
|
+
});
|
|
91
|
+
case "group":
|
|
92
|
+
return /* @__PURE__ */ jsx(CommentGroupMention, {
|
|
93
|
+
mention,
|
|
94
|
+
...props
|
|
62
95
|
});
|
|
63
96
|
default:
|
|
64
|
-
return assertNever(mention
|
|
97
|
+
return assertNever(mention, "Unhandled mention kind");
|
|
65
98
|
}
|
|
66
99
|
}
|
|
67
100
|
function CommentLink({
|
|
@@ -611,7 +644,8 @@ const Comment = forwardRef(
|
|
|
611
644
|
components: {
|
|
612
645
|
Mention: ({ mention }) => /* @__PURE__ */ jsx(CommentMention, {
|
|
613
646
|
mention,
|
|
614
|
-
onClick: (event) => onMentionClick?.(mention, event)
|
|
647
|
+
onClick: (event) => onMentionClick?.(mention, event),
|
|
648
|
+
overrides
|
|
615
649
|
}),
|
|
616
650
|
Link: CommentLink
|
|
617
651
|
}
|