@liveblocks/react-ui 3.2.1 → 3.3.1

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 (56) hide show
  1. package/dist/_private/index.cjs +4 -2
  2. package/dist/_private/index.cjs.map +1 -1
  3. package/dist/_private/index.d.cts +100 -33
  4. package/dist/_private/index.d.ts +100 -33
  5. package/dist/_private/index.js +3 -2
  6. package/dist/_private/index.js.map +1 -1
  7. package/dist/components/AiChat.cjs +11 -9
  8. package/dist/components/AiChat.cjs.map +1 -1
  9. package/dist/components/AiChat.js +12 -10
  10. package/dist/components/AiChat.js.map +1 -1
  11. package/dist/components/Composer.cjs +1 -1
  12. package/dist/components/Composer.cjs.map +1 -1
  13. package/dist/components/Composer.js +1 -1
  14. package/dist/components/Composer.js.map +1 -1
  15. package/dist/components/Thread.cjs +58 -0
  16. package/dist/components/Thread.cjs.map +1 -1
  17. package/dist/components/Thread.js +59 -1
  18. package/dist/components/Thread.js.map +1 -1
  19. package/dist/components/internal/AiComposer.cjs +132 -0
  20. package/dist/components/internal/AiComposer.cjs.map +1 -0
  21. package/dist/components/internal/AiComposer.js +130 -0
  22. package/dist/components/internal/AiComposer.js.map +1 -0
  23. package/dist/components/internal/Button.cjs.map +1 -1
  24. package/dist/components/internal/Button.js.map +1 -1
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +113 -11
  27. package/dist/index.d.ts +113 -11
  28. package/dist/index.js.map +1 -1
  29. package/dist/overrides.cjs +4 -3
  30. package/dist/overrides.cjs.map +1 -1
  31. package/dist/overrides.js +4 -3
  32. package/dist/overrides.js.map +1 -1
  33. package/dist/primitives/AiComposer/contexts.cjs +24 -0
  34. package/dist/primitives/AiComposer/contexts.cjs.map +1 -0
  35. package/dist/primitives/AiComposer/contexts.js +19 -0
  36. package/dist/primitives/AiComposer/contexts.js.map +1 -0
  37. package/dist/primitives/AiComposer/index.cjs +348 -0
  38. package/dist/primitives/AiComposer/index.cjs.map +1 -0
  39. package/dist/primitives/AiComposer/index.js +340 -0
  40. package/dist/primitives/AiComposer/index.js.map +1 -0
  41. package/dist/primitives/index.d.cts +8 -1
  42. package/dist/primitives/index.d.ts +8 -1
  43. package/dist/version.cjs +1 -1
  44. package/dist/version.js +1 -1
  45. package/package.json +4 -4
  46. package/src/styles/index.css +36 -10
  47. package/styles.css +1 -1
  48. package/styles.css.map +1 -1
  49. package/dist/components/internal/AiChatComposer.cjs +0 -161
  50. package/dist/components/internal/AiChatComposer.cjs.map +0 -1
  51. package/dist/components/internal/AiChatComposer.js +0 -159
  52. package/dist/components/internal/AiChatComposer.js.map +0 -1
  53. package/dist/primitives/AiChatComposer/index.cjs +0 -202
  54. package/dist/primitives/AiChatComposer/index.cjs.map +0 -1
  55. package/dist/primitives/AiChatComposer/index.js +0 -195
  56. package/dist/primitives/AiChatComposer/index.js.map +0 -1
@@ -0,0 +1,340 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { Signal, kInternal } from '@liveblocks/core';
3
+ import { useClient } from '@liveblocks/react';
4
+ import { useSignal, useLayoutEffect } from '@liveblocks/react/_private';
5
+ import { Slot } from '@radix-ui/react-slot';
6
+ import { forwardRef, useRef, useState, useCallback, useImperativeHandle, useMemo } from 'react';
7
+ import { createEditor, Transforms, Editor } from 'slate';
8
+ import { withHistory } from 'slate-history';
9
+ import { withReact, ReactEditor, Slate, Editable } from 'slate-react';
10
+ import { requestSubmit } from '../../utils/request-submit.js';
11
+ import { useInitial } from '../../utils/use-initial.js';
12
+ import { withNormalize } from '../slate/plugins/normalize.js';
13
+ import { isEmpty } from '../slate/utils/is-empty.js';
14
+ import { AiComposerEditorContext, AiComposerContext, useAiComposerEditorContext, useAiComposer } from './contexts.js';
15
+
16
+ const AI_COMPOSER_SUBMIT_NAME = "AiComposerSubmit";
17
+ const AI_COMPOSER_ABORT_NAME = "AiComposerAbort";
18
+ const AI_COMPOSER_EDITOR_NAME = "AiComposerEditor";
19
+ const AI_COMPOSER_FORM_NAME = "AiComposerForm";
20
+ const emptyMessages\u03A3 = new Signal([]);
21
+ function getLastMessageId(messages) {
22
+ const lastMessage = messages[messages.length - 1];
23
+ if (lastMessage === void 0) {
24
+ return null;
25
+ }
26
+ return lastMessage.id;
27
+ }
28
+ function getAbortableMessageId(messages) {
29
+ return messages.find(
30
+ (message) => message.role === "assistant" && (message.status === "generating" || message.status === "awaiting-tool")
31
+ )?.id;
32
+ }
33
+ const AiComposerForm = forwardRef(
34
+ ({
35
+ onComposerSubmit,
36
+ onSubmit,
37
+ disabled,
38
+ chatId,
39
+ branchId,
40
+ asChild,
41
+ ...props
42
+ }, forwardedRef) => {
43
+ const Component = asChild ? Slot : "form";
44
+ const client = useClient();
45
+ const formRef = useRef(null);
46
+ const editor = useInitial(
47
+ () => withNormalize(withHistory(withReact(createEditor())))
48
+ );
49
+ const [isEditorEmpty, setEditorEmpty] = useState(true);
50
+ const [isSubmitting, setSubmitting] = useState(false);
51
+ const [isFocused, setFocused] = useState(false);
52
+ const messages\u03A3 = chatId ? client[kInternal].ai.signals.getChatMessagesForBranch\u03A3(chatId, branchId) : emptyMessages\u03A3;
53
+ const lastMessageId = useSignal(messages\u03A3, getLastMessageId);
54
+ const abortableMessageId = useSignal(messages\u03A3, getAbortableMessageId);
55
+ const isDisabled = isSubmitting || disabled === true;
56
+ const canAbort = abortableMessageId !== void 0;
57
+ const canSubmit = !isEditorEmpty && !canAbort;
58
+ const clear = useCallback(() => {
59
+ Transforms.delete(editor, {
60
+ at: {
61
+ anchor: Editor.start(editor, []),
62
+ focus: Editor.end(editor, [])
63
+ }
64
+ });
65
+ }, [editor]);
66
+ const select = useCallback(() => {
67
+ Transforms.select(editor, Editor.end(editor, []));
68
+ }, [editor]);
69
+ const focus = useCallback(
70
+ (resetSelection = true) => {
71
+ try {
72
+ if (!ReactEditor.isFocused(editor)) {
73
+ Transforms.select(
74
+ editor,
75
+ resetSelection || !editor.selection ? Editor.end(editor, []) : editor.selection
76
+ );
77
+ ReactEditor.focus(editor);
78
+ }
79
+ } catch {
80
+ }
81
+ },
82
+ [editor]
83
+ );
84
+ const blur = useCallback(() => {
85
+ try {
86
+ ReactEditor.blur(editor);
87
+ } catch {
88
+ }
89
+ }, [editor]);
90
+ const onSubmitEnd = useCallback(() => {
91
+ clear();
92
+ setSubmitting(false);
93
+ }, [clear]);
94
+ const handleSubmit = useCallback(
95
+ (event) => {
96
+ if (disabled) {
97
+ return;
98
+ }
99
+ const isEditorEmpty2 = isEmpty(editor, editor.children);
100
+ if (isEditorEmpty2) {
101
+ event.preventDefault();
102
+ return;
103
+ }
104
+ onSubmit?.(event);
105
+ if (onComposerSubmit === void 0 || event.isDefaultPrevented()) {
106
+ event.preventDefault();
107
+ return;
108
+ }
109
+ const content = editor.children.map((block) => {
110
+ if ("type" in block && block.type === "paragraph") {
111
+ return block.children.map((child) => {
112
+ if ("text" in child) {
113
+ return child.text;
114
+ }
115
+ return "";
116
+ }).join("");
117
+ }
118
+ return "";
119
+ }).join("\n");
120
+ const promise = onComposerSubmit(
121
+ { text: content, lastMessageId },
122
+ event
123
+ );
124
+ event.preventDefault();
125
+ if (promise) {
126
+ setSubmitting(true);
127
+ promise.then(onSubmitEnd);
128
+ } else {
129
+ onSubmitEnd();
130
+ }
131
+ },
132
+ [disabled, editor, onSubmit, onComposerSubmit, onSubmitEnd, lastMessageId]
133
+ );
134
+ useLayoutEffect(() => {
135
+ setEditorEmpty(isEmpty(editor, editor.children));
136
+ }, [editor]);
137
+ const handleEditorValueChange = useCallback(() => {
138
+ setEditorEmpty(isEmpty(editor, editor.children));
139
+ }, [editor]);
140
+ const submit = useCallback(() => {
141
+ if (!canSubmit) {
142
+ return;
143
+ }
144
+ requestAnimationFrame(() => {
145
+ if (formRef.current) {
146
+ requestSubmit(formRef.current);
147
+ }
148
+ });
149
+ }, [canSubmit]);
150
+ const abort = useCallback(() => {
151
+ if (!canAbort || !abortableMessageId) {
152
+ return;
153
+ }
154
+ client[kInternal].ai.abort(abortableMessageId);
155
+ }, [canAbort, abortableMessageId, client]);
156
+ useImperativeHandle(
157
+ forwardedRef,
158
+ () => formRef.current,
159
+ []
160
+ );
161
+ return /* @__PURE__ */ jsx(AiComposerEditorContext.Provider, {
162
+ value: {
163
+ editor,
164
+ onEditorValueChange: handleEditorValueChange,
165
+ abortableMessageId,
166
+ setFocused
167
+ },
168
+ children: /* @__PURE__ */ jsx(AiComposerContext.Provider, {
169
+ value: {
170
+ isDisabled,
171
+ isEmpty: isEditorEmpty,
172
+ isFocused,
173
+ canSubmit,
174
+ canAbort,
175
+ submit,
176
+ abort,
177
+ clear,
178
+ focus,
179
+ blur,
180
+ select
181
+ },
182
+ children: /* @__PURE__ */ jsx(Component, {
183
+ onSubmit: handleSubmit,
184
+ ...props,
185
+ ref: formRef
186
+ })
187
+ })
188
+ });
189
+ }
190
+ );
191
+ function AiComposerEditorPlaceholder({
192
+ attributes,
193
+ children
194
+ }) {
195
+ const { opacity: _opacity, ...style } = attributes.style;
196
+ return /* @__PURE__ */ jsx("span", {
197
+ ...attributes,
198
+ style,
199
+ "data-placeholder": "",
200
+ children
201
+ });
202
+ }
203
+ const AiComposerEditor = forwardRef(
204
+ ({
205
+ defaultValue = "",
206
+ onKeyDown,
207
+ onFocus,
208
+ onBlur,
209
+ disabled,
210
+ autoFocus,
211
+ dir,
212
+ ...props
213
+ }, forwardedRef) => {
214
+ const { editor, onEditorValueChange, setFocused } = useAiComposerEditorContext();
215
+ const {
216
+ submit,
217
+ isDisabled: isComposerDisabled,
218
+ isFocused,
219
+ focus,
220
+ blur,
221
+ select
222
+ } = useAiComposer();
223
+ const isDisabled = disabled || isComposerDisabled;
224
+ const handleKeyDown = useCallback(
225
+ (event) => {
226
+ onKeyDown?.(event);
227
+ if (event.isDefaultPrevented())
228
+ return;
229
+ if (event.key === "Enter" && !event.shiftKey) {
230
+ event.preventDefault();
231
+ submit();
232
+ } else if (event.key === "Enter" && event.shiftKey) {
233
+ event.preventDefault();
234
+ editor.insertBreak();
235
+ } else if (event.key === "Escape") {
236
+ blur();
237
+ }
238
+ },
239
+ [editor, onKeyDown, submit, blur]
240
+ );
241
+ const handleFocus = useCallback(
242
+ (event) => {
243
+ onFocus?.(event);
244
+ if (!event.isDefaultPrevented()) {
245
+ setFocused(true);
246
+ }
247
+ },
248
+ [onFocus, setFocused]
249
+ );
250
+ const handleBlur = useCallback(
251
+ (event) => {
252
+ onBlur?.(event);
253
+ if (!event.isDefaultPrevented()) {
254
+ setFocused(false);
255
+ }
256
+ },
257
+ [onBlur, setFocused]
258
+ );
259
+ useImperativeHandle(
260
+ forwardedRef,
261
+ () => ReactEditor.toDOMNode(editor, editor),
262
+ [editor]
263
+ );
264
+ useLayoutEffect(() => {
265
+ if (autoFocus) {
266
+ focus();
267
+ }
268
+ }, [autoFocus, editor, focus]);
269
+ useLayoutEffect(() => {
270
+ if (isFocused && editor.selection === null) {
271
+ select();
272
+ }
273
+ }, [editor, select, isFocused]);
274
+ const initialValue = useMemo(() => {
275
+ return defaultValue.split("\n").map((text) => ({ type: "paragraph", children: [{ text }] }));
276
+ }, [defaultValue]);
277
+ return /* @__PURE__ */ jsx(Slate, {
278
+ editor,
279
+ initialValue,
280
+ onValueChange: onEditorValueChange,
281
+ children: /* @__PURE__ */ jsx(Editable, {
282
+ dir,
283
+ enterKeyHint: "send",
284
+ autoCapitalize: "sentences",
285
+ "aria-label": "Composer editor",
286
+ onKeyDown: handleKeyDown,
287
+ onFocus: handleFocus,
288
+ onBlur: handleBlur,
289
+ "data-focused": isFocused || void 0,
290
+ "data-disabled": isDisabled || void 0,
291
+ ...props,
292
+ readOnly: isDisabled,
293
+ disabled: isDisabled,
294
+ renderPlaceholder: AiComposerEditorPlaceholder
295
+ })
296
+ });
297
+ }
298
+ );
299
+ const AiComposerSubmit = forwardRef(({ disabled, asChild, ...props }, forwardedRef) => {
300
+ const Component = asChild ? Slot : "button";
301
+ const { isDisabled: isComposerDisabled, canSubmit } = useAiComposer();
302
+ const isDisabled = isComposerDisabled || disabled || !canSubmit;
303
+ return /* @__PURE__ */ jsx(Component, {
304
+ type: "submit",
305
+ ...props,
306
+ ref: forwardedRef,
307
+ disabled: isDisabled
308
+ });
309
+ });
310
+ const AiComposerAbort = forwardRef(({ disabled, onClick, asChild, ...props }, forwardedRef) => {
311
+ const Component = asChild ? Slot : "button";
312
+ const { isDisabled: isComposerDisabled, canAbort, abort } = useAiComposer();
313
+ const isDisabled = isComposerDisabled || disabled || !canAbort;
314
+ const handleClick = useCallback(
315
+ (event) => {
316
+ onClick?.(event);
317
+ if (event.isDefaultPrevented()) {
318
+ return;
319
+ }
320
+ abort();
321
+ },
322
+ [abort, onClick]
323
+ );
324
+ return /* @__PURE__ */ jsx(Component, {
325
+ type: "button",
326
+ ...props,
327
+ ref: forwardedRef,
328
+ disabled: isDisabled,
329
+ onClick: handleClick
330
+ });
331
+ });
332
+ if (process.env.NODE_ENV !== "production") {
333
+ AiComposerEditor.displayName = AI_COMPOSER_EDITOR_NAME;
334
+ AiComposerForm.displayName = AI_COMPOSER_FORM_NAME;
335
+ AiComposerSubmit.displayName = AI_COMPOSER_SUBMIT_NAME;
336
+ AiComposerAbort.displayName = AI_COMPOSER_ABORT_NAME;
337
+ }
338
+
339
+ export { AiComposerAbort as Abort, AiComposerAbort, AiComposerForm, AiComposerSubmit, AiComposerEditor as Editor, AiComposerForm as Form, AiComposerSubmit as Submit };
340
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../src/primitives/AiComposer/index.tsx"],"sourcesContent":["import {\n type AiChatMessage,\n kInternal,\n Signal,\n type WithNavigation,\n} from \"@liveblocks/core\";\nimport { useClient } from \"@liveblocks/react\";\nimport { useLayoutEffect, useSignal } from \"@liveblocks/react/_private\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport type { FocusEvent, FormEvent, KeyboardEvent, MouseEvent } from \"react\";\nimport {\n forwardRef,\n useCallback,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n createEditor,\n Editor as SlateEditor,\n Transforms as SlateTransforms,\n} from \"slate\";\nimport { withHistory } from \"slate-history\";\nimport {\n Editable,\n ReactEditor,\n type RenderPlaceholderProps,\n Slate,\n withReact,\n} from \"slate-react\";\n\nimport type { AiComposerBody } from \"../../types\";\nimport { requestSubmit } from \"../../utils/request-submit\";\nimport { useInitial } from \"../../utils/use-initial\";\nimport { withNormalize } from \"../slate/plugins/normalize\";\nimport { isEmpty } from \"../slate/utils/is-empty\";\nimport {\n AiComposerContext,\n AiComposerEditorContext,\n useAiComposer,\n useAiComposerEditorContext,\n} from \"./contexts\";\nimport type {\n AiComposerEditorProps,\n AiComposerFormProps,\n AiComposerSubmitProps,\n} from \"./types\";\n\nconst AI_COMPOSER_SUBMIT_NAME = \"AiComposerSubmit\";\nconst AI_COMPOSER_ABORT_NAME = \"AiComposerAbort\";\nconst AI_COMPOSER_EDITOR_NAME = \"AiComposerEditor\";\nconst AI_COMPOSER_FORM_NAME = \"AiComposerForm\";\n\ntype UiChatMessage = WithNavigation<AiChatMessage>;\n\n/* -------------------------------------------------------------------------------------------------\n * Form\n * -----------------------------------------------------------------------------------------------*/\n\nconst emptyMessagesΣ = new Signal<UiChatMessage[]>([]);\n\nfunction getLastMessageId(messages: UiChatMessage[]) {\n const lastMessage = messages[messages.length - 1];\n\n if (lastMessage === undefined) {\n return null;\n }\n\n return lastMessage.id;\n}\n\nfunction getAbortableMessageId(messages: UiChatMessage[]) {\n return messages.find(\n (message) =>\n message.role === \"assistant\" &&\n (message.status === \"generating\" || message.status === \"awaiting-tool\")\n )?.id;\n}\n\n/**\n * Surrounds the AI composer's content and handles submissions.\n *\n * @example\n * <AiComposer.Form onComposerSubmit={({ text }) => {}}>\n *\t <AiComposer.Editor />\n * <AiComposer.Submit />\n * </AiComposer.Form>\n */\nexport const AiComposerForm = forwardRef<HTMLFormElement, AiComposerFormProps>(\n (\n {\n onComposerSubmit,\n onSubmit,\n disabled,\n chatId,\n branchId,\n asChild,\n ...props\n },\n forwardedRef\n ) => {\n const Component = asChild ? Slot : \"form\";\n const client = useClient();\n const formRef = useRef<HTMLFormElement | null>(null);\n const editor = useInitial(() =>\n withNormalize(withHistory(withReact(createEditor())))\n );\n const [isEditorEmpty, setEditorEmpty] = useState(true);\n const [isSubmitting, setSubmitting] = useState(false);\n const [isFocused, setFocused] = useState(false);\n const messagesΣ = chatId\n ? client[kInternal].ai.signals.getChatMessagesForBranchΣ(chatId, branchId)\n : emptyMessagesΣ;\n const lastMessageId = useSignal(messagesΣ, getLastMessageId);\n const abortableMessageId = useSignal(messagesΣ, getAbortableMessageId);\n\n const isDisabled = isSubmitting || disabled === true;\n const canAbort = abortableMessageId !== undefined;\n const canSubmit = !isEditorEmpty && !canAbort;\n\n const clear = useCallback(() => {\n SlateTransforms.delete(editor, {\n at: {\n anchor: SlateEditor.start(editor, []),\n focus: SlateEditor.end(editor, []),\n },\n });\n }, [editor]);\n\n const select = useCallback(() => {\n SlateTransforms.select(editor, SlateEditor.end(editor, []));\n }, [editor]);\n\n const focus = useCallback(\n (resetSelection = true) => {\n try {\n if (!ReactEditor.isFocused(editor)) {\n SlateTransforms.select(\n editor,\n resetSelection || !editor.selection\n ? SlateEditor.end(editor, [])\n : editor.selection\n );\n ReactEditor.focus(editor);\n }\n } catch {\n // Slate's DOM-specific methods will throw if the editor's DOM\n // node no longer exists. This action doesn't make sense on an\n // unmounted editor so we can safely ignore it.\n }\n },\n [editor]\n );\n\n const blur = useCallback(() => {\n try {\n ReactEditor.blur(editor);\n } catch {\n // Slate's DOM-specific methods will throw if the editor's DOM\n // node no longer exists. This action doesn't make sense on an\n // unmounted editor so we can safely ignore it.\n }\n }, [editor]);\n\n const onSubmitEnd = useCallback(() => {\n clear();\n setSubmitting(false);\n }, [clear]);\n\n const handleSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n if (disabled) {\n return;\n }\n\n // In some situations (e.g. pressing Enter while composing diacritics), it's possible\n // for the form to be submitted as empty even though we already checked whether the\n // editor was empty when handling the key press.\n const isEditorEmpty = isEmpty(editor, editor.children);\n\n // We even prevent the user's `onSubmit` handler from being called if the editor is empty.\n if (isEditorEmpty) {\n event.preventDefault();\n\n return;\n }\n\n onSubmit?.(event);\n\n if (onComposerSubmit === undefined || event.isDefaultPrevented()) {\n event.preventDefault();\n return;\n }\n\n // Extract the text content from the editor.\n const content = editor.children\n .map((block) => {\n if (\"type\" in block && block.type === \"paragraph\") {\n return block.children\n .map((child) => {\n if (\"text\" in child) {\n return child.text;\n }\n return \"\";\n })\n .join(\"\");\n }\n return \"\";\n })\n .join(\"\\n\");\n\n const promise = onComposerSubmit(\n { text: content, lastMessageId },\n event\n );\n\n event.preventDefault();\n\n if (promise) {\n setSubmitting(true);\n promise.then(onSubmitEnd);\n } else {\n onSubmitEnd();\n }\n },\n [disabled, editor, onSubmit, onComposerSubmit, onSubmitEnd, lastMessageId]\n );\n\n useLayoutEffect(() => {\n setEditorEmpty(isEmpty(editor, editor.children));\n }, [editor]);\n\n const handleEditorValueChange = useCallback(() => {\n setEditorEmpty(isEmpty(editor, editor.children));\n }, [editor]);\n\n const submit = useCallback(() => {\n if (!canSubmit) {\n return;\n }\n\n // We need to wait for the next frame in some cases like when composing diacritics,\n // we want any native handling to be done first while still being handled on `keydown`.\n requestAnimationFrame(() => {\n if (formRef.current) {\n requestSubmit(formRef.current);\n }\n });\n }, [canSubmit]);\n\n const abort = useCallback(() => {\n if (!canAbort || !abortableMessageId) {\n return;\n }\n\n client[kInternal].ai.abort(abortableMessageId);\n }, [canAbort, abortableMessageId, client]);\n\n useImperativeHandle<HTMLFormElement | null, HTMLFormElement | null>(\n forwardedRef,\n () => formRef.current,\n []\n );\n\n return (\n <AiComposerEditorContext.Provider\n value={{\n editor,\n onEditorValueChange: handleEditorValueChange,\n abortableMessageId,\n setFocused,\n }}\n >\n <AiComposerContext.Provider\n value={{\n isDisabled,\n isEmpty: isEditorEmpty,\n isFocused,\n canSubmit,\n canAbort,\n submit,\n abort,\n clear,\n focus,\n blur,\n select,\n }}\n >\n <Component onSubmit={handleSubmit} {...props} ref={formRef} />\n </AiComposerContext.Provider>\n </AiComposerEditorContext.Provider>\n );\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * Editor\n * -----------------------------------------------------------------------------------------------*/\n\nfunction AiComposerEditorPlaceholder({\n attributes,\n children,\n}: RenderPlaceholderProps) {\n const { opacity: _opacity, ...style } = attributes.style;\n\n return (\n <span {...attributes} style={style} data-placeholder=\"\">\n {children}\n </span>\n );\n}\n\n/**\n * Displays the AI composer's editor.\n *\n * @example\n * <AiComposer.Editor placeholder=\"Write a message…\" />\n */\nconst AiComposerEditor = forwardRef<HTMLDivElement, AiComposerEditorProps>(\n (\n {\n defaultValue = \"\",\n onKeyDown,\n onFocus,\n onBlur,\n disabled,\n autoFocus,\n dir,\n ...props\n },\n forwardedRef\n ) => {\n const { editor, onEditorValueChange, setFocused } =\n useAiComposerEditorContext();\n const {\n submit,\n isDisabled: isComposerDisabled,\n isFocused,\n focus,\n blur,\n select,\n } = useAiComposer();\n const isDisabled = disabled || isComposerDisabled;\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n if (event.isDefaultPrevented()) return;\n\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n submit();\n } else if (event.key === \"Enter\" && event.shiftKey) {\n event.preventDefault();\n editor.insertBreak();\n } else if (event.key === \"Escape\") {\n blur();\n }\n },\n [editor, onKeyDown, submit, blur]\n );\n\n const handleFocus = useCallback(\n (event: FocusEvent<HTMLDivElement>) => {\n onFocus?.(event);\n\n if (!event.isDefaultPrevented()) {\n setFocused(true);\n }\n },\n [onFocus, setFocused]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLDivElement>) => {\n onBlur?.(event);\n\n if (!event.isDefaultPrevented()) {\n setFocused(false);\n }\n },\n [onBlur, setFocused]\n );\n\n useImperativeHandle(\n forwardedRef,\n () => ReactEditor.toDOMNode(editor, editor) as HTMLDivElement,\n [editor]\n );\n\n // Manually focus the editor when `autoFocus` is true\n useLayoutEffect(() => {\n if (autoFocus) {\n focus();\n }\n }, [autoFocus, editor, focus]);\n\n // Manually add a selection in the editor if the selection\n // is still empty after being focused\n useLayoutEffect(() => {\n if (isFocused && editor.selection === null) {\n select();\n }\n }, [editor, select, isFocused]);\n\n const initialValue: AiComposerBody = useMemo(() => {\n return defaultValue\n .split(\"\\n\")\n .map((text) => ({ type: \"paragraph\", children: [{ text }] }));\n }, [defaultValue]);\n\n return (\n <Slate\n editor={editor}\n initialValue={initialValue}\n onValueChange={onEditorValueChange}\n >\n <Editable\n dir={dir}\n enterKeyHint=\"send\"\n autoCapitalize=\"sentences\"\n aria-label=\"Composer editor\"\n onKeyDown={handleKeyDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n data-focused={isFocused || undefined}\n data-disabled={isDisabled || undefined}\n {...props}\n readOnly={isDisabled}\n disabled={isDisabled}\n renderPlaceholder={AiComposerEditorPlaceholder}\n />\n </Slate>\n );\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * Submit\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * A button to submit the AI composer's content.\n *\n * @example\n * <AiComposer.Submit>Send</AiComposer.Submit>\n */\nexport const AiComposerSubmit = forwardRef<\n HTMLButtonElement,\n AiComposerSubmitProps\n>(({ disabled, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"button\";\n const { isDisabled: isComposerDisabled, canSubmit } = useAiComposer();\n const isDisabled = isComposerDisabled || disabled || !canSubmit;\n\n return (\n <Component\n type=\"submit\"\n {...props}\n ref={forwardedRef}\n disabled={isDisabled}\n />\n );\n});\n\n/* -------------------------------------------------------------------------------------------------\n * Abort\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * A button to abort a response related to the AI composer.\n *\n * @example\n * <AiComposer.Abort>Cancel</AiComposer.Abort>\n */\nexport const AiComposerAbort = forwardRef<\n HTMLButtonElement,\n AiComposerSubmitProps\n>(({ disabled, onClick, asChild, ...props }, forwardedRef) => {\n const Component = asChild ? Slot : \"button\";\n const { isDisabled: isComposerDisabled, canAbort, abort } = useAiComposer();\n const isDisabled = isComposerDisabled || disabled || !canAbort;\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n abort();\n },\n [abort, onClick]\n );\n\n return (\n <Component\n type=\"button\"\n {...props}\n ref={forwardedRef}\n disabled={isDisabled}\n onClick={handleClick}\n />\n );\n});\n\nif (process.env.NODE_ENV !== \"production\") {\n AiComposerEditor.displayName = AI_COMPOSER_EDITOR_NAME;\n AiComposerForm.displayName = AI_COMPOSER_FORM_NAME;\n AiComposerSubmit.displayName = AI_COMPOSER_SUBMIT_NAME;\n AiComposerAbort.displayName = AI_COMPOSER_ABORT_NAME;\n}\n\n// NOTE: Every export from this file will be available publicly as AiComposer.*\nexport {\n AiComposerAbort as Abort,\n AiComposerEditor as Editor,\n AiComposerForm as Form,\n AiComposerSubmit as Submit,\n};\n"],"names":["SlateTransforms","SlateEditor","isEditorEmpty"],"mappings":";;;;;;;;;;;;;;;AAiDA,MAAM,uBAA0B,GAAA,kBAAA,CAAA;AAChC,MAAM,sBAAyB,GAAA,iBAAA,CAAA;AAC/B,MAAM,uBAA0B,GAAA,kBAAA,CAAA;AAChC,MAAM,qBAAwB,GAAA,gBAAA,CAAA;AAQ9B,MAAM,mBAAiB,GAAA,IAAI,MAAwB,CAAA,EAAE,CAAA,CAAA;AAErD,SAAS,iBAAiB,QAA2B,EAAA;AACnD,EAAM,MAAA,WAAA,GAAc,QAAS,CAAA,QAAA,CAAS,MAAS,GAAA,CAAA,CAAA,CAAA;AAE/C,EAAA,IAAI,gBAAgB,KAAW,CAAA,EAAA;AAC7B,IAAO,OAAA,IAAA,CAAA;AAAA,GACT;AAEA,EAAA,OAAO,WAAY,CAAA,EAAA,CAAA;AACrB,CAAA;AAEA,SAAS,sBAAsB,QAA2B,EAAA;AACxD,EAAA,OAAO,QAAS,CAAA,IAAA;AAAA,IACd,CAAC,YACC,OAAQ,CAAA,IAAA,KAAS,gBAChB,OAAQ,CAAA,MAAA,KAAW,YAAgB,IAAA,OAAA,CAAQ,MAAW,KAAA,eAAA,CAAA;AAAA,GACxD,EAAA,EAAA,CAAA;AACL,CAAA;AAWO,MAAM,cAAiB,GAAA,UAAA;AAAA,EAC5B,CACE;AAAA,IACE,gBAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA;AAAA,IACA,QAAA;AAAA,IACA,OAAA;AAAA,IACG,GAAA,KAAA;AAAA,KAEL,YACG,KAAA;AACH,IAAM,MAAA,SAAA,GAAY,UAAU,IAAO,GAAA,MAAA,CAAA;AACnC,IAAA,MAAM,SAAS,SAAU,EAAA,CAAA;AACzB,IAAM,MAAA,OAAA,GAAU,OAA+B,IAAI,CAAA,CAAA;AACnD,IAAA,MAAM,MAAS,GAAA,UAAA;AAAA,MAAW,MACxB,aAAc,CAAA,WAAA,CAAY,UAAU,YAAa,EAAC,CAAC,CAAC,CAAA;AAAA,KACtD,CAAA;AACA,IAAA,MAAM,CAAC,aAAA,EAAe,cAAc,CAAA,GAAI,SAAS,IAAI,CAAA,CAAA;AACrD,IAAA,MAAM,CAAC,YAAA,EAAc,aAAa,CAAA,GAAI,SAAS,KAAK,CAAA,CAAA;AACpD,IAAA,MAAM,CAAC,SAAA,EAAW,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA,CAAA;AAC9C,IAAM,MAAA,cAAA,GAAY,SACd,MAAO,CAAA,SAAA,CAAA,CAAW,GAAG,OAAQ,CAAA,8BAAA,CAA0B,MAAQ,EAAA,QAAQ,CACvE,GAAA,mBAAA,CAAA;AACJ,IAAM,MAAA,aAAA,GAAgB,SAAU,CAAA,cAAA,EAAW,gBAAgB,CAAA,CAAA;AAC3D,IAAM,MAAA,kBAAA,GAAqB,SAAU,CAAA,cAAA,EAAW,qBAAqB,CAAA,CAAA;AAErE,IAAM,MAAA,UAAA,GAAa,gBAAgB,QAAa,KAAA,IAAA,CAAA;AAChD,IAAA,MAAM,WAAW,kBAAuB,KAAA,KAAA,CAAA,CAAA;AACxC,IAAM,MAAA,SAAA,GAAY,CAAC,aAAA,IAAiB,CAAC,QAAA,CAAA;AAErC,IAAM,MAAA,KAAA,GAAQ,YAAY,MAAM;AAC9B,MAAAA,UAAA,CAAgB,OAAO,MAAQ,EAAA;AAAA,QAC7B,EAAI,EAAA;AAAA,UACF,MAAQ,EAAAC,MAAA,CAAY,KAAM,CAAA,MAAA,EAAQ,EAAE,CAAA;AAAA,UACpC,KAAO,EAAAA,MAAA,CAAY,GAAI,CAAA,MAAA,EAAQ,EAAE,CAAA;AAAA,SACnC;AAAA,OACD,CAAA,CAAA;AAAA,KACH,EAAG,CAAC,MAAM,CAAC,CAAA,CAAA;AAEX,IAAM,MAAA,MAAA,GAAS,YAAY,MAAM;AAC/B,MAAAD,UAAA,CAAgB,OAAO,MAAQ,EAAAC,MAAA,CAAY,IAAI,MAAQ,EAAA,EAAE,CAAC,CAAA,CAAA;AAAA,KAC5D,EAAG,CAAC,MAAM,CAAC,CAAA,CAAA;AAEX,IAAA,MAAM,KAAQ,GAAA,WAAA;AAAA,MACZ,CAAC,iBAAiB,IAAS,KAAA;AACzB,QAAI,IAAA;AACF,UAAA,IAAI,CAAC,WAAA,CAAY,SAAU,CAAA,MAAM,CAAG,EAAA;AAClC,YAAgBD,UAAA,CAAA,MAAA;AAAA,cACd,MAAA;AAAA,cACA,cAAA,IAAkB,CAAC,MAAA,CAAO,SACtB,GAAAC,MAAA,CAAY,IAAI,MAAQ,EAAA,EAAE,CAAA,GAC1B,MAAO,CAAA,SAAA;AAAA,aACb,CAAA;AACA,YAAA,WAAA,CAAY,MAAM,MAAM,CAAA,CAAA;AAAA,WAC1B;AAAA,SACA,CAAA,MAAA;AAAA,SAIF;AAAA,OACF;AAAA,MACA,CAAC,MAAM,CAAA;AAAA,KACT,CAAA;AAEA,IAAM,MAAA,IAAA,GAAO,YAAY,MAAM;AAC7B,MAAI,IAAA;AACF,QAAA,WAAA,CAAY,KAAK,MAAM,CAAA,CAAA;AAAA,OACvB,CAAA,MAAA;AAAA,OAIF;AAAA,KACF,EAAG,CAAC,MAAM,CAAC,CAAA,CAAA;AAEX,IAAM,MAAA,WAAA,GAAc,YAAY,MAAM;AACpC,MAAM,KAAA,EAAA,CAAA;AACN,MAAA,aAAA,CAAc,KAAK,CAAA,CAAA;AAAA,KACrB,EAAG,CAAC,KAAK,CAAC,CAAA,CAAA;AAEV,IAAA,MAAM,YAAe,GAAA,WAAA;AAAA,MACnB,CAAC,KAAsC,KAAA;AACrC,QAAA,IAAI,QAAU,EAAA;AACZ,UAAA,OAAA;AAAA,SACF;AAKA,QAAA,MAAMC,cAAgB,GAAA,OAAA,CAAQ,MAAQ,EAAA,MAAA,CAAO,QAAQ,CAAA,CAAA;AAGrD,QAAA,IAAIA,cAAe,EAAA;AACjB,UAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AAErB,UAAA,OAAA;AAAA,SACF;AAEA,QAAA,QAAA,GAAW,KAAK,CAAA,CAAA;AAEhB,QAAA,IAAI,gBAAqB,KAAA,KAAA,CAAA,IAAa,KAAM,CAAA,kBAAA,EAAsB,EAAA;AAChE,UAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,UAAA,OAAA;AAAA,SACF;AAGA,QAAA,MAAM,OAAU,GAAA,MAAA,CAAO,QACpB,CAAA,GAAA,CAAI,CAAC,KAAU,KAAA;AACd,UAAA,IAAI,MAAU,IAAA,KAAA,IAAS,KAAM,CAAA,IAAA,KAAS,WAAa,EAAA;AACjD,YAAA,OAAO,KAAM,CAAA,QAAA,CACV,GAAI,CAAA,CAAC,KAAU,KAAA;AACd,cAAA,IAAI,UAAU,KAAO,EAAA;AACnB,gBAAA,OAAO,KAAM,CAAA,IAAA,CAAA;AAAA,eACf;AACA,cAAO,OAAA,EAAA,CAAA;AAAA,aACR,CACA,CAAA,IAAA,CAAK,EAAE,CAAA,CAAA;AAAA,WACZ;AACA,UAAO,OAAA,EAAA,CAAA;AAAA,SACR,CACA,CAAA,IAAA,CAAK,IAAI,CAAA,CAAA;AAEZ,QAAA,MAAM,OAAU,GAAA,gBAAA;AAAA,UACd,EAAE,IAAM,EAAA,OAAA,EAAS,aAAc,EAAA;AAAA,UAC/B,KAAA;AAAA,SACF,CAAA;AAEA,QAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AAErB,QAAA,IAAI,OAAS,EAAA;AACX,UAAA,aAAA,CAAc,IAAI,CAAA,CAAA;AAClB,UAAA,OAAA,CAAQ,KAAK,WAAW,CAAA,CAAA;AAAA,SACnB,MAAA;AACL,UAAY,WAAA,EAAA,CAAA;AAAA,SACd;AAAA,OACF;AAAA,MACA,CAAC,QAAU,EAAA,MAAA,EAAQ,QAAU,EAAA,gBAAA,EAAkB,aAAa,aAAa,CAAA;AAAA,KAC3E,CAAA;AAEA,IAAA,eAAA,CAAgB,MAAM;AACpB,MAAA,cAAA,CAAe,OAAQ,CAAA,MAAA,EAAQ,MAAO,CAAA,QAAQ,CAAC,CAAA,CAAA;AAAA,KACjD,EAAG,CAAC,MAAM,CAAC,CAAA,CAAA;AAEX,IAAM,MAAA,uBAAA,GAA0B,YAAY,MAAM;AAChD,MAAA,cAAA,CAAe,OAAQ,CAAA,MAAA,EAAQ,MAAO,CAAA,QAAQ,CAAC,CAAA,CAAA;AAAA,KACjD,EAAG,CAAC,MAAM,CAAC,CAAA,CAAA;AAEX,IAAM,MAAA,MAAA,GAAS,YAAY,MAAM;AAC/B,MAAA,IAAI,CAAC,SAAW,EAAA;AACd,QAAA,OAAA;AAAA,OACF;AAIA,MAAA,qBAAA,CAAsB,MAAM;AAC1B,QAAA,IAAI,QAAQ,OAAS,EAAA;AACnB,UAAA,aAAA,CAAc,QAAQ,OAAO,CAAA,CAAA;AAAA,SAC/B;AAAA,OACD,CAAA,CAAA;AAAA,KACH,EAAG,CAAC,SAAS,CAAC,CAAA,CAAA;AAEd,IAAM,MAAA,KAAA,GAAQ,YAAY,MAAM;AAC9B,MAAI,IAAA,CAAC,QAAY,IAAA,CAAC,kBAAoB,EAAA;AACpC,QAAA,OAAA;AAAA,OACF;AAEA,MAAO,MAAA,CAAA,SAAA,CAAA,CAAW,EAAG,CAAA,KAAA,CAAM,kBAAkB,CAAA,CAAA;AAAA,KAC5C,EAAA,CAAC,QAAU,EAAA,kBAAA,EAAoB,MAAM,CAAC,CAAA,CAAA;AAEzC,IAAA,mBAAA;AAAA,MACE,YAAA;AAAA,MACA,MAAM,OAAQ,CAAA,OAAA;AAAA,MACd,EAAC;AAAA,KACH,CAAA;AAEA,IACE,uBAAA,GAAA,CAAC,wBAAwB,QAAxB,EAAA;AAAA,MACC,KAAO,EAAA;AAAA,QACL,MAAA;AAAA,QACA,mBAAqB,EAAA,uBAAA;AAAA,QACrB,kBAAA;AAAA,QACA,UAAA;AAAA,OACF;AAAA,MAEA,QAAA,kBAAA,GAAA,CAAC,kBAAkB,QAAlB,EAAA;AAAA,QACC,KAAO,EAAA;AAAA,UACL,UAAA;AAAA,UACA,OAAS,EAAA,aAAA;AAAA,UACT,SAAA;AAAA,UACA,SAAA;AAAA,UACA,QAAA;AAAA,UACA,MAAA;AAAA,UACA,KAAA;AAAA,UACA,KAAA;AAAA,UACA,KAAA;AAAA,UACA,IAAA;AAAA,UACA,MAAA;AAAA,SACF;AAAA,QAEA,QAAC,kBAAA,GAAA,CAAA,SAAA,EAAA;AAAA,UAAU,QAAU,EAAA,YAAA;AAAA,UAAe,GAAG,KAAA;AAAA,UAAO,GAAK,EAAA,OAAA;AAAA,SAAS,CAAA;AAAA,OAC9D,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GAEJ;AACF,EAAA;AAMA,SAAS,2BAA4B,CAAA;AAAA,EACnC,UAAA;AAAA,EACA,QAAA;AACF,CAA2B,EAAA;AACzB,EAAA,MAAM,EAAE,OAAA,EAAS,QAAa,EAAA,GAAA,KAAA,KAAU,UAAW,CAAA,KAAA,CAAA;AAEnD,EAAA,uBACG,GAAA,CAAA,MAAA,EAAA;AAAA,IAAM,GAAG,UAAA;AAAA,IAAY,KAAA;AAAA,IAAc,kBAAiB,EAAA,EAAA;AAAA,IAClD,QAAA;AAAA,GACH,CAAA,CAAA;AAEJ,CAAA;AAQA,MAAM,gBAAmB,GAAA,UAAA;AAAA,EACvB,CACE;AAAA,IACE,YAAe,GAAA,EAAA;AAAA,IACf,SAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,GAAA;AAAA,IACG,GAAA,KAAA;AAAA,KAEL,YACG,KAAA;AACH,IAAA,MAAM,EAAE,MAAA,EAAQ,mBAAqB,EAAA,UAAA,KACnC,0BAA2B,EAAA,CAAA;AAC7B,IAAM,MAAA;AAAA,MACJ,MAAA;AAAA,MACA,UAAY,EAAA,kBAAA;AAAA,MACZ,SAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,MAAA;AAAA,QACE,aAAc,EAAA,CAAA;AAClB,IAAA,MAAM,aAAa,QAAY,IAAA,kBAAA,CAAA;AAE/B,IAAA,MAAM,aAAgB,GAAA,WAAA;AAAA,MACpB,CAAC,KAAyC,KAAA;AACxC,QAAA,SAAA,GAAY,KAAK,CAAA,CAAA;AACjB,QAAA,IAAI,MAAM,kBAAmB,EAAA;AAAG,UAAA,OAAA;AAEhC,QAAA,IAAI,KAAM,CAAA,GAAA,KAAQ,OAAW,IAAA,CAAC,MAAM,QAAU,EAAA;AAC5C,UAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,UAAO,MAAA,EAAA,CAAA;AAAA,SACE,MAAA,IAAA,KAAA,CAAM,GAAQ,KAAA,OAAA,IAAW,MAAM,QAAU,EAAA;AAClD,UAAA,KAAA,CAAM,cAAe,EAAA,CAAA;AACrB,UAAA,MAAA,CAAO,WAAY,EAAA,CAAA;AAAA,SACrB,MAAA,IAAW,KAAM,CAAA,GAAA,KAAQ,QAAU,EAAA;AACjC,UAAK,IAAA,EAAA,CAAA;AAAA,SACP;AAAA,OACF;AAAA,MACA,CAAC,MAAA,EAAQ,SAAW,EAAA,MAAA,EAAQ,IAAI,CAAA;AAAA,KAClC,CAAA;AAEA,IAAA,MAAM,WAAc,GAAA,WAAA;AAAA,MAClB,CAAC,KAAsC,KAAA;AACrC,QAAA,OAAA,GAAU,KAAK,CAAA,CAAA;AAEf,QAAI,IAAA,CAAC,KAAM,CAAA,kBAAA,EAAsB,EAAA;AAC/B,UAAA,UAAA,CAAW,IAAI,CAAA,CAAA;AAAA,SACjB;AAAA,OACF;AAAA,MACA,CAAC,SAAS,UAAU,CAAA;AAAA,KACtB,CAAA;AAEA,IAAA,MAAM,UAAa,GAAA,WAAA;AAAA,MACjB,CAAC,KAAsC,KAAA;AACrC,QAAA,MAAA,GAAS,KAAK,CAAA,CAAA;AAEd,QAAI,IAAA,CAAC,KAAM,CAAA,kBAAA,EAAsB,EAAA;AAC/B,UAAA,UAAA,CAAW,KAAK,CAAA,CAAA;AAAA,SAClB;AAAA,OACF;AAAA,MACA,CAAC,QAAQ,UAAU,CAAA;AAAA,KACrB,CAAA;AAEA,IAAA,mBAAA;AAAA,MACE,YAAA;AAAA,MACA,MAAM,WAAA,CAAY,SAAU,CAAA,MAAA,EAAQ,MAAM,CAAA;AAAA,MAC1C,CAAC,MAAM,CAAA;AAAA,KACT,CAAA;AAGA,IAAA,eAAA,CAAgB,MAAM;AACpB,MAAA,IAAI,SAAW,EAAA;AACb,QAAM,KAAA,EAAA,CAAA;AAAA,OACR;AAAA,KACC,EAAA,CAAC,SAAW,EAAA,MAAA,EAAQ,KAAK,CAAC,CAAA,CAAA;AAI7B,IAAA,eAAA,CAAgB,MAAM;AACpB,MAAI,IAAA,SAAA,IAAa,MAAO,CAAA,SAAA,KAAc,IAAM,EAAA;AAC1C,QAAO,MAAA,EAAA,CAAA;AAAA,OACT;AAAA,KACC,EAAA,CAAC,MAAQ,EAAA,MAAA,EAAQ,SAAS,CAAC,CAAA,CAAA;AAE9B,IAAM,MAAA,YAAA,GAA+B,QAAQ,MAAM;AACjD,MAAA,OAAO,aACJ,KAAM,CAAA,IAAI,CACV,CAAA,GAAA,CAAI,CAAC,IAAU,MAAA,EAAE,IAAM,EAAA,WAAA,EAAa,UAAU,CAAC,EAAE,IAAK,EAAC,GAAI,CAAA,CAAA,CAAA;AAAA,KAChE,EAAG,CAAC,YAAY,CAAC,CAAA,CAAA;AAEjB,IAAA,uBACG,GAAA,CAAA,KAAA,EAAA;AAAA,MACC,MAAA;AAAA,MACA,YAAA;AAAA,MACA,aAAe,EAAA,mBAAA;AAAA,MAEf,QAAC,kBAAA,GAAA,CAAA,QAAA,EAAA;AAAA,QACC,GAAA;AAAA,QACA,YAAa,EAAA,MAAA;AAAA,QACb,cAAe,EAAA,WAAA;AAAA,QACf,YAAW,EAAA,iBAAA;AAAA,QACX,SAAW,EAAA,aAAA;AAAA,QACX,OAAS,EAAA,WAAA;AAAA,QACT,MAAQ,EAAA,UAAA;AAAA,QACR,gBAAc,SAAa,IAAA,KAAA,CAAA;AAAA,QAC3B,iBAAe,UAAc,IAAA,KAAA,CAAA;AAAA,QAC5B,GAAG,KAAA;AAAA,QACJ,QAAU,EAAA,UAAA;AAAA,QACV,QAAU,EAAA,UAAA;AAAA,QACV,iBAAmB,EAAA,2BAAA;AAAA,OACrB,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GAEJ;AACF,EAAA;AAYa,MAAA,gBAAA,GAAmB,WAG9B,CAAC,EAAE,UAAU,OAAY,EAAA,GAAA,KAAA,IAAS,YAAiB,KAAA;AACnD,EAAM,MAAA,SAAA,GAAY,UAAU,IAAO,GAAA,QAAA,CAAA;AACnC,EAAA,MAAM,EAAE,UAAA,EAAY,kBAAoB,EAAA,SAAA,KAAc,aAAc,EAAA,CAAA;AACpE,EAAM,MAAA,UAAA,GAAa,kBAAsB,IAAA,QAAA,IAAY,CAAC,SAAA,CAAA;AAEtD,EAAA,uBACG,GAAA,CAAA,SAAA,EAAA;AAAA,IACC,IAAK,EAAA,QAAA;AAAA,IACJ,GAAG,KAAA;AAAA,IACJ,GAAK,EAAA,YAAA;AAAA,IACL,QAAU,EAAA,UAAA;AAAA,GACZ,CAAA,CAAA;AAEJ,CAAC,EAAA;AAYY,MAAA,eAAA,GAAkB,WAG7B,CAAC,EAAE,UAAU,OAAS,EAAA,OAAA,EAAA,GAAY,KAAM,EAAA,EAAG,YAAiB,KAAA;AAC5D,EAAM,MAAA,SAAA,GAAY,UAAU,IAAO,GAAA,QAAA,CAAA;AACnC,EAAA,MAAM,EAAE,UAAY,EAAA,kBAAA,EAAoB,QAAU,EAAA,KAAA,KAAU,aAAc,EAAA,CAAA;AAC1E,EAAM,MAAA,UAAA,GAAa,kBAAsB,IAAA,QAAA,IAAY,CAAC,QAAA,CAAA;AAEtD,EAAA,MAAM,WAAc,GAAA,WAAA;AAAA,IAClB,CAAC,KAAyC,KAAA;AACxC,MAAA,OAAA,GAAU,KAAK,CAAA,CAAA;AAEf,MAAI,IAAA,KAAA,CAAM,oBAAsB,EAAA;AAC9B,QAAA,OAAA;AAAA,OACF;AAEA,MAAM,KAAA,EAAA,CAAA;AAAA,KACR;AAAA,IACA,CAAC,OAAO,OAAO,CAAA;AAAA,GACjB,CAAA;AAEA,EAAA,uBACG,GAAA,CAAA,SAAA,EAAA;AAAA,IACC,IAAK,EAAA,QAAA;AAAA,IACJ,GAAG,KAAA;AAAA,IACJ,GAAK,EAAA,YAAA;AAAA,IACL,QAAU,EAAA,UAAA;AAAA,IACV,OAAS,EAAA,WAAA;AAAA,GACX,CAAA,CAAA;AAEJ,CAAC,EAAA;AAED,IAAI,OAAA,CAAQ,GAAI,CAAA,QAAA,KAAa,YAAc,EAAA;AACzC,EAAA,gBAAA,CAAiB,WAAc,GAAA,uBAAA,CAAA;AAC/B,EAAA,cAAA,CAAe,WAAc,GAAA,qBAAA,CAAA;AAC7B,EAAA,gBAAA,CAAiB,WAAc,GAAA,uBAAA,CAAA;AAC/B,EAAA,eAAA,CAAgB,WAAc,GAAA,sBAAA,CAAA;AAChC;;;;"}
@@ -22,6 +22,13 @@ type ComposerBodyMarks = {
22
22
  [K in ComposerBodyMark]: boolean;
23
23
  };
24
24
 
25
+ interface AiComposerSubmitMessage {
26
+ /**
27
+ * The submitted message text.
28
+ */
29
+ text: string;
30
+ }
31
+
25
32
  type CommentMentionProps = ComponentPropsWithSlot<"span">;
26
33
  type CommentBodyMentionProps = {
27
34
  /**
@@ -498,4 +505,4 @@ interface TimestampProps extends Omit<ComponentPropsWithSlot<"time">, "children"
498
505
  */
499
506
  declare const Timestamp: react.ForwardRefExoticComponent<TimestampProps & react.RefAttributes<HTMLTimeElement>>;
500
507
 
501
- export { AttachmentTooLargeError, index$1 as Comment, CommentBodyComponents, CommentBodyLinkProps, CommentBodyMentionProps, CommentBodyProps, CommentLinkProps, CommentMentionProps, index as Composer, ComposerAttachFilesProps, ComposerAttachmentsDropAreaProps, ComposerBodyMark, ComposerBodyMarks, ComposerContext, ComposerEditorComponents, ComposerEditorFloatingToolbarProps, ComposerEditorLinkProps, ComposerEditorMentionProps, ComposerEditorMentionSuggestionsProps, ComposerEditorProps, ComposerFloatingToolbarProps, ComposerFormProps, ComposerLinkProps, ComposerMarkToggleProps, ComposerMentionProps, ComposerSubmitComment, ComposerSubmitProps, ComposerSuggestionsListItemProps, ComposerSuggestionsListProps, FileSize, FileSizeProps, Timestamp, TimestampProps, useComposer };
508
+ export { AiComposerSubmitMessage, AttachmentTooLargeError, index$1 as Comment, CommentBodyComponents, CommentBodyLinkProps, CommentBodyMentionProps, CommentBodyProps, CommentLinkProps, CommentMentionProps, index as Composer, ComposerAttachFilesProps, ComposerAttachmentsDropAreaProps, ComposerBodyMark, ComposerBodyMarks, ComposerContext, ComposerEditorComponents, ComposerEditorFloatingToolbarProps, ComposerEditorLinkProps, ComposerEditorMentionProps, ComposerEditorMentionSuggestionsProps, ComposerEditorProps, ComposerFloatingToolbarProps, ComposerFormProps, ComposerLinkProps, ComposerMarkToggleProps, ComposerMentionProps, ComposerSubmitComment, ComposerSubmitProps, ComposerSuggestionsListItemProps, ComposerSuggestionsListProps, FileSize, FileSizeProps, Timestamp, TimestampProps, useComposer };
@@ -22,6 +22,13 @@ type ComposerBodyMarks = {
22
22
  [K in ComposerBodyMark]: boolean;
23
23
  };
24
24
 
25
+ interface AiComposerSubmitMessage {
26
+ /**
27
+ * The submitted message text.
28
+ */
29
+ text: string;
30
+ }
31
+
25
32
  type CommentMentionProps = ComponentPropsWithSlot<"span">;
26
33
  type CommentBodyMentionProps = {
27
34
  /**
@@ -498,4 +505,4 @@ interface TimestampProps extends Omit<ComponentPropsWithSlot<"time">, "children"
498
505
  */
499
506
  declare const Timestamp: react.ForwardRefExoticComponent<TimestampProps & react.RefAttributes<HTMLTimeElement>>;
500
507
 
501
- export { AttachmentTooLargeError, index$1 as Comment, CommentBodyComponents, CommentBodyLinkProps, CommentBodyMentionProps, CommentBodyProps, CommentLinkProps, CommentMentionProps, index as Composer, ComposerAttachFilesProps, ComposerAttachmentsDropAreaProps, ComposerBodyMark, ComposerBodyMarks, ComposerContext, ComposerEditorComponents, ComposerEditorFloatingToolbarProps, ComposerEditorLinkProps, ComposerEditorMentionProps, ComposerEditorMentionSuggestionsProps, ComposerEditorProps, ComposerFloatingToolbarProps, ComposerFormProps, ComposerLinkProps, ComposerMarkToggleProps, ComposerMentionProps, ComposerSubmitComment, ComposerSubmitProps, ComposerSuggestionsListItemProps, ComposerSuggestionsListProps, FileSize, FileSizeProps, Timestamp, TimestampProps, useComposer };
508
+ export { AiComposerSubmitMessage, AttachmentTooLargeError, index$1 as Comment, CommentBodyComponents, CommentBodyLinkProps, CommentBodyMentionProps, CommentBodyProps, CommentLinkProps, CommentMentionProps, index as Composer, ComposerAttachFilesProps, ComposerAttachmentsDropAreaProps, ComposerBodyMark, ComposerBodyMarks, ComposerContext, ComposerEditorComponents, ComposerEditorFloatingToolbarProps, ComposerEditorLinkProps, ComposerEditorMentionProps, ComposerEditorMentionSuggestionsProps, ComposerEditorProps, ComposerFloatingToolbarProps, ComposerFormProps, ComposerLinkProps, ComposerMarkToggleProps, ComposerMentionProps, ComposerSubmitComment, ComposerSubmitProps, ComposerSuggestionsListItemProps, ComposerSuggestionsListProps, FileSize, FileSizeProps, Timestamp, TimestampProps, useComposer };
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.2.1" === "string" && "3.2.1";
4
+ const PKG_VERSION = typeof "3.3.1" === "string" && "3.3.1";
5
5
  const PKG_FORMAT = typeof "cjs" === "string" && "cjs";
6
6
 
7
7
  exports.PKG_FORMAT = PKG_FORMAT;
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const PKG_NAME = "@liveblocks/react-ui";
2
- const PKG_VERSION = typeof "3.2.1" === "string" && "3.2.1";
2
+ const PKG_VERSION = typeof "3.3.1" === "string" && "3.3.1";
3
3
  const PKG_FORMAT = typeof "esm" === "string" && "esm";
4
4
 
5
5
  export { PKG_FORMAT, PKG_NAME, PKG_VERSION };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/react-ui",
3
- "version": "3.2.1",
3
+ "version": "3.3.1",
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.2.1",
80
- "@liveblocks/core": "3.2.1",
81
- "@liveblocks/react": "3.2.1",
79
+ "@liveblocks/client": "3.3.1",
80
+ "@liveblocks/core": "3.3.1",
81
+ "@liveblocks/react": "3.3.1",
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",
@@ -306,6 +306,10 @@
306
306
  transition-property: background, color, opacity, box-shadow;
307
307
  }
308
308
 
309
+ &:where([data-variant="ghost"]) {
310
+ background: transparent;
311
+ }
312
+
309
313
  &:where(:has(.lb-button-label)) {
310
314
  gap: calc(0.175 * var(--lb-spacing));
311
315
  padding-inline: calc(0.55 * var(--lb-spacing));
@@ -1591,6 +1595,30 @@
1591
1595
  }
1592
1596
  }
1593
1597
 
1598
+ .lb-thread-show-more {
1599
+ position: relative;
1600
+ z-index: 1;
1601
+ display: flex;
1602
+ gap: calc(0.5 * var(--lb-spacing));
1603
+ justify-content: center;
1604
+ align-items: center;
1605
+
1606
+ &::before,
1607
+ &::after {
1608
+ content: "";
1609
+ z-index: 0;
1610
+ flex: 1 0 auto;
1611
+ min-inline-size: var(--lb-spacing);
1612
+ block-size: 0;
1613
+ border-block-start: 1px dashed var(--lb-foreground-subtle);
1614
+ transition-property: border;
1615
+ }
1616
+ }
1617
+
1618
+ :where(.lb-thread-show-more + .lb-thread-new-indicator) {
1619
+ margin-block-start: calc(0.5 * var(--lb-spacing));
1620
+ }
1621
+
1594
1622
  .lb-thread-new-indicator {
1595
1623
  position: relative;
1596
1624
  z-index: 1;
@@ -2408,18 +2436,16 @@
2408
2436
  }
2409
2437
 
2410
2438
  /*************************************
2411
- * Chat Composer *
2439
+ * AI Composer *
2412
2440
  *************************************/
2413
2441
 
2414
- .lb-ai-chat-composer {
2442
+ .lb-ai-composer {
2415
2443
  position: relative;
2416
2444
  inline-size: 100%;
2417
2445
  color: var(--lb-foreground);
2418
2446
  }
2419
2447
 
2420
- .lb-ai-chat-composer-form:where(
2421
- :has(.lb-ai-chat-composer-editor:not(:focus-visible))
2422
- ) {
2448
+ .lb-ai-composer-form:where(:has(.lb-ai-composer-editor:not(:focus-visible))) {
2423
2449
  :where(.lb-button[data-variant="primary"]) {
2424
2450
  --lb-button-background: var(--lb-foreground-subtle);
2425
2451
 
@@ -2433,7 +2459,7 @@
2433
2459
  }
2434
2460
  }
2435
2461
 
2436
- .lb-ai-chat-composer-editor {
2462
+ .lb-ai-composer-editor {
2437
2463
  max-block-size: 15rem;
2438
2464
  padding: var(--lb-spacing) var(--lb-spacing) 0;
2439
2465
  color: var(--lb-foreground-secondary);
@@ -2476,7 +2502,7 @@
2476
2502
  }
2477
2503
  }
2478
2504
 
2479
- .lb-ai-chat-composer-footer {
2505
+ .lb-ai-composer-footer {
2480
2506
  display: flex;
2481
2507
  gap: calc(0.75 * var(--lb-spacing));
2482
2508
  align-items: center;
@@ -2484,14 +2510,14 @@
2484
2510
  padding: var(--lb-spacing);
2485
2511
  }
2486
2512
 
2487
- .lb-ai-chat-composer-actions,
2488
- .lb-ai-chat-composer-editor-actions {
2513
+ .lb-ai-composer-actions,
2514
+ .lb-ai-composer-editor-actions {
2489
2515
  display: flex;
2490
2516
  gap: calc(0.125 * var(--lb-spacing));
2491
2517
  align-items: center;
2492
2518
  }
2493
2519
 
2494
- .lb-ai-chat-composer-editor-actions {
2520
+ .lb-ai-composer-editor-actions {
2495
2521
  margin-inline-end: auto;
2496
2522
  }
2497
2523