@liveblocks/react-ui 2.25.0-aiprivatebeta9 → 3.1.0-alpha1
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/package.json +2 -2
- package/dist/_private/index.cjs +8 -0
- package/dist/_private/index.cjs.map +1 -1
- package/dist/_private/index.d.cts +22 -5
- package/dist/_private/index.d.ts +22 -5
- package/dist/_private/index.js +4 -0
- package/dist/_private/index.js.map +1 -1
- package/dist/components/AiChat.cjs +17 -21
- package/dist/components/AiChat.cjs.map +1 -1
- package/dist/components/AiChat.js +18 -22
- package/dist/components/AiChat.js.map +1 -1
- package/dist/components/AiTool.cjs +61 -35
- package/dist/components/AiTool.cjs.map +1 -1
- package/dist/components/AiTool.js +62 -36
- package/dist/components/AiTool.js.map +1 -1
- package/dist/components/Comment.cjs +261 -242
- package/dist/components/Comment.cjs.map +1 -1
- package/dist/components/Comment.js +262 -243
- package/dist/components/Comment.js.map +1 -1
- package/dist/components/Composer.cjs +49 -40
- package/dist/components/Composer.cjs.map +1 -1
- package/dist/components/Composer.js +51 -42
- package/dist/components/Composer.js.map +1 -1
- package/dist/components/HistoryVersionSummary.cjs +2 -2
- package/dist/components/HistoryVersionSummary.cjs.map +1 -1
- package/dist/components/HistoryVersionSummary.js +2 -2
- package/dist/components/HistoryVersionSummary.js.map +1 -1
- package/dist/components/HistoryVersionSummaryList.cjs +2 -5
- package/dist/components/HistoryVersionSummaryList.cjs.map +1 -1
- package/dist/components/HistoryVersionSummaryList.js +2 -5
- package/dist/components/HistoryVersionSummaryList.js.map +1 -1
- package/dist/components/InboxNotification.cjs +4 -4
- package/dist/components/InboxNotification.cjs.map +1 -1
- package/dist/components/InboxNotification.js +4 -4
- package/dist/components/InboxNotification.js.map +1 -1
- package/dist/components/InboxNotificationList.cjs +2 -2
- package/dist/components/InboxNotificationList.cjs.map +1 -1
- package/dist/components/InboxNotificationList.js +2 -2
- package/dist/components/InboxNotificationList.js.map +1 -1
- package/dist/components/Thread.cjs +9 -3
- package/dist/components/Thread.cjs.map +1 -1
- package/dist/components/Thread.js +10 -4
- package/dist/components/Thread.js.map +1 -1
- package/dist/components/internal/AiChatAssistantMessage.cjs +47 -10
- package/dist/components/internal/AiChatAssistantMessage.cjs.map +1 -1
- package/dist/components/internal/AiChatAssistantMessage.js +49 -12
- package/dist/components/internal/AiChatAssistantMessage.js.map +1 -1
- package/dist/components/internal/AiChatComposer.cjs +2 -2
- package/dist/components/internal/AiChatComposer.cjs.map +1 -1
- package/dist/components/internal/AiChatComposer.js +2 -2
- package/dist/components/internal/AiChatComposer.js.map +1 -1
- package/dist/components/internal/AiChatUserMessage.cjs +2 -2
- package/dist/components/internal/AiChatUserMessage.cjs.map +1 -1
- package/dist/components/internal/AiChatUserMessage.js +2 -2
- package/dist/components/internal/AiChatUserMessage.js.map +1 -1
- package/dist/components/internal/Attachment.cjs +3 -3
- package/dist/components/internal/Attachment.cjs.map +1 -1
- package/dist/components/internal/Attachment.js +3 -3
- package/dist/components/internal/Attachment.js.map +1 -1
- package/dist/components/internal/Attribution.cjs +2 -2
- package/dist/components/internal/Attribution.cjs.map +1 -1
- package/dist/components/internal/Attribution.js +2 -2
- package/dist/components/internal/Attribution.js.map +1 -1
- package/dist/components/internal/Avatar.cjs +2 -2
- package/dist/components/internal/Avatar.cjs.map +1 -1
- package/dist/components/internal/Avatar.js +2 -2
- package/dist/components/internal/Avatar.js.map +1 -1
- package/dist/components/internal/Button.cjs +3 -3
- package/dist/components/internal/Button.cjs.map +1 -1
- package/dist/components/internal/Button.js +3 -3
- package/dist/components/internal/Button.js.map +1 -1
- package/dist/components/internal/CodeBlock.cjs +6 -3
- package/dist/components/internal/CodeBlock.cjs.map +1 -1
- package/dist/components/internal/CodeBlock.js +6 -3
- package/dist/components/internal/CodeBlock.js.map +1 -1
- package/dist/components/internal/Dropdown.cjs +4 -4
- package/dist/components/internal/Dropdown.cjs.map +1 -1
- package/dist/components/internal/Dropdown.js +5 -5
- package/dist/components/internal/Dropdown.js.map +1 -1
- package/dist/components/internal/Emoji.cjs +2 -2
- package/dist/components/internal/Emoji.cjs.map +1 -1
- package/dist/components/internal/Emoji.js +2 -2
- package/dist/components/internal/Emoji.js.map +1 -1
- package/dist/components/internal/EmojiPicker.cjs +6 -6
- package/dist/components/internal/EmojiPicker.cjs.map +1 -1
- package/dist/components/internal/EmojiPicker.js +7 -7
- package/dist/components/internal/EmojiPicker.js.map +1 -1
- package/dist/components/internal/Icon.cjs +2 -2
- package/dist/components/internal/Icon.cjs.map +1 -1
- package/dist/components/internal/Icon.js +2 -2
- package/dist/components/internal/Icon.js.map +1 -1
- package/dist/components/internal/InboxNotificationThread.cjs +7 -4
- package/dist/components/internal/InboxNotificationThread.cjs.map +1 -1
- package/dist/components/internal/InboxNotificationThread.js +8 -5
- package/dist/components/internal/InboxNotificationThread.js.map +1 -1
- package/dist/components/internal/List.cjs +2 -2
- package/dist/components/internal/List.cjs.map +1 -1
- package/dist/components/internal/List.js +2 -2
- package/dist/components/internal/List.js.map +1 -1
- package/dist/components/internal/Prose.cjs +2 -2
- package/dist/components/internal/Prose.cjs.map +1 -1
- package/dist/components/internal/Prose.js +2 -2
- package/dist/components/internal/Prose.js.map +1 -1
- package/dist/components/internal/Room.cjs +2 -2
- package/dist/components/internal/Room.cjs.map +1 -1
- package/dist/components/internal/Room.js +2 -2
- package/dist/components/internal/Room.js.map +1 -1
- package/dist/components/internal/Tooltip.cjs +3 -3
- package/dist/components/internal/Tooltip.cjs.map +1 -1
- package/dist/components/internal/Tooltip.js +4 -4
- package/dist/components/internal/Tooltip.js.map +1 -1
- package/dist/components/internal/User.cjs +2 -2
- package/dist/components/internal/User.cjs.map +1 -1
- package/dist/components/internal/User.js +2 -2
- package/dist/components/internal/User.js.map +1 -1
- package/dist/config.cjs +9 -9
- package/dist/config.cjs.map +1 -1
- package/dist/config.js +8 -8
- package/dist/config.js.map +1 -1
- package/dist/icons/CrossCircleFill.cjs +25 -0
- package/dist/icons/CrossCircleFill.cjs.map +1 -0
- package/dist/icons/CrossCircleFill.js +23 -0
- package/dist/icons/CrossCircleFill.js.map +1 -0
- package/dist/icons/MinusCircle.cjs +23 -0
- package/dist/icons/MinusCircle.cjs.map +1 -0
- package/dist/icons/MinusCircle.js +21 -0
- package/dist/icons/MinusCircle.js.map +1 -0
- package/dist/icons/index.cjs +4 -0
- package/dist/icons/index.cjs.map +1 -1
- package/dist/icons/index.js +2 -0
- package/dist/icons/index.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +238 -25
- package/dist/index.d.ts +238 -25
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/overrides.cjs +5 -1
- package/dist/overrides.cjs.map +1 -1
- package/dist/overrides.js +5 -1
- package/dist/overrides.js.map +1 -1
- package/dist/primitives/AiMessage/index.cjs +11 -67
- package/dist/primitives/AiMessage/index.cjs.map +1 -1
- package/dist/primitives/AiMessage/index.js +13 -69
- package/dist/primitives/AiMessage/index.js.map +1 -1
- package/dist/primitives/AiMessage/tool-invocation.cjs +70 -0
- package/dist/primitives/AiMessage/tool-invocation.cjs.map +1 -0
- package/dist/primitives/AiMessage/tool-invocation.js +68 -0
- package/dist/primitives/AiMessage/tool-invocation.js.map +1 -0
- package/dist/primitives/Collapsible/index.cjs +3 -3
- package/dist/primitives/Collapsible/index.cjs.map +1 -1
- package/dist/primitives/Collapsible/index.js +3 -3
- package/dist/primitives/Collapsible/index.js.map +1 -1
- package/dist/primitives/Comment/index.cjs +5 -4
- package/dist/primitives/Comment/index.cjs.map +1 -1
- package/dist/primitives/Comment/index.js +5 -4
- package/dist/primitives/Comment/index.js.map +1 -1
- package/dist/primitives/Composer/index.cjs +49 -41
- package/dist/primitives/Composer/index.cjs.map +1 -1
- package/dist/primitives/Composer/index.js +50 -42
- package/dist/primitives/Composer/index.js.map +1 -1
- package/dist/primitives/Composer/slate/plugins/mentions.cjs +4 -4
- package/dist/primitives/Composer/slate/plugins/mentions.cjs.map +1 -1
- package/dist/primitives/Composer/slate/plugins/mentions.js +4 -4
- package/dist/primitives/Composer/slate/plugins/mentions.js.map +1 -1
- package/dist/primitives/Composer/utils.cjs +3 -6
- package/dist/primitives/Composer/utils.cjs.map +1 -1
- package/dist/primitives/Composer/utils.js +3 -6
- package/dist/primitives/Composer/utils.js.map +1 -1
- package/dist/primitives/Markdown.cjs +6 -2
- package/dist/primitives/Markdown.cjs.map +1 -1
- package/dist/primitives/Markdown.js +6 -2
- package/dist/primitives/Markdown.js.map +1 -1
- package/dist/primitives/index.d.cts +18 -18
- package/dist/primitives/index.d.ts +18 -18
- package/dist/utils/{class-names.cjs → cn.cjs} +3 -3
- package/dist/utils/cn.cjs.map +1 -0
- package/dist/utils/{class-names.js → cn.js} +3 -3
- package/dist/utils/cn.js.map +1 -0
- package/dist/utils/use-controllable-state.cjs +25 -2
- package/dist/utils/use-controllable-state.cjs.map +1 -1
- package/dist/utils/use-controllable-state.js +25 -3
- package/dist/utils/use-controllable-state.js.map +1 -1
- package/dist/utils/use-visible.cjs +3 -1
- package/dist/utils/use-visible.cjs.map +1 -1
- package/dist/utils/use-visible.js +3 -1
- package/dist/utils/use-visible.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +16 -5
- package/primitives/package.json +2 -2
- package/src/styles/index.css +26 -7
- package/styles.css +1 -1
- package/styles.css.map +1 -1
- package/dist/utils/class-names.cjs.map +0 -1
- package/dist/utils/class-names.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import { Permission } from '@liveblocks/core';
|
|
3
|
+
import { assertNever, Permission } from '@liveblocks/core';
|
|
4
4
|
import { useRoom } from '@liveblocks/react';
|
|
5
5
|
import { useLayoutEffect, useCreateRoomThread, useCreateRoomComment, useEditRoomComment, useResolveMentionSuggestions, useRoomPermissions } from '@liveblocks/react/_private';
|
|
6
6
|
import { useCallback, useMemo, createContext, forwardRef, useRef, useSyncExternalStore } from 'react';
|
|
7
|
-
import {
|
|
7
|
+
import { useLiveblocksUiConfig } from '../config.js';
|
|
8
8
|
import { MENTION_CHARACTER, FLOATING_ELEMENT_SIDE_OFFSET } from '../constants.js';
|
|
9
9
|
import { AttachmentIcon } from '../icons/Attachment.js';
|
|
10
10
|
import { BoldIcon } from '../icons/Bold.js';
|
|
@@ -18,7 +18,7 @@ import { useOverrides } from '../overrides.js';
|
|
|
18
18
|
import { AttachFiles as ComposerAttachFiles, Mention as ComposerMention$1, Suggestions as ComposerSuggestions, SuggestionsList as ComposerSuggestionsList, SuggestionsListItem as ComposerSuggestionsListItem, MarkToggle as ComposerMarkToggle, FloatingToolbar as ComposerFloatingToolbar$1, Link as ComposerLink$1, Editor as ComposerEditor, Submit as ComposerSubmit, Form as ComposerForm } from '../primitives/Composer/index.js';
|
|
19
19
|
import { useComposer, useComposerEditorContext, useComposerAttachmentsContext } from '../primitives/Composer/contexts.js';
|
|
20
20
|
import { useComposerAttachmentsDropArea } from '../primitives/Composer/utils.js';
|
|
21
|
-
import {
|
|
21
|
+
import { cn } from '../utils/cn.js';
|
|
22
22
|
import { useControllableState } from '../utils/use-controllable-state.js';
|
|
23
23
|
import { FileAttachment } from './internal/Attachment.js';
|
|
24
24
|
import { Attribution } from './internal/Attribution.js';
|
|
@@ -55,7 +55,7 @@ function ComposerInsertMentionEditorAction({
|
|
|
55
55
|
return /* @__PURE__ */ jsx(Tooltip, {
|
|
56
56
|
content: tooltipLabel ?? label,
|
|
57
57
|
children: /* @__PURE__ */ jsx(Button, {
|
|
58
|
-
className:
|
|
58
|
+
className: cn("lb-composer-editor-action", className),
|
|
59
59
|
onPointerDown: preventDefault,
|
|
60
60
|
onClick: handleClick,
|
|
61
61
|
"aria-label": label,
|
|
@@ -86,7 +86,7 @@ function ComposerInsertEmojiEditorAction({
|
|
|
86
86
|
children: /* @__PURE__ */ jsx(PopoverTrigger, {
|
|
87
87
|
asChild: true,
|
|
88
88
|
children: /* @__PURE__ */ jsx(Button, {
|
|
89
|
-
className:
|
|
89
|
+
className: cn("lb-composer-editor-action", className),
|
|
90
90
|
onPointerDown: preventDefault,
|
|
91
91
|
onClick: stopPropagation,
|
|
92
92
|
"aria-label": label,
|
|
@@ -114,7 +114,7 @@ function ComposerAttachFilesEditorAction({
|
|
|
114
114
|
children: /* @__PURE__ */ jsx(ComposerAttachFiles, {
|
|
115
115
|
asChild: true,
|
|
116
116
|
children: /* @__PURE__ */ jsx(Button, {
|
|
117
|
-
className:
|
|
117
|
+
className: cn("lb-composer-editor-action", className),
|
|
118
118
|
onPointerDown: preventDefault,
|
|
119
119
|
onClick: stopPropagation,
|
|
120
120
|
"aria-label": label,
|
|
@@ -124,38 +124,50 @@ function ComposerAttachFilesEditorAction({
|
|
|
124
124
|
})
|
|
125
125
|
});
|
|
126
126
|
}
|
|
127
|
-
function ComposerMention({
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
127
|
+
function ComposerMention({ mention }) {
|
|
128
|
+
switch (mention.kind) {
|
|
129
|
+
case "user":
|
|
130
|
+
return /* @__PURE__ */ jsxs(ComposerMention$1, {
|
|
131
|
+
className: "lb-composer-mention",
|
|
132
|
+
children: [
|
|
133
|
+
MENTION_CHARACTER,
|
|
134
|
+
/* @__PURE__ */ jsx(User, {
|
|
135
|
+
userId: mention.id
|
|
136
|
+
})
|
|
137
|
+
]
|
|
138
|
+
});
|
|
139
|
+
default:
|
|
140
|
+
return assertNever(mention.kind, "Unhandled mention kind");
|
|
141
|
+
}
|
|
137
142
|
}
|
|
138
143
|
function ComposerMentionSuggestions({
|
|
139
|
-
|
|
144
|
+
mentions
|
|
140
145
|
}) {
|
|
141
|
-
return
|
|
146
|
+
return mentions.length > 0 ? /* @__PURE__ */ jsx(ComposerSuggestions, {
|
|
142
147
|
className: "lb-root lb-portal lb-elevation lb-composer-suggestions lb-composer-mention-suggestions",
|
|
143
148
|
children: /* @__PURE__ */ jsx(ComposerSuggestionsList, {
|
|
144
149
|
className: "lb-composer-suggestions-list lb-composer-mention-suggestions-list",
|
|
145
|
-
children:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
150
|
+
children: mentions.map((mention) => {
|
|
151
|
+
switch (mention.kind) {
|
|
152
|
+
case "user":
|
|
153
|
+
return /* @__PURE__ */ jsxs(ComposerSuggestionsListItem, {
|
|
154
|
+
className: "lb-composer-suggestions-list-item lb-composer-mention-suggestion",
|
|
155
|
+
value: mention.id,
|
|
156
|
+
children: [
|
|
157
|
+
/* @__PURE__ */ jsx(Avatar, {
|
|
158
|
+
userId: mention.id,
|
|
159
|
+
className: "lb-composer-mention-suggestion-avatar"
|
|
160
|
+
}),
|
|
161
|
+
/* @__PURE__ */ jsx(User, {
|
|
162
|
+
userId: mention.id,
|
|
163
|
+
className: "lb-composer-mention-suggestion-user"
|
|
164
|
+
})
|
|
165
|
+
]
|
|
166
|
+
}, mention.id);
|
|
167
|
+
default:
|
|
168
|
+
return assertNever(mention.kind, "Unhandled mention kind");
|
|
169
|
+
}
|
|
170
|
+
})
|
|
159
171
|
})
|
|
160
172
|
}) : null;
|
|
161
173
|
}
|
|
@@ -235,7 +247,7 @@ function ComposerFileAttachment({
|
|
|
235
247
|
removeAttachment(attachment.id);
|
|
236
248
|
}, [attachment.id, removeAttachment]);
|
|
237
249
|
return /* @__PURE__ */ jsx(FileAttachment, {
|
|
238
|
-
className:
|
|
250
|
+
className: cn("lb-composer-attachment", className),
|
|
239
251
|
...props,
|
|
240
252
|
attachment,
|
|
241
253
|
onDeleteClick: handleDeleteClick,
|
|
@@ -254,7 +266,7 @@ function ComposerAttachments({
|
|
|
254
266
|
return null;
|
|
255
267
|
}
|
|
256
268
|
return /* @__PURE__ */ jsx("div", {
|
|
257
|
-
className:
|
|
269
|
+
className: cn("lb-composer-attachments", className),
|
|
258
270
|
...props,
|
|
259
271
|
children: /* @__PURE__ */ jsx("div", {
|
|
260
272
|
className: "lb-attachments",
|
|
@@ -417,15 +429,15 @@ const Composer = forwardRef(
|
|
|
417
429
|
const createThread = useCreateRoomThread(roomId);
|
|
418
430
|
const createComment = useCreateRoomComment(roomId);
|
|
419
431
|
const editComment = useEditRoomComment(roomId);
|
|
420
|
-
const { preventUnsavedComposerChanges } =
|
|
432
|
+
const { preventUnsavedComposerChanges } = useLiveblocksUiConfig();
|
|
421
433
|
const hasResolveMentionSuggestions = useResolveMentionSuggestions() !== void 0;
|
|
422
434
|
const isEmptyRef = useRef(true);
|
|
423
435
|
const isEmojiPickerOpenRef = useRef(false);
|
|
424
436
|
const $ = useOverrides(overrides);
|
|
425
437
|
const [isCollapsed, onCollapsedChange] = useControllableState(
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
438
|
+
defaultCollapsed ?? false,
|
|
439
|
+
controlledCollapsed,
|
|
440
|
+
controlledOnCollapsedChange
|
|
429
441
|
);
|
|
430
442
|
const canCommentFallback = useSyncExternalStore(
|
|
431
443
|
useCallback(
|
|
@@ -527,10 +539,7 @@ const Composer = forwardRef(
|
|
|
527
539
|
return /* @__PURE__ */ jsx(TooltipProvider, {
|
|
528
540
|
children: /* @__PURE__ */ jsx(ComposerForm, {
|
|
529
541
|
onComposerSubmit: handleComposerSubmit,
|
|
530
|
-
className:
|
|
531
|
-
"lb-root lb-composer lb-composer-form",
|
|
532
|
-
className
|
|
533
|
-
),
|
|
542
|
+
className: cn("lb-root lb-composer lb-composer-form", className),
|
|
534
543
|
dir: $.dir,
|
|
535
544
|
...props,
|
|
536
545
|
ref: forwardedRef,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Composer.js","sources":["../../src/components/Composer.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n BaseMetadata,\n CommentAttachment,\n CommentMixedAttachment,\n DM,\n} from \"@liveblocks/core\";\nimport { Permission } from \"@liveblocks/core\";\nimport { useRoom } from \"@liveblocks/react\";\nimport {\n useCreateRoomComment,\n useCreateRoomThread,\n useEditRoomComment,\n useLayoutEffect,\n useResolveMentionSuggestions,\n useRoomPermissions,\n} from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n ComponentType,\n FocusEvent,\n FormEvent,\n ForwardedRef,\n MouseEvent,\n PropsWithChildren,\n ReactNode,\n RefAttributes,\n SyntheticEvent,\n} from \"react\";\nimport {\n createContext,\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\n\nimport { useLiveblocksUIConfig } from \"../config\";\nimport { FLOATING_ELEMENT_SIDE_OFFSET, MENTION_CHARACTER } from \"../constants\";\nimport { AttachmentIcon } from \"../icons/Attachment\";\nimport { BoldIcon } from \"../icons/Bold\";\nimport { CodeIcon } from \"../icons/Code\";\nimport { EmojiIcon } from \"../icons/Emoji\";\nimport { ItalicIcon } from \"../icons/Italic\";\nimport { MentionIcon } from \"../icons/Mention\";\nimport { SendIcon } from \"../icons/Send\";\nimport { StrikethroughIcon } from \"../icons/Strikethrough\";\nimport type { ComposerOverrides, GlobalOverrides } from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport * as ComposerPrimitive from \"../primitives/Composer\";\nimport {\n useComposer,\n useComposerAttachmentsContext,\n useComposerEditorContext,\n} from \"../primitives/Composer/contexts\";\nimport type {\n ComposerEditorComponents,\n ComposerEditorLinkProps,\n ComposerEditorMentionProps,\n ComposerEditorMentionSuggestionsProps,\n ComposerEditorProps,\n ComposerFormProps,\n ComposerMarkToggleProps,\n ComposerSubmitComment,\n} from \"../primitives/Composer/types\";\nimport { useComposerAttachmentsDropArea } from \"../primitives/Composer/utils\";\nimport type { ComposerBodyMark } from \"../types\";\nimport { classNames } from \"../utils/class-names\";\nimport { useControllableState } from \"../utils/use-controllable-state\";\nimport { FileAttachment } from \"./internal/Attachment\";\nimport { Attribution } from \"./internal/Attribution\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport type { EmojiPickerProps } from \"./internal/EmojiPicker\";\nimport { EmojiPicker, EmojiPickerTrigger } from \"./internal/EmojiPicker\";\nimport { ShortcutTooltip, Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ninterface EditorActionProps extends ComponentPropsWithoutRef<\"button\"> {\n label: string;\n tooltipLabel?: string;\n}\n\ninterface EmojiEditorActionProps extends EditorActionProps {\n onPickerOpenChange?: EmojiPickerProps[\"onOpenChange\"];\n}\n\ninterface MarkToggleProps extends ComposerMarkToggleProps {\n icon?: ReactNode;\n shortcut?: string;\n}\n\ntype ComposerCreateThreadProps<M extends BaseMetadata> = {\n threadId?: never;\n commentId?: never;\n\n /**\n * The metadata of the thread to create.\n */\n metadata?: M;\n};\n\ntype ComposerCreateCommentProps = {\n /**\n * The ID of the thread to reply to.\n */\n threadId: string;\n commentId?: never;\n metadata?: never;\n};\n\ntype ComposerEditCommentProps = {\n /**\n * The ID of the thread to edit a comment in.\n */\n threadId: string;\n\n /**\n * The ID of the comment to edit.\n */\n commentId: string;\n metadata?: never;\n};\n\nexport type ComposerProps<M extends BaseMetadata = DM> = Omit<\n ComponentPropsWithoutRef<\"form\">,\n \"defaultValue\"\n> &\n (\n | ComposerCreateThreadProps<M>\n | ComposerCreateCommentProps\n | ComposerEditCommentProps\n ) & {\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: (\n comment: ComposerSubmitComment,\n event: FormEvent<HTMLFormElement>\n ) => Promise<void> | void;\n\n /**\n * The composer's initial value.\n */\n defaultValue?: ComposerEditorProps[\"defaultValue\"];\n\n /**\n * The composer's initial attachments.\n */\n defaultAttachments?: CommentAttachment[];\n\n /**\n * Whether the composer is collapsed. Setting a value will make the composer controlled.\n */\n collapsed?: boolean;\n\n /**\n * The event handler called when the collapsed state of the composer changes.\n */\n onCollapsedChange?: (collapsed: boolean) => void;\n\n /**\n * Whether the composer is initially collapsed. Setting a value will make the composer uncontrolled.\n */\n defaultCollapsed?: boolean;\n\n /**\n * Whether to show and allow adding attachments.\n */\n showAttachments?: boolean;\n\n /**\n * Whether to show formatting controls (e.g. a floating toolbar with formatting toggles when selecting text)\n */\n showFormattingControls?: boolean;\n\n /**\n * Whether the composer is disabled.\n */\n disabled?: ComposerFormProps[\"disabled\"];\n\n /**\n * Whether to focus the composer on mount.\n */\n autoFocus?: ComposerEditorProps[\"autoFocus\"];\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n\n /**\n * @internal\n */\n actions?: ReactNode;\n\n /**\n * @internal\n */\n showAttribution?: boolean;\n\n /**\n * @internal\n */\n roomId?: string;\n };\n\ninterface ComposerEditorContainerProps\n extends Pick<\n ComposerProps,\n | \"defaultValue\"\n | \"showAttachments\"\n | \"showFormattingControls\"\n | \"showAttribution\"\n | \"overrides\"\n | \"actions\"\n | \"autoFocus\"\n | \"disabled\"\n > {\n isCollapsed: boolean | undefined;\n onEmptyChange: (isEmpty: boolean) => void;\n hasResolveMentionSuggestions: boolean;\n onEmojiPickerOpenChange: (isOpen: boolean) => void;\n onEditorClick: (event: MouseEvent<HTMLDivElement>) => void;\n}\n\nfunction ComposerInsertMentionEditorAction({\n label,\n tooltipLabel,\n className,\n onClick,\n ...props\n}: EditorActionProps) {\n const { createMention } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.isDefaultPrevented()) {\n event.stopPropagation();\n createMention();\n }\n },\n [createMention, onClick]\n );\n\n return (\n <Tooltip content={tooltipLabel ?? label}>\n <Button\n className={classNames(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={handleClick}\n aria-label={label}\n icon={<MentionIcon />}\n {...props}\n />\n </Tooltip>\n );\n}\n\nfunction ComposerInsertEmojiEditorAction({\n label,\n tooltipLabel,\n onPickerOpenChange,\n className,\n ...props\n}: EmojiEditorActionProps) {\n const { insertText } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <EmojiPicker onEmojiSelect={insertText} onOpenChange={onPickerOpenChange}>\n <Tooltip content={tooltipLabel ?? label}>\n <EmojiPickerTrigger asChild>\n <Button\n className={classNames(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n aria-label={label}\n icon={<EmojiIcon />}\n {...props}\n />\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n );\n}\n\nfunction ComposerAttachFilesEditorAction({\n label,\n tooltipLabel,\n className,\n ...props\n}: EditorActionProps) {\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <Tooltip content={tooltipLabel ?? label}>\n <ComposerPrimitive.AttachFiles asChild>\n <Button\n className={classNames(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n aria-label={label}\n icon={<AttachmentIcon />}\n {...props}\n />\n </ComposerPrimitive.AttachFiles>\n </Tooltip>\n );\n}\n\nfunction ComposerMention({ userId }: ComposerEditorMentionProps) {\n return (\n <ComposerPrimitive.Mention className=\"lb-composer-mention\">\n {MENTION_CHARACTER}\n <User userId={userId} />\n </ComposerPrimitive.Mention>\n );\n}\n\nfunction ComposerMentionSuggestions({\n userIds,\n}: ComposerEditorMentionSuggestionsProps) {\n return userIds.length > 0 ? (\n <ComposerPrimitive.Suggestions className=\"lb-root lb-portal lb-elevation lb-composer-suggestions lb-composer-mention-suggestions\">\n <ComposerPrimitive.SuggestionsList className=\"lb-composer-suggestions-list lb-composer-mention-suggestions-list\">\n {userIds.map((userId) => (\n <ComposerPrimitive.SuggestionsListItem\n key={userId}\n className=\"lb-composer-suggestions-list-item lb-composer-mention-suggestion\"\n value={userId}\n >\n <Avatar\n userId={userId}\n className=\"lb-composer-mention-suggestion-avatar\"\n />\n <User\n userId={userId}\n className=\"lb-composer-mention-suggestion-user\"\n />\n </ComposerPrimitive.SuggestionsListItem>\n ))}\n </ComposerPrimitive.SuggestionsList>\n </ComposerPrimitive.Suggestions>\n ) : null;\n}\n\nfunction MarkToggle({\n mark,\n icon,\n shortcut,\n children,\n ...props\n}: MarkToggleProps) {\n const $ = useOverrides();\n const label = useMemo(() => {\n return $.COMPOSER_TOGGLE_MARK(mark);\n }, [$, mark]);\n\n return (\n <ShortcutTooltip\n content={label}\n shortcut={shortcut}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET + 2}\n >\n <ComposerPrimitive.MarkToggle mark={mark} asChild {...props}>\n <Button aria-label={label} variant=\"toolbar\" icon={icon}>\n {children}\n </Button>\n </ComposerPrimitive.MarkToggle>\n </ShortcutTooltip>\n );\n}\n\ntype MarkToggles = {\n [K in ComposerBodyMark]: ComponentType<PropsWithChildren>;\n};\n\nconst markToggles: MarkToggles = {\n bold: () => <MarkToggle mark=\"bold\" shortcut=\"Mod-B\" icon={<BoldIcon />} />,\n italic: () => (\n <MarkToggle mark=\"italic\" shortcut=\"Mod-I\" icon={<ItalicIcon />} />\n ),\n strikethrough: () => (\n <MarkToggle\n mark=\"strikethrough\"\n shortcut=\"Mod-Shift-S\"\n icon={<StrikethroughIcon />}\n />\n ),\n code: () => <MarkToggle mark=\"code\" shortcut=\"Mod-E\" icon={<CodeIcon />} />,\n};\n\nconst markTogglesList = Object.entries(markToggles).map(([mark, Toggle]) => (\n <Toggle key={mark} />\n));\n\nfunction ComposerFloatingToolbar() {\n return (\n <ComposerPrimitive.FloatingToolbar className=\"lb-root lb-portal lb-elevation lb-composer-floating-toolbar\">\n {markTogglesList}\n </ComposerPrimitive.FloatingToolbar>\n );\n}\n\nfunction ComposerLink({ href, children }: ComposerEditorLinkProps) {\n return (\n <ComposerPrimitive.Link href={href} className=\"lb-composer-link\">\n {children}\n </ComposerPrimitive.Link>\n );\n}\n\ninterface ComposerAttachmentsProps extends ComponentPropsWithoutRef<\"div\"> {\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n}\n\ninterface ComposerFileAttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n}\n\nfunction ComposerFileAttachment({\n attachment,\n className,\n overrides,\n ...props\n}: ComposerFileAttachmentProps) {\n const { removeAttachment } = useComposer();\n const { roomId } = useComposerEditorContext();\n\n const handleDeleteClick = useCallback(() => {\n removeAttachment(attachment.id);\n }, [attachment.id, removeAttachment]);\n\n return (\n <FileAttachment\n className={classNames(\"lb-composer-attachment\", className)}\n {...props}\n attachment={attachment}\n onDeleteClick={handleDeleteClick}\n preventFocusOnDelete\n overrides={overrides}\n roomId={roomId}\n />\n );\n}\n\nfunction ComposerAttachments({\n overrides,\n className,\n ...props\n}: ComposerAttachmentsProps) {\n const { attachments } = useComposer();\n\n if (attachments.length === 0) {\n return null;\n }\n\n return (\n <div\n className={classNames(\"lb-composer-attachments\", className)}\n {...props}\n >\n <div className=\"lb-attachments\">\n {attachments.map((attachment) => {\n return (\n <ComposerFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n />\n );\n })}\n </div>\n </div>\n );\n}\n\nconst editorRequiredComponents: ComposerEditorComponents = {\n Mention: ComposerMention,\n MentionSuggestions: ComposerMentionSuggestions,\n Link: ComposerLink,\n};\n\nfunction ComposerEditorContainer({\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n defaultValue,\n isCollapsed,\n overrides,\n actions,\n autoFocus,\n disabled,\n hasResolveMentionSuggestions,\n onEmojiPickerOpenChange,\n onEmptyChange,\n onEditorClick,\n}: ComposerEditorContainerProps) {\n const { isEmpty } = useComposer();\n const { hasMaxAttachments } = useComposerAttachmentsContext();\n const $ = useOverrides(overrides);\n const components = useMemo(() => {\n return {\n ...editorRequiredComponents,\n FloatingToolbar: showFormattingControls\n ? ComposerFloatingToolbar\n : undefined,\n };\n }, [showFormattingControls]);\n\n const [isDraggingOver, dropAreaProps] = useComposerAttachmentsDropArea({\n disabled: disabled || hasMaxAttachments,\n });\n\n useLayoutEffect(() => {\n onEmptyChange(isEmpty);\n }, [isEmpty, onEmptyChange]);\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <div className=\"lb-composer-editor-container\" {...dropAreaProps}>\n <ComposerPrimitive.Editor\n className=\"lb-composer-editor\"\n onClick={onEditorClick}\n placeholder={$.COMPOSER_PLACEHOLDER}\n defaultValue={defaultValue}\n autoFocus={autoFocus}\n components={components}\n disabled={disabled}\n dir={$.dir}\n />\n {showAttachments && <ComposerAttachments overrides={overrides} />}\n {(!isCollapsed || isDraggingOver) && (\n <div className=\"lb-composer-footer\">\n <div className=\"lb-composer-editor-actions\">\n {hasResolveMentionSuggestions && (\n <ComposerInsertMentionEditorAction\n label={$.COMPOSER_INSERT_MENTION}\n disabled={disabled}\n />\n )}\n <ComposerInsertEmojiEditorAction\n label={$.COMPOSER_INSERT_EMOJI}\n onPickerOpenChange={onEmojiPickerOpenChange}\n disabled={disabled}\n />\n {showAttachments && (\n <ComposerAttachFilesEditorAction\n label={$.COMPOSER_ATTACH_FILES}\n disabled={disabled}\n />\n )}\n </div>\n {showAttribution && <Attribution />}\n <div className=\"lb-composer-actions\">\n {actions ?? (\n <>\n <ShortcutTooltip content={$.COMPOSER_SEND} shortcut=\"Enter\">\n <ComposerPrimitive.Submit asChild>\n <Button\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n className=\"lb-composer-action\"\n variant=\"primary\"\n aria-label={$.COMPOSER_SEND}\n icon={<SendIcon />}\n />\n </ComposerPrimitive.Submit>\n </ShortcutTooltip>\n </>\n )}\n </div>\n </div>\n )}\n {showAttachments && isDraggingOver && (\n <div className=\"lb-composer-attachments-drop-area\">\n <div className=\"lb-composer-attachments-drop-area-label\">\n <AttachmentIcon />\n {$.COMPOSER_ATTACH_FILES}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const ComposerRoomIdContext = createContext<string | null>(null);\n\n/**\n * Displays a composer to create comments.\n *\n * @example\n * <Composer />\n */\nexport const Composer = forwardRef(\n <M extends BaseMetadata = DM>(\n {\n threadId,\n commentId,\n metadata,\n defaultValue,\n defaultAttachments,\n onComposerSubmit,\n collapsed: controlledCollapsed,\n defaultCollapsed,\n onCollapsedChange: controlledOnCollapsedChange,\n overrides,\n actions,\n onBlur,\n className,\n onFocus,\n autoFocus,\n disabled,\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n roomId: _roomId,\n ...props\n }: ComposerProps<M>,\n forwardedRef: ForwardedRef<HTMLFormElement>\n ) => {\n const room = useRoom({ allowOutsideRoom: true });\n\n const roomId = _roomId !== undefined ? _roomId : room?.id;\n if (roomId === undefined) {\n throw new Error(\n \"Composer must be a descendant of RoomProvider component\"\n );\n }\n\n const createThread = useCreateRoomThread(roomId);\n const createComment = useCreateRoomComment(roomId);\n const editComment = useEditRoomComment(roomId);\n const { preventUnsavedComposerChanges } = useLiveblocksUIConfig();\n const hasResolveMentionSuggestions =\n useResolveMentionSuggestions() !== undefined;\n const isEmptyRef = useRef(true);\n const isEmojiPickerOpenRef = useRef(false);\n const $ = useOverrides(overrides);\n const [isCollapsed, onCollapsedChange] = useControllableState(\n // If the composer is neither controlled nor uncontrolled, it defaults to controlled as uncollapsed.\n controlledCollapsed === undefined && defaultCollapsed === undefined\n ? false\n : controlledCollapsed,\n controlledOnCollapsedChange,\n defaultCollapsed\n );\n\n const canCommentFallback = useSyncExternalStore(\n useCallback(\n (callback) => {\n if (room === null) return () => {};\n return room.events.self.subscribeOnce(callback);\n },\n [room]\n ),\n useCallback(() => {\n return room?.getSelf()?.canComment ?? true;\n }, [room]),\n useCallback(() => true, [])\n );\n\n const permissions = useRoomPermissions(roomId);\n const canComment =\n permissions.size > 0\n ? permissions.has(Permission.CommentsWrite) ||\n permissions.has(Permission.Write)\n : canCommentFallback;\n\n const setEmptyRef = useCallback((isEmpty: boolean) => {\n isEmptyRef.current = isEmpty;\n }, []);\n\n const setEmojiPickerOpenRef = useCallback((isEmojiPickerOpen: boolean) => {\n isEmojiPickerOpenRef.current = isEmojiPickerOpen;\n }, []);\n\n const handleFocus = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onFocus?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n if (isEmptyRef.current && canComment) {\n onCollapsedChange?.(false);\n }\n },\n [onCollapsedChange, onFocus, canComment]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onBlur?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const isOutside = !event.currentTarget.contains(\n event.relatedTarget ?? document.activeElement\n );\n\n if (isOutside && isEmptyRef.current && !isEmojiPickerOpenRef.current) {\n onCollapsedChange?.(true);\n }\n },\n [onBlur, onCollapsedChange]\n );\n\n const handleEditorClick = useCallback(\n (event: MouseEvent<HTMLDivElement>) => {\n event.stopPropagation();\n\n if (isEmptyRef.current && canComment) {\n onCollapsedChange?.(false);\n }\n },\n [onCollapsedChange, canComment]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n event.stopPropagation();\n\n if (commentId && threadId) {\n editComment({\n commentId,\n threadId,\n body: comment.body,\n attachments: comment.attachments,\n });\n } else if (threadId) {\n createComment({\n threadId,\n body: comment.body,\n attachments: comment.attachments,\n });\n } else {\n createThread({\n body: comment.body,\n metadata: metadata ?? {},\n attachments: comment.attachments,\n });\n }\n },\n [\n commentId,\n createComment,\n createThread,\n editComment,\n metadata,\n onComposerSubmit,\n threadId,\n ]\n );\n\n return (\n <TooltipProvider>\n <ComposerPrimitive.Form\n onComposerSubmit={handleComposerSubmit}\n className={classNames(\n \"lb-root lb-composer lb-composer-form\",\n className\n )}\n dir={$.dir}\n {...props}\n ref={forwardedRef}\n data-collapsed={isCollapsed ? \"\" : undefined}\n onFocus={handleFocus}\n onBlur={handleBlur}\n disabled={disabled || !canComment}\n defaultAttachments={defaultAttachments}\n pasteFilesAsAttachments={showAttachments}\n preventUnsavedChanges={preventUnsavedComposerChanges}\n roomId={roomId}\n >\n <ComposerEditorContainer\n defaultValue={defaultValue}\n actions={actions}\n overrides={overrides}\n isCollapsed={isCollapsed}\n showAttachments={showAttachments}\n showAttribution={showAttribution}\n showFormattingControls={showFormattingControls}\n hasResolveMentionSuggestions={hasResolveMentionSuggestions}\n onEmptyChange={setEmptyRef}\n onEmojiPickerOpenChange={setEmojiPickerOpenRef}\n onEditorClick={handleEditorClick}\n autoFocus={autoFocus}\n disabled={disabled}\n />\n </ComposerPrimitive.Form>\n </TooltipProvider>\n );\n }\n) as <M extends BaseMetadata = DM>(\n props: ComposerProps<M> & RefAttributes<HTMLFormElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoOA;AAA2C;AACzC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AAAoB;AAEhB;AAEA;AACE;AACA;AAAc;AAChB;AACF;AACuB;AAGzB;AACG;AAAiC;AAC/B;AAC6D;AAC7C;AACN;AACG;AACO;AACf;AACN;AAGN;AAEA;AAAyC;AACvC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AACG;AAA2B;AAA0B;AACnD;AAAiC;AAC/B;AAA0B;AACxB;AAC6D;AAC7C;AACN;AACG;AACK;AACb;AACN;AACF;AACF;AAGN;AAEA;AAAyC;AACvC;AACA;AACA;AAEF;AACE;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AACG;AAAiC;AAC/B;AAAqC;AACnC;AAC6D;AAC7C;AACN;AACG;AACU;AAClB;AACN;AACF;AAGN;AAEA;AACE;AACG;AAAoC;AAClC;AAAA;AACA;AAAK;AAAgB;AAAA;AAG5B;AAEA;AAAoC;AAEpC;AACE;AACG;AAAwC;AACtC;AAA4C;AAExC;AAEW;AACH;AAEP;AAAC;AACC;AACU;AACZ;AACC;AACC;AACU;AACZ;AAAA;AAEH;AACH;AAGN;AAEA;AAAoB;AAClB;AACA;AACA;AACA;AAEF;AACE;AACA;AACE;AAAkC;AAGpC;AACG;AACU;AACT;AAC2C;AAE1C;AAA6B;AAAmB;AAAK;AACnD;AAAmB;AAAe;AAAU;AAC1C;AACH;AACF;AAGN;AAMA;AAAiC;AAClB;AAAgB;AAAgB;AAAwB;AAAI;AAEtE;AAAgB;AAAkB;AAA0B;AAAI;AAGhE;AACM;AACI;AACgB;AAC3B;AAEW;AAAgB;AAAgB;AAAwB;AACvE;AAEA;AAIA;AACE;AACG;AAA4C;AAC1C;AAGP;AAEA;AACE;AACG;AAAuB;AAAsB;AAC3C;AAGP;AAWA;AAAgC;AAC9B;AACA;AACA;AAEF;AACE;AACA;AAEA;AACE;AAA8B;AAGhC;AACG;AAC0D;AACrD;AACJ;AACe;AACK;AACpB;AACA;AAGN;AAEA;AAA6B;AAC3B;AACA;AAEF;AACE;AAEA;AACE;AAAO;AAGT;AACG;AAC2D;AACtD;AAEH;AAAc;AAEX;AACG;AAEC;AACA;AACF;AAEH;AACH;AAGN;AAEA;AAA2D;AAChD;AACW;AAEtB;AAEA;AAAiC;AACb;AACO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACE;AAAO;AACF;AAGC;AACN;AAGF;AAAuE;AAC/C;AAGxB;AACE;AAAqB;AAGvB;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AACG;AAAc;AAAmC;AAChD;AAAC;AACW;AACD;AACM;AACf;AACA;AACA;AACA;AACO;AACT;AACqB;AAAoB;AAAsB;AAE5D;AAAc;AACb;AAAC;AAAc;AACZ;AACE;AACU;AACT;AACF;AAED;AACU;AACW;AACpB;AACF;AAEG;AACU;AACT;AACF;AAAA;AAEJ;AACiC;AAChC;AAAc;AAEX;AACG;AAA2B;AAAwB;AACjD;AAAgC;AAC9B;AACgB;AACN;AACC;AACF;AACM;AACE;AAClB;AACF;AACF;AACF;AAEJ;AAAA;AACF;AAGC;AAAc;AACZ;AAAc;AACb;AAAgB;AACb;AAAA;AACL;AACF;AAAA;AAIR;AAEa;AAQN;AAAiB;AAEpB;AACE;AACA;AACA;AACA;AACA;AACA;AACW;AACX;AACmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACkB;AACO;AACzB;AACQ;AACL;AAIL;AAEA;AACA;AACE;AAAU;AACR;AACF;AAGF;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAyC;AAInC;AACJ;AACA;AAGF;AAA2B;AACzB;AAEI;AAAmB;AAAa;AAChC;AAA8C;AAChD;AACK;AACP;AAEE;AAAsC;AAC/B;AACiB;AAG5B;AACA;AAMA;AACE;AAAqB;AAGvB;AACE;AAA+B;AAGjC;AAAoB;AAEhB;AAEA;AACE;AAAA;AAGF;AACE;AAAyB;AAC3B;AACF;AACuC;AAGzC;AAAmB;AAEf;AAEA;AACE;AAAA;AAGF;AAAuC;AACL;AAGlC;AACE;AAAwB;AAC1B;AACF;AAC0B;AAG5B;AAA0B;AAEtB;AAEA;AACE;AAAyB;AAC3B;AACF;AAC8B;AAGhC;AAA6B;AAEzB;AAEA;AACE;AAAA;AAGF;AAEA;AACE;AAAY;AACV;AACA;AACc;AACO;AACtB;AAED;AAAc;AACZ;AACc;AACO;AACtB;AAED;AAAa;AACG;AACS;AACF;AACtB;AACH;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AACG;AACE;AACmB;AACP;AACT;AACA;AACF;AACO;AACH;AACC;AAC8B;AAC1B;AACD;AACe;AACvB;AACyB;AACF;AACvB;AAEC;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACU;AACV;AACf;AACA;AACF;AACF;AACF;AAGN;;"}
|
|
1
|
+
{"version":3,"file":"Composer.js","sources":["../../src/components/Composer.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n BaseMetadata,\n CommentAttachment,\n CommentMixedAttachment,\n DM,\n} from \"@liveblocks/core\";\nimport { assertNever, Permission } from \"@liveblocks/core\";\nimport { useRoom } from \"@liveblocks/react\";\nimport {\n useCreateRoomComment,\n useCreateRoomThread,\n useEditRoomComment,\n useLayoutEffect,\n useResolveMentionSuggestions,\n useRoomPermissions,\n} from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n ComponentType,\n FocusEvent,\n FormEvent,\n ForwardedRef,\n MouseEvent,\n PropsWithChildren,\n ReactNode,\n RefAttributes,\n SyntheticEvent,\n} from \"react\";\nimport {\n createContext,\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\n\nimport { useLiveblocksUiConfig } from \"../config\";\nimport { FLOATING_ELEMENT_SIDE_OFFSET, MENTION_CHARACTER } from \"../constants\";\nimport { AttachmentIcon } from \"../icons/Attachment\";\nimport { BoldIcon } from \"../icons/Bold\";\nimport { CodeIcon } from \"../icons/Code\";\nimport { EmojiIcon } from \"../icons/Emoji\";\nimport { ItalicIcon } from \"../icons/Italic\";\nimport { MentionIcon } from \"../icons/Mention\";\nimport { SendIcon } from \"../icons/Send\";\nimport { StrikethroughIcon } from \"../icons/Strikethrough\";\nimport type { ComposerOverrides, GlobalOverrides } from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport * as ComposerPrimitive from \"../primitives/Composer\";\nimport {\n useComposer,\n useComposerAttachmentsContext,\n useComposerEditorContext,\n} from \"../primitives/Composer/contexts\";\nimport type {\n ComposerEditorComponents,\n ComposerEditorLinkProps,\n ComposerEditorMentionProps,\n ComposerEditorMentionSuggestionsProps,\n ComposerEditorProps,\n ComposerFormProps,\n ComposerMarkToggleProps,\n ComposerSubmitComment,\n} from \"../primitives/Composer/types\";\nimport { useComposerAttachmentsDropArea } from \"../primitives/Composer/utils\";\nimport type { ComposerBodyMark } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { useControllableState } from \"../utils/use-controllable-state\";\nimport { FileAttachment } from \"./internal/Attachment\";\nimport { Attribution } from \"./internal/Attribution\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport type { EmojiPickerProps } from \"./internal/EmojiPicker\";\nimport { EmojiPicker, EmojiPickerTrigger } from \"./internal/EmojiPicker\";\nimport { ShortcutTooltip, Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ninterface EditorActionProps extends ComponentPropsWithoutRef<\"button\"> {\n label: string;\n tooltipLabel?: string;\n}\n\ninterface EmojiEditorActionProps extends EditorActionProps {\n onPickerOpenChange?: EmojiPickerProps[\"onOpenChange\"];\n}\n\ninterface MarkToggleProps extends ComposerMarkToggleProps {\n icon?: ReactNode;\n shortcut?: string;\n}\n\ntype ComposerCreateThreadProps<M extends BaseMetadata> = {\n threadId?: never;\n commentId?: never;\n\n /**\n * The metadata of the thread to create.\n */\n metadata?: M;\n};\n\ntype ComposerCreateCommentProps = {\n /**\n * The ID of the thread to reply to.\n */\n threadId: string;\n commentId?: never;\n metadata?: never;\n};\n\ntype ComposerEditCommentProps = {\n /**\n * The ID of the thread to edit a comment in.\n */\n threadId: string;\n\n /**\n * The ID of the comment to edit.\n */\n commentId: string;\n metadata?: never;\n};\n\nexport type ComposerProps<M extends BaseMetadata = DM> = Omit<\n ComponentPropsWithoutRef<\"form\">,\n \"defaultValue\"\n> &\n (\n | ComposerCreateThreadProps<M>\n | ComposerCreateCommentProps\n | ComposerEditCommentProps\n ) & {\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: (\n comment: ComposerSubmitComment,\n event: FormEvent<HTMLFormElement>\n ) => Promise<void> | void;\n\n /**\n * The composer's initial value.\n */\n defaultValue?: ComposerEditorProps[\"defaultValue\"];\n\n /**\n * The composer's initial attachments.\n */\n defaultAttachments?: CommentAttachment[];\n\n /**\n * Whether the composer is collapsed. Setting a value will make the composer controlled.\n */\n collapsed?: boolean;\n\n /**\n * The event handler called when the collapsed state of the composer changes.\n */\n onCollapsedChange?: (collapsed: boolean) => void;\n\n /**\n * Whether the composer is initially collapsed. Setting a value will make the composer uncontrolled.\n */\n defaultCollapsed?: boolean;\n\n /**\n * Whether to show and allow adding attachments.\n */\n showAttachments?: boolean;\n\n /**\n * Whether to show formatting controls (e.g. a floating toolbar with formatting toggles when selecting text)\n */\n showFormattingControls?: boolean;\n\n /**\n * Whether the composer is disabled.\n */\n disabled?: ComposerFormProps[\"disabled\"];\n\n /**\n * Whether to focus the composer on mount.\n */\n autoFocus?: ComposerEditorProps[\"autoFocus\"];\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n\n /**\n * @internal\n */\n actions?: ReactNode;\n\n /**\n * @internal\n */\n showAttribution?: boolean;\n\n /**\n * @internal\n */\n roomId?: string;\n };\n\ninterface ComposerEditorContainerProps\n extends Pick<\n ComposerProps,\n | \"defaultValue\"\n | \"showAttachments\"\n | \"showFormattingControls\"\n | \"showAttribution\"\n | \"overrides\"\n | \"actions\"\n | \"autoFocus\"\n | \"disabled\"\n > {\n isCollapsed: boolean | undefined;\n onEmptyChange: (isEmpty: boolean) => void;\n hasResolveMentionSuggestions: boolean;\n onEmojiPickerOpenChange: (isOpen: boolean) => void;\n onEditorClick: (event: MouseEvent<HTMLDivElement>) => void;\n}\n\nfunction ComposerInsertMentionEditorAction({\n label,\n tooltipLabel,\n className,\n onClick,\n ...props\n}: EditorActionProps) {\n const { createMention } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.isDefaultPrevented()) {\n event.stopPropagation();\n createMention();\n }\n },\n [createMention, onClick]\n );\n\n return (\n <Tooltip content={tooltipLabel ?? label}>\n <Button\n className={cn(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={handleClick}\n aria-label={label}\n icon={<MentionIcon />}\n {...props}\n />\n </Tooltip>\n );\n}\n\nfunction ComposerInsertEmojiEditorAction({\n label,\n tooltipLabel,\n onPickerOpenChange,\n className,\n ...props\n}: EmojiEditorActionProps) {\n const { insertText } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <EmojiPicker onEmojiSelect={insertText} onOpenChange={onPickerOpenChange}>\n <Tooltip content={tooltipLabel ?? label}>\n <EmojiPickerTrigger asChild>\n <Button\n className={cn(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n aria-label={label}\n icon={<EmojiIcon />}\n {...props}\n />\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n );\n}\n\nfunction ComposerAttachFilesEditorAction({\n label,\n tooltipLabel,\n className,\n ...props\n}: EditorActionProps) {\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <Tooltip content={tooltipLabel ?? label}>\n <ComposerPrimitive.AttachFiles asChild>\n <Button\n className={cn(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n aria-label={label}\n icon={<AttachmentIcon />}\n {...props}\n />\n </ComposerPrimitive.AttachFiles>\n </Tooltip>\n );\n}\n\nfunction ComposerMention({ mention }: ComposerEditorMentionProps) {\n switch (mention.kind) {\n case \"user\":\n return (\n <ComposerPrimitive.Mention className=\"lb-composer-mention\">\n {MENTION_CHARACTER}\n <User userId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n\n default:\n return assertNever(mention.kind, \"Unhandled mention kind\");\n }\n}\n\nfunction ComposerMentionSuggestions({\n mentions,\n}: ComposerEditorMentionSuggestionsProps) {\n return mentions.length > 0 ? (\n <ComposerPrimitive.Suggestions className=\"lb-root lb-portal lb-elevation lb-composer-suggestions lb-composer-mention-suggestions\">\n <ComposerPrimitive.SuggestionsList className=\"lb-composer-suggestions-list lb-composer-mention-suggestions-list\">\n {mentions.map((mention) => {\n switch (mention.kind) {\n case \"user\":\n return (\n <ComposerPrimitive.SuggestionsListItem\n key={mention.id}\n className=\"lb-composer-suggestions-list-item lb-composer-mention-suggestion\"\n value={mention.id}\n >\n <Avatar\n userId={mention.id}\n className=\"lb-composer-mention-suggestion-avatar\"\n />\n <User\n userId={mention.id}\n className=\"lb-composer-mention-suggestion-user\"\n />\n </ComposerPrimitive.SuggestionsListItem>\n );\n\n default:\n return assertNever(mention.kind, \"Unhandled mention kind\");\n }\n })}\n </ComposerPrimitive.SuggestionsList>\n </ComposerPrimitive.Suggestions>\n ) : null;\n}\n\nfunction MarkToggle({\n mark,\n icon,\n shortcut,\n children,\n ...props\n}: MarkToggleProps) {\n const $ = useOverrides();\n const label = useMemo(() => {\n return $.COMPOSER_TOGGLE_MARK(mark);\n }, [$, mark]);\n\n return (\n <ShortcutTooltip\n content={label}\n shortcut={shortcut}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET + 2}\n >\n <ComposerPrimitive.MarkToggle mark={mark} asChild {...props}>\n <Button aria-label={label} variant=\"toolbar\" icon={icon}>\n {children}\n </Button>\n </ComposerPrimitive.MarkToggle>\n </ShortcutTooltip>\n );\n}\n\ntype MarkToggles = {\n [K in ComposerBodyMark]: ComponentType<PropsWithChildren>;\n};\n\nconst markToggles: MarkToggles = {\n bold: () => <MarkToggle mark=\"bold\" shortcut=\"Mod-B\" icon={<BoldIcon />} />,\n italic: () => (\n <MarkToggle mark=\"italic\" shortcut=\"Mod-I\" icon={<ItalicIcon />} />\n ),\n strikethrough: () => (\n <MarkToggle\n mark=\"strikethrough\"\n shortcut=\"Mod-Shift-S\"\n icon={<StrikethroughIcon />}\n />\n ),\n code: () => <MarkToggle mark=\"code\" shortcut=\"Mod-E\" icon={<CodeIcon />} />,\n};\n\nconst markTogglesList = Object.entries(markToggles).map(([mark, Toggle]) => (\n <Toggle key={mark} />\n));\n\nfunction ComposerFloatingToolbar() {\n return (\n <ComposerPrimitive.FloatingToolbar className=\"lb-root lb-portal lb-elevation lb-composer-floating-toolbar\">\n {markTogglesList}\n </ComposerPrimitive.FloatingToolbar>\n );\n}\n\nfunction ComposerLink({ href, children }: ComposerEditorLinkProps) {\n return (\n <ComposerPrimitive.Link href={href} className=\"lb-composer-link\">\n {children}\n </ComposerPrimitive.Link>\n );\n}\n\ninterface ComposerAttachmentsProps extends ComponentPropsWithoutRef<\"div\"> {\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n}\n\ninterface ComposerFileAttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n}\n\nfunction ComposerFileAttachment({\n attachment,\n className,\n overrides,\n ...props\n}: ComposerFileAttachmentProps) {\n const { removeAttachment } = useComposer();\n const { roomId } = useComposerEditorContext();\n\n const handleDeleteClick = useCallback(() => {\n removeAttachment(attachment.id);\n }, [attachment.id, removeAttachment]);\n\n return (\n <FileAttachment\n className={cn(\"lb-composer-attachment\", className)}\n {...props}\n attachment={attachment}\n onDeleteClick={handleDeleteClick}\n preventFocusOnDelete\n overrides={overrides}\n roomId={roomId}\n />\n );\n}\n\nfunction ComposerAttachments({\n overrides,\n className,\n ...props\n}: ComposerAttachmentsProps) {\n const { attachments } = useComposer();\n\n if (attachments.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(\"lb-composer-attachments\", className)} {...props}>\n <div className=\"lb-attachments\">\n {attachments.map((attachment) => {\n return (\n <ComposerFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n />\n );\n })}\n </div>\n </div>\n );\n}\n\nconst editorRequiredComponents: ComposerEditorComponents = {\n Mention: ComposerMention,\n MentionSuggestions: ComposerMentionSuggestions,\n Link: ComposerLink,\n};\n\nfunction ComposerEditorContainer({\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n defaultValue,\n isCollapsed,\n overrides,\n actions,\n autoFocus,\n disabled,\n hasResolveMentionSuggestions,\n onEmojiPickerOpenChange,\n onEmptyChange,\n onEditorClick,\n}: ComposerEditorContainerProps) {\n const { isEmpty } = useComposer();\n const { hasMaxAttachments } = useComposerAttachmentsContext();\n const $ = useOverrides(overrides);\n const components = useMemo(() => {\n return {\n ...editorRequiredComponents,\n FloatingToolbar: showFormattingControls\n ? ComposerFloatingToolbar\n : undefined,\n };\n }, [showFormattingControls]);\n\n const [isDraggingOver, dropAreaProps] = useComposerAttachmentsDropArea({\n disabled: disabled || hasMaxAttachments,\n });\n\n useLayoutEffect(() => {\n onEmptyChange(isEmpty);\n }, [isEmpty, onEmptyChange]);\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <div className=\"lb-composer-editor-container\" {...dropAreaProps}>\n <ComposerPrimitive.Editor\n className=\"lb-composer-editor\"\n onClick={onEditorClick}\n placeholder={$.COMPOSER_PLACEHOLDER}\n defaultValue={defaultValue}\n autoFocus={autoFocus}\n components={components}\n disabled={disabled}\n dir={$.dir}\n />\n {showAttachments && <ComposerAttachments overrides={overrides} />}\n {(!isCollapsed || isDraggingOver) && (\n <div className=\"lb-composer-footer\">\n <div className=\"lb-composer-editor-actions\">\n {hasResolveMentionSuggestions && (\n <ComposerInsertMentionEditorAction\n label={$.COMPOSER_INSERT_MENTION}\n disabled={disabled}\n />\n )}\n <ComposerInsertEmojiEditorAction\n label={$.COMPOSER_INSERT_EMOJI}\n onPickerOpenChange={onEmojiPickerOpenChange}\n disabled={disabled}\n />\n {showAttachments && (\n <ComposerAttachFilesEditorAction\n label={$.COMPOSER_ATTACH_FILES}\n disabled={disabled}\n />\n )}\n </div>\n {showAttribution && <Attribution />}\n <div className=\"lb-composer-actions\">\n {actions ?? (\n <>\n <ShortcutTooltip content={$.COMPOSER_SEND} shortcut=\"Enter\">\n <ComposerPrimitive.Submit asChild>\n <Button\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n className=\"lb-composer-action\"\n variant=\"primary\"\n aria-label={$.COMPOSER_SEND}\n icon={<SendIcon />}\n />\n </ComposerPrimitive.Submit>\n </ShortcutTooltip>\n </>\n )}\n </div>\n </div>\n )}\n {showAttachments && isDraggingOver && (\n <div className=\"lb-composer-attachments-drop-area\">\n <div className=\"lb-composer-attachments-drop-area-label\">\n <AttachmentIcon />\n {$.COMPOSER_ATTACH_FILES}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const ComposerRoomIdContext = createContext<string | null>(null);\n\n/**\n * Displays a composer to create comments.\n *\n * @example\n * <Composer />\n */\nexport const Composer = forwardRef(\n <M extends BaseMetadata = DM>(\n {\n threadId,\n commentId,\n metadata,\n defaultValue,\n defaultAttachments,\n onComposerSubmit,\n collapsed: controlledCollapsed,\n defaultCollapsed,\n onCollapsedChange: controlledOnCollapsedChange,\n overrides,\n actions,\n onBlur,\n className,\n onFocus,\n autoFocus,\n disabled,\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n roomId: _roomId,\n ...props\n }: ComposerProps<M>,\n forwardedRef: ForwardedRef<HTMLFormElement>\n ) => {\n const room = useRoom({ allowOutsideRoom: true });\n\n const roomId = _roomId !== undefined ? _roomId : room?.id;\n if (roomId === undefined) {\n throw new Error(\n \"Composer must be a descendant of RoomProvider component\"\n );\n }\n\n const createThread = useCreateRoomThread(roomId);\n const createComment = useCreateRoomComment(roomId);\n const editComment = useEditRoomComment(roomId);\n const { preventUnsavedComposerChanges } = useLiveblocksUiConfig();\n const hasResolveMentionSuggestions =\n useResolveMentionSuggestions() !== undefined;\n const isEmptyRef = useRef(true);\n const isEmojiPickerOpenRef = useRef(false);\n const $ = useOverrides(overrides);\n const [isCollapsed, onCollapsedChange] = useControllableState(\n defaultCollapsed ?? false,\n controlledCollapsed,\n controlledOnCollapsedChange\n );\n\n const canCommentFallback = useSyncExternalStore(\n useCallback(\n (callback) => {\n if (room === null) return () => {};\n return room.events.self.subscribeOnce(callback);\n },\n [room]\n ),\n useCallback(() => {\n return room?.getSelf()?.canComment ?? true;\n }, [room]),\n useCallback(() => true, [])\n );\n\n const permissions = useRoomPermissions(roomId);\n const canComment =\n permissions.size > 0\n ? permissions.has(Permission.CommentsWrite) ||\n permissions.has(Permission.Write)\n : canCommentFallback;\n\n const setEmptyRef = useCallback((isEmpty: boolean) => {\n isEmptyRef.current = isEmpty;\n }, []);\n\n const setEmojiPickerOpenRef = useCallback((isEmojiPickerOpen: boolean) => {\n isEmojiPickerOpenRef.current = isEmojiPickerOpen;\n }, []);\n\n const handleFocus = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onFocus?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n if (isEmptyRef.current && canComment) {\n onCollapsedChange?.(false);\n }\n },\n [onCollapsedChange, onFocus, canComment]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onBlur?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const isOutside = !event.currentTarget.contains(\n event.relatedTarget ?? document.activeElement\n );\n\n if (isOutside && isEmptyRef.current && !isEmojiPickerOpenRef.current) {\n onCollapsedChange?.(true);\n }\n },\n [onBlur, onCollapsedChange]\n );\n\n const handleEditorClick = useCallback(\n (event: MouseEvent<HTMLDivElement>) => {\n event.stopPropagation();\n\n if (isEmptyRef.current && canComment) {\n onCollapsedChange?.(false);\n }\n },\n [onCollapsedChange, canComment]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n event.stopPropagation();\n\n if (commentId && threadId) {\n editComment({\n commentId,\n threadId,\n body: comment.body,\n attachments: comment.attachments,\n });\n } else if (threadId) {\n createComment({\n threadId,\n body: comment.body,\n attachments: comment.attachments,\n });\n } else {\n createThread({\n body: comment.body,\n metadata: metadata ?? {},\n attachments: comment.attachments,\n });\n }\n },\n [\n commentId,\n createComment,\n createThread,\n editComment,\n metadata,\n onComposerSubmit,\n threadId,\n ]\n );\n\n return (\n <TooltipProvider>\n <ComposerPrimitive.Form\n onComposerSubmit={handleComposerSubmit}\n className={cn(\"lb-root lb-composer lb-composer-form\", className)}\n dir={$.dir}\n {...props}\n ref={forwardedRef}\n data-collapsed={isCollapsed ? \"\" : undefined}\n onFocus={handleFocus}\n onBlur={handleBlur}\n disabled={disabled || !canComment}\n defaultAttachments={defaultAttachments}\n pasteFilesAsAttachments={showAttachments}\n preventUnsavedChanges={preventUnsavedComposerChanges}\n roomId={roomId}\n >\n <ComposerEditorContainer\n defaultValue={defaultValue}\n actions={actions}\n overrides={overrides}\n isCollapsed={isCollapsed}\n showAttachments={showAttachments}\n showAttribution={showAttribution}\n showFormattingControls={showFormattingControls}\n hasResolveMentionSuggestions={hasResolveMentionSuggestions}\n onEmptyChange={setEmptyRef}\n onEmojiPickerOpenChange={setEmojiPickerOpenRef}\n onEditorClick={handleEditorClick}\n autoFocus={autoFocus}\n disabled={disabled}\n />\n </ComposerPrimitive.Form>\n </TooltipProvider>\n );\n }\n) as <M extends BaseMetadata = DM>(\n props: ComposerProps<M> & RefAttributes<HTMLFormElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoOA;AAA2C;AACzC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AAAoB;AAEhB;AAEA;AACE;AACA;AAAc;AAChB;AACF;AACuB;AAGzB;AACG;AAAiC;AAC/B;AACqD;AACrC;AACN;AACG;AACO;AACf;AACN;AAGN;AAEA;AAAyC;AACvC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AACG;AAA2B;AAA0B;AACnD;AAAiC;AAC/B;AAA0B;AACxB;AACqD;AACrC;AACN;AACG;AACK;AACb;AACN;AACF;AACF;AAGN;AAEA;AAAyC;AACvC;AACA;AACA;AAEF;AACE;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AACG;AAAiC;AAC/B;AAAqC;AACnC;AACqD;AACrC;AACN;AACG;AACU;AAClB;AACN;AACF;AAGN;AAEA;AACE;AAAsB;AAElB;AACG;AAAoC;AAClC;AAAA;AACA;AAAqB;AAAI;AAAA;AAC5B;AAIF;AAAyD;AAE/D;AAEA;AAAoC;AAEpC;AACE;AACG;AAAwC;AACtC;AAA4C;AAEzC;AAAsB;AAElB;AACG;AAEW;AACK;AAEf;AAAC;AACiB;AACN;AACZ;AACC;AACiB;AACN;AACZ;AAAA;AACF;AAIF;AAAyD;AAC7D;AACD;AACH;AAGN;AAEA;AAAoB;AAClB;AACA;AACA;AACA;AAEF;AACE;AACA;AACE;AAAkC;AAGpC;AACG;AACU;AACT;AAC2C;AAE1C;AAA6B;AAAmB;AAAK;AACnD;AAAmB;AAAe;AAAU;AAC1C;AACH;AACF;AAGN;AAMA;AAAiC;AAClB;AAAgB;AAAgB;AAAwB;AAAI;AAEtE;AAAgB;AAAkB;AAA0B;AAAI;AAGhE;AACM;AACI;AACgB;AAC3B;AAEW;AAAgB;AAAgB;AAAwB;AACvE;AAEA;AAIA;AACE;AACG;AAA4C;AAC1C;AAGP;AAEA;AACE;AACG;AAAuB;AAAsB;AAC3C;AAGP;AAWA;AAAgC;AAC9B;AACA;AACA;AAEF;AACE;AACA;AAEA;AACE;AAA8B;AAGhC;AACG;AACkD;AAC7C;AACJ;AACe;AACK;AACpB;AACA;AAGN;AAEA;AAA6B;AAC3B;AACA;AAEF;AACE;AAEA;AACE;AAAO;AAGT;AACG;AAAsD;AAAO;AAC3D;AAAc;AAEX;AACG;AAEC;AACA;AACF;AAEH;AACH;AAGN;AAEA;AAA2D;AAChD;AACW;AAEtB;AAEA;AAAiC;AACb;AACO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACE;AAAO;AACF;AAGC;AACN;AAGF;AAAuE;AAC/C;AAGxB;AACE;AAAqB;AAGvB;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AACG;AAAc;AAAmC;AAChD;AAAC;AACW;AACD;AACM;AACf;AACA;AACA;AACA;AACO;AACT;AACqB;AAAoB;AAAsB;AAE5D;AAAc;AACb;AAAC;AAAc;AACZ;AACE;AACU;AACT;AACF;AAED;AACU;AACW;AACpB;AACF;AAEG;AACU;AACT;AACF;AAAA;AAEJ;AACiC;AAChC;AAAc;AAEX;AACG;AAA2B;AAAwB;AACjD;AAAgC;AAC9B;AACgB;AACN;AACC;AACF;AACM;AACE;AAClB;AACF;AACF;AACF;AAEJ;AAAA;AACF;AAGC;AAAc;AACZ;AAAc;AACb;AAAgB;AACb;AAAA;AACL;AACF;AAAA;AAIR;AAEa;AAQN;AAAiB;AAEpB;AACE;AACA;AACA;AACA;AACA;AACA;AACW;AACX;AACmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACkB;AACO;AACzB;AACQ;AACL;AAIL;AAEA;AACA;AACE;AAAU;AACR;AACF;AAGF;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAyC;AACnB;AACpB;AACA;AAGF;AAA2B;AACzB;AAEI;AAAmB;AAAa;AAChC;AAA8C;AAChD;AACK;AACP;AAEE;AAAsC;AAC/B;AACiB;AAG5B;AACA;AAMA;AACE;AAAqB;AAGvB;AACE;AAA+B;AAGjC;AAAoB;AAEhB;AAEA;AACE;AAAA;AAGF;AACE;AAAyB;AAC3B;AACF;AACuC;AAGzC;AAAmB;AAEf;AAEA;AACE;AAAA;AAGF;AAAuC;AACL;AAGlC;AACE;AAAwB;AAC1B;AACF;AAC0B;AAG5B;AAA0B;AAEtB;AAEA;AACE;AAAyB;AAC3B;AACF;AAC8B;AAGhC;AAA6B;AAEzB;AAEA;AACE;AAAA;AAGF;AAEA;AACE;AAAY;AACV;AACA;AACc;AACO;AACtB;AAED;AAAc;AACZ;AACc;AACO;AACtB;AAED;AAAa;AACG;AACS;AACF;AACtB;AACH;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AACG;AACE;AACmB;AAC6C;AACxD;AACH;AACC;AAC8B;AAC1B;AACD;AACe;AACvB;AACyB;AACF;AACvB;AAEC;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACU;AACV;AACf;AACA;AACF;AACF;AACF;AAGN;;"}
|
|
@@ -5,7 +5,7 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var overrides = require('../overrides.cjs');
|
|
7
7
|
require('../primitives/index.cjs');
|
|
8
|
-
var
|
|
8
|
+
var cn = require('../utils/cn.cjs');
|
|
9
9
|
var List = require('./internal/List.cjs');
|
|
10
10
|
var User = require('./internal/User.cjs');
|
|
11
11
|
var Timestamp = require('../primitives/Timestamp.cjs');
|
|
@@ -16,7 +16,7 @@ const HistoryVersionSummary = react.forwardRef(({ version, selected, className,
|
|
|
16
16
|
const $ = overrides.useOverrides();
|
|
17
17
|
return /* @__PURE__ */ jsxRuntime.jsxs("button", {
|
|
18
18
|
...props,
|
|
19
|
-
className:
|
|
19
|
+
className: cn.cn("lb-root lb-history-version-summary", className),
|
|
20
20
|
ref: forwardedRef,
|
|
21
21
|
"data-selected": selected ? "" : void 0,
|
|
22
22
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HistoryVersionSummary.cjs","sources":["../../src/components/HistoryVersionSummary.tsx"],"sourcesContent":["\"use client\";\n\nimport type { HistoryVersion } from \"@liveblocks/core\";\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives\";\nimport {
|
|
1
|
+
{"version":3,"file":"HistoryVersionSummary.cjs","sources":["../../src/components/HistoryVersionSummary.tsx"],"sourcesContent":["\"use client\";\n\nimport type { HistoryVersion } from \"@liveblocks/core\";\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives\";\nimport { cn } from \"../utils/cn\";\nimport { List } from \"./internal/List\";\nimport { User } from \"./internal/User\";\n\nconst AUTHORS_TRUNCATE = 3;\n\nexport interface HistoryVersionSummaryProps\n extends ComponentPropsWithoutRef<\"button\"> {\n version: HistoryVersion;\n selected?: boolean;\n}\n\n/**\n * Displays some information about a version.\n *\n * @example\n * <HistoryVersionSummary version={version} />\n */\nexport const HistoryVersionSummary = forwardRef<\n HTMLButtonElement,\n HistoryVersionSummaryProps\n>(({ version, selected, className, ...props }, forwardedRef) => {\n const $ = useOverrides();\n\n return (\n <button\n {...props}\n className={cn(\"lb-root lb-history-version-summary\", className)}\n ref={forwardedRef}\n data-selected={selected ? \"\" : undefined}\n >\n <Timestamp\n locale={$.locale}\n date={version.createdAt}\n className=\"lb-date lb-history-version-summary-date\"\n />\n <span className=\"lb-history-version-summary-authors\">\n <List\n values={version.authors.map((author) => (\n <User key={author.id} userId={author.id} replaceSelf />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={AUTHORS_TRUNCATE}\n locale={$.locale}\n />\n </span>\n </button>\n );\n});\n"],"names":[],"mappings":";;;;;;;;;;;;;AAYA;AAca;AAIX;AAEA;AACG;AACK;AACyD;AACxD;AAC0B;AAE/B;AAAC;AACW;AACI;AACJ;AACZ;AACC;AAAe;AACb;AAEI;AAAoC;AAAe;AACrD;AACkB;AACT;AACA;AACZ;AACF;AAAA;AAGN;;"}
|
|
@@ -3,7 +3,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
3
3
|
import { forwardRef } from 'react';
|
|
4
4
|
import { useOverrides } from '../overrides.js';
|
|
5
5
|
import '../primitives/index.js';
|
|
6
|
-
import {
|
|
6
|
+
import { cn } from '../utils/cn.js';
|
|
7
7
|
import { List } from './internal/List.js';
|
|
8
8
|
import { User } from './internal/User.js';
|
|
9
9
|
import { Timestamp } from '../primitives/Timestamp.js';
|
|
@@ -14,7 +14,7 @@ const HistoryVersionSummary = forwardRef(({ version, selected, className, ...pro
|
|
|
14
14
|
const $ = useOverrides();
|
|
15
15
|
return /* @__PURE__ */ jsxs("button", {
|
|
16
16
|
...props,
|
|
17
|
-
className:
|
|
17
|
+
className: cn("lb-root lb-history-version-summary", className),
|
|
18
18
|
ref: forwardedRef,
|
|
19
19
|
"data-selected": selected ? "" : void 0,
|
|
20
20
|
children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HistoryVersionSummary.js","sources":["../../src/components/HistoryVersionSummary.tsx"],"sourcesContent":["\"use client\";\n\nimport type { HistoryVersion } from \"@liveblocks/core\";\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives\";\nimport {
|
|
1
|
+
{"version":3,"file":"HistoryVersionSummary.js","sources":["../../src/components/HistoryVersionSummary.tsx"],"sourcesContent":["\"use client\";\n\nimport type { HistoryVersion } from \"@liveblocks/core\";\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives\";\nimport { cn } from \"../utils/cn\";\nimport { List } from \"./internal/List\";\nimport { User } from \"./internal/User\";\n\nconst AUTHORS_TRUNCATE = 3;\n\nexport interface HistoryVersionSummaryProps\n extends ComponentPropsWithoutRef<\"button\"> {\n version: HistoryVersion;\n selected?: boolean;\n}\n\n/**\n * Displays some information about a version.\n *\n * @example\n * <HistoryVersionSummary version={version} />\n */\nexport const HistoryVersionSummary = forwardRef<\n HTMLButtonElement,\n HistoryVersionSummaryProps\n>(({ version, selected, className, ...props }, forwardedRef) => {\n const $ = useOverrides();\n\n return (\n <button\n {...props}\n className={cn(\"lb-root lb-history-version-summary\", className)}\n ref={forwardedRef}\n data-selected={selected ? \"\" : undefined}\n >\n <Timestamp\n locale={$.locale}\n date={version.createdAt}\n className=\"lb-date lb-history-version-summary-date\"\n />\n <span className=\"lb-history-version-summary-authors\">\n <List\n values={version.authors.map((author) => (\n <User key={author.id} userId={author.id} replaceSelf />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={AUTHORS_TRUNCATE}\n locale={$.locale}\n />\n </span>\n </button>\n );\n});\n"],"names":[],"mappings":";;;;;;;;;;;AAYA;AAca;AAIX;AAEA;AACG;AACK;AACyD;AACxD;AAC0B;AAE/B;AAAC;AACW;AACI;AACJ;AACZ;AACC;AAAe;AACb;AAEI;AAAoC;AAAe;AACrD;AACkB;AACT;AACA;AACZ;AACF;AAAA;AAGN;;"}
|
|
@@ -3,15 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var react = require('react');
|
|
6
|
-
var
|
|
6
|
+
var cn = require('../utils/cn.cjs');
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
const HistoryVersionSummaryList = react.forwardRef(({ children, className, ...props }, forwardedRef) => {
|
|
10
10
|
return /* @__PURE__ */ jsxRuntime.jsx("ol", {
|
|
11
|
-
className:
|
|
12
|
-
"lb-root lb-history-version-summary-list",
|
|
13
|
-
className
|
|
14
|
-
),
|
|
11
|
+
className: cn.cn("lb-root lb-history-version-summary-list", className),
|
|
15
12
|
...props,
|
|
16
13
|
ref: forwardedRef,
|
|
17
14
|
children: react.Children.map(children, (child, index) => /* @__PURE__ */ jsxRuntime.jsx("li", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HistoryVersionSummaryList.cjs","sources":["../../src/components/HistoryVersionSummaryList.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport { Children, forwardRef } from \"react\";\n\nimport {
|
|
1
|
+
{"version":3,"file":"HistoryVersionSummaryList.cjs","sources":["../../src/components/HistoryVersionSummaryList.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport { Children, forwardRef } from \"react\";\n\nimport { cn } from \"../utils/cn\";\n\nexport type HistoryVersionSummaryListProps = ComponentPropsWithoutRef<\"ol\">;\n\n/**\n * Displays versions summaries as a list.\n *\n * @example\n * <HistoryVersionSummaryList>\n * {versions.map((version) => (\n * <HistoryVersionSummary key={version.id} version={version} />\n * ))}\n * </HistoryVersionSummaryList>\n */\nexport const HistoryVersionSummaryList = forwardRef<\n HTMLOListElement,\n HistoryVersionSummaryListProps\n>(({ children, className, ...props }, forwardedRef) => {\n return (\n <ol\n className={cn(\"lb-root lb-history-version-summary-list\", className)}\n {...props}\n ref={forwardedRef}\n >\n {Children.map(children, (child, index) => (\n <li key={index} className=\"lb-history-version-summary-list-item\">\n {child}\n </li>\n ))}\n </ol>\n );\n});\n"],"names":[],"mappings":";;;;;;;;AAmBa;AAIX;AACG;AACmE;AAC9D;AACC;AAGF;AAAyB;AACvB;AAEJ;AAGP;;"}
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { forwardRef, Children } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { cn } from '../utils/cn.js';
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
const HistoryVersionSummaryList = forwardRef(({ children, className, ...props }, forwardedRef) => {
|
|
8
8
|
return /* @__PURE__ */ jsx("ol", {
|
|
9
|
-
className:
|
|
10
|
-
"lb-root lb-history-version-summary-list",
|
|
11
|
-
className
|
|
12
|
-
),
|
|
9
|
+
className: cn("lb-root lb-history-version-summary-list", className),
|
|
13
10
|
...props,
|
|
14
11
|
ref: forwardedRef,
|
|
15
12
|
children: Children.map(children, (child, index) => /* @__PURE__ */ jsx("li", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HistoryVersionSummaryList.js","sources":["../../src/components/HistoryVersionSummaryList.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport { Children, forwardRef } from \"react\";\n\nimport {
|
|
1
|
+
{"version":3,"file":"HistoryVersionSummaryList.js","sources":["../../src/components/HistoryVersionSummaryList.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentPropsWithoutRef } from \"react\";\nimport { Children, forwardRef } from \"react\";\n\nimport { cn } from \"../utils/cn\";\n\nexport type HistoryVersionSummaryListProps = ComponentPropsWithoutRef<\"ol\">;\n\n/**\n * Displays versions summaries as a list.\n *\n * @example\n * <HistoryVersionSummaryList>\n * {versions.map((version) => (\n * <HistoryVersionSummary key={version.id} version={version} />\n * ))}\n * </HistoryVersionSummaryList>\n */\nexport const HistoryVersionSummaryList = forwardRef<\n HTMLOListElement,\n HistoryVersionSummaryListProps\n>(({ children, className, ...props }, forwardedRef) => {\n return (\n <ol\n className={cn(\"lb-root lb-history-version-summary-list\", className)}\n {...props}\n ref={forwardedRef}\n >\n {Children.map(children, (child, index) => (\n <li key={index} className=\"lb-history-version-summary-list-item\">\n {child}\n </li>\n ))}\n </ol>\n );\n});\n"],"names":[],"mappings":";;;;;;AAmBa;AAIX;AACG;AACmE;AAC9D;AACC;AAGF;AAAyB;AACvB;AAEJ;AAGP;;"}
|
|
@@ -18,7 +18,7 @@ var Warning = require('../icons/Warning.cjs');
|
|
|
18
18
|
var overrides = require('../overrides.cjs');
|
|
19
19
|
var Timestamp = require('../primitives/Timestamp.cjs');
|
|
20
20
|
var shared = require('../shared.cjs');
|
|
21
|
-
var
|
|
21
|
+
var cn = require('../utils/cn.cjs');
|
|
22
22
|
var url = require('../utils/url.cjs');
|
|
23
23
|
var Avatar = require('./internal/Avatar.cjs');
|
|
24
24
|
var Button = require('./internal/Button.cjs');
|
|
@@ -97,7 +97,7 @@ const InboxNotificationLayout = react.forwardRef(
|
|
|
97
97
|
}, [inboxNotification.id, deleteInboxNotification]);
|
|
98
98
|
return /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive.TooltipProvider, {
|
|
99
99
|
children: /* @__PURE__ */ jsxRuntime.jsxs(Component, {
|
|
100
|
-
className:
|
|
100
|
+
className: cn.cn(
|
|
101
101
|
"lb-root lb-inbox-notification",
|
|
102
102
|
showActions === "hover" && "lb-inbox-notification:show-actions-hover",
|
|
103
103
|
isMoreActionOpen && "lb-inbox-notification:action-open",
|
|
@@ -200,7 +200,7 @@ function InboxNotificationIcon({
|
|
|
200
200
|
...props
|
|
201
201
|
}) {
|
|
202
202
|
return /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
203
|
-
className:
|
|
203
|
+
className: cn.cn("lb-inbox-notification-icon", className),
|
|
204
204
|
...props
|
|
205
205
|
});
|
|
206
206
|
}
|
|
@@ -209,7 +209,7 @@ function InboxNotificationAvatar({
|
|
|
209
209
|
...props
|
|
210
210
|
}) {
|
|
211
211
|
return /* @__PURE__ */ jsxRuntime.jsx(Avatar.Avatar, {
|
|
212
|
-
className:
|
|
212
|
+
className: cn.cn("lb-inbox-notification-avatar", className),
|
|
213
213
|
...props
|
|
214
214
|
});
|
|
215
215
|
}
|