@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
@@ -1 +1 @@
1
- {"version":3,"file":"AiChat.js","sources":["../../src/components/AiChat.tsx"],"sourcesContent":["import type {\n AiKnowledgeSource,\n AiOpaqueToolDefinition,\n CopilotId,\n MessageId,\n} from \"@liveblocks/core\";\nimport {\n RegisterAiKnowledge,\n RegisterAiTool,\n useAiChatMessages,\n} from \"@liveblocks/react\";\nimport { useLatest } from \"@liveblocks/react/_private\";\nimport {\n type ComponentProps,\n type ComponentType,\n forwardRef,\n type MutableRefObject,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { ArrowDownIcon } from \"../icons/ArrowDown\";\nimport { SpinnerIcon } from \"../icons/Spinner\";\nimport {\n type AiChatMessageOverrides,\n type AiChatOverrides,\n type AiComposerOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../overrides\";\nimport type { MarkdownComponents } from \"../primitives/Markdown\";\nimport { cn } from \"../utils/cn\";\nimport { useIntersectionCallback } from \"../utils/use-visible\";\nimport {\n AiChatAssistantMessage,\n type AiChatAssistantMessageProps,\n} from \"./internal/AiChatAssistantMessage\";\nimport { AiChatUserMessage } from \"./internal/AiChatUserMessage\";\nimport { AiComposer, type AiComposerProps } from \"./internal/AiComposer\";\n\n/**\n * The minimum number of pixels from the bottom of the scrollable area\n * before showing the scroll to bottom indicator.\n */\nconst MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR = 60;\n\nexport type AiChatComponentsEmptyProps = {\n /**\n * The chat ID provided to the `AiChat` component.\n */\n chatId: string;\n\n /**\n * The copilot ID provided to the `AiChat` component.\n */\n copilotId?: string;\n};\n\nexport type AiChatComponentsLoadingProps = Record<string, never>;\n\nexport type AiChatComponents = {\n /**\n * The component used to render the empty state of the chat.\n */\n Empty: ComponentType<AiChatComponentsEmptyProps>;\n\n /**\n * The component used to render the loading state of the chat.\n */\n Loading: ComponentType<AiChatComponentsLoadingProps>;\n\n /**\n * The components used to render Markdown content.\n */\n markdown?: Partial<MarkdownComponents>;\n};\n\nexport interface AiChatProps extends ComponentProps<\"div\"> {\n /**\n * The ID of the chat the composer belongs to.\n */\n chatId: string;\n\n /**\n * Whether to focus the chat composer on mount.\n */\n autoFocus?: boolean;\n\n /**\n * The ID of the copilot to use to send the message.\n */\n copilotId?: string;\n\n /**\n * The contextual knowledge to include in the chat. May be used by the\n * assistant when generating responses. In addition to the knowledge passed\n * in via this prop, the AiChat instance will also have access to any\n * globally registered knowledge via <RegisterAiKnowledge />.\n */\n knowledge?: AiKnowledgeSource[];\n\n /**\n * Tool definitions to make available within this chat. May be used by the assistant when generating responses.\n */\n tools?: Record<string, AiOpaqueToolDefinition>;\n\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: AiComposerProps[\"onComposerSubmit\"];\n\n /**\n * The layout of the chat and its composer.\n */\n layout?: \"inset\" | \"compact\";\n\n /**\n * How to show or hide reasoning.\n */\n showReasoning?: AiChatAssistantMessageProps[\"showReasoning\"];\n\n /**\n * How to show or hide retrievals.\n */\n showRetrievals?: AiChatAssistantMessageProps[\"showRetrievals\"];\n\n /**\n * Whether to show sources\n */\n showSources?: AiChatAssistantMessageProps[\"showSources\"];\n\n /**\n * The time, in milliseconds, before an AI response will timeout.\n */\n responseTimeout?: number;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n AiComposerOverrides &\n AiChatMessageOverrides &\n AiChatOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & AiChatComponents>;\n}\n\ninterface AiChatMessagesProps extends ComponentProps<\"div\"> {\n messages: NonNullable<ReturnType<typeof useAiChatMessages>[\"messages\"]>;\n overrides: AiChatProps[\"overrides\"];\n components: AiChatProps[\"components\"];\n showReasoning: AiChatProps[\"showReasoning\"];\n showRetrievals: AiChatProps[\"showRetrievals\"];\n showSources: AiChatProps[\"showSources\"];\n lastSentMessageId: MessageId | null;\n scrollToBottom: MutableRefObject<\n (behavior: \"instant\" | \"smooth\", includeTrailingSpace?: boolean) => void\n >;\n onScrollAtBottomChange: MutableRefObject<\n (isScrollAtBottom: boolean | null) => void\n >;\n containerRef: MutableRefObject<HTMLDivElement | null>;\n footerRef: MutableRefObject<HTMLDivElement | null>;\n messagesRef: MutableRefObject<HTMLDivElement | null>;\n bottomTrailingMarkerRef: MutableRefObject<HTMLDivElement | null>;\n trailingSpacerRef: MutableRefObject<HTMLDivElement | null>;\n}\n\nconst defaultComponents: AiChatComponents = {\n Empty: () => null,\n Loading: () => (\n <div className=\"lb-loading lb-ai-chat-loading\">\n <SpinnerIcon />\n </div>\n ),\n};\n\nconst AiChatMessages = forwardRef<HTMLDivElement, AiChatMessagesProps>(\n (\n {\n messages,\n overrides,\n components,\n showReasoning,\n showRetrievals,\n showSources,\n lastSentMessageId,\n scrollToBottom,\n onScrollAtBottomChange,\n containerRef,\n footerRef,\n messagesRef,\n bottomTrailingMarkerRef,\n trailingSpacerRef,\n className,\n ...props\n },\n forwardedRef\n ) => {\n const hasLastSentMessage = lastSentMessageId !== null;\n\n /**\n * Every time the container, footer, or messages list change size,\n * we calculate the trailing space that would allow the penultimate\n * message to be at the top of the viewport, and apply it.\n *\n * ┌─────────────────────────────────────────┐▲ A = The `scroll-margin-top`\n * │ ┌─────────────────────────┐ │▼▲ value of the penultimate message\n * │ │ The penultimate message │ │ │\n * │ └─────────────────────────┘ │ │ B = The height from the top of\n * │ │ │ the penultimate message to the\n * │ ┌─────────────────────────┐ │ │ bottom of the messages list,\n * │ │ The last message │ │ │ including the messages' heights,\n * │ └─────────────────────────┘ │ │ and any padding, gap, etc\n * │ │ │\n * ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤▲▼\n * │ ││ The trailing space needed to\n * │ = container height - (A + B + C) ││ allow the penultimate message\n * │ ││ to be at the top of the viewport\n * ├ ┬─────────────────────────────────────┬ ┤▼▲\n * │ │ │ │ │\n * │ │ │ │ │ C = The footer's height,\n * │ │ │ │ │ including any padding\n * │ └─────────────────────────────────────┘ │ │\n * └─────────────────────────────────────────┘ ▼\n */\n useEffect(\n () => {\n if (!hasLastSentMessage) {\n return;\n }\n\n const container = containerRef.current;\n const footer = footerRef.current;\n const messages = messagesRef.current;\n\n if (!container || !footer || !messages) {\n return;\n }\n\n const trailingSpacer = trailingSpacerRef.current;\n const bottomTrailingMarker = bottomTrailingMarkerRef.current;\n\n let containerHeight: number | undefined = undefined;\n let footerHeight: number | undefined = undefined;\n let messagesHeight: number | undefined = undefined;\n\n const resetTrailingSpace = () => {\n trailingSpacer?.style.removeProperty(\"height\");\n bottomTrailingMarker?.style.removeProperty(\"top\");\n };\n\n const updateTrailingSpace = (\n updatedContainerHeight?: number,\n updatedFooterHeight?: number,\n updatedMessagesHeight?: number\n ) => {\n if (!trailingSpacer || !bottomTrailingMarker) {\n return;\n }\n\n const lastMessage = messages.lastElementChild;\n const penultimateMessage = lastMessage?.previousElementSibling;\n\n if (updatedContainerHeight === undefined) {\n updatedContainerHeight = container.getBoundingClientRect().height;\n }\n\n if (updatedFooterHeight === undefined) {\n updatedFooterHeight = footer.getBoundingClientRect().height;\n }\n\n if (updatedMessagesHeight === undefined) {\n updatedMessagesHeight = messages.getBoundingClientRect().height;\n }\n\n // If the heights haven't changed, there's no need to update the trailing space.\n if (\n updatedContainerHeight === containerHeight &&\n updatedFooterHeight === footerHeight &&\n updatedMessagesHeight === messagesHeight\n ) {\n if (\n !lastMessage ||\n !penultimateMessage ||\n container.scrollHeight === container.clientHeight\n ) {\n resetTrailingSpace();\n }\n return;\n }\n\n // Now that we have compared them, we can update the heights.\n containerHeight = updatedContainerHeight;\n footerHeight = updatedFooterHeight;\n messagesHeight = updatedMessagesHeight;\n\n // If there's no last pair of messages, there's no need for any trailing space.\n if (!lastMessage || !penultimateMessage) {\n resetTrailingSpace();\n return;\n }\n\n // If the container isn't scrollable, there's no need for trailing space.\n if (container.scrollHeight === container.clientHeight) {\n resetTrailingSpace();\n return;\n }\n\n // A\n const penultimateMessageScrollMarginTop = Number.parseFloat(\n getComputedStyle(penultimateMessage as HTMLElement).scrollMarginTop\n );\n\n // B\n const messagesRect = messages.getBoundingClientRect();\n const penultimateMessageRect =\n penultimateMessage.getBoundingClientRect();\n const heightFromPenultimateMessageTopToMessagesListBottom =\n messagesRect.bottom - penultimateMessageRect.top;\n\n // A + B + C\n const differenceHeight =\n penultimateMessageScrollMarginTop +\n heightFromPenultimateMessageTopToMessagesListBottom +\n (footerHeight ?? 0);\n\n // = container height - (A + B + C)\n const trailingSpace = Math.max(containerHeight - differenceHeight, 0);\n\n // Update the trailing space.\n trailingSpacer.style.height = `${trailingSpace}px`;\n\n // Offset what \"the bottom\" is to the \"scroll at the bottom\" detection logic,\n // so that it doesn't include the trailing space.\n bottomTrailingMarker.style.top = `${-trailingSpace}px`;\n };\n\n const resizeObserver = new ResizeObserver((entries) => {\n let updatedContainerHeight: number | undefined = containerHeight;\n let updatedFooterHeight: number | undefined = footerHeight;\n let updatedMessagesHeight: number | undefined = messagesHeight;\n\n for (const entry of entries) {\n const entryHeight =\n entry.borderBoxSize?.[0]?.blockSize ?? entry.contentRect.height;\n\n if (entry.target === container) {\n updatedContainerHeight = entryHeight;\n } else if (entry.target === footer) {\n updatedFooterHeight = entryHeight;\n } else if (entry.target === messages) {\n updatedMessagesHeight = entryHeight;\n }\n }\n\n updateTrailingSpace(\n updatedContainerHeight,\n updatedFooterHeight,\n updatedMessagesHeight\n );\n });\n\n resizeObserver.observe(container);\n resizeObserver.observe(footer);\n resizeObserver.observe(messages);\n\n // Initialize before the first resize.\n requestAnimationFrame(() => updateTrailingSpace());\n\n return () => {\n resizeObserver.disconnect();\n resetTrailingSpace();\n };\n },\n // This effect only uses stable refs.\n [hasLastSentMessage] // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n /**\n * Update the \"scroll at bottom\" state when needed.\n */\n useIntersectionCallback(\n bottomTrailingMarkerRef,\n (isIntersecting) => {\n onScrollAtBottomChange.current(isIntersecting);\n },\n { root: containerRef, rootMargin: MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR }\n );\n\n /**\n * Instantly scroll to the bottom for the initial state.\n */\n useEffect(\n () => {\n scrollToBottom.current(\"instant\");\n },\n // `scrollToBottom` is a stable ref containing the callback.\n [] // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n /**\n * Scroll to new messages when sending them.\n */\n useEffect(\n () => {\n if (lastSentMessageId) {\n scrollToBottom.current(\"smooth\", true);\n }\n },\n // `scrollToBottom` is a stable ref containing the callback.\n [lastSentMessageId] // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n /**\n * Reset the \"scroll at bottom\" state when the component unmounts.\n */\n useEffect(\n () => {\n const onScrollAtBottomChangeCallback = onScrollAtBottomChange.current;\n\n return () => {\n onScrollAtBottomChangeCallback(null);\n };\n },\n // `onScrollAtBottomChange` is a stable ref containing the callback.\n [] // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n return (\n <div\n className={cn(\"lb-ai-chat-messages\", className)}\n ref={forwardedRef}\n {...props}\n >\n {messages.map((message) => {\n if (message.role === \"user\") {\n return (\n <AiChatUserMessage\n key={message.id}\n message={message}\n overrides={overrides}\n components={components}\n />\n );\n } else if (message.role === \"assistant\") {\n return (\n <AiChatAssistantMessage\n key={message.id}\n message={message}\n overrides={overrides}\n components={components}\n showReasoning={showReasoning}\n showRetrievals={showRetrievals}\n showSources={showSources}\n />\n );\n } else {\n return null;\n }\n })}\n </div>\n );\n }\n);\n\n// Call `Element.scrollIntoView()` unless the element is not displayed.\n// (with `display: none` or nested within elements with `display: none`)\n// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView\n//\n// This avoids browser quirks where they still attempt to scroll to the\n// element but it results in a scroll to the document's top.\nfunction scrollIntoView(\n element: HTMLElement | null,\n options?: ScrollIntoViewOptions\n) {\n if (!element) {\n return;\n }\n\n // Checking for at least one client rect allows 0 width/height elements,\n // unlike checking if the width/height is 0 with `getBoundingClientRect`.\n if (element.getClientRects().length === 0) {\n return;\n }\n\n element.scrollIntoView(options);\n}\n\nexport const AiChat = forwardRef<HTMLDivElement, AiChatProps>(\n (\n {\n chatId,\n copilotId,\n autoFocus,\n overrides,\n knowledge: localKnowledge,\n tools = {},\n onComposerSubmit,\n layout = \"inset\",\n showReasoning,\n showRetrievals,\n showSources,\n components,\n className,\n responseTimeout,\n ...props\n },\n forwardedRef\n ) => {\n const { messages, isLoading, error } = useAiChatMessages(chatId);\n const [lastSentMessageId, setLastSentMessageId] =\n useState<MessageId | null>(null);\n\n const $ = useOverrides(overrides);\n const Empty = components?.Empty ?? defaultComponents.Empty;\n const Loading = components?.Loading ?? defaultComponents.Loading;\n\n const containerRef = useRef<HTMLDivElement | null>(null);\n const messagesRef = useRef<HTMLDivElement | null>(null);\n const footerRef = useRef<HTMLDivElement | null>(null);\n const bottomMarkerRef = useRef<HTMLDivElement | null>(null);\n const bottomTrailingMarkerRef = useRef<HTMLDivElement | null>(null);\n const trailingSpacerRef = useRef<HTMLDivElement | null>(null);\n\n const [isScrollAtBottom, setScrollAtBottom] = useState<boolean | null>(\n null\n );\n // `useState`'s setter is stable but this is for clarity in the places it's used.\n const onScrollAtBottomChange = useLatest(setScrollAtBottom);\n const isScrollIndicatorVisible =\n messages && isScrollAtBottom !== null ? !isScrollAtBottom : false;\n\n useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(\n forwardedRef,\n () => containerRef.current,\n []\n );\n\n const scrollToBottom = useLatest(\n (behavior: \"instant\" | \"smooth\", includeTrailingSpace = false) => {\n if (includeTrailingSpace) {\n // Scroll to the bottom marker to include the trailing space,\n // but wait for the next tick in case the trailing space hasn't\n // been updated yet. (e.g. when sending a new message)\n setTimeout(() => {\n scrollIntoView(bottomMarkerRef.current, {\n behavior,\n block: \"end\",\n });\n }, 0);\n } else {\n // Scroll to the trailing space marker to only scroll to the\n // bottom of the messages, without including the trailing space.\n scrollIntoView(bottomTrailingMarkerRef.current, {\n behavior,\n block: \"end\",\n });\n }\n }\n );\n\n return (\n <div\n ref={containerRef}\n {...props}\n className={cn(\n \"lb-root lb-ai-chat\",\n `lb-ai-chat:layout-${layout}`,\n className\n )}\n >\n {Object.entries(tools).map(([name, tool]) => (\n <RegisterAiTool key={name} chatId={chatId} name={name} tool={tool} />\n ))}\n\n {localKnowledge\n ? localKnowledge.map((knowledge, index) => (\n <RegisterAiKnowledge\n key={`${index}:${knowledge.description}`}\n chatId={chatId}\n {...knowledge}\n />\n ))\n : null}\n\n <div className=\"lb-ai-chat-content\">\n {isLoading ? (\n <Loading />\n ) : error !== undefined ? (\n <div className=\"lb-error lb-ai-chat-error\">\n {$.AI_CHAT_MESSAGES_ERROR(error)}\n </div>\n ) : messages.length === 0 ? (\n <Empty chatId={chatId} copilotId={copilotId} />\n ) : (\n <>\n <AiChatMessages\n messages={messages}\n overrides={overrides}\n components={components}\n showReasoning={showReasoning}\n showRetrievals={showRetrievals}\n showSources={showSources}\n lastSentMessageId={lastSentMessageId}\n scrollToBottom={scrollToBottom}\n onScrollAtBottomChange={onScrollAtBottomChange}\n containerRef={containerRef}\n footerRef={footerRef}\n messagesRef={messagesRef}\n bottomTrailingMarkerRef={bottomTrailingMarkerRef}\n trailingSpacerRef={trailingSpacerRef}\n ref={forwardedRef}\n />\n\n {/**\n * This trailing spacer is used to extend the scrollable area beyond its actual\n * content, to allow messages to appear at the top of the viewport for example.\n */}\n <div\n ref={trailingSpacerRef}\n data-trailing-spacer=\"\"\n style={{\n pointerEvents: \"none\",\n height: 0,\n }}\n aria-hidden\n />\n </>\n )}\n </div>\n\n <div className=\"lb-ai-chat-footer\" ref={footerRef}>\n <div className=\"lb-ai-chat-footer-actions\">\n <div\n className=\"lb-root lb-elevation lb-elevation-moderate lb-ai-chat-scroll-indicator\"\n data-visible={isScrollIndicatorVisible ? \"\" : undefined}\n >\n <button\n className=\"lb-ai-chat-scroll-indicator-button\"\n tabIndex={isScrollIndicatorVisible ? 0 : -1}\n aria-hidden={!isScrollIndicatorVisible}\n onClick={() => scrollToBottom.current(\"smooth\")}\n >\n <span className=\"lb-icon-container\">\n <ArrowDownIcon />\n </span>\n </button>\n </div>\n </div>\n <AiComposer\n key={chatId}\n chatId={chatId}\n copilotId={copilotId as CopilotId}\n overrides={overrides}\n autoFocus={autoFocus}\n responseTimeout={responseTimeout}\n onComposerSubmit={onComposerSubmit}\n onComposerSubmitted={({ id }) => setLastSentMessageId(id)}\n className={cn(\n \"lb-ai-chat-composer\",\n layout === \"inset\"\n ? \"lb-elevation lb-elevation-moderate\"\n : undefined\n )}\n />\n </div>\n\n {/**\n * This invisible marker is a trick which allows us to use IntersectionObserver to detect when the\n * scrollable area is fully scrolled to the bottom instead of manually tracking the scroll position\n * and having to deal with resizes, etc.\n *\n * It's positioned at the bottom of the scrollable area and reliably only becomes \"visible\" to the\n * IntersectionObserver when the scrollable area is scrolled to the bottom.\n */}\n {messages && messages.length > 0 ? (\n <div\n ref={bottomMarkerRef}\n style={{ position: \"sticky\", height: 0 }}\n aria-hidden\n data-bottom-marker=\"\"\n >\n {/**\n * This inner marker is absolutely offset by the same distance as the trailing space so its\n * visibility means the scrollable area is at the bottom of the messages, not the full bottom.\n */}\n <div\n ref={bottomTrailingMarkerRef}\n style={{\n position: \"absolute\",\n height: 0,\n }}\n data-bottom-trailing-marker=\"\"\n />\n </div>\n ) : null}\n </div>\n );\n }\n);\n"],"names":["messages"],"mappings":"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"}
1
+ {"version":3,"file":"AiChat.js","sources":["../../src/components/AiChat.tsx"],"sourcesContent":["import type {\n AiKnowledgeSource,\n AiOpaqueToolDefinition,\n CopilotId,\n MessageId,\n} from \"@liveblocks/core\";\nimport {\n RegisterAiKnowledge,\n RegisterAiTool,\n useAiChatMessages,\n} from \"@liveblocks/react\";\nimport { useLatest } from \"@liveblocks/react/_private\";\nimport {\n type ComponentProps,\n type ComponentType,\n forwardRef,\n type MutableRefObject,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from \"react\";\n\nimport { useStableComponent } from \"../_private\";\nimport type { GlobalComponents } from \"../components\";\nimport { ArrowDownIcon } from \"../icons/ArrowDown\";\nimport { SpinnerIcon } from \"../icons/Spinner\";\nimport {\n type AiChatMessageOverrides,\n type AiChatOverrides,\n type AiComposerOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../overrides\";\nimport type { MarkdownComponents } from \"../primitives/Markdown\";\nimport { cn } from \"../utils/cn\";\nimport { useIntersectionCallback } from \"../utils/use-visible\";\nimport {\n AiChatAssistantMessage,\n type AiChatAssistantMessageProps,\n} from \"./internal/AiChatAssistantMessage\";\nimport { AiChatUserMessage } from \"./internal/AiChatUserMessage\";\nimport { AiComposer, type AiComposerProps } from \"./internal/AiComposer\";\n\n/**\n * The minimum number of pixels from the bottom of the scrollable area\n * before showing the scroll to bottom indicator.\n */\nconst MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR = 60;\n\nexport type AiChatComponentsEmptyProps = {\n /**\n * The chat ID provided to the `AiChat` component.\n */\n chatId: string;\n\n /**\n * The copilot ID provided to the `AiChat` component.\n */\n copilotId?: string;\n};\n\nexport type AiChatComponentsLoadingProps = Record<string, never>;\n\nexport type AiChatComponents = {\n /**\n * The component used to render the empty state of the chat.\n */\n Empty: ComponentType<AiChatComponentsEmptyProps>;\n\n /**\n * The component used to render the loading state of the chat.\n */\n Loading: ComponentType<AiChatComponentsLoadingProps>;\n\n /**\n * The components used to render Markdown content.\n */\n markdown?: Partial<MarkdownComponents>;\n};\n\nexport interface AiChatProps extends ComponentProps<\"div\"> {\n /**\n * The ID of the chat the composer belongs to.\n */\n chatId: string;\n\n /**\n * Whether to focus the chat composer on mount.\n */\n autoFocus?: boolean;\n\n /**\n * The ID of the copilot to use to send the message.\n */\n copilotId?: string;\n\n /**\n * The contextual knowledge to include in the chat. May be used by the\n * assistant when generating responses. In addition to the knowledge passed\n * in via this prop, the AiChat instance will also have access to any\n * globally registered knowledge via <RegisterAiKnowledge />.\n */\n knowledge?: AiKnowledgeSource[];\n\n /**\n * Tool definitions to make available within this chat. May be used by the assistant when generating responses.\n */\n tools?: Record<string, AiOpaqueToolDefinition>;\n\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: AiComposerProps[\"onComposerSubmit\"];\n\n /**\n * The layout of the chat and its composer.\n */\n layout?: \"inset\" | \"compact\";\n\n /**\n * How to show or hide reasoning.\n */\n showReasoning?: AiChatAssistantMessageProps[\"showReasoning\"];\n\n /**\n * How to show or hide retrievals.\n */\n showRetrievals?: AiChatAssistantMessageProps[\"showRetrievals\"];\n\n /**\n * Whether to show sources\n */\n showSources?: AiChatAssistantMessageProps[\"showSources\"];\n\n /**\n * The time, in milliseconds, before an AI response will timeout.\n */\n responseTimeout?: number;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n AiComposerOverrides &\n AiChatMessageOverrides &\n AiChatOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & AiChatComponents>;\n}\n\ninterface AiChatMessagesProps extends ComponentProps<\"div\"> {\n messages: NonNullable<ReturnType<typeof useAiChatMessages>[\"messages\"]>;\n overrides: AiChatProps[\"overrides\"];\n components: AiChatProps[\"components\"];\n showReasoning: AiChatProps[\"showReasoning\"];\n showRetrievals: AiChatProps[\"showRetrievals\"];\n showSources: AiChatProps[\"showSources\"];\n lastSentMessageId: MessageId | null;\n scrollToBottom: MutableRefObject<\n (behavior: \"instant\" | \"smooth\", includeTrailingSpace?: boolean) => void\n >;\n onScrollAtBottomChange: MutableRefObject<\n (isScrollAtBottom: boolean | null) => void\n >;\n containerRef: MutableRefObject<HTMLDivElement | null>;\n footerRef: MutableRefObject<HTMLDivElement | null>;\n messagesRef: MutableRefObject<HTMLDivElement | null>;\n bottomTrailingMarkerRef: MutableRefObject<HTMLDivElement | null>;\n trailingSpacerRef: MutableRefObject<HTMLDivElement | null>;\n}\n\nconst defaultComponents: AiChatComponents = {\n Empty: () => null,\n Loading: () => (\n <div className=\"lb-loading lb-ai-chat-loading\">\n <SpinnerIcon />\n </div>\n ),\n};\n\nconst AiChatMessages = forwardRef<HTMLDivElement, AiChatMessagesProps>(\n (\n {\n messages,\n overrides,\n components,\n showReasoning,\n showRetrievals,\n showSources,\n lastSentMessageId,\n scrollToBottom,\n onScrollAtBottomChange,\n containerRef,\n footerRef,\n messagesRef,\n bottomTrailingMarkerRef,\n trailingSpacerRef,\n className,\n ...props\n },\n forwardedRef\n ) => {\n const hasLastSentMessage = lastSentMessageId !== null;\n\n /**\n * Every time the container, footer, or messages list change size,\n * we calculate the trailing space that would allow the penultimate\n * message to be at the top of the viewport, and apply it.\n *\n * ┌─────────────────────────────────────────┐▲ A = The `scroll-margin-top`\n * │ ┌─────────────────────────┐ │▼▲ value of the penultimate message\n * │ │ The penultimate message │ │ │\n * │ └─────────────────────────┘ │ │ B = The height from the top of\n * │ │ │ the penultimate message to the\n * │ ┌─────────────────────────┐ │ │ bottom of the messages list,\n * │ │ The last message │ │ │ including the messages' heights,\n * │ └─────────────────────────┘ │ │ and any padding, gap, etc\n * │ │ │\n * ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤▲▼\n * │ ││ The trailing space needed to\n * │ = container height - (A + B + C) ││ allow the penultimate message\n * │ ││ to be at the top of the viewport\n * ├ ┬─────────────────────────────────────┬ ┤▼▲\n * │ │ │ │ │\n * │ │ │ │ │ C = The footer's height,\n * │ │ │ │ │ including any padding\n * │ └─────────────────────────────────────┘ │ │\n * └─────────────────────────────────────────┘ ▼\n */\n useEffect(\n () => {\n if (!hasLastSentMessage) {\n return;\n }\n\n const container = containerRef.current;\n const footer = footerRef.current;\n const messages = messagesRef.current;\n\n if (!container || !footer || !messages) {\n return;\n }\n\n const trailingSpacer = trailingSpacerRef.current;\n const bottomTrailingMarker = bottomTrailingMarkerRef.current;\n\n let containerHeight: number | undefined = undefined;\n let footerHeight: number | undefined = undefined;\n let messagesHeight: number | undefined = undefined;\n\n const resetTrailingSpace = () => {\n trailingSpacer?.style.removeProperty(\"height\");\n bottomTrailingMarker?.style.removeProperty(\"top\");\n };\n\n const updateTrailingSpace = (\n updatedContainerHeight?: number,\n updatedFooterHeight?: number,\n updatedMessagesHeight?: number\n ) => {\n if (!trailingSpacer || !bottomTrailingMarker) {\n return;\n }\n\n const lastMessage = messages.lastElementChild;\n const penultimateMessage = lastMessage?.previousElementSibling;\n\n if (updatedContainerHeight === undefined) {\n updatedContainerHeight = container.getBoundingClientRect().height;\n }\n\n if (updatedFooterHeight === undefined) {\n updatedFooterHeight = footer.getBoundingClientRect().height;\n }\n\n if (updatedMessagesHeight === undefined) {\n updatedMessagesHeight = messages.getBoundingClientRect().height;\n }\n\n // If the heights haven't changed, there's no need to update the trailing space.\n if (\n updatedContainerHeight === containerHeight &&\n updatedFooterHeight === footerHeight &&\n updatedMessagesHeight === messagesHeight\n ) {\n if (\n !lastMessage ||\n !penultimateMessage ||\n container.scrollHeight === container.clientHeight\n ) {\n resetTrailingSpace();\n }\n return;\n }\n\n // Now that we have compared them, we can update the heights.\n containerHeight = updatedContainerHeight;\n footerHeight = updatedFooterHeight;\n messagesHeight = updatedMessagesHeight;\n\n // If there's no last pair of messages, there's no need for any trailing space.\n if (!lastMessage || !penultimateMessage) {\n resetTrailingSpace();\n return;\n }\n\n // If the container isn't scrollable, there's no need for trailing space.\n if (container.scrollHeight === container.clientHeight) {\n resetTrailingSpace();\n return;\n }\n\n // A\n const penultimateMessageScrollMarginTop = Number.parseFloat(\n getComputedStyle(penultimateMessage as HTMLElement).scrollMarginTop\n );\n\n // B\n const messagesRect = messages.getBoundingClientRect();\n const penultimateMessageRect =\n penultimateMessage.getBoundingClientRect();\n const heightFromPenultimateMessageTopToMessagesListBottom =\n messagesRect.bottom - penultimateMessageRect.top;\n\n // A + B + C\n const differenceHeight =\n penultimateMessageScrollMarginTop +\n heightFromPenultimateMessageTopToMessagesListBottom +\n (footerHeight ?? 0);\n\n // = container height - (A + B + C)\n const trailingSpace = Math.max(containerHeight - differenceHeight, 0);\n\n // Update the trailing space.\n trailingSpacer.style.height = `${trailingSpace}px`;\n\n // Offset what \"the bottom\" is to the \"scroll at the bottom\" detection logic,\n // so that it doesn't include the trailing space.\n bottomTrailingMarker.style.top = `${-trailingSpace}px`;\n };\n\n const resizeObserver = new ResizeObserver((entries) => {\n let updatedContainerHeight: number | undefined = containerHeight;\n let updatedFooterHeight: number | undefined = footerHeight;\n let updatedMessagesHeight: number | undefined = messagesHeight;\n\n for (const entry of entries) {\n const entryHeight =\n entry.borderBoxSize?.[0]?.blockSize ?? entry.contentRect.height;\n\n if (entry.target === container) {\n updatedContainerHeight = entryHeight;\n } else if (entry.target === footer) {\n updatedFooterHeight = entryHeight;\n } else if (entry.target === messages) {\n updatedMessagesHeight = entryHeight;\n }\n }\n\n updateTrailingSpace(\n updatedContainerHeight,\n updatedFooterHeight,\n updatedMessagesHeight\n );\n });\n\n resizeObserver.observe(container);\n resizeObserver.observe(footer);\n resizeObserver.observe(messages);\n\n // Initialize before the first resize.\n requestAnimationFrame(() => updateTrailingSpace());\n\n return () => {\n resizeObserver.disconnect();\n resetTrailingSpace();\n };\n },\n // This effect only uses stable refs.\n [hasLastSentMessage] // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n /**\n * Update the \"scroll at bottom\" state when needed.\n */\n useIntersectionCallback(\n bottomTrailingMarkerRef,\n (isIntersecting) => {\n onScrollAtBottomChange.current(isIntersecting);\n },\n { root: containerRef, rootMargin: MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR }\n );\n\n /**\n * Instantly scroll to the bottom for the initial state.\n */\n useEffect(\n () => {\n scrollToBottom.current(\"instant\");\n },\n // `scrollToBottom` is a stable ref containing the callback.\n [] // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n /**\n * Scroll to new messages when sending them.\n */\n useEffect(\n () => {\n if (lastSentMessageId) {\n scrollToBottom.current(\"smooth\", true);\n }\n },\n // `scrollToBottom` is a stable ref containing the callback.\n [lastSentMessageId] // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n /**\n * Reset the \"scroll at bottom\" state when the component unmounts.\n */\n useEffect(\n () => {\n const onScrollAtBottomChangeCallback = onScrollAtBottomChange.current;\n\n return () => {\n onScrollAtBottomChangeCallback(null);\n };\n },\n // `onScrollAtBottomChange` is a stable ref containing the callback.\n [] // eslint-disable-line react-hooks/exhaustive-deps\n );\n\n return (\n <div\n className={cn(\"lb-ai-chat-messages\", className)}\n ref={forwardedRef}\n {...props}\n >\n {messages.map((message) => {\n if (message.role === \"user\") {\n return (\n <AiChatUserMessage\n key={message.id}\n message={message}\n overrides={overrides}\n components={components}\n />\n );\n } else if (message.role === \"assistant\") {\n return (\n <AiChatAssistantMessage\n key={message.id}\n message={message}\n overrides={overrides}\n components={components}\n showReasoning={showReasoning}\n showRetrievals={showRetrievals}\n showSources={showSources}\n />\n );\n } else {\n return null;\n }\n })}\n </div>\n );\n }\n);\n\n// Call `Element.scrollIntoView()` unless the element is not displayed.\n// (with `display: none` or nested within elements with `display: none`)\n// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView\n//\n// This avoids browser quirks where they still attempt to scroll to the\n// element but it results in a scroll to the document's top.\nfunction scrollIntoView(\n element: HTMLElement | null,\n options?: ScrollIntoViewOptions\n) {\n if (!element) {\n return;\n }\n\n // Checking for at least one client rect allows 0 width/height elements,\n // unlike checking if the width/height is 0 with `getBoundingClientRect`.\n if (element.getClientRects().length === 0) {\n return;\n }\n\n element.scrollIntoView(options);\n}\n\nexport const AiChat = forwardRef<HTMLDivElement, AiChatProps>(\n (\n {\n chatId,\n copilotId,\n autoFocus,\n overrides,\n knowledge: localKnowledge,\n tools = {},\n onComposerSubmit,\n layout = \"inset\",\n showReasoning,\n showRetrievals,\n showSources,\n components,\n className,\n responseTimeout,\n ...props\n },\n forwardedRef\n ) => {\n const { messages, isLoading, error } = useAiChatMessages(chatId);\n const [lastSentMessageId, setLastSentMessageId] =\n useState<MessageId | null>(null);\n\n const $ = useOverrides(overrides);\n const Empty = useStableComponent(\n components?.Empty,\n defaultComponents.Empty\n );\n const Loading = useStableComponent(\n components?.Loading,\n defaultComponents.Loading\n );\n\n const containerRef = useRef<HTMLDivElement | null>(null);\n const messagesRef = useRef<HTMLDivElement | null>(null);\n const footerRef = useRef<HTMLDivElement | null>(null);\n const bottomMarkerRef = useRef<HTMLDivElement | null>(null);\n const bottomTrailingMarkerRef = useRef<HTMLDivElement | null>(null);\n const trailingSpacerRef = useRef<HTMLDivElement | null>(null);\n\n const [isScrollAtBottom, setScrollAtBottom] = useState<boolean | null>(\n null\n );\n // `useState`'s setter is stable but this is for clarity in the places it's used.\n const onScrollAtBottomChange = useLatest(setScrollAtBottom);\n const isScrollIndicatorVisible =\n messages && isScrollAtBottom !== null ? !isScrollAtBottom : false;\n\n useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(\n forwardedRef,\n () => containerRef.current,\n []\n );\n\n const scrollToBottom = useLatest(\n (behavior: \"instant\" | \"smooth\", includeTrailingSpace = false) => {\n if (includeTrailingSpace) {\n // Scroll to the bottom marker to include the trailing space,\n // but wait for the next tick in case the trailing space hasn't\n // been updated yet. (e.g. when sending a new message)\n setTimeout(() => {\n scrollIntoView(bottomMarkerRef.current, {\n behavior,\n block: \"end\",\n });\n }, 0);\n } else {\n // Scroll to the trailing space marker to only scroll to the\n // bottom of the messages, without including the trailing space.\n scrollIntoView(bottomTrailingMarkerRef.current, {\n behavior,\n block: \"end\",\n });\n }\n }\n );\n\n return (\n <div\n ref={containerRef}\n {...props}\n className={cn(\n \"lb-root lb-ai-chat\",\n `lb-ai-chat:layout-${layout}`,\n className\n )}\n >\n {Object.entries(tools).map(([name, tool]) => (\n <RegisterAiTool key={name} chatId={chatId} name={name} tool={tool} />\n ))}\n\n {localKnowledge\n ? localKnowledge.map((knowledge, index) => (\n <RegisterAiKnowledge\n key={`${index}:${knowledge.description}`}\n chatId={chatId}\n {...knowledge}\n />\n ))\n : null}\n\n <div className=\"lb-ai-chat-content\">\n {isLoading ? (\n <Loading />\n ) : error !== undefined ? (\n <div className=\"lb-error lb-ai-chat-error\">\n {$.AI_CHAT_MESSAGES_ERROR(error)}\n </div>\n ) : messages.length === 0 ? (\n <Empty chatId={chatId} copilotId={copilotId} />\n ) : (\n <>\n <AiChatMessages\n messages={messages}\n overrides={overrides}\n components={components}\n showReasoning={showReasoning}\n showRetrievals={showRetrievals}\n showSources={showSources}\n lastSentMessageId={lastSentMessageId}\n scrollToBottom={scrollToBottom}\n onScrollAtBottomChange={onScrollAtBottomChange}\n containerRef={containerRef}\n footerRef={footerRef}\n messagesRef={messagesRef}\n bottomTrailingMarkerRef={bottomTrailingMarkerRef}\n trailingSpacerRef={trailingSpacerRef}\n ref={forwardedRef}\n />\n\n {/**\n * This trailing spacer is used to extend the scrollable area beyond its actual\n * content, to allow messages to appear at the top of the viewport for example.\n */}\n <div\n ref={trailingSpacerRef}\n data-trailing-spacer=\"\"\n style={{\n pointerEvents: \"none\",\n height: 0,\n }}\n aria-hidden\n />\n </>\n )}\n </div>\n\n <div className=\"lb-ai-chat-footer\" ref={footerRef}>\n <div className=\"lb-ai-chat-footer-actions\">\n <div\n className=\"lb-root lb-elevation lb-elevation-moderate lb-ai-chat-scroll-indicator\"\n data-visible={isScrollIndicatorVisible ? \"\" : undefined}\n >\n <button\n className=\"lb-ai-chat-scroll-indicator-button\"\n tabIndex={isScrollIndicatorVisible ? 0 : -1}\n aria-hidden={!isScrollIndicatorVisible}\n onClick={() => scrollToBottom.current(\"smooth\")}\n >\n <span className=\"lb-icon-container\">\n <ArrowDownIcon />\n </span>\n </button>\n </div>\n </div>\n <AiComposer\n key={chatId}\n chatId={chatId}\n copilotId={copilotId as CopilotId}\n overrides={overrides}\n autoFocus={autoFocus}\n responseTimeout={responseTimeout}\n onComposerSubmit={onComposerSubmit}\n onComposerSubmitted={({ id }) => setLastSentMessageId(id)}\n className={cn(\n \"lb-ai-chat-composer\",\n layout === \"inset\"\n ? \"lb-elevation lb-elevation-moderate\"\n : undefined\n )}\n />\n </div>\n\n {/**\n * This invisible marker is a trick which allows us to use IntersectionObserver to detect when the\n * scrollable area is fully scrolled to the bottom instead of manually tracking the scroll position\n * and having to deal with resizes, etc.\n *\n * It's positioned at the bottom of the scrollable area and reliably only becomes \"visible\" to the\n * IntersectionObserver when the scrollable area is scrolled to the bottom.\n */}\n {messages && messages.length > 0 ? (\n <div\n ref={bottomMarkerRef}\n style={{ position: \"sticky\", height: 0 }}\n aria-hidden\n data-bottom-marker=\"\"\n >\n {/**\n * This inner marker is absolutely offset by the same distance as the trailing space so its\n * visibility means the scrollable area is at the bottom of the messages, not the full bottom.\n */}\n <div\n ref={bottomTrailingMarkerRef}\n style={{\n position: \"absolute\",\n height: 0,\n }}\n data-bottom-trailing-marker=\"\"\n />\n </div>\n ) : null}\n </div>\n );\n }\n);\n"],"names":["messages"],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var react$1 = require('@liveblocks/react');
6
+ var react = require('react');
7
+ var constants = require('../constants.cjs');
8
+ var overrides = require('../overrides.cjs');
9
+ var cn = require('../utils/cn.cjs');
10
+ var Avatar = require('./internal/Avatar.cjs');
11
+ var Tooltip = require('./internal/Tooltip.cjs');
12
+ var User = require('./internal/User.cjs');
13
+
14
+
15
+ const AvatarStack = react.forwardRef(
16
+ ({
17
+ userIds: additionalUserIds = [],
18
+ max = 3,
19
+ size,
20
+ overrides: overrides$1,
21
+ className,
22
+ style,
23
+ ...props
24
+ }, forwardedRef) => {
25
+ const $ = overrides.useOverrides(overrides$1);
26
+ const otherIds = react$1.useOthers((others) => others.map((user) => user.id));
27
+ const selfId = react$1.useSelf((self) => self.id);
28
+ const userIds = react.useMemo(() => {
29
+ const uniqueUserIds = /* @__PURE__ */ new Set([
30
+ selfId,
31
+ ...otherIds,
32
+ ...additionalUserIds
33
+ ]);
34
+ return [...uniqueUserIds];
35
+ }, [selfId, otherIds, additionalUserIds]);
36
+ const maxAvatars = Math.max(1, Math.floor(max));
37
+ const visibleUserIds = userIds.slice(0, maxAvatars);
38
+ const hiddenUserIds = userIds.slice(visibleUserIds.length);
39
+ const remainingUsersCount = hiddenUserIds.length;
40
+ const visibleItemsCount = visibleUserIds.length + Number(remainingUsersCount > 0);
41
+ if (userIds.length === 0) {
42
+ return null;
43
+ }
44
+ return /* @__PURE__ */ jsxRuntime.jsx(Tooltip.TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(
45
+ "div",
46
+ {
47
+ className: cn.cn("lb-root lb-avatar-stack", className),
48
+ dir: $.dir,
49
+ style: {
50
+ "--lb-avatar-stack-count": visibleItemsCount - 1,
51
+ "--lb-avatar-stack-size": size,
52
+ ...style
53
+ },
54
+ ...props,
55
+ ref: forwardedRef,
56
+ children: [
57
+ visibleUserIds.map((userId, index) => {
58
+ if (!userId) {
59
+ return null;
60
+ }
61
+ return /* @__PURE__ */ jsxRuntime.jsx(
62
+ Tooltip.Tooltip,
63
+ {
64
+ content: /* @__PURE__ */ jsxRuntime.jsx(User.User, { userId }),
65
+ sideOffset: constants.FLOATING_ELEMENT_SIDE_OFFSET,
66
+ collisionPadding: constants.FLOATING_ELEMENT_COLLISION_PADDING,
67
+ side: "top",
68
+ align: "center",
69
+ children: /* @__PURE__ */ jsxRuntime.jsx(
70
+ Avatar.Avatar,
71
+ {
72
+ userId,
73
+ className: "lb-avatar-stack-avatar",
74
+ style: { "--lb-avatar-stack-index": index }
75
+ }
76
+ )
77
+ },
78
+ userId
79
+ );
80
+ }),
81
+ remainingUsersCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
82
+ Tooltip.Tooltip,
83
+ {
84
+ content: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "lb-users-tooltip-list", children: hiddenUserIds.map(
85
+ (userId) => userId ? /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "lb-users-tooltip-list-item", children: [
86
+ /* @__PURE__ */ jsxRuntime.jsx(Avatar.Avatar, { userId }),
87
+ /* @__PURE__ */ jsxRuntime.jsx(User.User, { userId })
88
+ ] }, userId) : null
89
+ ) }),
90
+ sideOffset: constants.FLOATING_ELEMENT_SIDE_OFFSET,
91
+ collisionPadding: constants.FLOATING_ELEMENT_COLLISION_PADDING,
92
+ side: "top",
93
+ align: "center",
94
+ className: "lb-users-tooltip",
95
+ children: /* @__PURE__ */ jsxRuntime.jsx(
96
+ "div",
97
+ {
98
+ className: "lb-avatar lb-avatar-stack-avatar lb-avatar-stack-more",
99
+ style: {
100
+ "--lb-avatar-stack-index": visibleUserIds.length
101
+ },
102
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "lb-avatar-fallback", children: [
103
+ "+",
104
+ remainingUsersCount
105
+ ] })
106
+ }
107
+ )
108
+ }
109
+ ) : null
110
+ ]
111
+ }
112
+ ) });
113
+ }
114
+ );
115
+
116
+ exports.AvatarStack = AvatarStack;
117
+ //# sourceMappingURL=AvatarStack.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AvatarStack.cjs","sources":["../../src/components/AvatarStack.tsx"],"sourcesContent":["\"use client\";\n\nimport { useOthers, useSelf } from \"@liveblocks/react\";\nimport type { ComponentPropsWithoutRef, CSSProperties } from \"react\";\nimport { forwardRef, useMemo } from \"react\";\n\nimport {\n FLOATING_ELEMENT_COLLISION_PADDING,\n FLOATING_ELEMENT_SIDE_OFFSET,\n} from \"../constants\";\nimport type { GlobalOverrides } from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { cn } from \"../utils/cn\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\nexport interface AvatarStackProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * Optional additional user IDs to include in the stack.\n */\n userIds?: string[];\n\n /**\n * The maximum number of visible avatars.\n * Defaults to 3, set to `undefined` to show all avatars.\n */\n max?: number;\n\n /**\n * The size of the avatars.\n */\n size?: string | number;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides>;\n}\n\n/**\n * Displays a stack of avatars for the users currently present in the room.\n */\nexport const AvatarStack = forwardRef<HTMLDivElement, AvatarStackProps>(\n (\n {\n userIds: additionalUserIds = [],\n max = 3,\n size,\n overrides,\n className,\n style,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const otherIds = useOthers((others) => others.map((user) => user.id));\n const selfId = useSelf((self) => self.id);\n const userIds = useMemo(() => {\n const uniqueUserIds = new Set([\n selfId,\n ...otherIds,\n ...additionalUserIds,\n ]);\n\n return [...uniqueUserIds];\n }, [selfId, otherIds, additionalUserIds]);\n const maxAvatars = Math.max(1, Math.floor(max));\n const visibleUserIds = userIds.slice(0, maxAvatars);\n const hiddenUserIds = userIds.slice(visibleUserIds.length);\n const remainingUsersCount = hiddenUserIds.length;\n const visibleItemsCount =\n visibleUserIds.length + Number(remainingUsersCount > 0);\n\n if (userIds.length === 0) {\n return null;\n }\n\n return (\n <TooltipProvider>\n <div\n className={cn(\"lb-root lb-avatar-stack\", className)}\n dir={$.dir}\n style={\n {\n \"--lb-avatar-stack-count\": visibleItemsCount - 1,\n \"--lb-avatar-stack-size\": size,\n ...style,\n } as CSSProperties\n }\n {...props}\n ref={forwardedRef}\n >\n {visibleUserIds.map((userId, index) => {\n if (!userId) {\n return null;\n }\n\n return (\n <Tooltip\n key={userId}\n content={<User userId={userId} />}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n side=\"top\"\n align=\"center\"\n >\n <Avatar\n userId={userId}\n className=\"lb-avatar-stack-avatar\"\n style={{ \"--lb-avatar-stack-index\": index } as CSSProperties}\n />\n </Tooltip>\n );\n })}\n {remainingUsersCount > 0 ? (\n <Tooltip\n content={\n <ul className=\"lb-users-tooltip-list\">\n {hiddenUserIds.map((userId) =>\n userId ? (\n <li key={userId} className=\"lb-users-tooltip-list-item\">\n <Avatar userId={userId} />\n <User userId={userId} />\n </li>\n ) : null\n )}\n </ul>\n }\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n side=\"top\"\n align=\"center\"\n className=\"lb-users-tooltip\"\n >\n <div\n className=\"lb-avatar lb-avatar-stack-avatar lb-avatar-stack-more\"\n style={\n {\n \"--lb-avatar-stack-index\": visibleUserIds.length,\n } as CSSProperties\n }\n >\n <span className=\"lb-avatar-fallback\">\n +{remainingUsersCount}\n </span>\n </div>\n </Tooltip>\n ) : null}\n </div>\n </TooltipProvider>\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;AA2CO;AAAoB;AAEvB;AACgC;AACxB;AACN;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACE;AAA8B;AAC5B;AACG;AACA;AAGL;AAAwB;AAE1B;AACA;AACA;AACA;AACA;AAGA;AACE;AAAO;AAGT;AAEI;AAAC;AAAA;AACmD;AAC3C;AAEL;AACiD;AACrB;AACvB;AACL;AAEE;AACC;AAEJ;AACC;AACE;AAAO;AAGT;AACE;AAAC;AAAA;AAEgC;AACnB;AACM;AACb;AACC;AAEN;AAAC;AAAA;AACC;AACU;AACgC;AAAA;AAC5C;AAAA;AAXK;AAYP;AAEH;AAEC;AAAC;AAAA;AAGoB;AAGT;AAAwB;AACF;AAEtB;AAER;AAEU;AACM;AACb;AACC;AACI;AAEV;AAAC;AAAA;AACW;AAER;AAC4C;AAC5C;AAGmC;AAAA;AACjC;AACJ;AAAA;AACF;AAAA;AAEA;AAAA;AAAA;AAER;AAGN;;"}
@@ -0,0 +1,115 @@
1
+ "use client";
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { useOthers, useSelf } from '@liveblocks/react';
4
+ import { forwardRef, useMemo } from 'react';
5
+ import { FLOATING_ELEMENT_SIDE_OFFSET, FLOATING_ELEMENT_COLLISION_PADDING } from '../constants.js';
6
+ import { useOverrides } from '../overrides.js';
7
+ import { cn } from '../utils/cn.js';
8
+ import { Avatar } from './internal/Avatar.js';
9
+ import { TooltipProvider, Tooltip } from './internal/Tooltip.js';
10
+ import { User } from './internal/User.js';
11
+
12
+
13
+ const AvatarStack = forwardRef(
14
+ ({
15
+ userIds: additionalUserIds = [],
16
+ max = 3,
17
+ size,
18
+ overrides,
19
+ className,
20
+ style,
21
+ ...props
22
+ }, forwardedRef) => {
23
+ const $ = useOverrides(overrides);
24
+ const otherIds = useOthers((others) => others.map((user) => user.id));
25
+ const selfId = useSelf((self) => self.id);
26
+ const userIds = useMemo(() => {
27
+ const uniqueUserIds = /* @__PURE__ */ new Set([
28
+ selfId,
29
+ ...otherIds,
30
+ ...additionalUserIds
31
+ ]);
32
+ return [...uniqueUserIds];
33
+ }, [selfId, otherIds, additionalUserIds]);
34
+ const maxAvatars = Math.max(1, Math.floor(max));
35
+ const visibleUserIds = userIds.slice(0, maxAvatars);
36
+ const hiddenUserIds = userIds.slice(visibleUserIds.length);
37
+ const remainingUsersCount = hiddenUserIds.length;
38
+ const visibleItemsCount = visibleUserIds.length + Number(remainingUsersCount > 0);
39
+ if (userIds.length === 0) {
40
+ return null;
41
+ }
42
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(
43
+ "div",
44
+ {
45
+ className: cn("lb-root lb-avatar-stack", className),
46
+ dir: $.dir,
47
+ style: {
48
+ "--lb-avatar-stack-count": visibleItemsCount - 1,
49
+ "--lb-avatar-stack-size": size,
50
+ ...style
51
+ },
52
+ ...props,
53
+ ref: forwardedRef,
54
+ children: [
55
+ visibleUserIds.map((userId, index) => {
56
+ if (!userId) {
57
+ return null;
58
+ }
59
+ return /* @__PURE__ */ jsx(
60
+ Tooltip,
61
+ {
62
+ content: /* @__PURE__ */ jsx(User, { userId }),
63
+ sideOffset: FLOATING_ELEMENT_SIDE_OFFSET,
64
+ collisionPadding: FLOATING_ELEMENT_COLLISION_PADDING,
65
+ side: "top",
66
+ align: "center",
67
+ children: /* @__PURE__ */ jsx(
68
+ Avatar,
69
+ {
70
+ userId,
71
+ className: "lb-avatar-stack-avatar",
72
+ style: { "--lb-avatar-stack-index": index }
73
+ }
74
+ )
75
+ },
76
+ userId
77
+ );
78
+ }),
79
+ remainingUsersCount > 0 ? /* @__PURE__ */ jsx(
80
+ Tooltip,
81
+ {
82
+ content: /* @__PURE__ */ jsx("ul", { className: "lb-users-tooltip-list", children: hiddenUserIds.map(
83
+ (userId) => userId ? /* @__PURE__ */ jsxs("li", { className: "lb-users-tooltip-list-item", children: [
84
+ /* @__PURE__ */ jsx(Avatar, { userId }),
85
+ /* @__PURE__ */ jsx(User, { userId })
86
+ ] }, userId) : null
87
+ ) }),
88
+ sideOffset: FLOATING_ELEMENT_SIDE_OFFSET,
89
+ collisionPadding: FLOATING_ELEMENT_COLLISION_PADDING,
90
+ side: "top",
91
+ align: "center",
92
+ className: "lb-users-tooltip",
93
+ children: /* @__PURE__ */ jsx(
94
+ "div",
95
+ {
96
+ className: "lb-avatar lb-avatar-stack-avatar lb-avatar-stack-more",
97
+ style: {
98
+ "--lb-avatar-stack-index": visibleUserIds.length
99
+ },
100
+ children: /* @__PURE__ */ jsxs("span", { className: "lb-avatar-fallback", children: [
101
+ "+",
102
+ remainingUsersCount
103
+ ] })
104
+ }
105
+ )
106
+ }
107
+ ) : null
108
+ ]
109
+ }
110
+ ) });
111
+ }
112
+ );
113
+
114
+ export { AvatarStack };
115
+ //# sourceMappingURL=AvatarStack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AvatarStack.js","sources":["../../src/components/AvatarStack.tsx"],"sourcesContent":["\"use client\";\n\nimport { useOthers, useSelf } from \"@liveblocks/react\";\nimport type { ComponentPropsWithoutRef, CSSProperties } from \"react\";\nimport { forwardRef, useMemo } from \"react\";\n\nimport {\n FLOATING_ELEMENT_COLLISION_PADDING,\n FLOATING_ELEMENT_SIDE_OFFSET,\n} from \"../constants\";\nimport type { GlobalOverrides } from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { cn } from \"../utils/cn\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\nexport interface AvatarStackProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * Optional additional user IDs to include in the stack.\n */\n userIds?: string[];\n\n /**\n * The maximum number of visible avatars.\n * Defaults to 3, set to `undefined` to show all avatars.\n */\n max?: number;\n\n /**\n * The size of the avatars.\n */\n size?: string | number;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides>;\n}\n\n/**\n * Displays a stack of avatars for the users currently present in the room.\n */\nexport const AvatarStack = forwardRef<HTMLDivElement, AvatarStackProps>(\n (\n {\n userIds: additionalUserIds = [],\n max = 3,\n size,\n overrides,\n className,\n style,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const otherIds = useOthers((others) => others.map((user) => user.id));\n const selfId = useSelf((self) => self.id);\n const userIds = useMemo(() => {\n const uniqueUserIds = new Set([\n selfId,\n ...otherIds,\n ...additionalUserIds,\n ]);\n\n return [...uniqueUserIds];\n }, [selfId, otherIds, additionalUserIds]);\n const maxAvatars = Math.max(1, Math.floor(max));\n const visibleUserIds = userIds.slice(0, maxAvatars);\n const hiddenUserIds = userIds.slice(visibleUserIds.length);\n const remainingUsersCount = hiddenUserIds.length;\n const visibleItemsCount =\n visibleUserIds.length + Number(remainingUsersCount > 0);\n\n if (userIds.length === 0) {\n return null;\n }\n\n return (\n <TooltipProvider>\n <div\n className={cn(\"lb-root lb-avatar-stack\", className)}\n dir={$.dir}\n style={\n {\n \"--lb-avatar-stack-count\": visibleItemsCount - 1,\n \"--lb-avatar-stack-size\": size,\n ...style,\n } as CSSProperties\n }\n {...props}\n ref={forwardedRef}\n >\n {visibleUserIds.map((userId, index) => {\n if (!userId) {\n return null;\n }\n\n return (\n <Tooltip\n key={userId}\n content={<User userId={userId} />}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n side=\"top\"\n align=\"center\"\n >\n <Avatar\n userId={userId}\n className=\"lb-avatar-stack-avatar\"\n style={{ \"--lb-avatar-stack-index\": index } as CSSProperties}\n />\n </Tooltip>\n );\n })}\n {remainingUsersCount > 0 ? (\n <Tooltip\n content={\n <ul className=\"lb-users-tooltip-list\">\n {hiddenUserIds.map((userId) =>\n userId ? (\n <li key={userId} className=\"lb-users-tooltip-list-item\">\n <Avatar userId={userId} />\n <User userId={userId} />\n </li>\n ) : null\n )}\n </ul>\n }\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}\n collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}\n side=\"top\"\n align=\"center\"\n className=\"lb-users-tooltip\"\n >\n <div\n className=\"lb-avatar lb-avatar-stack-avatar lb-avatar-stack-more\"\n style={\n {\n \"--lb-avatar-stack-index\": visibleUserIds.length,\n } as CSSProperties\n }\n >\n <span className=\"lb-avatar-fallback\">\n +{remainingUsersCount}\n </span>\n </div>\n </Tooltip>\n ) : null}\n </div>\n </TooltipProvider>\n );\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;AA2CO;AAAoB;AAEvB;AACgC;AACxB;AACN;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACE;AAA8B;AAC5B;AACG;AACA;AAGL;AAAwB;AAE1B;AACA;AACA;AACA;AACA;AAGA;AACE;AAAO;AAGT;AAEI;AAAC;AAAA;AACmD;AAC3C;AAEL;AACiD;AACrB;AACvB;AACL;AAEE;AACC;AAEJ;AACC;AACE;AAAO;AAGT;AACE;AAAC;AAAA;AAEgC;AACnB;AACM;AACb;AACC;AAEN;AAAC;AAAA;AACC;AACU;AACgC;AAAA;AAC5C;AAAA;AAXK;AAYP;AAEH;AAEC;AAAC;AAAA;AAGoB;AAGT;AAAwB;AACF;AAEtB;AAER;AAEU;AACM;AACb;AACC;AACI;AAEV;AAAC;AAAA;AACW;AAER;AAC4C;AAC5C;AAGmC;AAAA;AACjC;AACJ;AAAA;AACF;AAAA;AAEA;AAAA;AAAA;AAER;AAGN;;"}
@@ -4,7 +4,7 @@
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
  var core = require('@liveblocks/core');
6
6
  var _private = require('@liveblocks/react/_private');
7
- var TogglePrimitive = require('@radix-ui/react-toggle');
7
+ var radixUi = require('radix-ui');
8
8
  var react = require('react');
9
9
  var components = require('../components.cjs');
10
10
  var Check = require('../icons/Check.cjs');
@@ -33,28 +33,6 @@ var Group = require('./internal/Group.cjs');
33
33
  var List = require('./internal/List.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
- var TooltipPrimitive = require('@radix-ui/react-tooltip');
38
- var DropdownMenuPrimitive = require('@radix-ui/react-dropdown-menu');
39
-
40
- function _interopNamespaceDefault(e) {
41
- var n = Object.create(null);
42
- if (e) {
43
- Object.keys(e).forEach(function (k) {
44
- if (k !== 'default') {
45
- var d = Object.getOwnPropertyDescriptor(e, k);
46
- Object.defineProperty(n, k, d.get ? d : {
47
- enumerable: true,
48
- get: function () { return e[k]; }
49
- });
50
- }
51
- });
52
- }
53
- n.default = e;
54
- return Object.freeze(n);
55
- }
56
-
57
- var TogglePrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(TogglePrimitive);
58
36
 
59
37
 
60
38
  const REACTIONS_TRUNCATE = 5;
@@ -221,7 +199,7 @@ const CommentReaction = react.forwardRef(({ comment, reaction, overrides: overri
221
199
  multiline: true,
222
200
  className: "lb-comment-reaction-tooltip",
223
201
  children: /* @__PURE__ */ jsxRuntime.jsx(
224
- TogglePrimitive__namespace.Root,
202
+ radixUi.Toggle.Root,
225
203
  {
226
204
  asChild: true,
227
205
  pressed: isActive,
@@ -401,6 +379,7 @@ const Comment = Object.assign(
401
379
  children,
402
380
  ...props
403
381
  }, forwardedRef) => {
382
+ const bodyId = `${comment.id}:body`;
404
383
  const ref = react.useRef(null);
405
384
  const mergedRefs = useRefs.useRefs(forwardedRef, ref);
406
385
  const currentUserId = shared.useCurrentUserId();
@@ -513,10 +492,10 @@ const Comment = Object.assign(
513
492
  internalDropdownItems,
514
493
  commentDropdownItems
515
494
  ] }) : null;
516
- const dropdownContent = typeof dropdownItems === "function" ? dropdownItems({ children: defaultDropdownItems, comment }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
495
+ const dropdownContent = typeof dropdownItems === "function" ? dropdownItems({ children: defaultDropdownItems, comment }) : defaultDropdownItems || dropdownItems ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
517
496
  defaultDropdownItems,
518
497
  dropdownItems
519
- ] });
498
+ ] }) : null;
520
499
  let content;
521
500
  if (isEditing) {
522
501
  content = /* @__PURE__ */ jsxRuntime.jsx(
@@ -576,6 +555,7 @@ const Comment = Object.assign(
576
555
  index.Body,
577
556
  {
578
557
  className: "lb-comment-body",
558
+ id: bodyId,
579
559
  body: comment.body,
580
560
  components: {
581
561
  Mention: ({ mention }) => /* @__PURE__ */ jsxRuntime.jsx(
@@ -624,7 +604,7 @@ const Comment = Object.assign(
624
604
  },
625
605
  reaction.emoji
626
606
  )),
627
- canComment ? /* @__PURE__ */ jsxRuntime.jsx(EmojiPicker.EmojiPicker, { onEmojiSelect: handleReactionSelect, children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: $.COMMENT_ADD_REACTION, children: /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
607
+ canComment ? /* @__PURE__ */ jsxRuntime.jsx(EmojiPicker.EmojiPicker, { onEmojiSelect: handleReactionSelect, children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: $.COMMENT_ADD_REACTION, children: /* @__PURE__ */ jsxRuntime.jsx(EmojiPicker.EmojiPickerTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
628
608
  Button.Button,
629
609
  {
630
610
  className: "lb-comment-reaction lb-comment-reaction-add",
@@ -638,9 +618,10 @@ const Comment = Object.assign(
638
618
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "lb-comment-body", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "lb-comment-deleted", children: $.COMMENT_DELETED }) });
639
619
  content = typeof children === "function" ? children({ comment, children: content }) : children ?? content;
640
620
  }
641
- return /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive.TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(components.ComponentsProvider, { components: components$1, children: /* @__PURE__ */ jsxRuntime.jsxs(
621
+ return /* @__PURE__ */ jsxRuntime.jsx(Tooltip.TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(components.ComponentsProvider, { components: components$1, children: /* @__PURE__ */ jsxRuntime.jsxs(
642
622
  "div",
643
623
  {
624
+ role: "article",
644
625
  id: comment.id,
645
626
  className: cn.cn(
646
627
  "lb-root lb-comment",
@@ -652,6 +633,7 @@ const Comment = Object.assign(
652
633
  "data-deleted": !comment.body ? "" : void 0,
653
634
  "data-editing": isEditing ? "" : void 0,
654
635
  "data-target": isTarget ? "" : void 0,
636
+ "aria-labelledby": bodyId,
655
637
  dir: $.dir,
656
638
  ...props,
657
639
  ref: mergedRefs,
@@ -689,7 +671,7 @@ const Comment = Object.assign(
689
671
  onClick: handleAuthorClick
690
672
  }
691
673
  ),
692
- date ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "lb-comment-date", children: date }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
674
+ date ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "lb-comment-date", children: date }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "lb-comment-date", children: [
693
675
  /* @__PURE__ */ jsxRuntime.jsx(
694
676
  CommentDate,
695
677
  {
@@ -712,7 +694,7 @@ const Comment = Object.assign(
712
694
  {
713
695
  onEmojiSelect: handleReactionSelect,
714
696
  onOpenChange: setReactionActionOpen,
715
- children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: $.COMMENT_ADD_REACTION, children: /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
697
+ children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: $.COMMENT_ADD_REACTION, children: /* @__PURE__ */ jsxRuntime.jsx(EmojiPicker.EmojiPickerTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
716
698
  Button.Button,
717
699
  {
718
700
  className: "lb-comment-action",
@@ -730,7 +712,7 @@ const Comment = Object.assign(
730
712
  onOpenChange: setMoreActionOpen,
731
713
  align: "end",
732
714
  content: dropdownContent,
733
- children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: $.COMMENT_MORE, children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuPrimitive.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
715
+ children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip.Tooltip, { content: $.COMMENT_MORE, children: /* @__PURE__ */ jsxRuntime.jsx(Dropdown.DropdownTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
734
716
  Button.Button,
735
717
  {
736
718
  className: "lb-comment-action",