@liveblocks/react-ui 2.7.0-beta2 → 2.7.0-versions2

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.
Files changed (142) hide show
  1. package/_private/README.md +5 -0
  2. package/_private/package.json +4 -0
  3. package/dist/_private/index.d.mts +72 -0
  4. package/dist/_private/index.d.ts +72 -0
  5. package/dist/_private/index.js +46 -0
  6. package/dist/_private/index.js.map +1 -0
  7. package/dist/_private/index.mjs +21 -0
  8. package/dist/_private/index.mjs.map +1 -0
  9. package/dist/components/Comment.js +7 -65
  10. package/dist/components/Comment.js.map +1 -1
  11. package/dist/components/Comment.mjs +9 -66
  12. package/dist/components/Comment.mjs.map +1 -1
  13. package/dist/components/Composer.js +101 -217
  14. package/dist/components/Composer.js.map +1 -1
  15. package/dist/components/Composer.mjs +104 -220
  16. package/dist/components/Composer.mjs.map +1 -1
  17. package/dist/components/HistoryVersionSummary.js +42 -0
  18. package/dist/components/HistoryVersionSummary.js.map +1 -0
  19. package/dist/components/HistoryVersionSummary.mjs +40 -0
  20. package/dist/components/HistoryVersionSummary.mjs.map +1 -0
  21. package/dist/components/HistoryVersionSummaryList.js +22 -0
  22. package/dist/components/HistoryVersionSummaryList.js.map +1 -0
  23. package/dist/components/HistoryVersionSummaryList.mjs +20 -0
  24. package/dist/components/HistoryVersionSummaryList.mjs.map +1 -0
  25. package/dist/components/InboxNotification.js +10 -28
  26. package/dist/components/InboxNotification.js.map +1 -1
  27. package/dist/components/InboxNotification.mjs +10 -28
  28. package/dist/components/InboxNotification.mjs.map +1 -1
  29. package/dist/components/Thread.js +0 -2
  30. package/dist/components/Thread.js.map +1 -1
  31. package/dist/components/Thread.mjs +0 -2
  32. package/dist/components/Thread.mjs.map +1 -1
  33. package/dist/components/internal/Button.js +8 -1
  34. package/dist/components/internal/Button.js.map +1 -1
  35. package/dist/components/internal/Button.mjs +8 -1
  36. package/dist/components/internal/Button.mjs.map +1 -1
  37. package/dist/components/internal/EmojiPicker.js +3 -3
  38. package/dist/components/internal/EmojiPicker.js.map +1 -1
  39. package/dist/components/internal/EmojiPicker.mjs +3 -3
  40. package/dist/components/internal/EmojiPicker.mjs.map +1 -1
  41. package/dist/components/internal/InboxNotificationThread.js +2 -10
  42. package/dist/components/internal/InboxNotificationThread.js.map +1 -1
  43. package/dist/components/internal/InboxNotificationThread.mjs +3 -11
  44. package/dist/components/internal/InboxNotificationThread.mjs.map +1 -1
  45. package/dist/components/internal/User.js +3 -19
  46. package/dist/components/internal/User.js.map +1 -1
  47. package/dist/components/internal/User.mjs +3 -19
  48. package/dist/components/internal/User.mjs.map +1 -1
  49. package/dist/icons/ArrowUp.js +15 -0
  50. package/dist/icons/ArrowUp.js.map +1 -0
  51. package/dist/icons/ArrowUp.mjs +13 -0
  52. package/dist/icons/ArrowUp.mjs.map +1 -0
  53. package/dist/icons/{Warning.js → Missing.js} +3 -3
  54. package/dist/icons/{Warning.js.map → Missing.js.map} +1 -1
  55. package/dist/icons/{Warning.mjs → Missing.mjs} +3 -3
  56. package/dist/icons/{Warning.mjs.map → Missing.mjs.map} +1 -1
  57. package/dist/icons/Restore.js +17 -0
  58. package/dist/icons/Restore.js.map +1 -0
  59. package/dist/icons/Restore.mjs +15 -0
  60. package/dist/icons/Restore.mjs.map +1 -0
  61. package/dist/icons/Spinner.js +9 -3
  62. package/dist/icons/Spinner.js.map +1 -1
  63. package/dist/icons/Spinner.mjs +10 -4
  64. package/dist/icons/Spinner.mjs.map +1 -1
  65. package/dist/index.d.mts +74 -70
  66. package/dist/index.d.ts +74 -70
  67. package/dist/index.js +6 -0
  68. package/dist/index.js.map +1 -1
  69. package/dist/index.mjs +3 -0
  70. package/dist/index.mjs.map +1 -1
  71. package/dist/overrides.js +5 -6
  72. package/dist/overrides.js.map +1 -1
  73. package/dist/overrides.mjs +5 -6
  74. package/dist/overrides.mjs.map +1 -1
  75. package/dist/primitives/Composer/contexts.js +3 -17
  76. package/dist/primitives/Composer/contexts.js.map +1 -1
  77. package/dist/primitives/Composer/contexts.mjs +4 -15
  78. package/dist/primitives/Composer/contexts.mjs.map +1 -1
  79. package/dist/primitives/Composer/index.js +26 -185
  80. package/dist/primitives/Composer/index.js.map +1 -1
  81. package/dist/primitives/Composer/index.mjs +31 -188
  82. package/dist/primitives/Composer/index.mjs.map +1 -1
  83. package/dist/primitives/Composer/utils.js +0 -224
  84. package/dist/primitives/Composer/utils.js.map +1 -1
  85. package/dist/primitives/Composer/utils.mjs +1 -222
  86. package/dist/primitives/Composer/utils.mjs.map +1 -1
  87. package/dist/primitives/EmojiPicker/utils.js +2 -2
  88. package/dist/primitives/EmojiPicker/utils.js.map +1 -1
  89. package/dist/primitives/EmojiPicker/utils.mjs +1 -1
  90. package/dist/primitives/EmojiPicker/utils.mjs.map +1 -1
  91. package/dist/primitives/index.d.mts +3 -83
  92. package/dist/primitives/index.d.ts +3 -83
  93. package/dist/primitives/index.js +0 -4
  94. package/dist/primitives/index.js.map +1 -1
  95. package/dist/primitives/index.mjs +0 -2
  96. package/dist/primitives/index.mjs.map +1 -1
  97. package/dist/utils/chunk.js +12 -0
  98. package/dist/utils/chunk.js.map +1 -0
  99. package/dist/utils/chunk.mjs +10 -0
  100. package/dist/utils/chunk.mjs.map +1 -0
  101. package/dist/utils/intl.js +0 -6
  102. package/dist/utils/intl.js.map +1 -1
  103. package/dist/utils/intl.mjs +1 -6
  104. package/dist/utils/intl.mjs.map +1 -1
  105. package/dist/utils/use-initial.js +1 -2
  106. package/dist/utils/use-initial.js.map +1 -1
  107. package/dist/utils/use-initial.mjs +2 -3
  108. package/dist/utils/use-initial.mjs.map +1 -1
  109. package/dist/version.js +1 -1
  110. package/dist/version.js.map +1 -1
  111. package/dist/version.mjs +1 -1
  112. package/dist/version.mjs.map +1 -1
  113. package/package.json +16 -4
  114. package/src/styles/dark/index.css +0 -1
  115. package/src/styles/index.css +219 -325
  116. package/src/styles/utils.css +6 -44
  117. package/styles/dark/attributes.css +1 -1
  118. package/styles/dark/attributes.css.map +1 -1
  119. package/styles/dark/media-query.css +1 -1
  120. package/styles/dark/media-query.css.map +1 -1
  121. package/styles.css +1 -1
  122. package/styles.css.map +1 -1
  123. package/dist/components/internal/Attachment.js +0 -207
  124. package/dist/components/internal/Attachment.js.map +0 -1
  125. package/dist/components/internal/Attachment.mjs +0 -205
  126. package/dist/components/internal/Attachment.mjs.map +0 -1
  127. package/dist/icons/Attachment.js +0 -15
  128. package/dist/icons/Attachment.js.map +0 -1
  129. package/dist/icons/Attachment.mjs +0 -13
  130. package/dist/icons/Attachment.mjs.map +0 -1
  131. package/dist/primitives/FileSize.js +0 -33
  132. package/dist/primitives/FileSize.js.map +0 -1
  133. package/dist/primitives/FileSize.mjs +0 -31
  134. package/dist/primitives/FileSize.mjs.map +0 -1
  135. package/dist/utils/download.js +0 -14
  136. package/dist/utils/download.js.map +0 -1
  137. package/dist/utils/download.mjs +0 -12
  138. package/dist/utils/download.mjs.map +0 -1
  139. package/dist/utils/format-file-size.js +0 -45
  140. package/dist/utils/format-file-size.js.map +0 -1
  141. package/dist/utils/format-file-size.mjs +0 -43
  142. 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,4 @@
1
+ {
2
+ "main": "../dist/_private/index.js",
3
+ "types": "../dist/_private/index.d.ts"
4
+ }
@@ -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, index) => /* @__PURE__ */ React.createElement(User.User, {
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, attachments }, event) => {
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
- }), showAttachments && comment.attachments.length > 0 ? /* @__PURE__ */ React.createElement("div", {
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;;;;;;;"}