@liveblocks/react-ui 3.1.2-url1 → 3.1.3

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.
@@ -2,7 +2,6 @@
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var react$1 = require('@liveblocks/react');
5
- var _private = require('@liveblocks/react/_private');
6
5
  var react = require('react');
7
6
  var ArrowDown = require('../icons/ArrowDown.cjs');
8
7
  var Spinner = require('../icons/Spinner.cjs');
@@ -165,10 +164,12 @@ function AutoScrollHandler({
165
164
  lastSentMessageId,
166
165
  scrollToBottom
167
166
  }) {
168
- _private.useLayoutEffect(() => {
167
+ react.useEffect(() => {
169
168
  scrollToBottom("instant");
170
169
  }, [scrollToBottom]);
171
170
  react.useEffect(() => {
171
+ if (lastSentMessageId === null)
172
+ return;
172
173
  scrollToBottom("smooth");
173
174
  }, [lastSentMessageId, scrollToBottom]);
174
175
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"AiChat.cjs","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 { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n type ComponentProps,\n type ComponentType,\n forwardRef,\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 AiChatComposerOverrides,\n type AiChatMessageOverrides,\n type AiChatOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../overrides\";\nimport { cn } from \"../utils/cn\";\nimport { useVisible } from \"../utils/use-visible\";\nimport { AiChatAssistantMessage } from \"./internal/AiChatAssistantMessage\";\nimport { AiChatComposer } from \"./internal/AiChatComposer\";\nimport { AiChatUserMessage } from \"./internal/AiChatUserMessage\";\n\nexport type AiChatComponentsEmptyProps = {\n /**\n * The chat id provided to the `AiChat` component.\n */\n chatId: string;\n /**\n * The copilot id provided to the `AiChat` component.\n */\n copilotId?: string;\n};\n\nexport type AiChatComponentsLoadingProps = Record<string, never>;\n\n// TODO: Add Markdown components\nexport type AiChatComponents = {\n /**\n * The component used to render the empty state of the chat.\n */\n Empty: ComponentType<AiChatComponentsEmptyProps>;\n /**\n * The component used to render the loading state of the chat.\n */\n Loading: ComponentType<AiChatComponentsLoadingProps>;\n};\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 = 50;\n\nexport interface AiChatProps extends ComponentProps<\"div\"> {\n /**\n * The id of the chat the composer belongs to.\n */\n chatId: string;\n /**\n * Whether to focus the chat composer on mount.\n */\n autoFocus?: boolean;\n /**\n * The id of the copilot to use to send the message.\n */\n copilotId?: string;\n /**\n * The contextual knowledge to include in the chat. May be used by the assistant when generating responses.\n * Any knowledge you provide via this prop will be added to any already globally registered knowledge via <RegisterAiKnowledge />.\n */\n knowledge?: AiKnowledgeSource[];\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 * The layout of the chat and its composer.\n */\n layout?: \"inset\" | \"compact\";\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n AiChatMessageOverrides &\n AiChatComposerOverrides &\n AiChatOverrides\n >;\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & AiChatComponents>;\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\nexport const AiChat = forwardRef<HTMLDivElement, AiChatProps>(\n (\n {\n chatId,\n copilotId,\n autoFocus,\n overrides,\n knowledge,\n tools = {},\n layout = \"inset\",\n components,\n className,\n ...props\n },\n forwardedRef\n ) => {\n const { messages, isLoading, error } = useAiChatMessages(chatId);\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 containerBottomRef = useRef<HTMLDivElement | null>(null);\n const isScrollIndicatorEnabled = !isLoading && !error;\n const isScrollAtBottom = useVisible(containerBottomRef, {\n enabled: isScrollIndicatorEnabled,\n root: containerRef,\n rootMargin: MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR,\n initialValue: null,\n });\n const isScrollIndicatorVisible =\n isScrollIndicatorEnabled && isScrollAtBottom !== null\n ? !isScrollAtBottom\n : false;\n\n const [lastSentMessageId, setLastSentMessageId] =\n useState<MessageId | null>(null);\n\n useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(\n forwardedRef,\n () => containerRef.current,\n []\n );\n\n const scrollToBottomCallbackRef =\n useRef<(behavior: \"instant\" | \"smooth\") => void>(undefined);\n if (scrollToBottomCallbackRef.current === undefined) {\n scrollToBottomCallbackRef.current = function (\n behavior: \"instant\" | \"smooth\"\n ) {\n const container = containerRef.current;\n if (container === null) return;\n\n container.scrollTo({\n top: container.scrollHeight,\n behavior,\n });\n };\n }\n const scrollToBottom = scrollToBottomCallbackRef.current;\n\n return (\n <div\n ref={containerRef}\n {...props}\n className={cn(\n \"lb-root lb-ai-chat\",\n layout === \"compact\"\n ? \"lb-ai-chat:layout-compact\"\n : \"lb-ai-chat:layout-inset\",\n className\n )}\n >\n {knowledge\n ? knowledge.map((source, index) => (\n <RegisterAiKnowledge\n key={index}\n description={source.description}\n value={source.value}\n // knowledgeKey={source.knowledgeKey}\n />\n ))\n : null}\n\n {Object.entries(tools).map(([name, tool]) => (\n <RegisterAiTool key={name} chatId={chatId} name={name} tool={tool} />\n ))}\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 <AutoScrollHandler\n lastSentMessageId={lastSentMessageId}\n scrollToBottom={scrollToBottom}\n />\n <div className=\"lb-ai-chat-messages\">\n {messages.map((message) => {\n if (message.role === \"user\") {\n return (\n <AiChatUserMessage\n key={message.id}\n message={message}\n overrides={overrides}\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 />\n );\n } else {\n return null;\n }\n })}\n </div>\n </>\n )}\n </div>\n\n <div className=\"lb-ai-chat-footer\">\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(\"smooth\")}\n >\n <span className=\"lb-icon-container\">\n <ArrowDownIcon />\n </span>\n </button>\n </div>\n </div>\n <AiChatComposer\n key={chatId}\n chatId={chatId}\n copilotId={copilotId as CopilotId}\n overrides={overrides}\n autoFocus={autoFocus}\n onUserMessageCreate={({ id }) => setLastSentMessageId(id)}\n className={\n layout === \"inset\"\n ? \"lb-elevation lb-elevation-moderate\"\n : undefined\n }\n />\n </div>\n {/* This invisible element 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 fully scrolled.\n */}\n <div\n ref={containerBottomRef}\n style={{ position: \"sticky\", height: 0 }}\n aria-hidden\n data-scroll-at-bottom={isScrollAtBottom ? \"\" : undefined}\n />\n </div>\n );\n }\n);\n\nfunction AutoScrollHandler({\n lastSentMessageId,\n scrollToBottom,\n}: {\n lastSentMessageId: MessageId | null;\n scrollToBottom: (behavior: \"instant\" | \"smooth\") => void;\n}) {\n // Scroll to bottom when the component first mounts\n useLayoutEffect(() => {\n scrollToBottom(\"instant\");\n }, [scrollToBottom]);\n\n // Scroll to bottom when sending a new message\n useEffect(() => {\n scrollToBottom(\"smooth\");\n }, [lastSentMessageId, scrollToBottom]);\n\n return null;\n}\n"],"names":["jsx","SpinnerIcon","forwardRef","overrides","useAiChatMessages","useOverrides","useRef","useVisible","useState","useImperativeHandle","jsxs","cn","RegisterAiKnowledge","RegisterAiTool","Fragment","AiChatUserMessage","AiChatAssistantMessage","ArrowDownIcon","AiChatComposer","useLayoutEffect","useEffect"],"mappings":"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"}
1
+ {"version":3,"file":"AiChat.cjs","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 {\n type ComponentProps,\n type ComponentType,\n forwardRef,\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 AiChatComposerOverrides,\n type AiChatMessageOverrides,\n type AiChatOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../overrides\";\nimport { cn } from \"../utils/cn\";\nimport { useVisible } from \"../utils/use-visible\";\nimport { AiChatAssistantMessage } from \"./internal/AiChatAssistantMessage\";\nimport { AiChatComposer } from \"./internal/AiChatComposer\";\nimport { AiChatUserMessage } from \"./internal/AiChatUserMessage\";\n\nexport type AiChatComponentsEmptyProps = {\n /**\n * The chat id provided to the `AiChat` component.\n */\n chatId: string;\n /**\n * The copilot id provided to the `AiChat` component.\n */\n copilotId?: string;\n};\n\nexport type AiChatComponentsLoadingProps = Record<string, never>;\n\n// TODO: Add Markdown components\nexport type AiChatComponents = {\n /**\n * The component used to render the empty state of the chat.\n */\n Empty: ComponentType<AiChatComponentsEmptyProps>;\n /**\n * The component used to render the loading state of the chat.\n */\n Loading: ComponentType<AiChatComponentsLoadingProps>;\n};\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 = 50;\n\nexport interface AiChatProps extends ComponentProps<\"div\"> {\n /**\n * The id of the chat the composer belongs to.\n */\n chatId: string;\n /**\n * Whether to focus the chat composer on mount.\n */\n autoFocus?: boolean;\n /**\n * The id of the copilot to use to send the message.\n */\n copilotId?: string;\n /**\n * The contextual knowledge to include in the chat. May be used by the assistant when generating responses.\n * Any knowledge you provide via this prop will be added to any already globally registered knowledge via <RegisterAiKnowledge />.\n */\n knowledge?: AiKnowledgeSource[];\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 * The layout of the chat and its composer.\n */\n layout?: \"inset\" | \"compact\";\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n AiChatMessageOverrides &\n AiChatComposerOverrides &\n AiChatOverrides\n >;\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & AiChatComponents>;\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\nexport const AiChat = forwardRef<HTMLDivElement, AiChatProps>(\n (\n {\n chatId,\n copilotId,\n autoFocus,\n overrides,\n knowledge,\n tools = {},\n layout = \"inset\",\n components,\n className,\n ...props\n },\n forwardedRef\n ) => {\n const { messages, isLoading, error } = useAiChatMessages(chatId);\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 containerBottomRef = useRef<HTMLDivElement | null>(null);\n const isScrollIndicatorEnabled = !isLoading && !error;\n const isScrollAtBottom = useVisible(containerBottomRef, {\n enabled: isScrollIndicatorEnabled,\n root: containerRef,\n rootMargin: MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR,\n initialValue: null,\n });\n const isScrollIndicatorVisible =\n isScrollIndicatorEnabled && isScrollAtBottom !== null\n ? !isScrollAtBottom\n : false;\n\n const [lastSentMessageId, setLastSentMessageId] =\n useState<MessageId | null>(null);\n\n useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(\n forwardedRef,\n () => containerRef.current,\n []\n );\n\n const scrollToBottomCallbackRef =\n useRef<(behavior: \"instant\" | \"smooth\") => void>(undefined);\n if (scrollToBottomCallbackRef.current === undefined) {\n scrollToBottomCallbackRef.current = function (\n behavior: \"instant\" | \"smooth\"\n ) {\n const container = containerRef.current;\n if (container === null) return;\n\n container.scrollTo({\n top: container.scrollHeight,\n behavior,\n });\n };\n }\n const scrollToBottom = scrollToBottomCallbackRef.current;\n\n return (\n <div\n ref={containerRef}\n {...props}\n className={cn(\n \"lb-root lb-ai-chat\",\n layout === \"compact\"\n ? \"lb-ai-chat:layout-compact\"\n : \"lb-ai-chat:layout-inset\",\n className\n )}\n >\n {knowledge\n ? knowledge.map((source, index) => (\n <RegisterAiKnowledge\n key={index}\n description={source.description}\n value={source.value}\n // knowledgeKey={source.knowledgeKey}\n />\n ))\n : null}\n\n {Object.entries(tools).map(([name, tool]) => (\n <RegisterAiTool key={name} chatId={chatId} name={name} tool={tool} />\n ))}\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 <AutoScrollHandler\n lastSentMessageId={lastSentMessageId}\n scrollToBottom={scrollToBottom}\n />\n <div className=\"lb-ai-chat-messages\">\n {messages.map((message) => {\n if (message.role === \"user\") {\n return (\n <AiChatUserMessage\n key={message.id}\n message={message}\n overrides={overrides}\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 />\n );\n } else {\n return null;\n }\n })}\n </div>\n </>\n )}\n </div>\n\n <div className=\"lb-ai-chat-footer\">\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(\"smooth\")}\n >\n <span className=\"lb-icon-container\">\n <ArrowDownIcon />\n </span>\n </button>\n </div>\n </div>\n <AiChatComposer\n key={chatId}\n chatId={chatId}\n copilotId={copilotId as CopilotId}\n overrides={overrides}\n autoFocus={autoFocus}\n onUserMessageCreate={({ id }) => setLastSentMessageId(id)}\n className={\n layout === \"inset\"\n ? \"lb-elevation lb-elevation-moderate\"\n : undefined\n }\n />\n </div>\n {/* This invisible element 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 fully scrolled.\n */}\n <div\n ref={containerBottomRef}\n style={{ position: \"sticky\", height: 0 }}\n aria-hidden\n data-scroll-at-bottom={isScrollAtBottom ? \"\" : undefined}\n />\n </div>\n );\n }\n);\n\nfunction AutoScrollHandler({\n lastSentMessageId,\n scrollToBottom,\n}: {\n lastSentMessageId: MessageId | null;\n scrollToBottom: (behavior: \"instant\" | \"smooth\") => void;\n}) {\n // Scroll to bottom when the component first mounts\n useEffect(() => {\n scrollToBottom(\"instant\");\n }, [scrollToBottom]);\n\n // Scroll to bottom when sending a new message\n useEffect(() => {\n if (lastSentMessageId === null) return;\n scrollToBottom(\"smooth\");\n }, [lastSentMessageId, scrollToBottom]);\n\n return null;\n}\n"],"names":["jsx","SpinnerIcon","forwardRef","overrides","useAiChatMessages","useOverrides","useRef","useVisible","useState","useImperativeHandle","jsxs","cn","RegisterAiKnowledge","RegisterAiTool","Fragment","AiChatUserMessage","AiChatAssistantMessage","ArrowDownIcon","AiChatComposer","useEffect"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { useAiChatMessages, RegisterAiKnowledge, RegisterAiTool } from '@liveblocks/react';
3
- import { useLayoutEffect } from '@liveblocks/react/_private';
4
3
  import { forwardRef, useRef, useState, useImperativeHandle, useEffect } from 'react';
5
4
  import { ArrowDownIcon } from '../icons/ArrowDown.js';
6
5
  import { SpinnerIcon } from '../icons/Spinner.js';
@@ -163,10 +162,12 @@ function AutoScrollHandler({
163
162
  lastSentMessageId,
164
163
  scrollToBottom
165
164
  }) {
166
- useLayoutEffect(() => {
165
+ useEffect(() => {
167
166
  scrollToBottom("instant");
168
167
  }, [scrollToBottom]);
169
168
  useEffect(() => {
169
+ if (lastSentMessageId === null)
170
+ return;
170
171
  scrollToBottom("smooth");
171
172
  }, [lastSentMessageId, scrollToBottom]);
172
173
  return null;
@@ -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 { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n type ComponentProps,\n type ComponentType,\n forwardRef,\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 AiChatComposerOverrides,\n type AiChatMessageOverrides,\n type AiChatOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../overrides\";\nimport { cn } from \"../utils/cn\";\nimport { useVisible } from \"../utils/use-visible\";\nimport { AiChatAssistantMessage } from \"./internal/AiChatAssistantMessage\";\nimport { AiChatComposer } from \"./internal/AiChatComposer\";\nimport { AiChatUserMessage } from \"./internal/AiChatUserMessage\";\n\nexport type AiChatComponentsEmptyProps = {\n /**\n * The chat id provided to the `AiChat` component.\n */\n chatId: string;\n /**\n * The copilot id provided to the `AiChat` component.\n */\n copilotId?: string;\n};\n\nexport type AiChatComponentsLoadingProps = Record<string, never>;\n\n// TODO: Add Markdown components\nexport type AiChatComponents = {\n /**\n * The component used to render the empty state of the chat.\n */\n Empty: ComponentType<AiChatComponentsEmptyProps>;\n /**\n * The component used to render the loading state of the chat.\n */\n Loading: ComponentType<AiChatComponentsLoadingProps>;\n};\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 = 50;\n\nexport interface AiChatProps extends ComponentProps<\"div\"> {\n /**\n * The id of the chat the composer belongs to.\n */\n chatId: string;\n /**\n * Whether to focus the chat composer on mount.\n */\n autoFocus?: boolean;\n /**\n * The id of the copilot to use to send the message.\n */\n copilotId?: string;\n /**\n * The contextual knowledge to include in the chat. May be used by the assistant when generating responses.\n * Any knowledge you provide via this prop will be added to any already globally registered knowledge via <RegisterAiKnowledge />.\n */\n knowledge?: AiKnowledgeSource[];\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 * The layout of the chat and its composer.\n */\n layout?: \"inset\" | \"compact\";\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n AiChatMessageOverrides &\n AiChatComposerOverrides &\n AiChatOverrides\n >;\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & AiChatComponents>;\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\nexport const AiChat = forwardRef<HTMLDivElement, AiChatProps>(\n (\n {\n chatId,\n copilotId,\n autoFocus,\n overrides,\n knowledge,\n tools = {},\n layout = \"inset\",\n components,\n className,\n ...props\n },\n forwardedRef\n ) => {\n const { messages, isLoading, error } = useAiChatMessages(chatId);\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 containerBottomRef = useRef<HTMLDivElement | null>(null);\n const isScrollIndicatorEnabled = !isLoading && !error;\n const isScrollAtBottom = useVisible(containerBottomRef, {\n enabled: isScrollIndicatorEnabled,\n root: containerRef,\n rootMargin: MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR,\n initialValue: null,\n });\n const isScrollIndicatorVisible =\n isScrollIndicatorEnabled && isScrollAtBottom !== null\n ? !isScrollAtBottom\n : false;\n\n const [lastSentMessageId, setLastSentMessageId] =\n useState<MessageId | null>(null);\n\n useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(\n forwardedRef,\n () => containerRef.current,\n []\n );\n\n const scrollToBottomCallbackRef =\n useRef<(behavior: \"instant\" | \"smooth\") => void>(undefined);\n if (scrollToBottomCallbackRef.current === undefined) {\n scrollToBottomCallbackRef.current = function (\n behavior: \"instant\" | \"smooth\"\n ) {\n const container = containerRef.current;\n if (container === null) return;\n\n container.scrollTo({\n top: container.scrollHeight,\n behavior,\n });\n };\n }\n const scrollToBottom = scrollToBottomCallbackRef.current;\n\n return (\n <div\n ref={containerRef}\n {...props}\n className={cn(\n \"lb-root lb-ai-chat\",\n layout === \"compact\"\n ? \"lb-ai-chat:layout-compact\"\n : \"lb-ai-chat:layout-inset\",\n className\n )}\n >\n {knowledge\n ? knowledge.map((source, index) => (\n <RegisterAiKnowledge\n key={index}\n description={source.description}\n value={source.value}\n // knowledgeKey={source.knowledgeKey}\n />\n ))\n : null}\n\n {Object.entries(tools).map(([name, tool]) => (\n <RegisterAiTool key={name} chatId={chatId} name={name} tool={tool} />\n ))}\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 <AutoScrollHandler\n lastSentMessageId={lastSentMessageId}\n scrollToBottom={scrollToBottom}\n />\n <div className=\"lb-ai-chat-messages\">\n {messages.map((message) => {\n if (message.role === \"user\") {\n return (\n <AiChatUserMessage\n key={message.id}\n message={message}\n overrides={overrides}\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 />\n );\n } else {\n return null;\n }\n })}\n </div>\n </>\n )}\n </div>\n\n <div className=\"lb-ai-chat-footer\">\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(\"smooth\")}\n >\n <span className=\"lb-icon-container\">\n <ArrowDownIcon />\n </span>\n </button>\n </div>\n </div>\n <AiChatComposer\n key={chatId}\n chatId={chatId}\n copilotId={copilotId as CopilotId}\n overrides={overrides}\n autoFocus={autoFocus}\n onUserMessageCreate={({ id }) => setLastSentMessageId(id)}\n className={\n layout === \"inset\"\n ? \"lb-elevation lb-elevation-moderate\"\n : undefined\n }\n />\n </div>\n {/* This invisible element 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 fully scrolled.\n */}\n <div\n ref={containerBottomRef}\n style={{ position: \"sticky\", height: 0 }}\n aria-hidden\n data-scroll-at-bottom={isScrollAtBottom ? \"\" : undefined}\n />\n </div>\n );\n }\n);\n\nfunction AutoScrollHandler({\n lastSentMessageId,\n scrollToBottom,\n}: {\n lastSentMessageId: MessageId | null;\n scrollToBottom: (behavior: \"instant\" | \"smooth\") => void;\n}) {\n // Scroll to bottom when the component first mounts\n useLayoutEffect(() => {\n scrollToBottom(\"instant\");\n }, [scrollToBottom]);\n\n // Scroll to bottom when sending a new message\n useEffect(() => {\n scrollToBottom(\"smooth\");\n }, [lastSentMessageId, scrollToBottom]);\n\n return null;\n}\n"],"names":[],"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 {\n type ComponentProps,\n type ComponentType,\n forwardRef,\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 AiChatComposerOverrides,\n type AiChatMessageOverrides,\n type AiChatOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../overrides\";\nimport { cn } from \"../utils/cn\";\nimport { useVisible } from \"../utils/use-visible\";\nimport { AiChatAssistantMessage } from \"./internal/AiChatAssistantMessage\";\nimport { AiChatComposer } from \"./internal/AiChatComposer\";\nimport { AiChatUserMessage } from \"./internal/AiChatUserMessage\";\n\nexport type AiChatComponentsEmptyProps = {\n /**\n * The chat id provided to the `AiChat` component.\n */\n chatId: string;\n /**\n * The copilot id provided to the `AiChat` component.\n */\n copilotId?: string;\n};\n\nexport type AiChatComponentsLoadingProps = Record<string, never>;\n\n// TODO: Add Markdown components\nexport type AiChatComponents = {\n /**\n * The component used to render the empty state of the chat.\n */\n Empty: ComponentType<AiChatComponentsEmptyProps>;\n /**\n * The component used to render the loading state of the chat.\n */\n Loading: ComponentType<AiChatComponentsLoadingProps>;\n};\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 = 50;\n\nexport interface AiChatProps extends ComponentProps<\"div\"> {\n /**\n * The id of the chat the composer belongs to.\n */\n chatId: string;\n /**\n * Whether to focus the chat composer on mount.\n */\n autoFocus?: boolean;\n /**\n * The id of the copilot to use to send the message.\n */\n copilotId?: string;\n /**\n * The contextual knowledge to include in the chat. May be used by the assistant when generating responses.\n * Any knowledge you provide via this prop will be added to any already globally registered knowledge via <RegisterAiKnowledge />.\n */\n knowledge?: AiKnowledgeSource[];\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 * The layout of the chat and its composer.\n */\n layout?: \"inset\" | \"compact\";\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n AiChatMessageOverrides &\n AiChatComposerOverrides &\n AiChatOverrides\n >;\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & AiChatComponents>;\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\nexport const AiChat = forwardRef<HTMLDivElement, AiChatProps>(\n (\n {\n chatId,\n copilotId,\n autoFocus,\n overrides,\n knowledge,\n tools = {},\n layout = \"inset\",\n components,\n className,\n ...props\n },\n forwardedRef\n ) => {\n const { messages, isLoading, error } = useAiChatMessages(chatId);\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 containerBottomRef = useRef<HTMLDivElement | null>(null);\n const isScrollIndicatorEnabled = !isLoading && !error;\n const isScrollAtBottom = useVisible(containerBottomRef, {\n enabled: isScrollIndicatorEnabled,\n root: containerRef,\n rootMargin: MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR,\n initialValue: null,\n });\n const isScrollIndicatorVisible =\n isScrollIndicatorEnabled && isScrollAtBottom !== null\n ? !isScrollAtBottom\n : false;\n\n const [lastSentMessageId, setLastSentMessageId] =\n useState<MessageId | null>(null);\n\n useImperativeHandle<HTMLDivElement | null, HTMLDivElement | null>(\n forwardedRef,\n () => containerRef.current,\n []\n );\n\n const scrollToBottomCallbackRef =\n useRef<(behavior: \"instant\" | \"smooth\") => void>(undefined);\n if (scrollToBottomCallbackRef.current === undefined) {\n scrollToBottomCallbackRef.current = function (\n behavior: \"instant\" | \"smooth\"\n ) {\n const container = containerRef.current;\n if (container === null) return;\n\n container.scrollTo({\n top: container.scrollHeight,\n behavior,\n });\n };\n }\n const scrollToBottom = scrollToBottomCallbackRef.current;\n\n return (\n <div\n ref={containerRef}\n {...props}\n className={cn(\n \"lb-root lb-ai-chat\",\n layout === \"compact\"\n ? \"lb-ai-chat:layout-compact\"\n : \"lb-ai-chat:layout-inset\",\n className\n )}\n >\n {knowledge\n ? knowledge.map((source, index) => (\n <RegisterAiKnowledge\n key={index}\n description={source.description}\n value={source.value}\n // knowledgeKey={source.knowledgeKey}\n />\n ))\n : null}\n\n {Object.entries(tools).map(([name, tool]) => (\n <RegisterAiTool key={name} chatId={chatId} name={name} tool={tool} />\n ))}\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 <AutoScrollHandler\n lastSentMessageId={lastSentMessageId}\n scrollToBottom={scrollToBottom}\n />\n <div className=\"lb-ai-chat-messages\">\n {messages.map((message) => {\n if (message.role === \"user\") {\n return (\n <AiChatUserMessage\n key={message.id}\n message={message}\n overrides={overrides}\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 />\n );\n } else {\n return null;\n }\n })}\n </div>\n </>\n )}\n </div>\n\n <div className=\"lb-ai-chat-footer\">\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(\"smooth\")}\n >\n <span className=\"lb-icon-container\">\n <ArrowDownIcon />\n </span>\n </button>\n </div>\n </div>\n <AiChatComposer\n key={chatId}\n chatId={chatId}\n copilotId={copilotId as CopilotId}\n overrides={overrides}\n autoFocus={autoFocus}\n onUserMessageCreate={({ id }) => setLastSentMessageId(id)}\n className={\n layout === \"inset\"\n ? \"lb-elevation lb-elevation-moderate\"\n : undefined\n }\n />\n </div>\n {/* This invisible element 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 fully scrolled.\n */}\n <div\n ref={containerBottomRef}\n style={{ position: \"sticky\", height: 0 }}\n aria-hidden\n data-scroll-at-bottom={isScrollAtBottom ? \"\" : undefined}\n />\n </div>\n );\n }\n);\n\nfunction AutoScrollHandler({\n lastSentMessageId,\n scrollToBottom,\n}: {\n lastSentMessageId: MessageId | null;\n scrollToBottom: (behavior: \"instant\" | \"smooth\") => void;\n}) {\n // Scroll to bottom when the component first mounts\n useEffect(() => {\n scrollToBottom(\"instant\");\n }, [scrollToBottom]);\n\n // Scroll to bottom when sending a new message\n useEffect(() => {\n if (lastSentMessageId === null) return;\n scrollToBottom(\"smooth\");\n }, [lastSentMessageId, scrollToBottom]);\n\n return null;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAkEA,MAAM,oCAAuC,GAAA,EAAA,CAAA;AA2C7C,MAAM,iBAAsC,GAAA;AAAA,EAC1C,OAAO,MAAM,IAAA;AAAA,EACb,OAAA,EAAS,sBACN,GAAA,CAAA,KAAA,EAAA;AAAA,IAAI,SAAU,EAAA,+BAAA;AAAA,IACb,8BAAC,WAAY,EAAA,EAAA,CAAA;AAAA,GACf,CAAA;AAEJ,CAAA,CAAA;AAEO,MAAM,MAAS,GAAA,UAAA;AAAA,EACpB,CACE;AAAA,IACE,MAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAQ,EAAC;AAAA,IACT,MAAS,GAAA,OAAA;AAAA,IACT,UAAA;AAAA,IACA,SAAA;AAAA,IACG,GAAA,KAAA;AAAA,KAEL,YACG,KAAA;AACH,IAAA,MAAM,EAAE,QAAU,EAAA,SAAA,EAAW,KAAM,EAAA,GAAI,kBAAkB,MAAM,CAAA,CAAA;AAC/D,IAAM,MAAA,CAAA,GAAI,aAAa,SAAS,CAAA,CAAA;AAChC,IAAM,MAAA,KAAA,GAAQ,UAAY,EAAA,KAAA,IAAS,iBAAkB,CAAA,KAAA,CAAA;AACrD,IAAM,MAAA,OAAA,GAAU,UAAY,EAAA,OAAA,IAAW,iBAAkB,CAAA,OAAA,CAAA;AAEzD,IAAM,MAAA,YAAA,GAAe,OAA8B,IAAI,CAAA,CAAA;AACvD,IAAM,MAAA,kBAAA,GAAqB,OAA8B,IAAI,CAAA,CAAA;AAC7D,IAAM,MAAA,wBAAA,GAA2B,CAAC,SAAA,IAAa,CAAC,KAAA,CAAA;AAChD,IAAM,MAAA,gBAAA,GAAmB,WAAW,kBAAoB,EAAA;AAAA,MACtD,OAAS,EAAA,wBAAA;AAAA,MACT,IAAM,EAAA,YAAA;AAAA,MACN,UAAY,EAAA,oCAAA;AAAA,MACZ,YAAc,EAAA,IAAA;AAAA,KACf,CAAA,CAAA;AACD,IAAA,MAAM,wBACJ,GAAA,wBAAA,IAA4B,gBAAqB,KAAA,IAAA,GAC7C,CAAC,gBACD,GAAA,KAAA,CAAA;AAEN,IAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAC5C,SAA2B,IAAI,CAAA,CAAA;AAEjC,IAAA,mBAAA;AAAA,MACE,YAAA;AAAA,MACA,MAAM,YAAa,CAAA,OAAA;AAAA,MACnB,EAAC;AAAA,KACH,CAAA;AAEA,IAAM,MAAA,yBAAA,GACJ,OAAiD,KAAS,CAAA,CAAA,CAAA;AAC5D,IAAI,IAAA,yBAAA,CAA0B,YAAY,KAAW,CAAA,EAAA;AACnD,MAA0B,yBAAA,CAAA,OAAA,GAAU,SAClC,QACA,EAAA;AACA,QAAA,MAAM,YAAY,YAAa,CAAA,OAAA,CAAA;AAC/B,QAAA,IAAI,SAAc,KAAA,IAAA;AAAM,UAAA,OAAA;AAExB,QAAA,SAAA,CAAU,QAAS,CAAA;AAAA,UACjB,KAAK,SAAU,CAAA,YAAA;AAAA,UACf,QAAA;AAAA,SACD,CAAA,CAAA;AAAA,OACH,CAAA;AAAA,KACF;AACA,IAAA,MAAM,iBAAiB,yBAA0B,CAAA,OAAA,CAAA;AAEjD,IAAA,uBACG,IAAA,CAAA,KAAA,EAAA;AAAA,MACC,GAAK,EAAA,YAAA;AAAA,MACJ,GAAG,KAAA;AAAA,MACJ,SAAW,EAAA,EAAA;AAAA,QACT,oBAAA;AAAA,QACA,MAAA,KAAW,YACP,2BACA,GAAA,yBAAA;AAAA,QACJ,SAAA;AAAA,OACF;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,SAAA,GACG,SAAU,CAAA,GAAA,CAAI,CAAC,MAAA,EAAQ,0BACpB,GAAA,CAAA,mBAAA,EAAA;AAAA,UAEC,aAAa,MAAO,CAAA,WAAA;AAAA,UACpB,OAAO,MAAO,CAAA,KAAA;AAAA,SAFT,EAAA,KAIP,CACD,CACD,GAAA,IAAA;AAAA,QAEH,MAAA,CAAO,OAAQ,CAAA,KAAK,CAAE,CAAA,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,IAAI,CAAA,qBACpC,GAAA,CAAA,cAAA,EAAA;AAAA,UAA0B,MAAA;AAAA,UAAgB,IAAA;AAAA,UAAY,IAAA;AAAA,SAAA,EAAlC,IAA8C,CACpE,CAAA;AAAA,wBAEA,GAAA,CAAA,KAAA,EAAA;AAAA,UAAI,SAAU,EAAA,oBAAA;AAAA,UACZ,sCACE,GAAA,CAAA,OAAA,EAAA,EAAQ,CACP,GAAA,KAAA,KAAU,yBACX,GAAA,CAAA,KAAA,EAAA;AAAA,YAAI,SAAU,EAAA,2BAAA;AAAA,YACZ,QAAA,EAAA,CAAA,CAAE,uBAAuB,KAAK,CAAA;AAAA,WACjC,CACE,GAAA,QAAA,CAAS,MAAW,KAAA,CAAA,mBACrB,GAAA,CAAA,KAAA,EAAA;AAAA,YAAM,MAAA;AAAA,YAAgB,SAAA;AAAA,WAAsB,CAE7C,mBAAA,IAAA,CAAA,QAAA,EAAA;AAAA,YACE,QAAA,EAAA;AAAA,8BAAC,GAAA,CAAA,iBAAA,EAAA;AAAA,gBACC,iBAAA;AAAA,gBACA,cAAA;AAAA,eACF,CAAA;AAAA,8BACC,GAAA,CAAA,KAAA,EAAA;AAAA,gBAAI,SAAU,EAAA,qBAAA;AAAA,gBACZ,QAAA,EAAA,QAAA,CAAS,GAAI,CAAA,CAAC,OAAY,KAAA;AACzB,kBAAI,IAAA,OAAA,CAAQ,SAAS,MAAQ,EAAA;AAC3B,oBAAA,uBACG,GAAA,CAAA,iBAAA,EAAA;AAAA,sBAEC,OAAA;AAAA,sBACA,SAAA;AAAA,qBAAA,EAFK,QAAQ,EAGf,CAAA,CAAA;AAAA,mBAEJ,MAAA,IAAW,OAAQ,CAAA,IAAA,KAAS,WAAa,EAAA;AACvC,oBAAA,uBACG,GAAA,CAAA,sBAAA,EAAA;AAAA,sBAEC,OAAA;AAAA,sBACA,SAAA;AAAA,sBACA,UAAA;AAAA,qBAAA,EAHK,QAAQ,EAIf,CAAA,CAAA;AAAA,mBAEG,MAAA;AACL,oBAAO,OAAA,IAAA,CAAA;AAAA,mBACT;AAAA,iBACD,CAAA;AAAA,eACH,CAAA;AAAA,aAAA;AAAA,WACF,CAAA;AAAA,SAEJ,CAAA;AAAA,wBAEC,IAAA,CAAA,KAAA,EAAA;AAAA,UAAI,SAAU,EAAA,mBAAA;AAAA,UACb,QAAA,EAAA;AAAA,4BAAC,GAAA,CAAA,KAAA,EAAA;AAAA,cAAI,SAAU,EAAA,2BAAA;AAAA,cACb,QAAC,kBAAA,GAAA,CAAA,KAAA,EAAA;AAAA,gBACC,SAAU,EAAA,wEAAA;AAAA,gBACV,cAAA,EAAc,2BAA2B,EAAK,GAAA,KAAA,CAAA;AAAA,gBAE9C,QAAC,kBAAA,GAAA,CAAA,QAAA,EAAA;AAAA,kBACC,SAAU,EAAA,oCAAA;AAAA,kBACV,QAAA,EAAU,2BAA2B,CAAI,GAAA,CAAA,CAAA;AAAA,kBACzC,eAAa,CAAC,wBAAA;AAAA,kBACd,OAAA,EAAS,MAAM,cAAA,CAAe,QAAQ,CAAA;AAAA,kBAEtC,QAAC,kBAAA,GAAA,CAAA,MAAA,EAAA;AAAA,oBAAK,SAAU,EAAA,mBAAA;AAAA,oBACd,8BAAC,aAAc,EAAA,EAAA,CAAA;AAAA,mBACjB,CAAA;AAAA,iBACF,CAAA;AAAA,eACF,CAAA;AAAA,aACF,CAAA;AAAA,4BACC,GAAA,CAAA,cAAA,EAAA;AAAA,cAEC,MAAA;AAAA,cACA,SAAA;AAAA,cACA,SAAA;AAAA,cACA,SAAA;AAAA,cACA,qBAAqB,CAAC,EAAE,EAAG,EAAA,KAAM,qBAAqB,EAAE,CAAA;AAAA,cACxD,SAAA,EACE,MAAW,KAAA,OAAA,GACP,oCACA,GAAA,KAAA,CAAA;AAAA,aAAA,EATD,MAWP,CAAA;AAAA,WAAA;AAAA,SACF,CAAA;AAAA,wBAQC,GAAA,CAAA,KAAA,EAAA;AAAA,UACC,GAAK,EAAA,kBAAA;AAAA,UACL,KAAO,EAAA,EAAE,QAAU,EAAA,QAAA,EAAU,QAAQ,CAAE,EAAA;AAAA,UACvC,aAAW,EAAA,IAAA;AAAA,UACX,uBAAA,EAAuB,mBAAmB,EAAK,GAAA,KAAA,CAAA;AAAA,SACjD,CAAA;AAAA,OAAA;AAAA,KACF,CAAA,CAAA;AAAA,GAEJ;AACF,EAAA;AAEA,SAAS,iBAAkB,CAAA;AAAA,EACzB,iBAAA;AAAA,EACA,cAAA;AACF,CAGG,EAAA;AAED,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,cAAA,CAAe,SAAS,CAAA,CAAA;AAAA,GAC1B,EAAG,CAAC,cAAc,CAAC,CAAA,CAAA;AAGnB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,iBAAsB,KAAA,IAAA;AAAM,MAAA,OAAA;AAChC,IAAA,cAAA,CAAe,QAAQ,CAAA,CAAA;AAAA,GACtB,EAAA,CAAC,iBAAmB,EAAA,cAAc,CAAC,CAAA,CAAA;AAEtC,EAAO,OAAA,IAAA,CAAA;AACT;;;;"}
package/dist/version.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const PKG_NAME = "@liveblocks/react-ui";
4
- const PKG_VERSION = typeof "3.1.2-url1" === "string" && "3.1.2-url1";
4
+ const PKG_VERSION = typeof "3.1.3" === "string" && "3.1.3";
5
5
  const PKG_FORMAT = typeof "cjs" === "string" && "cjs";
6
6
 
7
7
  exports.PKG_FORMAT = PKG_FORMAT;
@@ -1 +1 @@
1
- {"version":3,"file":"version.cjs","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-ui\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_FORMAT;\n"],"names":[],"mappings":";;AAGO,MAAM,QAAW,GAAA,uBAAA;AACX,MAAA,WAAA,GAAc,OAAO,YAAA,KAAgB,QAAY,IAAA,aAAA;AACjD,MAAA,UAAA,GAAa,OAAO,KAAA,KAAkB,QAAY,IAAA;;;;;;"}
1
+ {"version":3,"file":"version.cjs","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-ui\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_FORMAT;\n"],"names":[],"mappings":";;AAGO,MAAM,QAAW,GAAA,uBAAA;AACX,MAAA,WAAA,GAAc,OAAO,OAAA,KAAgB,QAAY,IAAA,QAAA;AACjD,MAAA,UAAA,GAAa,OAAO,KAAA,KAAkB,QAAY,IAAA;;;;;;"}
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const PKG_NAME = "@liveblocks/react-ui";
2
- const PKG_VERSION = typeof "3.1.2-url1" === "string" && "3.1.2-url1";
2
+ const PKG_VERSION = typeof "3.1.3" === "string" && "3.1.3";
3
3
  const PKG_FORMAT = typeof "esm" === "string" && "esm";
4
4
 
5
5
  export { PKG_FORMAT, PKG_NAME, PKG_VERSION };
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-ui\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_FORMAT;\n"],"names":[],"mappings":"AAGO,MAAM,QAAW,GAAA,uBAAA;AACX,MAAA,WAAA,GAAc,OAAO,YAAA,KAAgB,QAAY,IAAA,aAAA;AACjD,MAAA,UAAA,GAAa,OAAO,KAAA,KAAkB,QAAY,IAAA;;;;"}
1
+ {"version":3,"file":"version.js","sources":["../src/version.ts"],"sourcesContent":["declare const __VERSION__: string;\ndeclare const ROLLUP_FORMAT: string;\n\nexport const PKG_NAME = \"@liveblocks/react-ui\";\nexport const PKG_VERSION = typeof __VERSION__ === \"string\" && __VERSION__;\nexport const PKG_FORMAT = typeof ROLLUP_FORMAT === \"string\" && ROLLUP_FORMAT;\n"],"names":[],"mappings":"AAGO,MAAM,QAAW,GAAA,uBAAA;AACX,MAAA,WAAA,GAAc,OAAO,OAAA,KAAgB,QAAY,IAAA,QAAA;AACjD,MAAA,UAAA,GAAa,OAAO,KAAA,KAAkB,QAAY,IAAA;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/react-ui",
3
- "version": "3.1.2-url1",
3
+ "version": "3.1.3",
4
4
  "description": "A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -76,9 +76,9 @@
76
76
  },
77
77
  "dependencies": {
78
78
  "@floating-ui/react-dom": "^2.1.2",
79
- "@liveblocks/client": "3.1.2-url1",
80
- "@liveblocks/core": "3.1.2-url1",
81
- "@liveblocks/react": "3.1.2-url1",
79
+ "@liveblocks/client": "3.1.3",
80
+ "@liveblocks/core": "3.1.3",
81
+ "@liveblocks/react": "3.1.3",
82
82
  "@radix-ui/react-dropdown-menu": "^2.1.2",
83
83
  "@radix-ui/react-popover": "^1.1.2",
84
84
  "@radix-ui/react-slot": "^1.1.0",