@liveblocks/react-ui 2.7.0-beta1 → 2.7.0-versions
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/_private/README.md +5 -0
- package/_private/package.json +4 -0
- package/dist/_private/index.d.mts +72 -0
- package/dist/_private/index.d.ts +72 -0
- package/dist/_private/index.js +46 -0
- package/dist/_private/index.js.map +1 -0
- package/dist/_private/index.mjs +21 -0
- package/dist/_private/index.mjs.map +1 -0
- package/dist/components/Comment.js +7 -65
- package/dist/components/Comment.js.map +1 -1
- package/dist/components/Comment.mjs +9 -66
- package/dist/components/Comment.mjs.map +1 -1
- package/dist/components/Composer.js +101 -217
- package/dist/components/Composer.js.map +1 -1
- package/dist/components/Composer.mjs +104 -220
- package/dist/components/Composer.mjs.map +1 -1
- package/dist/components/HistoryVersionSummary.js +42 -0
- package/dist/components/HistoryVersionSummary.js.map +1 -0
- package/dist/components/HistoryVersionSummary.mjs +40 -0
- package/dist/components/HistoryVersionSummary.mjs.map +1 -0
- package/dist/components/HistoryVersionSummaryList.js +22 -0
- package/dist/components/HistoryVersionSummaryList.js.map +1 -0
- package/dist/components/HistoryVersionSummaryList.mjs +20 -0
- package/dist/components/HistoryVersionSummaryList.mjs.map +1 -0
- package/dist/components/InboxNotification.js +10 -25
- package/dist/components/InboxNotification.js.map +1 -1
- package/dist/components/InboxNotification.mjs +10 -25
- package/dist/components/InboxNotification.mjs.map +1 -1
- package/dist/components/Thread.js +0 -2
- package/dist/components/Thread.js.map +1 -1
- package/dist/components/Thread.mjs +0 -2
- package/dist/components/Thread.mjs.map +1 -1
- package/dist/components/internal/Button.js +8 -1
- package/dist/components/internal/Button.js.map +1 -1
- package/dist/components/internal/Button.mjs +8 -1
- package/dist/components/internal/Button.mjs.map +1 -1
- package/dist/components/internal/EmojiPicker.js +3 -3
- package/dist/components/internal/EmojiPicker.js.map +1 -1
- package/dist/components/internal/EmojiPicker.mjs +3 -3
- package/dist/components/internal/EmojiPicker.mjs.map +1 -1
- package/dist/components/internal/InboxNotificationThread.js +2 -10
- package/dist/components/internal/InboxNotificationThread.js.map +1 -1
- package/dist/components/internal/InboxNotificationThread.mjs +3 -11
- package/dist/components/internal/InboxNotificationThread.mjs.map +1 -1
- package/dist/components/internal/User.js +3 -19
- package/dist/components/internal/User.js.map +1 -1
- package/dist/components/internal/User.mjs +3 -19
- package/dist/components/internal/User.mjs.map +1 -1
- package/dist/icons/ArrowUp.js +15 -0
- package/dist/icons/ArrowUp.js.map +1 -0
- package/dist/icons/ArrowUp.mjs +13 -0
- package/dist/icons/ArrowUp.mjs.map +1 -0
- package/dist/icons/{Warning.js → Missing.js} +3 -3
- package/dist/icons/{Warning.js.map → Missing.js.map} +1 -1
- package/dist/icons/{Warning.mjs → Missing.mjs} +3 -3
- package/dist/icons/{Warning.mjs.map → Missing.mjs.map} +1 -1
- package/dist/icons/Restore.js +17 -0
- package/dist/icons/Restore.js.map +1 -0
- package/dist/icons/Restore.mjs +15 -0
- package/dist/icons/Restore.mjs.map +1 -0
- package/dist/icons/Spinner.js +9 -3
- package/dist/icons/Spinner.js.map +1 -1
- package/dist/icons/Spinner.mjs +10 -4
- package/dist/icons/Spinner.mjs.map +1 -1
- package/dist/index.d.mts +74 -70
- package/dist/index.d.ts +74 -70
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -1
- package/dist/overrides.js +5 -6
- package/dist/overrides.js.map +1 -1
- package/dist/overrides.mjs +5 -6
- package/dist/overrides.mjs.map +1 -1
- package/dist/primitives/Composer/contexts.js +3 -17
- package/dist/primitives/Composer/contexts.js.map +1 -1
- package/dist/primitives/Composer/contexts.mjs +4 -15
- package/dist/primitives/Composer/contexts.mjs.map +1 -1
- package/dist/primitives/Composer/index.js +26 -185
- package/dist/primitives/Composer/index.js.map +1 -1
- package/dist/primitives/Composer/index.mjs +31 -188
- package/dist/primitives/Composer/index.mjs.map +1 -1
- package/dist/primitives/Composer/utils.js +0 -224
- package/dist/primitives/Composer/utils.js.map +1 -1
- package/dist/primitives/Composer/utils.mjs +1 -222
- package/dist/primitives/Composer/utils.mjs.map +1 -1
- package/dist/primitives/EmojiPicker/utils.js +2 -2
- package/dist/primitives/EmojiPicker/utils.js.map +1 -1
- package/dist/primitives/EmojiPicker/utils.mjs +1 -1
- package/dist/primitives/EmojiPicker/utils.mjs.map +1 -1
- package/dist/primitives/index.d.mts +3 -83
- package/dist/primitives/index.d.ts +3 -83
- package/dist/primitives/index.js +0 -4
- package/dist/primitives/index.js.map +1 -1
- package/dist/primitives/index.mjs +0 -2
- package/dist/primitives/index.mjs.map +1 -1
- package/dist/utils/chunk.js +12 -0
- package/dist/utils/chunk.js.map +1 -0
- package/dist/utils/chunk.mjs +10 -0
- package/dist/utils/chunk.mjs.map +1 -0
- package/dist/utils/intl.js +0 -6
- package/dist/utils/intl.js.map +1 -1
- package/dist/utils/intl.mjs +1 -6
- package/dist/utils/intl.mjs.map +1 -1
- package/dist/utils/use-initial.js +1 -2
- package/dist/utils/use-initial.js.map +1 -1
- package/dist/utils/use-initial.mjs +2 -3
- package/dist/utils/use-initial.mjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/version.mjs.map +1 -1
- package/package.json +16 -4
- package/src/styles/dark/index.css +0 -1
- package/src/styles/index.css +219 -325
- package/src/styles/utils.css +6 -44
- package/styles/dark/attributes.css +1 -1
- package/styles/dark/attributes.css.map +1 -1
- package/styles/dark/media-query.css +1 -1
- package/styles/dark/media-query.css.map +1 -1
- package/styles.css +1 -1
- package/styles.css.map +1 -1
- package/dist/components/internal/Attachment.js +0 -226
- package/dist/components/internal/Attachment.js.map +0 -1
- package/dist/components/internal/Attachment.mjs +0 -224
- package/dist/components/internal/Attachment.mjs.map +0 -1
- package/dist/icons/Attachment.js +0 -15
- package/dist/icons/Attachment.js.map +0 -1
- package/dist/icons/Attachment.mjs +0 -13
- package/dist/icons/Attachment.mjs.map +0 -1
- package/dist/primitives/FileSize.js +0 -33
- package/dist/primitives/FileSize.js.map +0 -1
- package/dist/primitives/FileSize.mjs +0 -31
- package/dist/primitives/FileSize.mjs.map +0 -1
- package/dist/utils/download.js +0 -14
- package/dist/utils/download.js.map +0 -1
- package/dist/utils/download.mjs +0 -12
- package/dist/utils/download.mjs.map +0 -1
- package/dist/utils/format-file-size.js +0 -45
- package/dist/utils/format-file-size.js.map +0 -1
- package/dist/utils/format-file-size.mjs +0 -43
- package/dist/utils/format-file-size.mjs.map +0 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
What is this directory? It exists solely to support subpath imports for node10.
|
|
2
|
+
|
|
3
|
+
While we're not interested in supporting this long-past EOL version 10 of Node,
|
|
4
|
+
we add this to acknowledge the reality that many TypeScript projects out there
|
|
5
|
+
are still using `--moduleResolution node`.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React, { ComponentProps, ElementType, ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface ButtonProps extends ComponentProps<"button"> {
|
|
4
|
+
variant?: "default" | "outline" | "primary";
|
|
5
|
+
size?: "default" | "large";
|
|
6
|
+
disableable?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
9
|
+
|
|
10
|
+
declare type SlotProp = {
|
|
11
|
+
/**
|
|
12
|
+
* Replace the rendered element by the one passed as a child.
|
|
13
|
+
*/
|
|
14
|
+
asChild?: boolean;
|
|
15
|
+
};
|
|
16
|
+
declare type ComponentPropsWithSlot<TElement extends ElementType<any>> = ComponentPropsWithoutRef<TElement> & SlotProp;
|
|
17
|
+
|
|
18
|
+
interface ListProps extends ComponentPropsWithSlot<"span"> {
|
|
19
|
+
values: ReactNode[];
|
|
20
|
+
formatRemaining?: (amount: number) => string;
|
|
21
|
+
truncate?: number;
|
|
22
|
+
locale?: string;
|
|
23
|
+
}
|
|
24
|
+
declare const List: React.ForwardRefExoticComponent<ListProps & React.RefAttributes<HTMLSpanElement>>;
|
|
25
|
+
|
|
26
|
+
interface UserProps extends ComponentProps<"span"> {
|
|
27
|
+
/**
|
|
28
|
+
* The user ID to display the user name for.
|
|
29
|
+
*/
|
|
30
|
+
userId: string;
|
|
31
|
+
/**
|
|
32
|
+
* Whether to replace the user name with "you" ($.USER_SELF) for the current user.
|
|
33
|
+
*/
|
|
34
|
+
replaceSelf?: boolean;
|
|
35
|
+
}
|
|
36
|
+
declare function User({ userId, replaceSelf, className, ...props }: UserProps): React.JSX.Element;
|
|
37
|
+
|
|
38
|
+
declare function ArrowDownIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
39
|
+
|
|
40
|
+
declare function ArrowUpIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
41
|
+
|
|
42
|
+
declare function CheckIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
43
|
+
|
|
44
|
+
declare function CrossIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
45
|
+
|
|
46
|
+
declare function DeleteIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
47
|
+
|
|
48
|
+
declare function EditIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
49
|
+
|
|
50
|
+
declare function EllipsisIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
51
|
+
|
|
52
|
+
declare function EmojiIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
53
|
+
|
|
54
|
+
declare function EmojiAddIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
55
|
+
|
|
56
|
+
declare function MentionIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
57
|
+
|
|
58
|
+
declare function MissingIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
59
|
+
|
|
60
|
+
declare function ResolveIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
61
|
+
|
|
62
|
+
declare function ResolvedIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
63
|
+
|
|
64
|
+
declare function RestoreIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
65
|
+
|
|
66
|
+
declare function SearchIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
67
|
+
|
|
68
|
+
declare function SendIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
69
|
+
|
|
70
|
+
declare function SpinnerIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
71
|
+
|
|
72
|
+
export { ArrowDownIcon, ArrowUpIcon, Button, CheckIcon, CrossIcon, DeleteIcon, EditIcon, EllipsisIcon, EmojiAddIcon, EmojiIcon, List, MentionIcon, MissingIcon, ResolveIcon, ResolvedIcon, RestoreIcon, SearchIcon, SendIcon, SpinnerIcon, User };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React, { ComponentProps, ElementType, ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
interface ButtonProps extends ComponentProps<"button"> {
|
|
4
|
+
variant?: "default" | "outline" | "primary";
|
|
5
|
+
size?: "default" | "large";
|
|
6
|
+
disableable?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
9
|
+
|
|
10
|
+
declare type SlotProp = {
|
|
11
|
+
/**
|
|
12
|
+
* Replace the rendered element by the one passed as a child.
|
|
13
|
+
*/
|
|
14
|
+
asChild?: boolean;
|
|
15
|
+
};
|
|
16
|
+
declare type ComponentPropsWithSlot<TElement extends ElementType<any>> = ComponentPropsWithoutRef<TElement> & SlotProp;
|
|
17
|
+
|
|
18
|
+
interface ListProps extends ComponentPropsWithSlot<"span"> {
|
|
19
|
+
values: ReactNode[];
|
|
20
|
+
formatRemaining?: (amount: number) => string;
|
|
21
|
+
truncate?: number;
|
|
22
|
+
locale?: string;
|
|
23
|
+
}
|
|
24
|
+
declare const List: React.ForwardRefExoticComponent<ListProps & React.RefAttributes<HTMLSpanElement>>;
|
|
25
|
+
|
|
26
|
+
interface UserProps extends ComponentProps<"span"> {
|
|
27
|
+
/**
|
|
28
|
+
* The user ID to display the user name for.
|
|
29
|
+
*/
|
|
30
|
+
userId: string;
|
|
31
|
+
/**
|
|
32
|
+
* Whether to replace the user name with "you" ($.USER_SELF) for the current user.
|
|
33
|
+
*/
|
|
34
|
+
replaceSelf?: boolean;
|
|
35
|
+
}
|
|
36
|
+
declare function User({ userId, replaceSelf, className, ...props }: UserProps): React.JSX.Element;
|
|
37
|
+
|
|
38
|
+
declare function ArrowDownIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
39
|
+
|
|
40
|
+
declare function ArrowUpIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
41
|
+
|
|
42
|
+
declare function CheckIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
43
|
+
|
|
44
|
+
declare function CrossIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
45
|
+
|
|
46
|
+
declare function DeleteIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
47
|
+
|
|
48
|
+
declare function EditIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
49
|
+
|
|
50
|
+
declare function EllipsisIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
51
|
+
|
|
52
|
+
declare function EmojiIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
53
|
+
|
|
54
|
+
declare function EmojiAddIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
55
|
+
|
|
56
|
+
declare function MentionIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
57
|
+
|
|
58
|
+
declare function MissingIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
59
|
+
|
|
60
|
+
declare function ResolveIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
61
|
+
|
|
62
|
+
declare function ResolvedIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
63
|
+
|
|
64
|
+
declare function RestoreIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
65
|
+
|
|
66
|
+
declare function SearchIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
67
|
+
|
|
68
|
+
declare function SendIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
69
|
+
|
|
70
|
+
declare function SpinnerIcon(props: ComponentProps<"svg">): React.JSX.Element;
|
|
71
|
+
|
|
72
|
+
export { ArrowDownIcon, ArrowUpIcon, Button, CheckIcon, CrossIcon, DeleteIcon, EditIcon, EllipsisIcon, EmojiAddIcon, EmojiIcon, List, MentionIcon, MissingIcon, ResolveIcon, ResolvedIcon, RestoreIcon, SearchIcon, SendIcon, SpinnerIcon, User };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Button = require('../components/internal/Button.js');
|
|
4
|
+
var List = require('../components/internal/List.js');
|
|
5
|
+
var User = require('../components/internal/User.js');
|
|
6
|
+
var ArrowDown = require('../icons/ArrowDown.js');
|
|
7
|
+
var ArrowUp = require('../icons/ArrowUp.js');
|
|
8
|
+
var Check = require('../icons/Check.js');
|
|
9
|
+
var Cross = require('../icons/Cross.js');
|
|
10
|
+
var Delete = require('../icons/Delete.js');
|
|
11
|
+
var Edit = require('../icons/Edit.js');
|
|
12
|
+
var Ellipsis = require('../icons/Ellipsis.js');
|
|
13
|
+
var Emoji = require('../icons/Emoji.js');
|
|
14
|
+
var EmojiAdd = require('../icons/EmojiAdd.js');
|
|
15
|
+
var Mention = require('../icons/Mention.js');
|
|
16
|
+
var Missing = require('../icons/Missing.js');
|
|
17
|
+
var Resolve = require('../icons/Resolve.js');
|
|
18
|
+
var Resolved = require('../icons/Resolved.js');
|
|
19
|
+
var Restore = require('../icons/Restore.js');
|
|
20
|
+
var Search = require('../icons/Search.js');
|
|
21
|
+
var Send = require('../icons/Send.js');
|
|
22
|
+
var Spinner = require('../icons/Spinner.js');
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
exports.Button = Button.Button;
|
|
27
|
+
exports.List = List.List;
|
|
28
|
+
exports.User = User.User;
|
|
29
|
+
exports.ArrowDownIcon = ArrowDown.ArrowDownIcon;
|
|
30
|
+
exports.ArrowUpIcon = ArrowUp.ArrowUpIcon;
|
|
31
|
+
exports.CheckIcon = Check.CheckIcon;
|
|
32
|
+
exports.CrossIcon = Cross.CrossIcon;
|
|
33
|
+
exports.DeleteIcon = Delete.DeleteIcon;
|
|
34
|
+
exports.EditIcon = Edit.EditIcon;
|
|
35
|
+
exports.EllipsisIcon = Ellipsis.EllipsisIcon;
|
|
36
|
+
exports.EmojiIcon = Emoji.EmojiIcon;
|
|
37
|
+
exports.EmojiAddIcon = EmojiAdd.EmojiAddIcon;
|
|
38
|
+
exports.MentionIcon = Mention.MentionIcon;
|
|
39
|
+
exports.MissingIcon = Missing.MissingIcon;
|
|
40
|
+
exports.ResolveIcon = Resolve.ResolveIcon;
|
|
41
|
+
exports.ResolvedIcon = Resolved.ResolvedIcon;
|
|
42
|
+
exports.RestoreIcon = Restore.RestoreIcon;
|
|
43
|
+
exports.SearchIcon = Search.SearchIcon;
|
|
44
|
+
exports.SendIcon = Send.SendIcon;
|
|
45
|
+
exports.SpinnerIcon = Spinner.SpinnerIcon;
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { Button } from '../components/internal/Button.mjs';
|
|
2
|
+
export { List } from '../components/internal/List.mjs';
|
|
3
|
+
export { User } from '../components/internal/User.mjs';
|
|
4
|
+
export { ArrowDownIcon } from '../icons/ArrowDown.mjs';
|
|
5
|
+
export { ArrowUpIcon } from '../icons/ArrowUp.mjs';
|
|
6
|
+
export { CheckIcon } from '../icons/Check.mjs';
|
|
7
|
+
export { CrossIcon } from '../icons/Cross.mjs';
|
|
8
|
+
export { DeleteIcon } from '../icons/Delete.mjs';
|
|
9
|
+
export { EditIcon } from '../icons/Edit.mjs';
|
|
10
|
+
export { EllipsisIcon } from '../icons/Ellipsis.mjs';
|
|
11
|
+
export { EmojiIcon } from '../icons/Emoji.mjs';
|
|
12
|
+
export { EmojiAddIcon } from '../icons/EmojiAdd.mjs';
|
|
13
|
+
export { MentionIcon } from '../icons/Mention.mjs';
|
|
14
|
+
export { MissingIcon } from '../icons/Missing.mjs';
|
|
15
|
+
export { ResolveIcon } from '../icons/Resolve.mjs';
|
|
16
|
+
export { ResolvedIcon } from '../icons/Resolved.mjs';
|
|
17
|
+
export { RestoreIcon } from '../icons/Restore.mjs';
|
|
18
|
+
export { SearchIcon } from '../icons/Search.mjs';
|
|
19
|
+
export { SendIcon } from '../icons/Send.mjs';
|
|
20
|
+
export { SpinnerIcon } from '../icons/Spinner.mjs';
|
|
21
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;"}
|
|
@@ -17,12 +17,10 @@ var Timestamp = require('../primitives/Timestamp.js');
|
|
|
17
17
|
var shared = require('../shared.js');
|
|
18
18
|
var mentions = require('../slate/plugins/mentions.js');
|
|
19
19
|
var classNames = require('../utils/class-names.js');
|
|
20
|
-
var download = require('../utils/download.js');
|
|
21
20
|
var useRefs = require('../utils/use-refs.js');
|
|
22
21
|
var useVisible = require('../utils/use-visible.js');
|
|
23
22
|
var useWindowFocus = require('../utils/use-window-focus.js');
|
|
24
23
|
var Composer = require('./Composer.js');
|
|
25
|
-
var Attachment = require('./internal/Attachment.js');
|
|
26
24
|
var Avatar = require('./internal/Avatar.js');
|
|
27
25
|
var Button = require('./internal/Button.js');
|
|
28
26
|
var Dropdown = require('./internal/Dropdown.js');
|
|
@@ -121,14 +119,14 @@ const CommentReaction = React.forwardRef(({ comment, reaction, overrides: overri
|
|
|
121
119
|
const tooltipContent = React.useMemo(
|
|
122
120
|
() => /* @__PURE__ */ React.createElement("span", null, $.COMMENT_REACTION_LIST(
|
|
123
121
|
/* @__PURE__ */ React.createElement(List.List, {
|
|
124
|
-
values: reaction.users.map((users
|
|
122
|
+
values: reaction.users.map((users) => /* @__PURE__ */ React.createElement(User.User, {
|
|
125
123
|
key: users.id,
|
|
126
124
|
userId: users.id,
|
|
127
|
-
capitalize: index === 0,
|
|
128
125
|
replaceSelf: true
|
|
129
126
|
})),
|
|
130
127
|
formatRemaining: $.LIST_REMAINING_USERS,
|
|
131
|
-
truncate: REACTIONS_TRUNCATE
|
|
128
|
+
truncate: REACTIONS_TRUNCATE,
|
|
129
|
+
locale: $.locale
|
|
132
130
|
}),
|
|
133
131
|
reaction.emoji,
|
|
134
132
|
reaction.users.length
|
|
@@ -188,49 +186,6 @@ const CommentNonInteractiveReaction = React.forwardRef(({ reaction, overrides, .
|
|
|
188
186
|
ref: forwardedRef
|
|
189
187
|
});
|
|
190
188
|
});
|
|
191
|
-
function CommentFileAttachment({
|
|
192
|
-
attachment,
|
|
193
|
-
onAttachmentClick,
|
|
194
|
-
className,
|
|
195
|
-
overrides,
|
|
196
|
-
...props
|
|
197
|
-
}) {
|
|
198
|
-
const { url } = react.useAttachmentUrl(attachment.id);
|
|
199
|
-
const handleClick = React.useCallback(
|
|
200
|
-
(event) => {
|
|
201
|
-
if (!url) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
const args = { attachment, url };
|
|
205
|
-
onAttachmentClick?.(args, event);
|
|
206
|
-
if (event.isDefaultPrevented()) {
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
if (attachment.mimeType === "application/pdf" || attachment.mimeType.startsWith("image/") || attachment.mimeType.startsWith("video/") || attachment.mimeType.startsWith("audio/")) {
|
|
210
|
-
window.open(url, "_blank");
|
|
211
|
-
} else {
|
|
212
|
-
download.download(url, attachment.name);
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
[attachment, onAttachmentClick, url]
|
|
216
|
-
);
|
|
217
|
-
return /* @__PURE__ */ React.createElement(Attachment.FileAttachment, {
|
|
218
|
-
className: classNames.classNames("lb-comment-attachment", className),
|
|
219
|
-
...props,
|
|
220
|
-
attachment,
|
|
221
|
-
overrides,
|
|
222
|
-
onClick: url ? handleClick : void 0
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
function CommentNonInteractiveFileAttachment({
|
|
226
|
-
className,
|
|
227
|
-
...props
|
|
228
|
-
}) {
|
|
229
|
-
return /* @__PURE__ */ React.createElement(Attachment.FileAttachment, {
|
|
230
|
-
className: classNames.classNames("lb-comment-attachment", className),
|
|
231
|
-
...props
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
189
|
function AutoMarkReadThreadIdHandler({
|
|
235
190
|
threadId,
|
|
236
191
|
commentRef
|
|
@@ -255,10 +210,8 @@ const Comment = React.forwardRef(
|
|
|
255
210
|
showDeleted,
|
|
256
211
|
showActions = "hover",
|
|
257
212
|
showReactions = true,
|
|
258
|
-
showAttachments = true,
|
|
259
213
|
onAuthorClick,
|
|
260
214
|
onMentionClick,
|
|
261
|
-
onAttachmentClick,
|
|
262
215
|
onCommentEdit,
|
|
263
216
|
onCommentDelete,
|
|
264
217
|
overrides: overrides$1,
|
|
@@ -295,15 +248,14 @@ const Comment = React.forwardRef(
|
|
|
295
248
|
[]
|
|
296
249
|
);
|
|
297
250
|
const handleEditSubmit = React.useCallback(
|
|
298
|
-
({ body
|
|
251
|
+
({ body }, event) => {
|
|
299
252
|
onCommentEdit?.(comment);
|
|
300
253
|
event.preventDefault();
|
|
301
254
|
setEditing(false);
|
|
302
255
|
editComment({
|
|
303
256
|
commentId: comment.id,
|
|
304
257
|
threadId: comment.threadId,
|
|
305
|
-
body
|
|
306
|
-
attachments
|
|
258
|
+
body
|
|
307
259
|
});
|
|
308
260
|
},
|
|
309
261
|
[comment, editComment, onCommentEdit]
|
|
@@ -401,7 +353,7 @@ const Comment = React.forwardRef(
|
|
|
401
353
|
}, /* @__PURE__ */ React.createElement(Timestamp.Timestamp, {
|
|
402
354
|
locale: $.locale,
|
|
403
355
|
date: comment.createdAt,
|
|
404
|
-
className: "lb-comment-date-created"
|
|
356
|
+
className: "lb-date lb-comment-date-created"
|
|
405
357
|
}), comment.editedAt && comment.body && /* @__PURE__ */ React.createElement(React.Fragment, null, " ", /* @__PURE__ */ React.createElement("span", {
|
|
406
358
|
className: "lb-comment-date-edited"
|
|
407
359
|
}, $.COMMENT_EDITED))))), showActions && !isEditing && /* @__PURE__ */ React.createElement("div", {
|
|
@@ -454,10 +406,8 @@ const Comment = React.forwardRef(
|
|
|
454
406
|
className: "lb-comment-composer",
|
|
455
407
|
onComposerSubmit: handleEditSubmit,
|
|
456
408
|
defaultValue: comment.body,
|
|
457
|
-
defaultAttachments: comment.attachments,
|
|
458
409
|
autoFocus: true,
|
|
459
410
|
showAttribution: false,
|
|
460
|
-
showAttachments,
|
|
461
411
|
actions: /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Tooltip.Tooltip, {
|
|
462
412
|
content: $.COMMENT_EDIT_COMPOSER_CANCEL,
|
|
463
413
|
"aria-label": $.COMMENT_EDIT_COMPOSER_CANCEL
|
|
@@ -494,14 +444,7 @@ const Comment = React.forwardRef(
|
|
|
494
444
|
}),
|
|
495
445
|
Link: CommentLink
|
|
496
446
|
}
|
|
497
|
-
}),
|
|
498
|
-
className: "lb-comment-attachments"
|
|
499
|
-
}, comment.attachments.map((attachment) => /* @__PURE__ */ React.createElement(CommentFileAttachment, {
|
|
500
|
-
key: attachment.id,
|
|
501
|
-
attachment,
|
|
502
|
-
overrides: overrides$1,
|
|
503
|
-
onAttachmentClick
|
|
504
|
-
}))) : null, showReactions && comment.reactions.length > 0 && /* @__PURE__ */ React.createElement("div", {
|
|
447
|
+
}), showReactions && comment.reactions.length > 0 && /* @__PURE__ */ React.createElement("div", {
|
|
505
448
|
className: "lb-comment-reactions"
|
|
506
449
|
}, comment.reactions.map((reaction) => /* @__PURE__ */ React.createElement(CommentReaction, {
|
|
507
450
|
key: reaction.emoji,
|
|
@@ -532,7 +475,6 @@ const Comment = React.forwardRef(
|
|
|
532
475
|
exports.Comment = Comment;
|
|
533
476
|
exports.CommentLink = CommentLink;
|
|
534
477
|
exports.CommentMention = CommentMention;
|
|
535
|
-
exports.CommentNonInteractiveFileAttachment = CommentNonInteractiveFileAttachment;
|
|
536
478
|
exports.CommentNonInteractiveLink = CommentNonInteractiveLink;
|
|
537
479
|
exports.CommentNonInteractiveReaction = CommentNonInteractiveReaction;
|
|
538
480
|
exports.CommentReaction = CommentReaction;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Comment.js","sources":["../../src/components/Comment.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n CommentAttachment,\n CommentData,\n CommentReaction as CommentReactionData,\n} from \"@liveblocks/core\";\nimport {\n RoomContext,\n useAddReaction,\n useAttachmentUrl,\n useDeleteComment,\n useEditComment,\n useMarkThreadAsRead,\n useRemoveReaction,\n} from \"@liveblocks/react\";\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 React, {\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\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 { EmojiAddIcon } from \"../icons/EmojiAdd\";\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 { MENTION_CHARACTER } from \"../slate/plugins/mentions\";\nimport type { CommentAttachmentArgs } from \"../types\";\nimport { classNames } from \"../utils/class-names\";\nimport { download } from \"../utils/download\";\nimport { useRefs } from \"../utils/use-refs\";\nimport { useVisibleCallback } from \"../utils/use-visible\";\nimport { useWindowFocus } from \"../utils/use-window-focus\";\nimport { Composer } from \"./Composer\";\nimport { FileAttachment } from \"./internal/Attachment\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button } 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 {\n ShortcutTooltip,\n ShortcutTooltipKey,\n Tooltip,\n TooltipProvider,\n} 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 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?: (userId: string, event: MouseEvent<HTMLElement>) => 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 * @internal\n */\n autoMarkReadThreadId?: string;\n\n /**\n * @internal\n */\n additionalActions?: 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 CommentFileAttachmentProps\n extends ComponentProps<typeof FileAttachment> {\n attachment: CommentAttachment;\n onAttachmentClick?: CommentProps[\"onAttachmentClick\"];\n}\n\nexport function CommentMention({\n userId,\n className,\n ...props\n}: CommentBodyMentionProps & CommentMentionProps) {\n const currentId = useCurrentUserId();\n return (\n <CommentPrimitive.Mention\n className={classNames(\"lb-comment-mention\", className)}\n data-self={userId === currentId ? \"\" : undefined}\n {...props}\n >\n {MENTION_CHARACTER}\n <User userId={userId} />\n </CommentPrimitive.Mention>\n );\n}\n\nexport function CommentLink({\n href,\n children,\n className,\n ...props\n}: CommentBodyLinkProps & CommentLinkProps) {\n return (\n <CommentPrimitive.Link\n className={classNames(\"lb-comment-link\", className)}\n href={href}\n {...props}\n >\n {children}\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={classNames(\"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 <Button\n className={classNames(\"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 </Button>\n );\n});\n\nexport const CommentReaction = forwardRef<\n HTMLButtonElement,\n CommentReactionProps\n>(({ comment, reaction, overrides, disabled, ...props }, forwardedRef) => {\n const addReaction = useAddReaction();\n const removeReaction = useRemoveReaction();\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, index) => (\n <User\n key={users.id}\n userId={users.id}\n capitalize={index === 0}\n replaceSelf\n />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={REACTIONS_TRUNCATE}\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 CommentFileAttachment({\n attachment,\n onAttachmentClick,\n className,\n overrides,\n ...props\n}: CommentFileAttachmentProps) {\n const { url } = useAttachmentUrl(attachment.id);\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 // 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 [attachment, onAttachmentClick, url]\n );\n\n return (\n <FileAttachment\n className={classNames(\"lb-comment-attachment\", className)}\n {...props}\n attachment={attachment}\n overrides={overrides}\n onClick={url ? handleClick : undefined}\n />\n );\n}\n\nexport function CommentNonInteractiveFileAttachment({\n className,\n ...props\n}: CommentFileAttachmentProps) {\n return (\n <FileAttachment\n className={classNames(\"lb-comment-attachment\", className)}\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 commentRef,\n}: {\n threadId: string;\n commentRef: RefObject<HTMLElement>;\n}) {\n const markThreadAsRead = useMarkThreadAsRead();\n const isWindowFocused = useWindowFocus();\n\n useVisibleCallback(\n commentRef,\n () => {\n markThreadAsRead(threadId);\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 onAuthorClick,\n onMentionClick,\n onAttachmentClick,\n onCommentEdit,\n onCommentDelete,\n overrides,\n className,\n additionalActions,\n additionalActionsClassName,\n autoMarkReadThreadId,\n ...props\n },\n forwardedRef\n ) => {\n const isInRoom = Boolean(useContext(RoomContext));\n const ref = useRef<HTMLDivElement>(null);\n const mergedRefs = useRefs(forwardedRef, ref);\n const currentUserId = useCurrentUserId();\n const deleteComment = useDeleteComment();\n const editComment = useEditComment();\n const addReaction = useAddReaction();\n const removeReaction = useRemoveReaction();\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\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 event.preventDefault();\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 {isInRoom && autoMarkReadThreadId && (\n <AutoMarkReadThreadIdHandler\n commentRef={ref}\n threadId={autoMarkReadThreadId}\n />\n )}\n <div\n id={comment.id}\n className={classNames(\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-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={classNames(\n \"lb-comment-actions\",\n additionalActionsClassName\n )}\n >\n {additionalActions ?? null}\n {showReactions && (\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 >\n <EmojiAddIcon className=\"lb-button-icon\" />\n </Button>\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n )}\n {comment.userId === currentUserId && (\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n <DropdownItem\n onSelect={handleEdit}\n onClick={stopPropagation}\n >\n <EditIcon className=\"lb-dropdown-item-icon\" />\n {$.COMMENT_EDIT}\n </DropdownItem>\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n >\n <DeleteIcon className=\"lb-dropdown-item-icon\" />\n {$.COMMENT_DELETE}\n </DropdownItem>\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 >\n <EllipsisIcon className=\"lb-button-icon\" />\n </Button>\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n )}\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 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 >\n <CrossIcon className=\"lb-button-icon\" />\n </Button>\n </Tooltip>\n <ShortcutTooltip\n content={$.COMMENT_EDIT_COMPOSER_SAVE}\n shortcut={<ShortcutTooltipKey name=\"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 >\n <CheckIcon className=\"lb-button-icon\" />\n </Button>\n </ComposerPrimitive.Submit>\n </ShortcutTooltip>\n </>\n }\n overrides={{\n COMPOSER_PLACEHOLDER: $.COMMENT_EDIT_COMPOSER_PLACEHOLDER,\n }}\n />\n ) : comment.body ? (\n <>\n <CommentPrimitive.Body\n className=\"lb-comment-body\"\n body={comment.body}\n components={{\n Mention: ({ userId }) => (\n <CommentMention\n userId={userId}\n onClick={(event) => onMentionClick?.(userId, event)}\n />\n ),\n Link: CommentLink,\n }}\n />\n {showAttachments && comment.attachments.length > 0 ? (\n <div className=\"lb-comment-attachments\">\n {comment.attachments.map((attachment) => (\n <CommentFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n onAttachmentClick={onAttachmentClick}\n />\n ))}\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 />\n ))}\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 >\n <EmojiAddIcon className=\"lb-button-icon\" />\n </Button>\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\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 </TooltipProvider>\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkFA;AAsGO;AAAwB;AAC7B;AACA;AAEF;AACE;AACA;AACG;AACsD;AACd;AACnC;AAGH;AAAK;AAGZ;AAEO;AAAqB;AAC1B;AACA;AACA;AAEF;AACE;AACG;AACmD;AAClD;AACI;AAKV;AAEO;AAAmC;AAClC;AACN;AACA;AAEF;AACE;AACG;AAAuD;AAAO;AAInE;AAEA;AAIE;AACA;AACG;AACuD;AAC9C;AACM;AACH;AACM;AACjB;AACI;AACC;AAEJ;AAAgB;AAA4C;AAC5D;AAAe;AAGtB;AAEa;AAIX;AACA;AACA;AACA;AACE;AAA4D;AAE9D;AACA;AAAuB;AAGd;AACA;AAEI;AACY;AACG;AACQ;AACX;AAEd;AACkB;AACT;AACZ;AACS;AACM;AAEnB;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;AAKd;AAEa;AAIX;AACA;AACE;AAA4D;AAG9D;AACG;AACc;AACc;AAC3B;AACA;AACI;AACC;AAGX;AAEA;AAA+B;AAC7B;AACA;AACA;AACA;AAEF;AACE;AAEA;AAAoB;AAEhB;AACE;AAAA;AAGF;AAEA;AAEA;AACE;AAAA;AAKF;AAME;AAAyB;AAEzB;AAA6B;AAC/B;AACF;AACmC;AAGrC;AACG;AACyD;AACpD;AACJ;AACA;AAC6B;AAGnC;AAEO;AAA6C;AAClD;AAEF;AACE;AACG;AACyD;AACpD;AAGV;AAMA;AAAqC;AACnC;AAEF;AAIE;AACA;AAEA;AAAA;AACE;AAEE;AAAyB;AAC3B;AACA;AAEW;AACX;AAGF;AACF;AAYO;AAAgB;AAEnB;AACE;AACgB;AAChB;AACc;AACE;AACE;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACE;AAAsB;AAGxB;AACE;AAAe;AAGjB;AAAyB;AAErB;AACA;AAAgB;AAClB;AACC;AAGH;AAAyB;AAMrB;AAEA;AACA;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;AAGyC;AACf;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;AAGO;AACa;AACF;AAGb;AACa;AACD;AACT;AACiB;AACU;AAEzB;AACF;AACF;AACmC;AACJ;AAEF;AACtB;AACH;AACC;AAEJ;AAAc;AACZ;AAAc;AACZ;AACW;AACM;AACP;AAEV;AAAe;AACb;AACW;AACM;AACP;AAEV;AAAe;AACb;AACW;AACI;AACJ;AAKP;AAAe;AASvB;AACY;AACT;AACA;AACF;AAIG;AACgB;AACD;AAEb;AAAmB;AACjB;AAA0B;AACxB;AACW;AACD;AACK;AAEb;AAAuB;AAO/B;AACO;AACQ;AACR;AAGD;AACW;AACD;AAER;AAAmB;AAGrB;AACW;AACD;AAER;AAAqB;AAG1B;AAGD;AAAmB;AACjB;AAAuB;AACrB;AACW;AACS;AACV;AACK;AAEb;AAAuB;AASvC;AAAc;AAEV;AACW;AACQ;AACI;AACM;AACnB;AACQ;AACjB;AAGK;AACY;AACG;AAEb;AACW;AACD;AAER;AAAoB;AAGxB;AACY;AACA;AAAwB;AAAQ;AAE1C;AAAgC;AAC9B;AACS;AACE;AACD;AACK;AAEb;AAAoB;AAI7B;AAES;AACe;AAC1B;AAIC;AACW;AACI;AACF;AAEP;AACC;AACkD;AACpD;AAEI;AACR;AAGC;AAAc;AAEV;AACiB;AAChB;AACA;AACA;AAML;AAAc;AAEV;AACe;AACd;AACA;AACA;AAGH;AAA2B;AACzB;AAAmB;AACjB;AAA0B;AACxB;AACW;AACF;AACC;AACK;AAEb;AAAuB;AASrC;AAAc;AACZ;AAAY;AAKvB;AAGN;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"Comment.js","sources":["../../src/components/Comment.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n CommentData,\n CommentReaction as CommentReactionData,\n} from \"@liveblocks/core\";\nimport {\n RoomContext,\n useAddReaction,\n useDeleteComment,\n useEditComment,\n useMarkThreadAsRead,\n useRemoveReaction,\n} from \"@liveblocks/react\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport type {\n ComponentPropsWithoutRef,\n FormEvent,\n MouseEvent,\n ReactNode,\n RefObject,\n SyntheticEvent,\n} from \"react\";\nimport React, {\n forwardRef,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\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 { EmojiAddIcon } from \"../icons/EmojiAdd\";\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 { MENTION_CHARACTER } from \"../slate/plugins/mentions\";\nimport { classNames } from \"../utils/class-names\";\nimport { useRefs } from \"../utils/use-refs\";\nimport { useVisibleCallback } from \"../utils/use-visible\";\nimport { useWindowFocus } from \"../utils/use-window-focus\";\nimport { Composer } from \"./Composer\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button } 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 {\n ShortcutTooltip,\n ShortcutTooltipKey,\n Tooltip,\n TooltipProvider,\n} 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 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?: (userId: string, event: MouseEvent<HTMLElement>) => void;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & CommentOverrides & ComposerOverrides>;\n\n /**\n * @internal\n */\n autoMarkReadThreadId?: string;\n\n /**\n * @internal\n */\n additionalActions?: 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\nexport function CommentMention({\n userId,\n className,\n ...props\n}: CommentBodyMentionProps & CommentMentionProps) {\n const currentId = useCurrentUserId();\n return (\n <CommentPrimitive.Mention\n className={classNames(\"lb-comment-mention\", className)}\n data-self={userId === currentId ? \"\" : undefined}\n {...props}\n >\n {MENTION_CHARACTER}\n <User userId={userId} />\n </CommentPrimitive.Mention>\n );\n}\n\nexport function CommentLink({\n href,\n children,\n className,\n ...props\n}: CommentBodyLinkProps & CommentLinkProps) {\n return (\n <CommentPrimitive.Link\n className={classNames(\"lb-comment-link\", className)}\n href={href}\n {...props}\n >\n {children}\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={classNames(\"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 <Button\n className={classNames(\"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 </Button>\n );\n});\n\nexport const CommentReaction = forwardRef<\n HTMLButtonElement,\n CommentReactionProps\n>(({ comment, reaction, overrides, disabled, ...props }, forwardedRef) => {\n const addReaction = useAddReaction();\n const removeReaction = useRemoveReaction();\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\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 commentRef,\n}: {\n threadId: string;\n commentRef: RefObject<HTMLElement>;\n}) {\n const markThreadAsRead = useMarkThreadAsRead();\n const isWindowFocused = useWindowFocus();\n\n useVisibleCallback(\n commentRef,\n () => {\n markThreadAsRead(threadId);\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 onAuthorClick,\n onMentionClick,\n onCommentEdit,\n onCommentDelete,\n overrides,\n className,\n additionalActions,\n additionalActionsClassName,\n autoMarkReadThreadId,\n ...props\n },\n forwardedRef\n ) => {\n const isInRoom = Boolean(useContext(RoomContext));\n const ref = useRef<HTMLDivElement>(null);\n const mergedRefs = useRefs(forwardedRef, ref);\n const currentUserId = useCurrentUserId();\n const deleteComment = useDeleteComment();\n const editComment = useEditComment();\n const addReaction = useAddReaction();\n const removeReaction = useRemoveReaction();\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\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 ({ body }: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\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 event.preventDefault();\n setEditing(false);\n editComment({\n commentId: comment.id,\n threadId: comment.threadId,\n body,\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 {isInRoom && autoMarkReadThreadId && (\n <AutoMarkReadThreadIdHandler\n commentRef={ref}\n threadId={autoMarkReadThreadId}\n />\n )}\n <div\n id={comment.id}\n className={classNames(\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={classNames(\n \"lb-comment-actions\",\n additionalActionsClassName\n )}\n >\n {additionalActions ?? null}\n {showReactions && (\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 >\n <EmojiAddIcon className=\"lb-button-icon\" />\n </Button>\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n )}\n {comment.userId === currentUserId && (\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n <DropdownItem\n onSelect={handleEdit}\n onClick={stopPropagation}\n >\n <EditIcon className=\"lb-dropdown-item-icon\" />\n {$.COMMENT_EDIT}\n </DropdownItem>\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n >\n <DeleteIcon className=\"lb-dropdown-item-icon\" />\n {$.COMMENT_DELETE}\n </DropdownItem>\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 >\n <EllipsisIcon className=\"lb-button-icon\" />\n </Button>\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n )}\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 autoFocus\n showAttribution={false}\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 >\n <CrossIcon className=\"lb-button-icon\" />\n </Button>\n </Tooltip>\n <ShortcutTooltip\n content={$.COMMENT_EDIT_COMPOSER_SAVE}\n shortcut={<ShortcutTooltipKey name=\"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 >\n <CheckIcon className=\"lb-button-icon\" />\n </Button>\n </ComposerPrimitive.Submit>\n </ShortcutTooltip>\n </>\n }\n overrides={{\n COMPOSER_PLACEHOLDER: $.COMMENT_EDIT_COMPOSER_PLACEHOLDER,\n }}\n />\n ) : comment.body ? (\n <>\n <CommentPrimitive.Body\n className=\"lb-comment-body\"\n body={comment.body}\n components={{\n Mention: ({ userId }) => (\n <CommentMention\n userId={userId}\n onClick={(event) => onMentionClick?.(userId, event)}\n />\n ),\n Link: CommentLink,\n }}\n />\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 />\n ))}\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 >\n <EmojiAddIcon className=\"lb-button-icon\" />\n </Button>\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\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 </TooltipProvider>\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4EA;AAmFO;AAAwB;AAC7B;AACA;AAEF;AACE;AACA;AACG;AACsD;AACd;AACnC;AAGH;AAAK;AAGZ;AAEO;AAAqB;AAC1B;AACA;AACA;AAEF;AACE;AACG;AACmD;AAClD;AACI;AAKV;AAEO;AAAmC;AAClC;AACN;AACA;AAEF;AACE;AACG;AAAuD;AAAO;AAInE;AAEA;AAIE;AACA;AACG;AACuD;AAC9C;AACM;AACH;AACM;AACjB;AACI;AACC;AAEJ;AAAgB;AAA4C;AAC5D;AAAe;AAGtB;AAEa;AAIX;AACA;AACA;AACA;AACE;AAA4D;AAE9D;AACA;AAAuB;AAGd;AACA;AAEI;AAAgB;AAAkB;AAAe;AACnD;AACkB;AACT;AACA;AACZ;AACS;AACM;AAEnB;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;AAKd;AAEa;AAIX;AACA;AACE;AAA4D;AAG9D;AACG;AACc;AACc;AAC3B;AACA;AACI;AACC;AAGX;AAMA;AAAqC;AACnC;AAEF;AAIE;AACA;AAEA;AAAA;AACE;AAEE;AAAyB;AAC3B;AACA;AAEW;AACX;AAGF;AACF;AAYO;AAAgB;AAEnB;AACE;AACgB;AAChB;AACc;AACE;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACE;AAAsB;AAGxB;AACE;AAAe;AAGjB;AAAyB;AAErB;AACA;AAAgB;AAClB;AACC;AAGH;AAAyB;AAGrB;AAEA;AACA;AACA;AAAY;AACS;AACD;AAClB;AACD;AACH;AACoC;AAGtC;AAEE;AAEA;AAAc;AACO;AACD;AACnB;AAGH;AAA0B;AAEtB;AAAqC;AACvC;AAC8B;AAGhC;AAA6B;AAEzB;AAAwC;AACL;AAGnC;AAGyC;AACf;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;AAGO;AACa;AACF;AAGb;AACa;AACD;AACT;AACiB;AACU;AAEzB;AACF;AACF;AACmC;AACJ;AAEF;AACtB;AACH;AACC;AAEJ;AAAc;AACZ;AAAc;AACZ;AACW;AACM;AACP;AAEV;AAAe;AACb;AACW;AACM;AACP;AAEV;AAAe;AACb;AACW;AACI;AACJ;AAKP;AAAe;AASvB;AACY;AACT;AACA;AACF;AAIG;AACgB;AACD;AAEb;AAAmB;AACjB;AAA0B;AACxB;AACW;AACD;AACK;AAEb;AAAuB;AAO/B;AACO;AACQ;AACR;AAGD;AACW;AACD;AAER;AAAmB;AAGrB;AACW;AACD;AAER;AAAqB;AAG1B;AAGD;AAAmB;AACjB;AAAuB;AACrB;AACW;AACS;AACV;AACK;AAEb;AAAuB;AASvC;AAAc;AAEV;AACW;AACQ;AACI;AACb;AACQ;AAGZ;AACY;AACG;AAEb;AACW;AACD;AAER;AAAoB;AAGxB;AACY;AACA;AAAwB;AAAQ;AAE1C;AAAgC;AAC9B;AACS;AACE;AACD;AACK;AAEb;AAAoB;AAI7B;AAES;AACe;AAC1B;AAIC;AACW;AACI;AACF;AAEP;AACC;AACkD;AACpD;AAEI;AACR;AAGC;AAAc;AAEV;AACe;AACd;AACA;AACA;AAGH;AAA2B;AACzB;AAAmB;AACjB;AAA0B;AACxB;AACW;AACF;AACC;AACK;AAEb;AAAuB;AASrC;AAAc;AACZ;AAAY;AAKvB;AAGN;;;;;;;"}
|