@liveblocks/react-ui 3.1.3 → 3.2.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 (71) hide show
  1. package/dist/_private/index.d.cts +272 -37
  2. package/dist/_private/index.d.ts +272 -37
  3. package/dist/components/AiChat.cjs +213 -62
  4. package/dist/components/AiChat.cjs.map +1 -1
  5. package/dist/components/AiChat.js +215 -64
  6. package/dist/components/AiChat.js.map +1 -1
  7. package/dist/components/Composer.cjs +2 -0
  8. package/dist/components/Composer.cjs.map +1 -1
  9. package/dist/components/Composer.js +2 -0
  10. package/dist/components/Composer.js.map +1 -1
  11. package/dist/components/Thread.cjs +2 -0
  12. package/dist/components/Thread.cjs.map +1 -1
  13. package/dist/components/Thread.js +2 -0
  14. package/dist/components/Thread.js.map +1 -1
  15. package/dist/components/internal/AiChatAssistantMessage.cjs +38 -22
  16. package/dist/components/internal/AiChatAssistantMessage.cjs.map +1 -1
  17. package/dist/components/internal/AiChatAssistantMessage.js +38 -22
  18. package/dist/components/internal/AiChatAssistantMessage.js.map +1 -1
  19. package/dist/components/internal/AiChatUserMessage.cjs +2 -1
  20. package/dist/components/internal/AiChatUserMessage.cjs.map +1 -1
  21. package/dist/components/internal/AiChatUserMessage.js +2 -1
  22. package/dist/components/internal/AiChatUserMessage.js.map +1 -1
  23. package/dist/components/internal/Prose.cjs +15 -7
  24. package/dist/components/internal/Prose.cjs.map +1 -1
  25. package/dist/components/internal/Prose.js +16 -8
  26. package/dist/components/internal/Prose.js.map +1 -1
  27. package/dist/index.d.cts +277 -4
  28. package/dist/index.d.ts +277 -4
  29. package/dist/primitives/AiMessage/index.cjs +3 -2
  30. package/dist/primitives/AiMessage/index.cjs.map +1 -1
  31. package/dist/primitives/AiMessage/index.js +3 -2
  32. package/dist/primitives/AiMessage/index.js.map +1 -1
  33. package/dist/primitives/AiMessage/tool-invocation.cjs +6 -3
  34. package/dist/primitives/AiMessage/tool-invocation.cjs.map +1 -1
  35. package/dist/primitives/AiMessage/tool-invocation.js +6 -3
  36. package/dist/primitives/AiMessage/tool-invocation.js.map +1 -1
  37. package/dist/primitives/Composer/index.cjs +5 -2
  38. package/dist/primitives/Composer/index.cjs.map +1 -1
  39. package/dist/primitives/Composer/index.js +5 -2
  40. package/dist/primitives/Composer/index.js.map +1 -1
  41. package/dist/primitives/Composer/utils.cjs +1 -2
  42. package/dist/primitives/Composer/utils.cjs.map +1 -1
  43. package/dist/primitives/Composer/utils.js +1 -2
  44. package/dist/primitives/Composer/utils.js.map +1 -1
  45. package/dist/primitives/Markdown.cjs +267 -336
  46. package/dist/primitives/Markdown.cjs.map +1 -1
  47. package/dist/primitives/Markdown.js +269 -338
  48. package/dist/primitives/Markdown.js.map +1 -1
  49. package/dist/primitives/index.d.cts +4 -0
  50. package/dist/primitives/index.d.ts +4 -0
  51. package/dist/utils/use-observable.cjs +2 -2
  52. package/dist/utils/use-observable.cjs.map +1 -1
  53. package/dist/utils/use-observable.js +1 -1
  54. package/dist/utils/use-observable.js.map +1 -1
  55. package/dist/utils/use-visible.cjs +8 -6
  56. package/dist/utils/use-visible.cjs.map +1 -1
  57. package/dist/utils/use-visible.js +7 -5
  58. package/dist/utils/use-visible.js.map +1 -1
  59. package/dist/version.cjs +1 -1
  60. package/dist/version.js +1 -1
  61. package/package.json +4 -4
  62. package/src/styles/constants.css +2 -2
  63. package/src/styles/index.css +14 -1
  64. package/styles/dark/attributes.css +1 -1
  65. package/styles/dark/media-query.css +1 -1
  66. package/styles.css +1 -1
  67. package/styles.css.map +1 -1
  68. package/dist/utils/use-latest.cjs +0 -14
  69. package/dist/utils/use-latest.cjs.map +0 -1
  70. package/dist/utils/use-latest.js +0 -12
  71. package/dist/utils/use-latest.js.map +0 -1
@@ -2,6 +2,7 @@
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');
5
6
  var react = require('react');
6
7
  var ArrowDown = require('../icons/ArrowDown.cjs');
7
8
  var Spinner = require('../icons/Spinner.cjs');
@@ -12,7 +13,7 @@ var AiChatAssistantMessage = require('./internal/AiChatAssistantMessage.cjs');
12
13
  var AiChatComposer = require('./internal/AiChatComposer.cjs');
13
14
  var AiChatUserMessage = require('./internal/AiChatUserMessage.cjs');
14
15
 
15
- const MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR = 50;
16
+ const MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR = 60;
16
17
  const defaultComponents = {
17
18
  Empty: () => null,
18
19
  Loading: () => /* @__PURE__ */ jsxRuntime.jsx("div", {
@@ -20,6 +21,156 @@ const defaultComponents = {
20
21
  children: /* @__PURE__ */ jsxRuntime.jsx(Spinner.SpinnerIcon, {})
21
22
  })
22
23
  };
24
+ const AiChatMessages = react.forwardRef(
25
+ ({
26
+ messages,
27
+ copilotId,
28
+ overrides,
29
+ components,
30
+ lastSentMessageId,
31
+ scrollToBottom,
32
+ onScrollAtBottomChange,
33
+ containerRef,
34
+ footerRef,
35
+ messagesRef,
36
+ bottomTrailingMarkerRef,
37
+ trailingSpacerRef,
38
+ className,
39
+ ...props
40
+ }, forwardedRef) => {
41
+ const hasLastSentMessage = lastSentMessageId !== null;
42
+ react.useEffect(
43
+ () => {
44
+ if (!hasLastSentMessage) {
45
+ return;
46
+ }
47
+ const container = containerRef.current;
48
+ const footer = footerRef.current;
49
+ const messages2 = messagesRef.current;
50
+ if (!container || !footer || !messages2) {
51
+ return;
52
+ }
53
+ const trailingSpacer = trailingSpacerRef.current;
54
+ const bottomTrailingMarker = bottomTrailingMarkerRef.current;
55
+ let containerHeight = null;
56
+ let footerHeight = null;
57
+ let messagesHeight = null;
58
+ const resetTrailingSpace = () => {
59
+ trailingSpacer?.style.removeProperty("height");
60
+ bottomTrailingMarker?.style.removeProperty("top");
61
+ };
62
+ const resizeObserver = new ResizeObserver((entries) => {
63
+ if (!trailingSpacer || !bottomTrailingMarker) {
64
+ return;
65
+ }
66
+ const lastMessage = messages2.lastElementChild;
67
+ const penultimateMessage = lastMessage?.previousElementSibling;
68
+ if (!lastMessage || !penultimateMessage) {
69
+ resetTrailingSpace();
70
+ return;
71
+ }
72
+ if (container.scrollHeight === container.clientHeight) {
73
+ resetTrailingSpace();
74
+ return;
75
+ }
76
+ let updatedContainerHeight = containerHeight;
77
+ let updatedFooterHeight = footerHeight;
78
+ let updatedMessagesHeight = messagesHeight;
79
+ for (const entry of entries) {
80
+ const entryHeight = entry.borderBoxSize?.[0]?.blockSize ?? entry.contentRect.height;
81
+ if (entry.target === container) {
82
+ updatedContainerHeight = entryHeight ?? null;
83
+ } else if (entry.target === footer) {
84
+ updatedFooterHeight = entryHeight ?? null;
85
+ } else if (entry.target === messages2) {
86
+ updatedMessagesHeight = entryHeight ?? null;
87
+ }
88
+ }
89
+ if (updatedContainerHeight === null || updatedFooterHeight === null || updatedMessagesHeight === null) {
90
+ resetTrailingSpace();
91
+ return;
92
+ }
93
+ if (updatedContainerHeight === containerHeight && updatedFooterHeight === footerHeight && updatedMessagesHeight === messagesHeight) {
94
+ return;
95
+ }
96
+ containerHeight = updatedContainerHeight;
97
+ footerHeight = updatedFooterHeight;
98
+ messagesHeight = updatedMessagesHeight;
99
+ const penultimateMessageScrollMarginTop = Number.parseFloat(
100
+ getComputedStyle(penultimateMessage).scrollMarginTop
101
+ );
102
+ const messagesRect = messages2.getBoundingClientRect();
103
+ const penultimateMessageRect = penultimateMessage.getBoundingClientRect();
104
+ const heightFromPenultimateMessageTopToMessagesListBottom = messagesRect.bottom - penultimateMessageRect.top;
105
+ const differenceHeight = penultimateMessageScrollMarginTop + heightFromPenultimateMessageTopToMessagesListBottom + (footerHeight ?? 0);
106
+ const trailingSpace = Math.max(containerHeight - differenceHeight, 0);
107
+ trailingSpacer.style.height = `${trailingSpace}px`;
108
+ bottomTrailingMarker.style.top = `${-trailingSpace}px`;
109
+ });
110
+ resizeObserver.observe(container);
111
+ resizeObserver.observe(footer);
112
+ resizeObserver.observe(messages2);
113
+ return () => {
114
+ resizeObserver.disconnect();
115
+ resetTrailingSpace();
116
+ };
117
+ },
118
+ [hasLastSentMessage]
119
+ );
120
+ useVisible.useIntersectionCallback(
121
+ bottomTrailingMarkerRef,
122
+ (isIntersecting) => {
123
+ onScrollAtBottomChange.current(isIntersecting);
124
+ },
125
+ { root: containerRef, rootMargin: MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR }
126
+ );
127
+ react.useEffect(
128
+ () => {
129
+ scrollToBottom.current("instant");
130
+ },
131
+ []
132
+ );
133
+ react.useEffect(
134
+ () => {
135
+ if (lastSentMessageId) {
136
+ scrollToBottom.current("smooth", true);
137
+ }
138
+ },
139
+ [lastSentMessageId]
140
+ );
141
+ react.useEffect(
142
+ () => {
143
+ const onScrollAtBottomChangeCallback = onScrollAtBottomChange.current;
144
+ return () => {
145
+ onScrollAtBottomChangeCallback(null);
146
+ };
147
+ },
148
+ []
149
+ );
150
+ return /* @__PURE__ */ jsxRuntime.jsx("div", {
151
+ className: cn.cn("lb-ai-chat-messages", className),
152
+ ref: forwardedRef,
153
+ ...props,
154
+ children: messages.map((message) => {
155
+ if (message.role === "user") {
156
+ return /* @__PURE__ */ jsxRuntime.jsx(AiChatUserMessage.AiChatUserMessage, {
157
+ message,
158
+ overrides
159
+ }, message.id);
160
+ } else if (message.role === "assistant") {
161
+ return /* @__PURE__ */ jsxRuntime.jsx(AiChatAssistantMessage.AiChatAssistantMessage, {
162
+ message,
163
+ overrides,
164
+ components,
165
+ copilotId
166
+ }, message.id);
167
+ } else {
168
+ return null;
169
+ }
170
+ })
171
+ });
172
+ }
173
+ );
23
174
  const AiChat = react.forwardRef(
24
175
  ({
25
176
  chatId,
@@ -34,38 +185,43 @@ const AiChat = react.forwardRef(
34
185
  ...props
35
186
  }, forwardedRef) => {
36
187
  const { messages, isLoading, error } = react$1.useAiChatMessages(chatId);
188
+ const [lastSentMessageId, setLastSentMessageId] = react.useState(null);
37
189
  const $ = overrides.useOverrides(overrides$1);
38
190
  const Empty = components?.Empty ?? defaultComponents.Empty;
39
191
  const Loading = components?.Loading ?? defaultComponents.Loading;
40
192
  const containerRef = react.useRef(null);
41
- const containerBottomRef = react.useRef(null);
42
- const isScrollIndicatorEnabled = !isLoading && !error;
43
- const isScrollAtBottom = useVisible.useVisible(containerBottomRef, {
44
- enabled: isScrollIndicatorEnabled,
45
- root: containerRef,
46
- rootMargin: MIN_DISTANCE_BOTTOM_SCROLL_INDICATOR,
47
- initialValue: null
48
- });
49
- const isScrollIndicatorVisible = isScrollIndicatorEnabled && isScrollAtBottom !== null ? !isScrollAtBottom : false;
50
- const [lastSentMessageId, setLastSentMessageId] = react.useState(null);
193
+ const messagesRef = react.useRef(null);
194
+ const footerRef = react.useRef(null);
195
+ const bottomMarkerRef = react.useRef(null);
196
+ const bottomTrailingMarkerRef = react.useRef(null);
197
+ const trailingSpacerRef = react.useRef(null);
198
+ const [isScrollAtBottom, setScrollAtBottom] = react.useState(
199
+ null
200
+ );
201
+ const onScrollAtBottomChange = _private.useLatest(setScrollAtBottom);
202
+ const isScrollIndicatorVisible = messages && isScrollAtBottom !== null ? !isScrollAtBottom : false;
51
203
  react.useImperativeHandle(
52
204
  forwardedRef,
53
205
  () => containerRef.current,
54
206
  []
55
207
  );
56
- const scrollToBottomCallbackRef = react.useRef(void 0);
57
- if (scrollToBottomCallbackRef.current === void 0) {
58
- scrollToBottomCallbackRef.current = function(behavior) {
59
- const container = containerRef.current;
60
- if (container === null)
61
- return;
62
- container.scrollTo({
63
- top: container.scrollHeight,
64
- behavior
65
- });
66
- };
67
- }
68
- const scrollToBottom = scrollToBottomCallbackRef.current;
208
+ const scrollToBottom = _private.useLatest(
209
+ (behavior, includeTrailingSpace = false) => {
210
+ if (includeTrailingSpace) {
211
+ requestAnimationFrame(() => {
212
+ bottomMarkerRef.current?.scrollIntoView({
213
+ behavior,
214
+ block: "end"
215
+ });
216
+ });
217
+ } else {
218
+ bottomTrailingMarkerRef.current?.scrollIntoView({
219
+ behavior,
220
+ block: "end"
221
+ });
222
+ }
223
+ }
224
+ );
69
225
  return /* @__PURE__ */ jsxRuntime.jsxs("div", {
70
226
  ref: containerRef,
71
227
  ...props,
@@ -94,34 +250,35 @@ const AiChat = react.forwardRef(
94
250
  copilotId
95
251
  }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, {
96
252
  children: [
97
- /* @__PURE__ */ jsxRuntime.jsx(AutoScrollHandler, {
253
+ /* @__PURE__ */ jsxRuntime.jsx(AiChatMessages, {
254
+ ref: messagesRef,
255
+ copilotId,
256
+ messages,
257
+ overrides: overrides$1,
258
+ components,
98
259
  lastSentMessageId,
99
- scrollToBottom
260
+ scrollToBottom,
261
+ onScrollAtBottomChange,
262
+ containerRef,
263
+ footerRef,
264
+ messagesRef,
265
+ bottomTrailingMarkerRef,
266
+ trailingSpacerRef
100
267
  }),
101
268
  /* @__PURE__ */ jsxRuntime.jsx("div", {
102
- className: "lb-ai-chat-messages",
103
- children: messages.map((message) => {
104
- if (message.role === "user") {
105
- return /* @__PURE__ */ jsxRuntime.jsx(AiChatUserMessage.AiChatUserMessage, {
106
- message,
107
- overrides: overrides$1
108
- }, message.id);
109
- } else if (message.role === "assistant") {
110
- return /* @__PURE__ */ jsxRuntime.jsx(AiChatAssistantMessage.AiChatAssistantMessage, {
111
- message,
112
- overrides: overrides$1,
113
- components
114
- }, message.id);
115
- } else {
116
- return null;
117
- }
118
- })
269
+ ref: trailingSpacerRef,
270
+ "data-trailing-spacer": "",
271
+ style: {
272
+ pointerEvents: "none"
273
+ },
274
+ "aria-hidden": true
119
275
  })
120
276
  ]
121
277
  })
122
278
  }),
123
279
  /* @__PURE__ */ jsxRuntime.jsxs("div", {
124
280
  className: "lb-ai-chat-footer",
281
+ ref: footerRef,
125
282
  children: [
126
283
  /* @__PURE__ */ jsxRuntime.jsx("div", {
127
284
  className: "lb-ai-chat-footer-actions",
@@ -132,7 +289,7 @@ const AiChat = react.forwardRef(
132
289
  className: "lb-ai-chat-scroll-indicator-button",
133
290
  tabIndex: isScrollIndicatorVisible ? 0 : -1,
134
291
  "aria-hidden": !isScrollIndicatorVisible,
135
- onClick: () => scrollToBottom("smooth"),
292
+ onClick: () => scrollToBottom.current("smooth"),
136
293
  children: /* @__PURE__ */ jsxRuntime.jsx("span", {
137
294
  className: "lb-icon-container",
138
295
  children: /* @__PURE__ */ jsxRuntime.jsx(ArrowDown.ArrowDownIcon, {})
@@ -150,30 +307,24 @@ const AiChat = react.forwardRef(
150
307
  }, chatId)
151
308
  ]
152
309
  }),
153
- /* @__PURE__ */ jsxRuntime.jsx("div", {
154
- ref: containerBottomRef,
310
+ messages && messages.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", {
311
+ ref: bottomMarkerRef,
155
312
  style: { position: "sticky", height: 0 },
156
313
  "aria-hidden": true,
157
- "data-scroll-at-bottom": isScrollAtBottom ? "" : void 0
158
- })
314
+ "data-bottom-marker": "",
315
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", {
316
+ ref: bottomTrailingMarkerRef,
317
+ style: {
318
+ position: "absolute",
319
+ height: 0
320
+ },
321
+ "data-bottom-trailing-marker": ""
322
+ })
323
+ }) : null
159
324
  ]
160
325
  });
161
326
  }
162
327
  );
163
- function AutoScrollHandler({
164
- lastSentMessageId,
165
- scrollToBottom
166
- }) {
167
- react.useEffect(() => {
168
- scrollToBottom("instant");
169
- }, [scrollToBottom]);
170
- react.useEffect(() => {
171
- if (lastSentMessageId === null)
172
- return;
173
- scrollToBottom("smooth");
174
- }, [lastSentMessageId, scrollToBottom]);
175
- return null;
176
- }
177
328
 
178
329
  exports.AiChat = AiChat;
179
330
  //# sourceMappingURL=AiChat.cjs.map
@@ -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 {\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
+ {"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 { 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 AiChatComposerOverrides,\n type AiChatMessageOverrides,\n type AiChatOverrides,\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 { AiChatAssistantMessage } from \"./internal/AiChatAssistantMessage\";\nimport { AiChatComposer } from \"./internal/AiChatComposer\";\nimport { AiChatUserMessage } from \"./internal/AiChatUserMessage\";\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 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 /**\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 layout of the chat and its composer.\n */\n layout?: \"inset\" | \"compact\";\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n AiChatMessageOverrides &\n AiChatComposerOverrides &\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 copilotId: AiChatProps[\"copilotId\"];\n overrides: AiChatProps[\"overrides\"];\n components: AiChatProps[\"components\"];\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 copilotId,\n overrides,\n components,\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 | null = null;\n let footerHeight: number | null = null;\n let messagesHeight: number | null = null;\n\n const resetTrailingSpace = () => {\n trailingSpacer?.style.removeProperty(\"height\");\n bottomTrailingMarker?.style.removeProperty(\"top\");\n };\n\n const resizeObserver = new ResizeObserver((entries) => {\n if (!trailingSpacer || !bottomTrailingMarker) {\n return;\n }\n\n const lastMessage = messages.lastElementChild;\n const penultimateMessage = lastMessage?.previousElementSibling;\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's height is based on its content, the container isn't scrollable and there's no need for any trailing space.\n if (container.scrollHeight === container.clientHeight) {\n resetTrailingSpace();\n return;\n }\n\n let updatedContainerHeight: number | null = containerHeight;\n let updatedFooterHeight: number | null = footerHeight;\n let updatedMessagesHeight: number | null = 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 ?? null;\n } else if (entry.target === footer) {\n updatedFooterHeight = entryHeight ?? null;\n } else if (entry.target === messages) {\n updatedMessagesHeight = entryHeight ?? null;\n }\n }\n\n // If we don't have all the heights, we can't compute the trailing space.\n if (\n updatedContainerHeight === null ||\n updatedFooterHeight === null ||\n updatedMessagesHeight === null\n ) {\n resetTrailingSpace();\n return;\n }\n\n // If none of the heights have changed, we don't need to do anything.\n if (\n updatedContainerHeight === containerHeight &&\n updatedFooterHeight === footerHeight &&\n updatedMessagesHeight === messagesHeight\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 // 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 resizeObserver.observe(container);\n resizeObserver.observe(footer);\n resizeObserver.observe(messages);\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 />\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 copilotId={copilotId}\n />\n );\n } else {\n return null;\n }\n })}\n </div>\n );\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 [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 // and wait for a frame in case the trailing space hasn't\n // been updated yet. (e.g. when sending a new message)\n requestAnimationFrame(() => {\n bottomMarkerRef.current?.scrollIntoView({\n behavior,\n block: \"end\",\n });\n });\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 bottomTrailingMarkerRef.current?.scrollIntoView({\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 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 <AiChatMessages\n ref={messagesRef}\n copilotId={copilotId}\n messages={messages}\n overrides={overrides}\n components={components}\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 />\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 }}\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 <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\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":["jsx","SpinnerIcon","forwardRef","useEffect","messages","useIntersectionCallback","cn","AiChatUserMessage","AiChatAssistantMessage","overrides","useAiChatMessages","useState","useOverrides","useRef","useLatest","useImperativeHandle","jsxs","RegisterAiKnowledge","RegisterAiTool","Fragment","ArrowDownIcon","AiChatComposer"],"mappings":";;;;;;;;;;;;;;;AA4CA,MAAM,oCAAuC,GAAA,EAAA,CAAA;AAoG7C,MAAM,iBAAsC,GAAA;AAAA,EAC1C,OAAO,MAAM,IAAA;AAAA,EACb,OAAA,EAAS,sBACNA,cAAA,CAAA,KAAA,EAAA;AAAA,IAAI,SAAU,EAAA,+BAAA;AAAA,IACb,yCAACC,mBAAY,EAAA,EAAA,CAAA;AAAA,GACf,CAAA;AAEJ,CAAA,CAAA;AAEA,MAAM,cAAiB,GAAAC,gBAAA;AAAA,EACrB,CACE;AAAA,IACE,QAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA,UAAA;AAAA,IACA,iBAAA;AAAA,IACA,cAAA;AAAA,IACA,sBAAA;AAAA,IACA,YAAA;AAAA,IACA,SAAA;AAAA,IACA,WAAA;AAAA,IACA,uBAAA;AAAA,IACA,iBAAA;AAAA,IACA,SAAA;AAAA,IACG,GAAA,KAAA;AAAA,KAEL,YACG,KAAA;AACH,IAAA,MAAM,qBAAqB,iBAAsB,KAAA,IAAA,CAAA;AA2BjD,IAAAC,eAAA;AAAA,MACE,MAAM;AACJ,QAAA,IAAI,CAAC,kBAAoB,EAAA;AACvB,UAAA,OAAA;AAAA,SACF;AAEA,QAAA,MAAM,YAAY,YAAa,CAAA,OAAA,CAAA;AAC/B,QAAA,MAAM,SAAS,SAAU,CAAA,OAAA,CAAA;AACzB,QAAA,MAAMC,YAAW,WAAY,CAAA,OAAA,CAAA;AAE7B,QAAA,IAAI,CAAC,SAAA,IAAa,CAAC,MAAA,IAAU,CAACA,SAAU,EAAA;AACtC,UAAA,OAAA;AAAA,SACF;AAEA,QAAA,MAAM,iBAAiB,iBAAkB,CAAA,OAAA,CAAA;AACzC,QAAA,MAAM,uBAAuB,uBAAwB,CAAA,OAAA,CAAA;AAErD,QAAA,IAAI,eAAiC,GAAA,IAAA,CAAA;AACrC,QAAA,IAAI,YAA8B,GAAA,IAAA,CAAA;AAClC,QAAA,IAAI,cAAgC,GAAA,IAAA,CAAA;AAEpC,QAAA,MAAM,qBAAqB,MAAM;AAC/B,UAAgB,cAAA,EAAA,KAAA,CAAM,eAAe,QAAQ,CAAA,CAAA;AAC7C,UAAsB,oBAAA,EAAA,KAAA,CAAM,eAAe,KAAK,CAAA,CAAA;AAAA,SAClD,CAAA;AAEA,QAAA,MAAM,cAAiB,GAAA,IAAI,cAAe,CAAA,CAAC,OAAY,KAAA;AACrD,UAAI,IAAA,CAAC,cAAkB,IAAA,CAAC,oBAAsB,EAAA;AAC5C,YAAA,OAAA;AAAA,WACF;AAEA,UAAA,MAAM,cAAcA,SAAS,CAAA,gBAAA,CAAA;AAC7B,UAAA,MAAM,qBAAqB,WAAa,EAAA,sBAAA,CAAA;AAGxC,UAAI,IAAA,CAAC,WAAe,IAAA,CAAC,kBAAoB,EAAA;AACvC,YAAmB,kBAAA,EAAA,CAAA;AACnB,YAAA,OAAA;AAAA,WACF;AAGA,UAAI,IAAA,SAAA,CAAU,YAAiB,KAAA,SAAA,CAAU,YAAc,EAAA;AACrD,YAAmB,kBAAA,EAAA,CAAA;AACnB,YAAA,OAAA;AAAA,WACF;AAEA,UAAA,IAAI,sBAAwC,GAAA,eAAA,CAAA;AAC5C,UAAA,IAAI,mBAAqC,GAAA,YAAA,CAAA;AACzC,UAAA,IAAI,qBAAuC,GAAA,cAAA,CAAA;AAE3C,UAAA,KAAA,MAAW,SAAS,OAAS,EAAA;AAC3B,YAAA,MAAM,cACJ,KAAM,CAAA,aAAA,GAAgB,CAAI,CAAA,EAAA,SAAA,IAAa,MAAM,WAAY,CAAA,MAAA,CAAA;AAE3D,YAAI,IAAA,KAAA,CAAM,WAAW,SAAW,EAAA;AAC9B,cAAA,sBAAA,GAAyB,WAAe,IAAA,IAAA,CAAA;AAAA,aAC1C,MAAA,IAAW,KAAM,CAAA,MAAA,KAAW,MAAQ,EAAA;AAClC,cAAA,mBAAA,GAAsB,WAAe,IAAA,IAAA,CAAA;AAAA,aACvC,MAAA,IAAW,KAAM,CAAA,MAAA,KAAWA,SAAU,EAAA;AACpC,cAAA,qBAAA,GAAwB,WAAe,IAAA,IAAA,CAAA;AAAA,aACzC;AAAA,WACF;AAGA,UAAA,IACE,sBAA2B,KAAA,IAAA,IAC3B,mBAAwB,KAAA,IAAA,IACxB,0BAA0B,IAC1B,EAAA;AACA,YAAmB,kBAAA,EAAA,CAAA;AACnB,YAAA,OAAA;AAAA,WACF;AAGA,UAAA,IACE,sBAA2B,KAAA,eAAA,IAC3B,mBAAwB,KAAA,YAAA,IACxB,0BAA0B,cAC1B,EAAA;AACA,YAAA,OAAA;AAAA,WACF;AAGA,UAAkB,eAAA,GAAA,sBAAA,CAAA;AAClB,UAAe,YAAA,GAAA,mBAAA,CAAA;AACf,UAAiB,cAAA,GAAA,qBAAA,CAAA;AAGjB,UAAA,MAAM,oCAAoC,MAAO,CAAA,UAAA;AAAA,YAC/C,gBAAA,CAAiB,kBAAiC,CAAE,CAAA,eAAA;AAAA,WACtD,CAAA;AAGA,UAAM,MAAA,YAAA,GAAeA,UAAS,qBAAsB,EAAA,CAAA;AACpD,UAAM,MAAA,sBAAA,GACJ,mBAAmB,qBAAsB,EAAA,CAAA;AAC3C,UAAM,MAAA,mDAAA,GACJ,YAAa,CAAA,MAAA,GAAS,sBAAuB,CAAA,GAAA,CAAA;AAG/C,UAAM,MAAA,gBAAA,GACJ,iCACA,GAAA,mDAAA,IACC,YAAgB,IAAA,CAAA,CAAA,CAAA;AAGnB,UAAA,MAAM,aAAgB,GAAA,IAAA,CAAK,GAAI,CAAA,eAAA,GAAkB,kBAAkB,CAAC,CAAA,CAAA;AAGpE,UAAe,cAAA,CAAA,KAAA,CAAM,SAAS,CAAG,EAAA,aAAA,CAAA,EAAA,CAAA,CAAA;AAIjC,UAAqB,oBAAA,CAAA,KAAA,CAAM,GAAM,GAAA,CAAA,EAAG,CAAC,aAAA,CAAA,EAAA,CAAA,CAAA;AAAA,SACtC,CAAA,CAAA;AAED,QAAA,cAAA,CAAe,QAAQ,SAAS,CAAA,CAAA;AAChC,QAAA,cAAA,CAAe,QAAQ,MAAM,CAAA,CAAA;AAC7B,QAAA,cAAA,CAAe,QAAQA,SAAQ,CAAA,CAAA;AAE/B,QAAA,OAAO,MAAM;AACX,UAAA,cAAA,CAAe,UAAW,EAAA,CAAA;AAC1B,UAAmB,kBAAA,EAAA,CAAA;AAAA,SACrB,CAAA;AAAA,OACF;AAAA,MAEA,CAAC,kBAAkB,CAAA;AAAA,KACrB,CAAA;AAKA,IAAAC,kCAAA;AAAA,MACE,uBAAA;AAAA,MACA,CAAC,cAAmB,KAAA;AAClB,QAAA,sBAAA,CAAuB,QAAQ,cAAc,CAAA,CAAA;AAAA,OAC/C;AAAA,MACA,EAAE,IAAA,EAAM,YAAc,EAAA,UAAA,EAAY,oCAAqC,EAAA;AAAA,KACzE,CAAA;AAKA,IAAAF,eAAA;AAAA,MACE,MAAM;AACJ,QAAA,cAAA,CAAe,QAAQ,SAAS,CAAA,CAAA;AAAA,OAClC;AAAA,MAEA,EAAC;AAAA,KACH,CAAA;AAKA,IAAAA,eAAA;AAAA,MACE,MAAM;AACJ,QAAA,IAAI,iBAAmB,EAAA;AACrB,UAAe,cAAA,CAAA,OAAA,CAAQ,UAAU,IAAI,CAAA,CAAA;AAAA,SACvC;AAAA,OACF;AAAA,MAEA,CAAC,iBAAiB,CAAA;AAAA,KACpB,CAAA;AAKA,IAAAA,eAAA;AAAA,MACE,MAAM;AACJ,QAAA,MAAM,iCAAiC,sBAAuB,CAAA,OAAA,CAAA;AAE9D,QAAA,OAAO,MAAM;AACX,UAAA,8BAAA,CAA+B,IAAI,CAAA,CAAA;AAAA,SACrC,CAAA;AAAA,OACF;AAAA,MAEA,EAAC;AAAA,KACH,CAAA;AAEA,IAAA,uBACGH,cAAA,CAAA,KAAA,EAAA;AAAA,MACC,SAAA,EAAWM,KAAG,CAAA,qBAAA,EAAuB,SAAS,CAAA;AAAA,MAC9C,GAAK,EAAA,YAAA;AAAA,MACJ,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA,QAAA,CAAS,GAAI,CAAA,CAAC,OAAY,KAAA;AACzB,QAAI,IAAA,OAAA,CAAQ,SAAS,MAAQ,EAAA;AAC3B,UAAA,uBACGN,cAAA,CAAAO,mCAAA,EAAA;AAAA,YAEC,OAAA;AAAA,YACA,SAAA;AAAA,WAAA,EAFK,QAAQ,EAGf,CAAA,CAAA;AAAA,SAEJ,MAAA,IAAW,OAAQ,CAAA,IAAA,KAAS,WAAa,EAAA;AACvC,UAAA,uBACGP,cAAA,CAAAQ,6CAAA,EAAA;AAAA,YAEC,OAAA;AAAA,YACA,SAAA;AAAA,YACA,UAAA;AAAA,YACA,SAAA;AAAA,WAAA,EAJK,QAAQ,EAKf,CAAA,CAAA;AAAA,SAEG,MAAA;AACL,UAAO,OAAA,IAAA,CAAA;AAAA,SACT;AAAA,OACD,CAAA;AAAA,KACH,CAAA,CAAA;AAAA,GAEJ;AACF,CAAA,CAAA;AAEO,MAAM,MAAS,GAAAN,gBAAA;AAAA,EACpB,CACE;AAAA,IACE,MAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,eACAO,WAAA;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,GAAIC,0BAAkB,MAAM,CAAA,CAAA;AAC/D,IAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAC5CC,eAA2B,IAAI,CAAA,CAAA;AAEjC,IAAM,MAAA,CAAA,GAAIC,uBAAaH,WAAS,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,GAAeI,aAA8B,IAAI,CAAA,CAAA;AACvD,IAAM,MAAA,WAAA,GAAcA,aAA8B,IAAI,CAAA,CAAA;AACtD,IAAM,MAAA,SAAA,GAAYA,aAA8B,IAAI,CAAA,CAAA;AACpD,IAAM,MAAA,eAAA,GAAkBA,aAA8B,IAAI,CAAA,CAAA;AAC1D,IAAM,MAAA,uBAAA,GAA0BA,aAA8B,IAAI,CAAA,CAAA;AAClE,IAAM,MAAA,iBAAA,GAAoBA,aAA8B,IAAI,CAAA,CAAA;AAE5D,IAAM,MAAA,CAAC,gBAAkB,EAAA,iBAAiB,CAAI,GAAAF,cAAA;AAAA,MAC5C,IAAA;AAAA,KACF,CAAA;AAEA,IAAM,MAAA,sBAAA,GAAyBG,mBAAU,iBAAiB,CAAA,CAAA;AAC1D,IAAA,MAAM,wBACJ,GAAA,QAAA,IAAY,gBAAqB,KAAA,IAAA,GAAO,CAAC,gBAAmB,GAAA,KAAA,CAAA;AAE9D,IAAAC,yBAAA;AAAA,MACE,YAAA;AAAA,MACA,MAAM,YAAa,CAAA,OAAA;AAAA,MACnB,EAAC;AAAA,KACH,CAAA;AAEA,IAAA,MAAM,cAAiB,GAAAD,kBAAA;AAAA,MACrB,CAAC,QAAgC,EAAA,oBAAA,GAAuB,KAAU,KAAA;AAChE,QAAA,IAAI,oBAAsB,EAAA;AAIxB,UAAA,qBAAA,CAAsB,MAAM;AAC1B,YAAA,eAAA,CAAgB,SAAS,cAAe,CAAA;AAAA,cACtC,QAAA;AAAA,cACA,KAAO,EAAA,KAAA;AAAA,aACR,CAAA,CAAA;AAAA,WACF,CAAA,CAAA;AAAA,SACI,MAAA;AAGL,UAAA,uBAAA,CAAwB,SAAS,cAAe,CAAA;AAAA,YAC9C,QAAA;AAAA,YACA,KAAO,EAAA,KAAA;AAAA,WACR,CAAA,CAAA;AAAA,SACH;AAAA,OACF;AAAA,KACF,CAAA;AAEA,IAAA,uBACGE,eAAA,CAAA,KAAA,EAAA;AAAA,MACC,GAAK,EAAA,YAAA;AAAA,MACJ,GAAG,KAAA;AAAA,MACJ,SAAW,EAAAV,KAAA;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,0BACpBN,cAAA,CAAAiB,2BAAA,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,qBACpCjB,cAAA,CAAAkB,sBAAA,EAAA;AAAA,UAA0B,MAAA;AAAA,UAAgB,IAAA;AAAA,UAAY,IAAA;AAAA,SAAA,EAAlC,IAA8C,CACpE,CAAA;AAAA,wBAEAlB,cAAA,CAAA,KAAA,EAAA;AAAA,UAAI,SAAU,EAAA,oBAAA;AAAA,UACZ,sCACEA,cAAA,CAAA,OAAA,EAAA,EAAQ,CACP,GAAA,KAAA,KAAU,yBACXA,cAAA,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,mBACrBA,cAAA,CAAA,KAAA,EAAA;AAAA,YAAM,MAAA;AAAA,YAAgB,SAAA;AAAA,WAAsB,CAE7C,mBAAAgB,eAAA,CAAAG,mBAAA,EAAA;AAAA,YACE,QAAA,EAAA;AAAA,8BAACnB,cAAA,CAAA,cAAA,EAAA;AAAA,gBACC,GAAK,EAAA,WAAA;AAAA,gBACL,SAAA;AAAA,gBACA,QAAA;AAAA,2BACAS,WAAA;AAAA,gBACA,UAAA;AAAA,gBACA,iBAAA;AAAA,gBACA,cAAA;AAAA,gBACA,sBAAA;AAAA,gBACA,YAAA;AAAA,gBACA,SAAA;AAAA,gBACA,WAAA;AAAA,gBACA,uBAAA;AAAA,gBACA,iBAAA;AAAA,eACF,CAAA;AAAA,8BAMCT,cAAA,CAAA,KAAA,EAAA;AAAA,gBACC,GAAK,EAAA,iBAAA;AAAA,gBACL,sBAAqB,EAAA,EAAA;AAAA,gBACrB,KAAO,EAAA;AAAA,kBACL,aAAe,EAAA,MAAA;AAAA,iBACjB;AAAA,gBACA,aAAW,EAAA,IAAA;AAAA,eACb,CAAA;AAAA,aAAA;AAAA,WACF,CAAA;AAAA,SAEJ,CAAA;AAAA,wBAECgB,eAAA,CAAA,KAAA,EAAA;AAAA,UAAI,SAAU,EAAA,mBAAA;AAAA,UAAoB,GAAK,EAAA,SAAA;AAAA,UACtC,QAAA,EAAA;AAAA,4BAAChB,cAAA,CAAA,KAAA,EAAA;AAAA,cAAI,SAAU,EAAA,2BAAA;AAAA,cACb,QAAC,kBAAAA,cAAA,CAAA,KAAA,EAAA;AAAA,gBACC,SAAU,EAAA,wEAAA;AAAA,gBACV,cAAA,EAAc,2BAA2B,EAAK,GAAA,KAAA,CAAA;AAAA,gBAE9C,QAAC,kBAAAA,cAAA,CAAA,QAAA,EAAA;AAAA,kBACC,SAAU,EAAA,oCAAA;AAAA,kBACV,QAAA,EAAU,2BAA2B,CAAI,GAAA,CAAA,CAAA;AAAA,kBACzC,eAAa,CAAC,wBAAA;AAAA,kBACd,OAAS,EAAA,MAAM,cAAe,CAAA,OAAA,CAAQ,QAAQ,CAAA;AAAA,kBAE9C,QAAC,kBAAAA,cAAA,CAAA,MAAA,EAAA;AAAA,oBAAK,SAAU,EAAA,mBAAA;AAAA,oBACd,yCAACoB,uBAAc,EAAA,EAAA,CAAA;AAAA,mBACjB,CAAA;AAAA,iBACF,CAAA;AAAA,eACF,CAAA;AAAA,aACF,CAAA;AAAA,4BACCpB,cAAA,CAAAqB,6BAAA,EAAA;AAAA,cAEC,MAAA;AAAA,cACA,SAAA;AAAA,yBACAZ,WAAA;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,QAUC,QAAY,IAAA,QAAA,CAAS,MAAS,GAAA,CAAA,mBAC5BT,cAAA,CAAA,KAAA,EAAA;AAAA,UACC,GAAK,EAAA,eAAA;AAAA,UACL,KAAO,EAAA,EAAE,QAAU,EAAA,QAAA,EAAU,QAAQ,CAAE,EAAA;AAAA,UACvC,aAAW,EAAA,IAAA;AAAA,UACX,oBAAmB,EAAA,EAAA;AAAA,UAMnB,QAAC,kBAAAA,cAAA,CAAA,KAAA,EAAA;AAAA,YACC,GAAK,EAAA,uBAAA;AAAA,YACL,KAAO,EAAA;AAAA,cACL,QAAU,EAAA,UAAA;AAAA,cACV,MAAQ,EAAA,CAAA;AAAA,aACV;AAAA,YACA,6BAA4B,EAAA,EAAA;AAAA,WAC9B,CAAA;AAAA,SACF,CACE,GAAA,IAAA;AAAA,OAAA;AAAA,KACN,CAAA,CAAA;AAAA,GAEJ;AACF;;;;"}