@liveblocks/react-ui 3.15.0-thread1 → 3.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/README.md +6 -16
  2. package/dist/_private/index.cjs +3 -5
  3. package/dist/_private/index.cjs.map +1 -1
  4. package/dist/_private/index.d.cts +10 -4
  5. package/dist/_private/index.d.ts +10 -4
  6. package/dist/_private/index.js +2 -2
  7. package/dist/components/AiChat.cjs +10 -2
  8. package/dist/components/AiChat.cjs.map +1 -1
  9. package/dist/components/AiChat.js +10 -2
  10. package/dist/components/AiChat.js.map +1 -1
  11. package/dist/components/AvatarStack.cjs +117 -0
  12. package/dist/components/AvatarStack.cjs.map +1 -0
  13. package/dist/components/AvatarStack.js +115 -0
  14. package/dist/components/AvatarStack.js.map +1 -0
  15. package/dist/components/Comment.cjs +13 -31
  16. package/dist/components/Comment.cjs.map +1 -1
  17. package/dist/components/Comment.js +15 -14
  18. package/dist/components/Comment.js.map +1 -1
  19. package/dist/components/CommentPin.cjs +36 -0
  20. package/dist/components/CommentPin.cjs.map +1 -0
  21. package/dist/components/CommentPin.js +34 -0
  22. package/dist/components/CommentPin.js.map +1 -0
  23. package/dist/components/Composer.cjs +2 -4
  24. package/dist/components/Composer.cjs.map +1 -1
  25. package/dist/components/Composer.js +3 -5
  26. package/dist/components/Composer.js.map +1 -1
  27. package/dist/components/Cursor.cjs +40 -0
  28. package/dist/components/Cursor.cjs.map +1 -0
  29. package/dist/components/Cursor.js +38 -0
  30. package/dist/components/Cursor.js.map +1 -0
  31. package/dist/components/Cursors.cjs +256 -0
  32. package/dist/components/Cursors.cjs.map +1 -0
  33. package/dist/components/Cursors.js +254 -0
  34. package/dist/components/Cursors.js.map +1 -0
  35. package/dist/components/FloatingComposer.cjs +82 -0
  36. package/dist/components/FloatingComposer.cjs.map +1 -0
  37. package/dist/components/FloatingComposer.js +80 -0
  38. package/dist/components/FloatingComposer.js.map +1 -0
  39. package/dist/components/FloatingThread.cjs +82 -0
  40. package/dist/components/FloatingThread.cjs.map +1 -0
  41. package/dist/components/FloatingThread.js +80 -0
  42. package/dist/components/FloatingThread.js.map +1 -0
  43. package/dist/components/InboxNotification.cjs +4 -6
  44. package/dist/components/InboxNotification.cjs.map +1 -1
  45. package/dist/components/InboxNotification.js +5 -7
  46. package/dist/components/InboxNotification.js.map +1 -1
  47. package/dist/components/Thread.cjs +21 -29
  48. package/dist/components/Thread.cjs.map +1 -1
  49. package/dist/components/Thread.js +21 -10
  50. package/dist/components/Thread.js.map +1 -1
  51. package/dist/components/internal/AiComposer.cjs +1 -2
  52. package/dist/components/internal/AiComposer.cjs.map +1 -1
  53. package/dist/components/internal/AiComposer.js +1 -2
  54. package/dist/components/internal/AiComposer.js.map +1 -1
  55. package/dist/components/internal/Avatar.cjs +10 -13
  56. package/dist/components/internal/Avatar.cjs.map +1 -1
  57. package/dist/components/internal/Avatar.js +11 -14
  58. package/dist/components/internal/Avatar.js.map +1 -1
  59. package/dist/components/internal/CodeBlock.cjs +1 -2
  60. package/dist/components/internal/CodeBlock.cjs.map +1 -1
  61. package/dist/components/internal/CodeBlock.js +1 -2
  62. package/dist/components/internal/CodeBlock.js.map +1 -1
  63. package/dist/components/internal/Dropdown.cjs +7 -28
  64. package/dist/components/internal/Dropdown.cjs.map +1 -1
  65. package/dist/components/internal/Dropdown.js +7 -7
  66. package/dist/components/internal/Dropdown.js.map +1 -1
  67. package/dist/components/internal/EmojiPicker.cjs +6 -27
  68. package/dist/components/internal/EmojiPicker.cjs.map +1 -1
  69. package/dist/components/internal/EmojiPicker.js +6 -6
  70. package/dist/components/internal/EmojiPicker.js.map +1 -1
  71. package/dist/components/internal/List.cjs +2 -2
  72. package/dist/components/internal/List.cjs.map +1 -1
  73. package/dist/components/internal/List.js +2 -2
  74. package/dist/components/internal/List.js.map +1 -1
  75. package/dist/components/internal/Tooltip.cjs +7 -28
  76. package/dist/components/internal/Tooltip.cjs.map +1 -1
  77. package/dist/components/internal/Tooltip.js +7 -7
  78. package/dist/components/internal/Tooltip.js.map +1 -1
  79. package/dist/index.cjs +12 -0
  80. package/dist/index.cjs.map +1 -1
  81. package/dist/index.d.cts +232 -137
  82. package/dist/index.d.ts +232 -137
  83. package/dist/index.js +6 -0
  84. package/dist/index.js.map +1 -1
  85. package/dist/primitives/AiComposer/index.cjs +5 -4
  86. package/dist/primitives/AiComposer/index.cjs.map +1 -1
  87. package/dist/primitives/AiComposer/index.js +5 -4
  88. package/dist/primitives/AiComposer/index.js.map +1 -1
  89. package/dist/primitives/AiMessage/index.cjs +2 -2
  90. package/dist/primitives/AiMessage/index.cjs.map +1 -1
  91. package/dist/primitives/AiMessage/index.js +2 -2
  92. package/dist/primitives/AiMessage/index.js.map +1 -1
  93. package/dist/primitives/Collapsible/index.cjs +4 -4
  94. package/dist/primitives/Collapsible/index.cjs.map +1 -1
  95. package/dist/primitives/Collapsible/index.js +4 -4
  96. package/dist/primitives/Collapsible/index.js.map +1 -1
  97. package/dist/primitives/Comment/index.cjs +4 -4
  98. package/dist/primitives/Comment/index.cjs.map +1 -1
  99. package/dist/primitives/Comment/index.js +4 -4
  100. package/dist/primitives/Comment/index.js.map +1 -1
  101. package/dist/primitives/Composer/index.cjs +23 -35
  102. package/dist/primitives/Composer/index.cjs.map +1 -1
  103. package/dist/primitives/Composer/index.js +23 -16
  104. package/dist/primitives/Composer/index.js.map +1 -1
  105. package/dist/primitives/Duration.cjs +2 -2
  106. package/dist/primitives/Duration.cjs.map +1 -1
  107. package/dist/primitives/Duration.js +2 -2
  108. package/dist/primitives/Duration.js.map +1 -1
  109. package/dist/primitives/FileSize.cjs +2 -2
  110. package/dist/primitives/FileSize.cjs.map +1 -1
  111. package/dist/primitives/FileSize.js +2 -2
  112. package/dist/primitives/FileSize.js.map +1 -1
  113. package/dist/primitives/Markdown.cjs +2 -2
  114. package/dist/primitives/Markdown.cjs.map +1 -1
  115. package/dist/primitives/Markdown.js +2 -2
  116. package/dist/primitives/Markdown.js.map +1 -1
  117. package/dist/primitives/Timestamp.cjs +2 -2
  118. package/dist/primitives/Timestamp.cjs.map +1 -1
  119. package/dist/primitives/Timestamp.js +2 -2
  120. package/dist/primitives/Timestamp.js.map +1 -1
  121. package/dist/utils/Portal.cjs +2 -2
  122. package/dist/utils/Portal.cjs.map +1 -1
  123. package/dist/utils/Portal.js +2 -2
  124. package/dist/utils/Portal.js.map +1 -1
  125. package/dist/utils/animation-loop.cjs +44 -0
  126. package/dist/utils/animation-loop.cjs.map +1 -0
  127. package/dist/utils/animation-loop.js +42 -0
  128. package/dist/utils/animation-loop.js.map +1 -0
  129. package/dist/utils/use-pre-resolve-user.cjs +18 -0
  130. package/dist/utils/use-pre-resolve-user.cjs.map +1 -0
  131. package/dist/utils/use-pre-resolve-user.js +16 -0
  132. package/dist/utils/use-pre-resolve-user.js.map +1 -0
  133. package/dist/utils/use-stable-component.cjs +32 -0
  134. package/dist/utils/use-stable-component.cjs.map +1 -0
  135. package/dist/utils/use-stable-component.js +30 -0
  136. package/dist/utils/use-stable-component.js.map +1 -0
  137. package/dist/version.cjs +1 -1
  138. package/dist/version.cjs.map +1 -1
  139. package/dist/version.js +1 -1
  140. package/dist/version.js.map +1 -1
  141. package/package.json +7 -10
  142. package/src/styles/dark/index.css +1 -1
  143. package/src/styles/index.css +252 -4
  144. package/styles/dark/attributes.css +1 -1
  145. package/styles/dark/attributes.css.map +1 -1
  146. package/styles/dark/media-query.css +1 -1
  147. package/styles/dark/media-query.css.map +1 -1
  148. package/styles.css +1 -1
  149. package/styles.css.map +1 -1
@@ -33,9 +33,7 @@ var Group = require('./internal/Group.cjs');
33
33
  var GroupDescription = require('./internal/GroupDescription.cjs');
34
34
  var Tooltip = require('./internal/Tooltip.cjs');
35
35
  var User = require('./internal/User.cjs');
36
- var PopoverPrimitive = require('@radix-ui/react-popover');
37
36
  var Users = require('../icons/Users.cjs');
38
- var TooltipPrimitive = require('@radix-ui/react-tooltip');
39
37
 
40
38
 
41
39
  function ComposerInsertMentionEditorAction({
@@ -85,7 +83,7 @@ function ComposerInsertEmojiEditorAction({
85
83
  const stopPropagation = react.useCallback((event) => {
86
84
  event.stopPropagation();
87
85
  }, []);
88
- return /* @__PURE__ */ jsxRuntime.jsx(EmojiPicker.EmojiPicker, { onEmojiSelect: insertText, onOpenChange: onPickerOpenChange, children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: tooltipLabel ?? label, children: /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
86
+ return /* @__PURE__ */ jsxRuntime.jsx(EmojiPicker.EmojiPicker, { onEmojiSelect: insertText, onOpenChange: onPickerOpenChange, children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: tooltipLabel ?? label, children: /* @__PURE__ */ jsxRuntime.jsx(EmojiPicker.EmojiPickerTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
89
87
  Button.Button,
90
88
  {
91
89
  className: cn.cn("lb-composer-editor-action", className),
@@ -537,7 +535,7 @@ const Composer = react.forwardRef(
537
535
  threadId
538
536
  ]
539
537
  );
540
- return /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive.TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
538
+ return /* @__PURE__ */ jsxRuntime.jsx(Tooltip.TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
541
539
  index.Form,
542
540
  {
543
541
  onComposerSubmit: handleComposerSubmit,
@@ -1 +1 @@
1
- {"version":3,"file":"Composer.cjs","sources":["../../src/components/Composer.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n BaseMetadata,\n CommentAttachment,\n CommentMixedAttachment,\n DCM,\n DTM,\n GroupMentionData,\n Patchable,\n} from \"@liveblocks/core\";\nimport { assertNever, MENTION_CHARACTER, 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 } from \"../constants\";\nimport { UsersIcon } from \"../icons\";\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 { useIsGroupMentionMember } from \"../utils/use-group-mention\";\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 { Group } from \"./internal/Group\";\nimport { GroupDescription } from \"./internal/GroupDescription\";\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<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> = {\n threadId?: never;\n\n commentId?: never;\n\n /**\n * The metadata of the thread to create.\n */\n metadata?: TM;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\ntype ComposerCreateCommentProps<CM extends BaseMetadata> = {\n /**\n * The ID of the thread to reply to.\n */\n threadId: string;\n\n commentId?: never;\n\n metadata?: never;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\ntype ComposerEditCommentProps<CM extends BaseMetadata> = {\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\n metadata?: never;\n\n /**\n * The metadata of the comment to edit.\n */\n commentMetadata?: Patchable<CM>;\n};\n\nexport type ComposerProps<\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n> = Omit<ComponentPropsWithoutRef<\"form\">, \"defaultValue\"> &\n (\n | ComposerCreateThreadProps<TM, CM>\n | ComposerCreateCommentProps<CM>\n | ComposerEditCommentProps<CM>\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 * Whether to blur the composer editor when the composer is submitted.\n */\n blurOnSubmit?: boolean;\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\ninterface ComposerMentionProps extends ComposerEditorMentionProps {\n overrides?: ComposerProps[\"overrides\"];\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 ComposerUserMention({ mention }: ComposerMentionProps) {\n return (\n <ComposerPrimitive.Mention className=\"lb-mention lb-composer-mention\">\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <User userId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nfunction ComposerGroupMention({ mention }: ComposerMentionProps) {\n const isMember = useIsGroupMentionMember(mention as GroupMentionData);\n\n return (\n <ComposerPrimitive.Mention\n className=\"lb-mention lb-composer-mention\"\n data-self={isMember ? \"\" : undefined}\n >\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <Group groupId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nexport function ComposerMention({ mention, ...props }: ComposerMentionProps) {\n switch (mention.kind) {\n case \"user\":\n return <ComposerUserMention mention={mention} {...props} />;\n\n case \"group\":\n return <ComposerGroupMention mention={mention} {...props} />;\n\n default:\n return assertNever(mention, \"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 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 {mention.kind === \"user\" ? (\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 </>\n ) : mention.kind === \"group\" ? (\n <>\n <Avatar\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-avatar\"\n icon={<UsersIcon />}\n />\n <Group\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group\"\n >\n <GroupDescription\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group-description\"\n />\n </Group>\n </>\n ) : (\n assertNever(mention, \"Unhandled mention kind\")\n )}\n </ComposerPrimitive.SuggestionsListItem>\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 || !showAttachments || 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 <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n {\n threadId,\n commentId,\n metadata,\n commentMetadata,\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 blurOnSubmit = true,\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n roomId: _roomId,\n ...props\n }: ComposerProps<TM, CM>,\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 metadata: commentMetadata,\n attachments: comment.attachments,\n });\n } else if (threadId) {\n createComment({\n threadId,\n body: comment.body,\n metadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n } else {\n createThread({\n body: comment.body,\n metadata,\n commentMetadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n }\n },\n [\n commentId,\n createComment,\n createThread,\n editComment,\n commentMetadata,\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 blurOnSubmit={blurOnSubmit}\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 <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n props: ComposerProps<TM, CM> & RefAttributes<HTMLFormElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0QA;AAA2C;AACzC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AAAoB;AAEhB;AAEA;AACE;AACA;AAAc;AAChB;AACF;AACuB;AAGzB;AAEI;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACO;AACf;AAAA;AAIZ;AAEA;AAAyC;AACvC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAIQ;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACK;AACb;AAAA;AAMhB;AAEA;AAAyC;AACvC;AACA;AACA;AAEF;AACE;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAGM;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACU;AAClB;AAAA;AAKd;AAEA;AACE;AAEI;AAAuD;AAC7B;AAGhC;AAEA;AACE;AAEA;AACE;AAAmB;AAAlB;AACW;AACiB;AAE3B;AAAuD;AAC3B;AAAA;AAAA;AAGlC;AAEO;AACL;AAAsB;AAElB;AAAyD;AAGzD;AAA0D;AAG1D;AAAoD;AAE1D;AAEA;AAAoC;AAEpC;AACE;AAIQ;AACE;AAAmB;AAAlB;AAEW;AACK;AAIX;AAAA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AACA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AAIA;AAAA;AAAC;AAAA;AACkB;AACP;AACO;AAAA;AACnB;AACA;AAAC;AAAA;AACkB;AACP;AAEV;AAAC;AAAA;AACkB;AACP;AAAA;AACZ;AAAA;AACF;AAG2C;AAAA;AAjClC;AAmCf;AAMZ;AAEA;AAAoB;AAClB;AACA;AACA;AACA;AAEF;AACE;AACA;AACE;AAAkC;AAGpC;AACE;AAAC;AAAA;AACU;AACT;AAC2C;AAM3C;AAAA;AAGN;AAMA;AAAiC;AAC0C;AAEN;AAGjE;AAAC;AAAA;AACM;AACI;AACgB;AAAA;AAC3B;AAGJ;AAEA;AAIA;AACE;AAKF;AAEA;AACE;AAKF;AAWA;AAAgC;AAC9B;AACA;AACA;AAEF;AACE;AACA;AAEA;AACE;AAA8B;AAGhC;AACE;AAAC;AAAA;AACkD;AAC7C;AACJ;AACe;AACK;AACpB;AACA;AAAA;AAGN;AAEA;AAA6B;AAC3B;AACA;AAEF;AACE;AAEA;AACE;AAAO;AAGT;AAIQ;AACE;AAAC;AAAA;AAEC;AACA;AAAA;AAFgB;AAGlB;AAMZ;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;AAC3B;AAG5C;AACE;AAAqB;AAGvB;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAEI;AAAA;AAAmB;AAAlB;AACW;AACD;AACM;AACf;AACA;AACA;AACA;AACO;AAAA;AACT;AAC+D;AAG3D;AACG;AACC;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEF;AAAC;AAAA;AACU;AACW;AACpB;AAAA;AACF;AAEE;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEJ;AACiC;AAMvB;AAAC;AAAA;AACgB;AACN;AACC;AACF;AACM;AACE;AAAA;AAM5B;AACF;AAKI;AAAgB;AACb;AAEP;AAIR;AAEa;AAQN;AAAiB;AAEpB;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACW;AACX;AACmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACG;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;AACJ;AACW;AACtB;AAED;AAAc;AACZ;AACc;AACJ;AACW;AACtB;AAED;AAAa;AACG;AACd;AACA;AACqB;AACtB;AACH;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AAEI;AAAmB;AAAlB;AACmB;AAC6C;AACxD;AACH;AACC;AAC8B;AAC1B;AACD;AACe;AACvB;AACyB;AACF;AACvB;AACA;AAEA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACU;AACV;AACf;AACA;AAAA;AACF;AAAA;AAEJ;AAGN;;;;"}
1
+ {"version":3,"file":"Composer.cjs","sources":["../../src/components/Composer.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n BaseMetadata,\n CommentAttachment,\n CommentMixedAttachment,\n DCM,\n DTM,\n GroupMentionData,\n Patchable,\n} from \"@liveblocks/core\";\nimport { assertNever, MENTION_CHARACTER, 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 } from \"../constants\";\nimport { UsersIcon } from \"../icons\";\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 { useIsGroupMentionMember } from \"../utils/use-group-mention\";\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 { Group } from \"./internal/Group\";\nimport { GroupDescription } from \"./internal/GroupDescription\";\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\nexport type ComposerCreateThreadProps<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> = {\n threadId?: never;\n\n commentId?: never;\n\n /**\n * The metadata of the thread to create.\n */\n metadata?: TM;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\nexport type ComposerCreateCommentProps<CM extends BaseMetadata> = {\n /**\n * The ID of the thread to reply to.\n */\n threadId: string;\n\n commentId?: never;\n\n metadata?: never;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\nexport type ComposerEditCommentProps<CM extends BaseMetadata> = {\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\n metadata?: never;\n\n /**\n * The metadata of the comment to edit.\n */\n commentMetadata?: Patchable<CM>;\n};\n\nexport type ComposerProps<\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n> = Omit<ComponentPropsWithoutRef<\"form\">, \"defaultValue\"> &\n (\n | ComposerCreateThreadProps<TM, CM>\n | ComposerCreateCommentProps<CM>\n | ComposerEditCommentProps<CM>\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 * Whether to blur the composer editor when the composer is submitted.\n */\n blurOnSubmit?: boolean;\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\ninterface ComposerMentionProps extends ComposerEditorMentionProps {\n overrides?: ComposerProps[\"overrides\"];\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 ComposerUserMention({ mention }: ComposerMentionProps) {\n return (\n <ComposerPrimitive.Mention className=\"lb-mention lb-composer-mention\">\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <User userId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nfunction ComposerGroupMention({ mention }: ComposerMentionProps) {\n const isMember = useIsGroupMentionMember(mention as GroupMentionData);\n\n return (\n <ComposerPrimitive.Mention\n className=\"lb-mention lb-composer-mention\"\n data-self={isMember ? \"\" : undefined}\n >\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <Group groupId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nexport function ComposerMention({ mention, ...props }: ComposerMentionProps) {\n switch (mention.kind) {\n case \"user\":\n return <ComposerUserMention mention={mention} {...props} />;\n\n case \"group\":\n return <ComposerGroupMention mention={mention} {...props} />;\n\n default:\n return assertNever(mention, \"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 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 {mention.kind === \"user\" ? (\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 </>\n ) : mention.kind === \"group\" ? (\n <>\n <Avatar\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-avatar\"\n icon={<UsersIcon />}\n />\n <Group\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group\"\n >\n <GroupDescription\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group-description\"\n />\n </Group>\n </>\n ) : (\n assertNever(mention, \"Unhandled mention kind\")\n )}\n </ComposerPrimitive.SuggestionsListItem>\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 || !showAttachments || 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 <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n {\n threadId,\n commentId,\n metadata,\n commentMetadata,\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 blurOnSubmit = true,\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n roomId: _roomId,\n ...props\n }: ComposerProps<TM, CM>,\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 metadata: commentMetadata,\n attachments: comment.attachments,\n });\n } else if (threadId) {\n createComment({\n threadId,\n body: comment.body,\n metadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n } else {\n createThread({\n body: comment.body,\n metadata,\n commentMetadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n }\n },\n [\n commentId,\n createComment,\n createThread,\n editComment,\n commentMetadata,\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 blurOnSubmit={blurOnSubmit}\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 <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n props: ComposerProps<TM, CM> & RefAttributes<HTMLFormElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0QA;AAA2C;AACzC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AAAoB;AAEhB;AAEA;AACE;AACA;AAAc;AAChB;AACF;AACuB;AAGzB;AAEI;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACO;AACf;AAAA;AAIZ;AAEA;AAAyC;AACvC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAIQ;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACK;AACb;AAAA;AAMhB;AAEA;AAAyC;AACvC;AACA;AACA;AAEF;AACE;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAGM;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACU;AAClB;AAAA;AAKd;AAEA;AACE;AAEI;AAAuD;AAC7B;AAGhC;AAEA;AACE;AAEA;AACE;AAAmB;AAAlB;AACW;AACiB;AAE3B;AAAuD;AAC3B;AAAA;AAAA;AAGlC;AAEO;AACL;AAAsB;AAElB;AAAyD;AAGzD;AAA0D;AAG1D;AAAoD;AAE1D;AAEA;AAAoC;AAEpC;AACE;AAIQ;AACE;AAAmB;AAAlB;AAEW;AACK;AAIX;AAAA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AACA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AAIA;AAAA;AAAC;AAAA;AACkB;AACP;AACO;AAAA;AACnB;AACA;AAAC;AAAA;AACkB;AACP;AAEV;AAAC;AAAA;AACkB;AACP;AAAA;AACZ;AAAA;AACF;AAG2C;AAAA;AAjClC;AAmCf;AAMZ;AAEA;AAAoB;AAClB;AACA;AACA;AACA;AAEF;AACE;AACA;AACE;AAAkC;AAGpC;AACE;AAAC;AAAA;AACU;AACT;AAC2C;AAM3C;AAAA;AAGN;AAMA;AAAiC;AAC0C;AAEN;AAGjE;AAAC;AAAA;AACM;AACI;AACgB;AAAA;AAC3B;AAGJ;AAEA;AAIA;AACE;AAKF;AAEA;AACE;AAKF;AAWA;AAAgC;AAC9B;AACA;AACA;AAEF;AACE;AACA;AAEA;AACE;AAA8B;AAGhC;AACE;AAAC;AAAA;AACkD;AAC7C;AACJ;AACe;AACK;AACpB;AACA;AAAA;AAGN;AAEA;AAA6B;AAC3B;AACA;AAEF;AACE;AAEA;AACE;AAAO;AAGT;AAIQ;AACE;AAAC;AAAA;AAEC;AACA;AAAA;AAFgB;AAGlB;AAMZ;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;AAC3B;AAG5C;AACE;AAAqB;AAGvB;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAEI;AAAA;AAAmB;AAAlB;AACW;AACD;AACM;AACf;AACA;AACA;AACA;AACO;AAAA;AACT;AAC+D;AAG3D;AACG;AACC;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEF;AAAC;AAAA;AACU;AACW;AACpB;AAAA;AACF;AAEE;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEJ;AACiC;AAMvB;AAAC;AAAA;AACgB;AACN;AACC;AACF;AACM;AACE;AAAA;AAM5B;AACF;AAKI;AAAgB;AACb;AAEP;AAIR;AAEa;AAQN;AAAiB;AAEpB;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACW;AACX;AACmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACG;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;AACJ;AACW;AACtB;AAED;AAAc;AACZ;AACc;AACJ;AACW;AACtB;AAED;AAAa;AACG;AACd;AACA;AACqB;AACtB;AACH;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AAEI;AAAmB;AAAlB;AACmB;AAC6C;AACxD;AACH;AACC;AAC8B;AAC1B;AACD;AACe;AACvB;AACyB;AACF;AACvB;AACA;AAEA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACU;AACV;AACf;AACA;AAAA;AACF;AAAA;AAEJ;AAGN;;;;"}
@@ -26,14 +26,12 @@ import { FileAttachment } from './internal/Attachment.js';
26
26
  import { Attribution } from './internal/Attribution.js';
27
27
  import { Avatar } from './internal/Avatar.js';
28
28
  import { Button } from './internal/Button.js';
29
- import { EmojiPicker } from './internal/EmojiPicker.js';
29
+ import { EmojiPicker, EmojiPickerTrigger } from './internal/EmojiPicker.js';
30
30
  import { Group } from './internal/Group.js';
31
31
  import { GroupDescription } from './internal/GroupDescription.js';
32
- import { Tooltip, ShortcutTooltip } from './internal/Tooltip.js';
32
+ import { Tooltip, ShortcutTooltip, TooltipProvider } from './internal/Tooltip.js';
33
33
  import { User } from './internal/User.js';
34
- import { PopoverTrigger } from '@radix-ui/react-popover';
35
34
  import { UsersIcon } from '../icons/Users.js';
36
- import { TooltipProvider } from '@radix-ui/react-tooltip';
37
35
 
38
36
 
39
37
  function ComposerInsertMentionEditorAction({
@@ -83,7 +81,7 @@ function ComposerInsertEmojiEditorAction({
83
81
  const stopPropagation = useCallback((event) => {
84
82
  event.stopPropagation();
85
83
  }, []);
86
- return /* @__PURE__ */ jsx(EmojiPicker, { onEmojiSelect: insertText, onOpenChange: onPickerOpenChange, children: /* @__PURE__ */ jsx(Tooltip, { content: tooltipLabel ?? label, children: /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
84
+ return /* @__PURE__ */ jsx(EmojiPicker, { onEmojiSelect: insertText, onOpenChange: onPickerOpenChange, children: /* @__PURE__ */ jsx(Tooltip, { content: tooltipLabel ?? label, children: /* @__PURE__ */ jsx(EmojiPickerTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
87
85
  Button,
88
86
  {
89
87
  className: cn("lb-composer-editor-action", className),
@@ -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 DCM,\n DTM,\n GroupMentionData,\n Patchable,\n} from \"@liveblocks/core\";\nimport { assertNever, MENTION_CHARACTER, 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 } from \"../constants\";\nimport { UsersIcon } from \"../icons\";\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 { useIsGroupMentionMember } from \"../utils/use-group-mention\";\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 { Group } from \"./internal/Group\";\nimport { GroupDescription } from \"./internal/GroupDescription\";\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<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> = {\n threadId?: never;\n\n commentId?: never;\n\n /**\n * The metadata of the thread to create.\n */\n metadata?: TM;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\ntype ComposerCreateCommentProps<CM extends BaseMetadata> = {\n /**\n * The ID of the thread to reply to.\n */\n threadId: string;\n\n commentId?: never;\n\n metadata?: never;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\ntype ComposerEditCommentProps<CM extends BaseMetadata> = {\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\n metadata?: never;\n\n /**\n * The metadata of the comment to edit.\n */\n commentMetadata?: Patchable<CM>;\n};\n\nexport type ComposerProps<\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n> = Omit<ComponentPropsWithoutRef<\"form\">, \"defaultValue\"> &\n (\n | ComposerCreateThreadProps<TM, CM>\n | ComposerCreateCommentProps<CM>\n | ComposerEditCommentProps<CM>\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 * Whether to blur the composer editor when the composer is submitted.\n */\n blurOnSubmit?: boolean;\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\ninterface ComposerMentionProps extends ComposerEditorMentionProps {\n overrides?: ComposerProps[\"overrides\"];\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 ComposerUserMention({ mention }: ComposerMentionProps) {\n return (\n <ComposerPrimitive.Mention className=\"lb-mention lb-composer-mention\">\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <User userId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nfunction ComposerGroupMention({ mention }: ComposerMentionProps) {\n const isMember = useIsGroupMentionMember(mention as GroupMentionData);\n\n return (\n <ComposerPrimitive.Mention\n className=\"lb-mention lb-composer-mention\"\n data-self={isMember ? \"\" : undefined}\n >\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <Group groupId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nexport function ComposerMention({ mention, ...props }: ComposerMentionProps) {\n switch (mention.kind) {\n case \"user\":\n return <ComposerUserMention mention={mention} {...props} />;\n\n case \"group\":\n return <ComposerGroupMention mention={mention} {...props} />;\n\n default:\n return assertNever(mention, \"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 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 {mention.kind === \"user\" ? (\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 </>\n ) : mention.kind === \"group\" ? (\n <>\n <Avatar\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-avatar\"\n icon={<UsersIcon />}\n />\n <Group\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group\"\n >\n <GroupDescription\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group-description\"\n />\n </Group>\n </>\n ) : (\n assertNever(mention, \"Unhandled mention kind\")\n )}\n </ComposerPrimitive.SuggestionsListItem>\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 || !showAttachments || 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 <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n {\n threadId,\n commentId,\n metadata,\n commentMetadata,\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 blurOnSubmit = true,\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n roomId: _roomId,\n ...props\n }: ComposerProps<TM, CM>,\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 metadata: commentMetadata,\n attachments: comment.attachments,\n });\n } else if (threadId) {\n createComment({\n threadId,\n body: comment.body,\n metadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n } else {\n createThread({\n body: comment.body,\n metadata,\n commentMetadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n }\n },\n [\n commentId,\n createComment,\n createThread,\n editComment,\n commentMetadata,\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 blurOnSubmit={blurOnSubmit}\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 <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n props: ComposerProps<TM, CM> & RefAttributes<HTMLFormElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0QA;AAA2C;AACzC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AAAoB;AAEhB;AAEA;AACE;AACA;AAAc;AAChB;AACF;AACuB;AAGzB;AAEI;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACO;AACf;AAAA;AAIZ;AAEA;AAAyC;AACvC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAIQ;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACK;AACb;AAAA;AAMhB;AAEA;AAAyC;AACvC;AACA;AACA;AAEF;AACE;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAGM;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACU;AAClB;AAAA;AAKd;AAEA;AACE;AAEI;AAAuD;AAC7B;AAGhC;AAEA;AACE;AAEA;AACE;AAAmB;AAAlB;AACW;AACiB;AAE3B;AAAuD;AAC3B;AAAA;AAAA;AAGlC;AAEO;AACL;AAAsB;AAElB;AAAyD;AAGzD;AAA0D;AAG1D;AAAoD;AAE1D;AAEA;AAAoC;AAEpC;AACE;AAIQ;AACE;AAAmB;AAAlB;AAEW;AACK;AAIX;AAAA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AACA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AAIA;AAAA;AAAC;AAAA;AACkB;AACP;AACO;AAAA;AACnB;AACA;AAAC;AAAA;AACkB;AACP;AAEV;AAAC;AAAA;AACkB;AACP;AAAA;AACZ;AAAA;AACF;AAG2C;AAAA;AAjClC;AAmCf;AAMZ;AAEA;AAAoB;AAClB;AACA;AACA;AACA;AAEF;AACE;AACA;AACE;AAAkC;AAGpC;AACE;AAAC;AAAA;AACU;AACT;AAC2C;AAM3C;AAAA;AAGN;AAMA;AAAiC;AAC0C;AAEN;AAGjE;AAAC;AAAA;AACM;AACI;AACgB;AAAA;AAC3B;AAGJ;AAEA;AAIA;AACE;AAKF;AAEA;AACE;AAKF;AAWA;AAAgC;AAC9B;AACA;AACA;AAEF;AACE;AACA;AAEA;AACE;AAA8B;AAGhC;AACE;AAAC;AAAA;AACkD;AAC7C;AACJ;AACe;AACK;AACpB;AACA;AAAA;AAGN;AAEA;AAA6B;AAC3B;AACA;AAEF;AACE;AAEA;AACE;AAAO;AAGT;AAIQ;AACE;AAAC;AAAA;AAEC;AACA;AAAA;AAFgB;AAGlB;AAMZ;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;AAC3B;AAG5C;AACE;AAAqB;AAGvB;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAEI;AAAA;AAAmB;AAAlB;AACW;AACD;AACM;AACf;AACA;AACA;AACA;AACO;AAAA;AACT;AAC+D;AAG3D;AACG;AACC;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEF;AAAC;AAAA;AACU;AACW;AACpB;AAAA;AACF;AAEE;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEJ;AACiC;AAMvB;AAAC;AAAA;AACgB;AACN;AACC;AACF;AACM;AACE;AAAA;AAM5B;AACF;AAKI;AAAgB;AACb;AAEP;AAIR;AAEa;AAQN;AAAiB;AAEpB;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACW;AACX;AACmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACG;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;AACJ;AACW;AACtB;AAED;AAAc;AACZ;AACc;AACJ;AACW;AACtB;AAED;AAAa;AACG;AACd;AACA;AACqB;AACtB;AACH;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AAEI;AAAmB;AAAlB;AACmB;AAC6C;AACxD;AACH;AACC;AAC8B;AAC1B;AACD;AACe;AACvB;AACyB;AACF;AACvB;AACA;AAEA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACU;AACV;AACf;AACA;AAAA;AACF;AAAA;AAEJ;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 DCM,\n DTM,\n GroupMentionData,\n Patchable,\n} from \"@liveblocks/core\";\nimport { assertNever, MENTION_CHARACTER, 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 } from \"../constants\";\nimport { UsersIcon } from \"../icons\";\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 { useIsGroupMentionMember } from \"../utils/use-group-mention\";\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 { Group } from \"./internal/Group\";\nimport { GroupDescription } from \"./internal/GroupDescription\";\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\nexport type ComposerCreateThreadProps<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> = {\n threadId?: never;\n\n commentId?: never;\n\n /**\n * The metadata of the thread to create.\n */\n metadata?: TM;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\nexport type ComposerCreateCommentProps<CM extends BaseMetadata> = {\n /**\n * The ID of the thread to reply to.\n */\n threadId: string;\n\n commentId?: never;\n\n metadata?: never;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\nexport type ComposerEditCommentProps<CM extends BaseMetadata> = {\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\n metadata?: never;\n\n /**\n * The metadata of the comment to edit.\n */\n commentMetadata?: Patchable<CM>;\n};\n\nexport type ComposerProps<\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n> = Omit<ComponentPropsWithoutRef<\"form\">, \"defaultValue\"> &\n (\n | ComposerCreateThreadProps<TM, CM>\n | ComposerCreateCommentProps<CM>\n | ComposerEditCommentProps<CM>\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 * Whether to blur the composer editor when the composer is submitted.\n */\n blurOnSubmit?: boolean;\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\ninterface ComposerMentionProps extends ComposerEditorMentionProps {\n overrides?: ComposerProps[\"overrides\"];\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 ComposerUserMention({ mention }: ComposerMentionProps) {\n return (\n <ComposerPrimitive.Mention className=\"lb-mention lb-composer-mention\">\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <User userId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nfunction ComposerGroupMention({ mention }: ComposerMentionProps) {\n const isMember = useIsGroupMentionMember(mention as GroupMentionData);\n\n return (\n <ComposerPrimitive.Mention\n className=\"lb-mention lb-composer-mention\"\n data-self={isMember ? \"\" : undefined}\n >\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <Group groupId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nexport function ComposerMention({ mention, ...props }: ComposerMentionProps) {\n switch (mention.kind) {\n case \"user\":\n return <ComposerUserMention mention={mention} {...props} />;\n\n case \"group\":\n return <ComposerGroupMention mention={mention} {...props} />;\n\n default:\n return assertNever(mention, \"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 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 {mention.kind === \"user\" ? (\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 </>\n ) : mention.kind === \"group\" ? (\n <>\n <Avatar\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-avatar\"\n icon={<UsersIcon />}\n />\n <Group\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group\"\n >\n <GroupDescription\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group-description\"\n />\n </Group>\n </>\n ) : (\n assertNever(mention, \"Unhandled mention kind\")\n )}\n </ComposerPrimitive.SuggestionsListItem>\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 || !showAttachments || 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 <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n {\n threadId,\n commentId,\n metadata,\n commentMetadata,\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 blurOnSubmit = true,\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n roomId: _roomId,\n ...props\n }: ComposerProps<TM, CM>,\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 metadata: commentMetadata,\n attachments: comment.attachments,\n });\n } else if (threadId) {\n createComment({\n threadId,\n body: comment.body,\n metadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n } else {\n createThread({\n body: comment.body,\n metadata,\n commentMetadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n }\n },\n [\n commentId,\n createComment,\n createThread,\n editComment,\n commentMetadata,\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 blurOnSubmit={blurOnSubmit}\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 <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n props: ComposerProps<TM, CM> & RefAttributes<HTMLFormElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0QA;AAA2C;AACzC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AAAoB;AAEhB;AAEA;AACE;AACA;AAAc;AAChB;AACF;AACuB;AAGzB;AAEI;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACO;AACf;AAAA;AAIZ;AAEA;AAAyC;AACvC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAIQ;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACK;AACb;AAAA;AAMhB;AAEA;AAAyC;AACvC;AACA;AACA;AAEF;AACE;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAGM;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACU;AAClB;AAAA;AAKd;AAEA;AACE;AAEI;AAAuD;AAC7B;AAGhC;AAEA;AACE;AAEA;AACE;AAAmB;AAAlB;AACW;AACiB;AAE3B;AAAuD;AAC3B;AAAA;AAAA;AAGlC;AAEO;AACL;AAAsB;AAElB;AAAyD;AAGzD;AAA0D;AAG1D;AAAoD;AAE1D;AAEA;AAAoC;AAEpC;AACE;AAIQ;AACE;AAAmB;AAAlB;AAEW;AACK;AAIX;AAAA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AACA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AAIA;AAAA;AAAC;AAAA;AACkB;AACP;AACO;AAAA;AACnB;AACA;AAAC;AAAA;AACkB;AACP;AAEV;AAAC;AAAA;AACkB;AACP;AAAA;AACZ;AAAA;AACF;AAG2C;AAAA;AAjClC;AAmCf;AAMZ;AAEA;AAAoB;AAClB;AACA;AACA;AACA;AAEF;AACE;AACA;AACE;AAAkC;AAGpC;AACE;AAAC;AAAA;AACU;AACT;AAC2C;AAM3C;AAAA;AAGN;AAMA;AAAiC;AAC0C;AAEN;AAGjE;AAAC;AAAA;AACM;AACI;AACgB;AAAA;AAC3B;AAGJ;AAEA;AAIA;AACE;AAKF;AAEA;AACE;AAKF;AAWA;AAAgC;AAC9B;AACA;AACA;AAEF;AACE;AACA;AAEA;AACE;AAA8B;AAGhC;AACE;AAAC;AAAA;AACkD;AAC7C;AACJ;AACe;AACK;AACpB;AACA;AAAA;AAGN;AAEA;AAA6B;AAC3B;AACA;AAEF;AACE;AAEA;AACE;AAAO;AAGT;AAIQ;AACE;AAAC;AAAA;AAEC;AACA;AAAA;AAFgB;AAGlB;AAMZ;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;AAC3B;AAG5C;AACE;AAAqB;AAGvB;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAEI;AAAA;AAAmB;AAAlB;AACW;AACD;AACM;AACf;AACA;AACA;AACA;AACO;AAAA;AACT;AAC+D;AAG3D;AACG;AACC;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEF;AAAC;AAAA;AACU;AACW;AACpB;AAAA;AACF;AAEE;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEJ;AACiC;AAMvB;AAAC;AAAA;AACgB;AACN;AACC;AACF;AACM;AACE;AAAA;AAM5B;AACF;AAKI;AAAgB;AACb;AAEP;AAIR;AAEa;AAQN;AAAiB;AAEpB;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACW;AACX;AACmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACG;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;AACJ;AACW;AACtB;AAED;AAAc;AACZ;AACc;AACJ;AACW;AACtB;AAED;AAAa;AACG;AACd;AACA;AACqB;AACtB;AACH;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AAEI;AAAmB;AAAlB;AACmB;AAC6C;AACxD;AACH;AACC;AAC8B;AAC1B;AACD;AACe;AACvB;AACyB;AACF;AACvB;AACA;AAEA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACU;AACV;AACf;AACA;AAAA;AACF;AAAA;AAEJ;AAGN;;"}
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var cn = require('../utils/cn.cjs');
6
+
7
+ const Cursor = react.forwardRef(
8
+ ({ className, label, color, style, ...props }, forwardedRef) => {
9
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10
+ "div",
11
+ {
12
+ className: cn.cn("lb-root lb-cursor", className),
13
+ style: { "--lb-cursor-color": color, ...style },
14
+ ...props,
15
+ ref: forwardedRef,
16
+ children: [
17
+ /* @__PURE__ */ jsxRuntime.jsx(
18
+ "svg",
19
+ {
20
+ xmlns: "http://www.w3.org/2000/svg",
21
+ viewBox: "0 0 32 32",
22
+ className: "lb-cursor-pointer",
23
+ children: /* @__PURE__ */ jsxRuntime.jsx(
24
+ "path",
25
+ {
26
+ fill: "currentColor",
27
+ d: "m.088 1.75 11.25 29.422c.409 1.07 1.908 1.113 2.377.067l5.223-11.653c.13-.288.36-.518.648-.648l11.653-5.223c1.046-.47 1.004-1.968-.067-2.377L1.75.088C.71-.31-.31.71.088 1.75Z"
28
+ }
29
+ )
30
+ }
31
+ ),
32
+ label ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "lb-cursor-bubble", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "lb-cursor-bubble-label", children: label }) }) : null
33
+ ]
34
+ }
35
+ );
36
+ }
37
+ );
38
+
39
+ exports.Cursor = Cursor;
40
+ //# sourceMappingURL=Cursor.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cursor.cjs","sources":["../../src/components/Cursor.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, CSSProperties, ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../utils/cn\";\n\nexport interface CursorProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * A floating label to display next to the cursor.\n */\n label?: ReactNode;\n\n /**\n * The color of the cursor.\n */\n color?: string;\n}\n\n/**\n * Displays a multiplayer cursor.\n */\nexport const Cursor = forwardRef<HTMLDivElement, CursorProps>(\n ({ className, label, color, style, ...props }, forwardedRef) => {\n return (\n <div\n className={cn(\"lb-root lb-cursor\", className)}\n style={{ \"--lb-cursor-color\": color, ...style } as CSSProperties}\n {...props}\n ref={forwardedRef}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 32 32\"\n className=\"lb-cursor-pointer\"\n >\n <path\n fill=\"currentColor\"\n d=\"m.088 1.75 11.25 29.422c.409 1.07 1.908 1.113 2.377.067l5.223-11.653c.13-.288.36-.518.648-.648l11.653-5.223c1.046-.47 1.004-1.968-.067-2.377L1.75.088C.71-.31-.31.71.088 1.75Z\"\n />\n </svg>\n {label ? (\n <div className=\"lb-cursor-bubble\">\n <span className=\"lb-cursor-bubble-label\">{label}</span>\n </div>\n ) : null}\n </div>\n );\n }\n);\n"],"names":["forwardRef","jsxs","cn","jsx"],"mappings":";;;;;;AAoBO,MAAM,MAAS,GAAAA,gBAAA;AAAA,EACpB,CAAC,EAAE,SAAW,EAAA,KAAA,EAAO,OAAO,KAAO,EAAA,GAAG,KAAM,EAAA,EAAG,YAAiB,KAAA;AAC9D,IACE,uBAAAC,eAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAWC,KAAG,CAAA,mBAAA,EAAqB,SAAS,CAAA;AAAA,QAC5C,KAAO,EAAA,EAAE,mBAAqB,EAAA,KAAA,EAAO,GAAG,KAAM,EAAA;AAAA,QAC7C,GAAG,KAAA;AAAA,QACJ,GAAK,EAAA,YAAA;AAAA,QAEL,QAAA,EAAA;AAAA,0BAAAC,cAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,KAAM,EAAA,4BAAA;AAAA,cACN,OAAQ,EAAA,WAAA;AAAA,cACR,SAAU,EAAA,mBAAA;AAAA,cAEV,QAAA,kBAAAA,cAAA;AAAA,gBAAC,MAAA;AAAA,gBAAA;AAAA,kBACC,IAAK,EAAA,cAAA;AAAA,kBACL,CAAE,EAAA,gLAAA;AAAA,iBAAA;AAAA,eACJ;AAAA,aAAA;AAAA,WACF;AAAA,UACC,KAAA,mBACEA,cAAA,CAAA,KAAA,EAAA,EAAI,SAAU,EAAA,kBAAA,EACb,QAAC,kBAAAA,cAAA,CAAA,MAAA,EAAA,EAAK,SAAU,EAAA,wBAAA,EAA0B,QAAM,EAAA,KAAA,EAAA,CAAA,EAClD,CACE,GAAA,IAAA;AAAA,SAAA;AAAA,OAAA;AAAA,KACN,CAAA;AAAA,GAEJ;AACF;;;;"}
@@ -0,0 +1,38 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { forwardRef } from 'react';
3
+ import { cn } from '../utils/cn.js';
4
+
5
+ const Cursor = forwardRef(
6
+ ({ className, label, color, style, ...props }, forwardedRef) => {
7
+ return /* @__PURE__ */ jsxs(
8
+ "div",
9
+ {
10
+ className: cn("lb-root lb-cursor", className),
11
+ style: { "--lb-cursor-color": color, ...style },
12
+ ...props,
13
+ ref: forwardedRef,
14
+ children: [
15
+ /* @__PURE__ */ jsx(
16
+ "svg",
17
+ {
18
+ xmlns: "http://www.w3.org/2000/svg",
19
+ viewBox: "0 0 32 32",
20
+ className: "lb-cursor-pointer",
21
+ children: /* @__PURE__ */ jsx(
22
+ "path",
23
+ {
24
+ fill: "currentColor",
25
+ d: "m.088 1.75 11.25 29.422c.409 1.07 1.908 1.113 2.377.067l5.223-11.653c.13-.288.36-.518.648-.648l11.653-5.223c1.046-.47 1.004-1.968-.067-2.377L1.75.088C.71-.31-.31.71.088 1.75Z"
26
+ }
27
+ )
28
+ }
29
+ ),
30
+ label ? /* @__PURE__ */ jsx("div", { className: "lb-cursor-bubble", children: /* @__PURE__ */ jsx("span", { className: "lb-cursor-bubble-label", children: label }) }) : null
31
+ ]
32
+ }
33
+ );
34
+ }
35
+ );
36
+
37
+ export { Cursor };
38
+ //# sourceMappingURL=Cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cursor.js","sources":["../../src/components/Cursor.tsx"],"sourcesContent":["import type { ComponentPropsWithoutRef, CSSProperties, ReactNode } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../utils/cn\";\n\nexport interface CursorProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * A floating label to display next to the cursor.\n */\n label?: ReactNode;\n\n /**\n * The color of the cursor.\n */\n color?: string;\n}\n\n/**\n * Displays a multiplayer cursor.\n */\nexport const Cursor = forwardRef<HTMLDivElement, CursorProps>(\n ({ className, label, color, style, ...props }, forwardedRef) => {\n return (\n <div\n className={cn(\"lb-root lb-cursor\", className)}\n style={{ \"--lb-cursor-color\": color, ...style } as CSSProperties}\n {...props}\n ref={forwardedRef}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 32 32\"\n className=\"lb-cursor-pointer\"\n >\n <path\n fill=\"currentColor\"\n d=\"m.088 1.75 11.25 29.422c.409 1.07 1.908 1.113 2.377.067l5.223-11.653c.13-.288.36-.518.648-.648l11.653-5.223c1.046-.47 1.004-1.968-.067-2.377L1.75.088C.71-.31-.31.71.088 1.75Z\"\n />\n </svg>\n {label ? (\n <div className=\"lb-cursor-bubble\">\n <span className=\"lb-cursor-bubble-label\">{label}</span>\n </div>\n ) : null}\n </div>\n );\n }\n);\n"],"names":[],"mappings":";;;;AAoBO,MAAM,MAAS,GAAA,UAAA;AAAA,EACpB,CAAC,EAAE,SAAW,EAAA,KAAA,EAAO,OAAO,KAAO,EAAA,GAAG,KAAM,EAAA,EAAG,YAAiB,KAAA;AAC9D,IACE,uBAAA,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,EAAG,CAAA,mBAAA,EAAqB,SAAS,CAAA;AAAA,QAC5C,KAAO,EAAA,EAAE,mBAAqB,EAAA,KAAA,EAAO,GAAG,KAAM,EAAA;AAAA,QAC7C,GAAG,KAAA;AAAA,QACJ,GAAK,EAAA,YAAA;AAAA,QAEL,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,KAAM,EAAA,4BAAA;AAAA,cACN,OAAQ,EAAA,WAAA;AAAA,cACR,SAAU,EAAA,mBAAA;AAAA,cAEV,QAAA,kBAAA,GAAA;AAAA,gBAAC,MAAA;AAAA,gBAAA;AAAA,kBACC,IAAK,EAAA,cAAA;AAAA,kBACL,CAAE,EAAA,gLAAA;AAAA,iBAAA;AAAA,eACJ;AAAA,aAAA;AAAA,WACF;AAAA,UACC,KAAA,mBACE,GAAA,CAAA,KAAA,EAAA,EAAI,SAAU,EAAA,kBAAA,EACb,QAAC,kBAAA,GAAA,CAAA,MAAA,EAAA,EAAK,SAAU,EAAA,wBAAA,EAA0B,QAAM,EAAA,KAAA,EAAA,CAAA,EAClD,CACE,GAAA,IAAA;AAAA,SAAA;AAAA,OAAA;AAAA,KACN,CAAA;AAAA,GAEJ;AACF;;;;"}