@assistant-ui/react 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs CHANGED
@@ -10,137 +10,26 @@ __export(thread_exports, {
10
10
  Empty: () => ThreadEmpty,
11
11
  If: () => ThreadIf,
12
12
  Messages: () => ThreadMessages,
13
- Provider: () => ThreadProvider,
14
13
  Root: () => ThreadRoot,
15
14
  Viewport: () => ThreadViewport
16
15
  });
17
16
 
18
- // src/utils/hooks/useBranches.tsx
19
- import { useCallback, useMemo, useRef } from "react";
20
- var ROOT_ID = "__ROOT_ID__";
21
- var UPCOMING_MESSAGE_ID = "__UPCOMING_MESSAGE_ID__";
22
- var updateBranchData = (data, messages) => {
23
- for (let i = 0; i < messages.length; i++) {
24
- const child = messages[i];
25
- const childId = child.id;
26
- const parentId = messages[i - 1]?.id ?? ROOT_ID;
27
- data.parentMap.set(childId, parentId);
28
- let parentArray = data.branchMap.get(parentId);
29
- if (!parentArray) {
30
- data.branchMap.set(parentId, [childId]);
31
- } else if (!parentArray.includes(childId)) {
32
- parentArray.push(childId);
33
- }
34
- data.snapshots.set(childId, messages);
35
- }
36
- };
37
- var getParentId = (data, messages, message) => {
38
- if (message.id === UPCOMING_MESSAGE_ID) {
39
- const parent = messages.at(-1);
40
- if (!parent)
41
- return ROOT_ID;
42
- return parent.id;
17
+ // src/primitives/thread/ThreadRoot.tsx
18
+ import { forwardRef } from "react";
19
+ import {
20
+ Primitive
21
+ } from "@radix-ui/react-primitive";
22
+ var ThreadRoot = forwardRef(
23
+ (props, ref) => {
24
+ return /* @__PURE__ */ React.createElement(Primitive.div, { ...props, ref });
43
25
  }
44
- const parentId = data.parentMap.get(message.id);
45
- if (!parentId)
46
- throw new Error("Unexpected: Message parent not found");
47
- return parentId;
48
- };
49
- var getBranchStateImpl = (data, messages, message) => {
50
- const parentId = getParentId(data, messages, message);
51
- const branches = data.branchMap.get(parentId) ?? [];
52
- const branchId = message.id === UPCOMING_MESSAGE_ID ? branches.length : branches.indexOf(message.id);
53
- if (branchId === -1)
54
- throw new Error("Unexpected: Message not found in parent children");
55
- const upcomingOffset = message.id === UPCOMING_MESSAGE_ID ? 1 : 0;
56
- return {
57
- branchId,
58
- branchCount: branches.length + upcomingOffset
59
- };
60
- };
61
- var switchToBranchImpl = (data, messages, message, branchId) => {
62
- const parentId = getParentId(data, messages, message);
63
- const branches = data.branchMap.get(parentId);
64
- if (!branches)
65
- throw new Error("Unexpected: Parent children not found");
66
- const newMessageId = branches[branchId];
67
- if (!newMessageId)
68
- throw new Error("Unexpected: Requested branch not found");
69
- if (branchId < 0 || branchId >= branches.length)
70
- throw new Error("Switch to branch called with a branch index out of range");
71
- if (newMessageId === message.id)
72
- return messages;
73
- const snapshot = data.snapshots.get(newMessageId);
74
- if (!snapshot)
75
- throw new Error("Unexpected: Branch snapshot not found");
76
- return snapshot;
77
- };
78
- var sliceMessagesUntil = (messages, message) => {
79
- if (message.id === UPCOMING_MESSAGE_ID)
80
- return messages;
81
- const messageIdx = messages.findIndex((m) => m.id === message.id);
82
- if (messageIdx === -1)
83
- throw new Error("Unexpected: Message not found");
84
- return messages.slice(0, messageIdx);
85
- };
86
- var useChatWithBranches = (chat) => {
87
- const data = useRef({
88
- parentMap: /* @__PURE__ */ new Map(),
89
- branchMap: /* @__PURE__ */ new Map(),
90
- snapshots: /* @__PURE__ */ new Map()
91
- }).current;
92
- updateBranchData(data, chat.messages);
93
- const getBranchState = useCallback(
94
- (message) => {
95
- return getBranchStateImpl(data, chat.messages, message);
96
- },
97
- [chat.messages]
98
- );
99
- const switchToBranch = useCallback(
100
- (message, branchId) => {
101
- const newMessages = switchToBranchImpl(
102
- data,
103
- chat.messages,
104
- message,
105
- branchId
106
- );
107
- chat.setMessages(newMessages);
108
- },
109
- [chat.messages, chat.setMessages]
110
- );
111
- const reloadAt = useCallback(
112
- async (message) => {
113
- const newMessages = sliceMessagesUntil(chat.messages, message);
114
- chat.setMessages(newMessages);
115
- await chat.reload();
116
- },
117
- [chat.messages, chat.setMessages, chat.reload]
118
- );
119
- const editAt = useCallback(
120
- async (message, newMessage) => {
121
- const newMessages = sliceMessagesUntil(chat.messages, message);
122
- chat.setMessages(newMessages);
123
- await chat.append(newMessage);
124
- },
125
- [chat.messages, chat.setMessages, chat.append]
126
- );
127
- return useMemo(
128
- () => ({
129
- ...chat,
130
- getBranchState,
131
- switchToBranch,
132
- editAt,
133
- reloadAt
134
- }),
135
- [chat, getBranchState, switchToBranch, editAt, reloadAt]
136
- );
137
- };
26
+ );
138
27
 
139
28
  // src/utils/context/createStoreContext.tsx
140
29
  import {
141
30
  createContext,
142
31
  useContext,
143
- useMemo as useMemo2,
32
+ useMemo,
144
33
  useState
145
34
  } from "react";
146
35
  import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector";
@@ -179,7 +68,9 @@ var createStoreContext = (providerName) => {
179
68
  return () => listeners.delete(cb);
180
69
  },
181
70
  emit: () => {
182
- listeners.forEach((l) => l());
71
+ for (const listener of listeners) {
72
+ listener();
73
+ }
183
74
  },
184
75
  snapshot: () => {
185
76
  return state;
@@ -190,7 +81,7 @@ var createStoreContext = (providerName) => {
190
81
  }
191
82
  };
192
83
  });
193
- useMemo2(
84
+ useMemo(
194
85
  () => store.setState(unstableContext),
195
86
  Object.values(unstableContext)
196
87
  );
@@ -216,21 +107,6 @@ var createStoreContext = (providerName) => {
216
107
  // src/utils/context/ThreadContext.ts
217
108
  var [ThreadContextProvider, useThreadContext] = createStoreContext("Thread.Provider");
218
109
 
219
- // src/primitives/thread/ThreadProvider.tsx
220
- var ThreadProvider = ({ chat, children }) => {
221
- const branches = useChatWithBranches(chat);
222
- return /* @__PURE__ */ React.createElement(ThreadContextProvider, { chat: branches }, children);
223
- };
224
-
225
- // src/primitives/thread/ThreadRoot.tsx
226
- import { forwardRef } from "react";
227
- import { Primitive } from "@radix-ui/react-primitive";
228
- var ThreadRoot = forwardRef(
229
- (props, ref) => {
230
- return /* @__PURE__ */ React.createElement(Primitive.div, { ...props, ref });
231
- }
232
- );
233
-
234
110
  // src/primitives/thread/ThreadIf.tsx
235
111
  var useThreadIf = (props) => {
236
112
  return useThreadContext("Thread.If", (s) => {
@@ -257,15 +133,17 @@ var ThreadEmpty = ({ children }) => {
257
133
  };
258
134
 
259
135
  // src/primitives/thread/ThreadViewport.tsx
260
- import { forwardRef as forwardRef2, useRef as useRef3, useState as useState2 } from "react";
261
- import { Primitive as Primitive2 } from "@radix-ui/react-primitive";
136
+ import { forwardRef as forwardRef2, useRef as useRef2, useState as useState2 } from "react";
137
+ import {
138
+ Primitive as Primitive2
139
+ } from "@radix-ui/react-primitive";
262
140
  import { useComposedRefs } from "@radix-ui/react-compose-refs";
263
141
  import { composeEventHandlers } from "@radix-ui/primitive";
264
142
 
265
143
  // src/utils/hooks/useOnResizeContent.tsx
266
- import { useLayoutEffect, useRef as useRef2 } from "react";
144
+ import { useLayoutEffect, useRef } from "react";
267
145
  var useOnResizeContent = (ref, callback) => {
268
- const callbackRef = useRef2(callback);
146
+ const callbackRef = useRef(callback);
269
147
  callbackRef.current = callback;
270
148
  useLayoutEffect(() => {
271
149
  const el = ref.current;
@@ -275,31 +153,37 @@ var useOnResizeContent = (ref, callback) => {
275
153
  callbackRef.current();
276
154
  });
277
155
  const mutationObserver = new MutationObserver((mutations) => {
278
- mutations.forEach((mutation) => {
279
- mutation.addedNodes.forEach((node) => {
280
- if (node instanceof HTMLElement) {
156
+ for (const mutation of mutations) {
157
+ for (const node of mutation.addedNodes) {
158
+ if (node instanceof Element) {
281
159
  resizeObserver.observe(node);
282
160
  }
283
- });
284
- mutation.removedNodes.forEach((node) => {
285
- if (node instanceof HTMLElement) {
161
+ }
162
+ for (const node of mutation.removedNodes) {
163
+ if (node instanceof Element) {
286
164
  resizeObserver.unobserve(node);
287
165
  }
288
- });
289
- });
166
+ }
167
+ }
290
168
  callbackRef.current();
291
169
  });
170
+ resizeObserver.observe(el);
292
171
  mutationObserver.observe(el, { childList: true });
172
+ for (const child of el.children) {
173
+ resizeObserver.observe(child);
174
+ console.log("observing child", child);
175
+ }
293
176
  return () => {
177
+ console.log("disconnecting");
294
178
  resizeObserver.disconnect();
295
179
  mutationObserver.disconnect();
296
180
  };
297
- }, []);
181
+ }, [ref.current]);
298
182
  };
299
183
 
300
184
  // src/primitives/thread/ThreadViewport.tsx
301
185
  var ThreadViewport = forwardRef2(({ onScroll, children, ...rest }, forwardedRef) => {
302
- const divRef = useRef3(null);
186
+ const divRef = useRef2(null);
303
187
  const ref = useComposedRefs(forwardedRef, divRef);
304
188
  const [isAtBottom, setIsAtBottom] = useState2(true);
305
189
  useOnResizeContent(divRef, () => {
@@ -312,8 +196,9 @@ var ThreadViewport = forwardRef2(({ onScroll, children, ...rest }, forwardedRef)
312
196
  const div = divRef.current;
313
197
  if (!div)
314
198
  return;
315
- setIsAtBottom(div.scrollHeight - div.scrollTop <= div.clientHeight);
199
+ setIsAtBottom(div.scrollHeight - div.scrollTop <= div.clientHeight + 50);
316
200
  };
201
+ console.log(isAtBottom);
317
202
  return /* @__PURE__ */ React.createElement(
318
203
  Primitive2.div,
319
204
  {
@@ -325,6 +210,127 @@ var ThreadViewport = forwardRef2(({ onScroll, children, ...rest }, forwardedRef)
325
210
  );
326
211
  });
327
212
 
213
+ // src/utils/hooks/useBranches.tsx
214
+ import { useCallback, useMemo as useMemo2, useRef as useRef3 } from "react";
215
+ var ROOT_ID = "__ROOT_ID__";
216
+ var UPCOMING_MESSAGE_ID = "__UPCOMING_MESSAGE_ID__";
217
+ var updateBranchData = (data, messages) => {
218
+ for (let i = 0; i < messages.length; i++) {
219
+ const child = messages[i];
220
+ const childId = child.id;
221
+ const parentId = messages[i - 1]?.id ?? ROOT_ID;
222
+ data.parentMap.set(childId, parentId);
223
+ const parentArray = data.branchMap.get(parentId);
224
+ if (!parentArray) {
225
+ data.branchMap.set(parentId, [childId]);
226
+ } else if (!parentArray.includes(childId)) {
227
+ parentArray.push(childId);
228
+ }
229
+ data.snapshots.set(childId, messages);
230
+ }
231
+ };
232
+ var getParentId = (data, messages, message) => {
233
+ if (message.id === UPCOMING_MESSAGE_ID) {
234
+ const parent = messages.at(-1);
235
+ if (!parent)
236
+ return ROOT_ID;
237
+ return parent.id;
238
+ }
239
+ const parentId = data.parentMap.get(message.id);
240
+ if (!parentId)
241
+ throw new Error("Unexpected: Message parent not found");
242
+ return parentId;
243
+ };
244
+ var getBranchStateImpl = (data, messages, message) => {
245
+ const parentId = getParentId(data, messages, message);
246
+ const branches = data.branchMap.get(parentId) ?? [];
247
+ const branchId = message.id === UPCOMING_MESSAGE_ID ? branches.length : branches.indexOf(message.id);
248
+ if (branchId === -1)
249
+ throw new Error("Unexpected: Message not found in parent children");
250
+ const upcomingOffset = message.id === UPCOMING_MESSAGE_ID ? 1 : 0;
251
+ return {
252
+ branchId,
253
+ branchCount: branches.length + upcomingOffset
254
+ };
255
+ };
256
+ var switchToBranchImpl = (data, messages, message, branchId) => {
257
+ const parentId = getParentId(data, messages, message);
258
+ const branches = data.branchMap.get(parentId);
259
+ if (!branches)
260
+ throw new Error("Unexpected: Parent children not found");
261
+ const newMessageId = branches[branchId];
262
+ if (!newMessageId)
263
+ throw new Error("Unexpected: Requested branch not found");
264
+ if (branchId < 0 || branchId >= branches.length)
265
+ throw new Error("Switch to branch called with a branch index out of range");
266
+ if (newMessageId === message.id)
267
+ return messages;
268
+ const snapshot = data.snapshots.get(newMessageId);
269
+ if (!snapshot)
270
+ throw new Error("Unexpected: Branch snapshot not found");
271
+ return snapshot;
272
+ };
273
+ var sliceMessagesUntil = (messages, message) => {
274
+ if (message.id === UPCOMING_MESSAGE_ID)
275
+ return messages;
276
+ const messageIdx = messages.findIndex((m) => m.id === message.id);
277
+ if (messageIdx === -1)
278
+ throw new Error("Unexpected: Message not found");
279
+ return messages.slice(0, messageIdx);
280
+ };
281
+ var useChatWithBranches = (chat) => {
282
+ const data = useRef3({
283
+ parentMap: /* @__PURE__ */ new Map(),
284
+ branchMap: /* @__PURE__ */ new Map(),
285
+ snapshots: /* @__PURE__ */ new Map()
286
+ }).current;
287
+ updateBranchData(data, chat.messages);
288
+ const getBranchState = useCallback(
289
+ (message) => {
290
+ return getBranchStateImpl(data, chat.messages, message);
291
+ },
292
+ [data, chat.messages]
293
+ );
294
+ const switchToBranch = useCallback(
295
+ (message, branchId) => {
296
+ const newMessages = switchToBranchImpl(
297
+ data,
298
+ chat.messages,
299
+ message,
300
+ branchId
301
+ );
302
+ chat.setMessages(newMessages);
303
+ },
304
+ [data, chat.messages, chat.setMessages]
305
+ );
306
+ const reloadAt = useCallback(
307
+ async (message) => {
308
+ const newMessages = sliceMessagesUntil(chat.messages, message);
309
+ chat.setMessages(newMessages);
310
+ await chat.reload();
311
+ },
312
+ [chat.messages, chat.setMessages, chat.reload]
313
+ );
314
+ const editAt = useCallback(
315
+ async (message, newMessage) => {
316
+ const newMessages = sliceMessagesUntil(chat.messages, message);
317
+ chat.setMessages(newMessages);
318
+ await chat.append(newMessage);
319
+ },
320
+ [chat.messages, chat.setMessages, chat.append]
321
+ );
322
+ return useMemo2(
323
+ () => ({
324
+ ...chat,
325
+ getBranchState,
326
+ switchToBranch,
327
+ editAt,
328
+ reloadAt
329
+ }),
330
+ [chat, getBranchState, switchToBranch, editAt, reloadAt]
331
+ );
332
+ };
333
+
328
334
  // src/primitives/message/index.ts
329
335
  var message_exports = {};
330
336
  __export(message_exports, {
@@ -377,7 +383,9 @@ var MessageProvider = ({
377
383
 
378
384
  // src/primitives/message/MessageRoot.tsx
379
385
  import { forwardRef as forwardRef3 } from "react";
380
- import { Primitive as Primitive3 } from "@radix-ui/react-primitive";
386
+ import {
387
+ Primitive as Primitive3
388
+ } from "@radix-ui/react-primitive";
381
389
  import { composeEventHandlers as composeEventHandlers2 } from "@radix-ui/primitive";
382
390
  var MessageRoot = forwardRef3(
383
391
  ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
@@ -445,35 +453,10 @@ var MessageContent = () => {
445
453
  };
446
454
 
447
455
  // src/primitives/message/MessageEditableContent.tsx
448
- import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
449
- import { forwardRef as forwardRef4, useRef as useRef4 } from "react";
450
-
451
- // src/utils/hooks/useAutosize.tsx
452
- import { useLayoutEffect as useLayoutEffect2 } from "react";
453
- var useAutosize = (ref) => {
454
- const el = ref.current;
455
- useLayoutEffect2(() => {
456
- const el2 = ref.current;
457
- if (!el2)
458
- return;
459
- const callback = () => {
460
- el2.style.height = "0px";
461
- el2.style.height = el2.scrollHeight + "px";
462
- };
463
- el2.addEventListener("input", callback);
464
- callback();
465
- return () => {
466
- el2.removeEventListener("input", callback);
467
- };
468
- }, [ref, el]);
469
- };
470
-
471
- // src/primitives/message/MessageEditableContent.tsx
456
+ import { forwardRef as forwardRef4 } from "react";
472
457
  import { composeEventHandlers as composeEventHandlers3 } from "@radix-ui/primitive";
458
+ import TextareaAutosize from "react-textarea-autosize";
473
459
  var MessageEditableContent = forwardRef4(({ onChange, value, ...rest }, forwardedRef) => {
474
- const textareaRef = useRef4(null);
475
- const ref = useComposedRefs2(forwardedRef, textareaRef);
476
- useAutosize(textareaRef);
477
460
  const [editState, setEditState] = useMessageContext(
478
461
  "Message.EditableContent",
479
462
  (s) => [s.editState, s.setEditState]
@@ -486,10 +469,10 @@ var MessageEditableContent = forwardRef4(({ onChange, value, ...rest }, forwarde
486
469
  "Message.EditableContent may only be rendered when edit mode is enabled. Consider wrapping the component in <Message.If editing>."
487
470
  );
488
471
  return /* @__PURE__ */ React.createElement(
489
- "textarea",
472
+ TextareaAutosize,
490
473
  {
491
474
  ...rest,
492
- ref,
475
+ ref: forwardedRef,
493
476
  onChange: composeEventHandlers3(onChange, handleChange),
494
477
  value: editState.value || value
495
478
  }
@@ -497,15 +480,24 @@ var MessageEditableContent = forwardRef4(({ onChange, value, ...rest }, forwarde
497
480
  });
498
481
 
499
482
  // src/primitives/thread/ThreadMessages.tsx
500
- var ThreadMessages = ({
501
- components: { Message }
502
- }) => {
483
+ var getComponents = (components) => {
484
+ return {
485
+ EditingUserMessage: components.EditingUserMessage ?? components.UserMessage ?? components.Message,
486
+ UserMessage: components.UserMessage ?? components.Message,
487
+ AssistantMessage: components.AssistantMessage ?? components.Message
488
+ };
489
+ };
490
+ var ThreadMessages = ({ components }) => {
503
491
  const chat = useThreadContext("Thread.Messages", (s) => s.chat);
504
492
  const messages = chat.messages;
493
+ const { UserMessage, EditingUserMessage, AssistantMessage } = getComponents(components);
505
494
  if (messages.length === 0)
506
495
  return null;
507
- return /* @__PURE__ */ React.createElement(React.Fragment, null, messages.map((message, index) => {
508
- return /* @__PURE__ */ React.createElement(MessageProvider, { key: index, message }, /* @__PURE__ */ React.createElement(Message, null));
496
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, messages.map((message, idx) => {
497
+ return (
498
+ // biome-ignore lint/suspicious/noArrayIndexKey: fixes a11y issues with branch navigation
499
+ /* @__PURE__ */ React.createElement(MessageProvider, { key: idx, message }, /* @__PURE__ */ React.createElement(MessageIf, { user: true, editing: false }, /* @__PURE__ */ React.createElement(UserMessage, null)), /* @__PURE__ */ React.createElement(MessageIf, { user: true, editing: true }, /* @__PURE__ */ React.createElement(EditingUserMessage, null)), /* @__PURE__ */ React.createElement(MessageIf, { assistant: true }, /* @__PURE__ */ React.createElement(AssistantMessage, null)))
500
+ );
509
501
  }), chat.isLoading && chat.messages[chat.messages.length - 1]?.role !== "assistant" && /* @__PURE__ */ React.createElement(
510
502
  MessageProvider,
511
503
  {
@@ -515,7 +507,7 @@ var ThreadMessages = ({
515
507
  content: "..."
516
508
  }
517
509
  },
518
- /* @__PURE__ */ React.createElement(Message, null)
510
+ /* @__PURE__ */ React.createElement(AssistantMessage, null)
519
511
  ));
520
512
  };
521
513
 
@@ -529,10 +521,12 @@ __export(composer_exports, {
529
521
  });
530
522
 
531
523
  // src/primitives/composer/ComposerRoot.tsx
532
- import { createContext as createContext2, forwardRef as forwardRef5, useContext as useContext2, useMemo as useMemo4, useRef as useRef5 } from "react";
533
- import { Primitive as Primitive4 } from "@radix-ui/react-primitive";
524
+ import { createContext as createContext2, forwardRef as forwardRef5, useContext as useContext2, useMemo as useMemo4, useRef as useRef4 } from "react";
525
+ import {
526
+ Primitive as Primitive4
527
+ } from "@radix-ui/react-primitive";
534
528
  import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
535
- import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
529
+ import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
536
530
  var ComposerContext = createContext2(null);
537
531
  var useComposerContext = () => {
538
532
  const context = useContext2(ComposerContext);
@@ -549,8 +543,8 @@ var ComposerRoot = forwardRef5(
549
543
  "Composer.Root",
550
544
  (s) => s.chat.handleSubmit
551
545
  );
552
- const formRef = useRef5(null);
553
- const ref = useComposedRefs3(forwardedRef, formRef);
546
+ const formRef = useRef4(null);
547
+ const ref = useComposedRefs2(forwardedRef, formRef);
554
548
  const composerContextValue = useMemo4(
555
549
  () => ({
556
550
  submit: () => formRef.current?.dispatchEvent(
@@ -571,10 +565,10 @@ var ComposerRoot = forwardRef5(
571
565
  );
572
566
 
573
567
  // src/primitives/composer/ComposerInput.tsx
574
- import { forwardRef as forwardRef6, useRef as useRef6 } from "react";
568
+ import { forwardRef as forwardRef6 } from "react";
575
569
  import { Slot } from "@radix-ui/react-slot";
576
570
  import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive";
577
- import { useComposedRefs as useComposedRefs4 } from "@radix-ui/react-compose-refs";
571
+ import TextareaAutosize2 from "react-textarea-autosize";
578
572
  var ComposerInput = forwardRef6(({ asChild, onChange, onKeyDown, ...rest }, forwardedRef) => {
579
573
  const chat = useThreadContext(
580
574
  "Composer.Input",
@@ -584,15 +578,12 @@ var ComposerInput = forwardRef6(({ asChild, onChange, onKeyDown, ...rest }, forw
584
578
  isLoading
585
579
  })
586
580
  );
587
- const Component = asChild ? Slot : "textarea";
588
- const textareaRef = useRef6(null);
589
- const ref = useComposedRefs4(forwardedRef, textareaRef);
590
- useAutosize(textareaRef);
581
+ const Component = asChild ? Slot : TextareaAutosize2;
591
582
  const composer = useComposerContext();
592
583
  const handleKeyPress = (e) => {
593
584
  if (chat.isLoading || rest.disabled)
594
585
  return;
595
- if (e.key === "Enter" && e.shiftKey == false) {
586
+ if (e.key === "Enter" && e.shiftKey === false) {
596
587
  e.preventDefault();
597
588
  composer.submit();
598
589
  }
@@ -602,7 +593,7 @@ var ComposerInput = forwardRef6(({ asChild, onChange, onKeyDown, ...rest }, forw
602
593
  {
603
594
  value: chat.input,
604
595
  ...rest,
605
- ref,
596
+ ref: forwardedRef,
606
597
  onChange: composeEventHandlers5(onChange, chat.handleInputChange),
607
598
  onKeyDown: composeEventHandlers5(onKeyDown, handleKeyPress)
608
599
  }
@@ -611,7 +602,9 @@ var ComposerInput = forwardRef6(({ asChild, onChange, onKeyDown, ...rest }, forw
611
602
 
612
603
  // src/primitives/composer/ComposerSend.tsx
613
604
  import { forwardRef as forwardRef7 } from "react";
614
- import { Primitive as Primitive5 } from "@radix-ui/react-primitive";
605
+ import {
606
+ Primitive as Primitive5
607
+ } from "@radix-ui/react-primitive";
615
608
  var ComposerSend = forwardRef7(
616
609
  ({ disabled, ...rest }, ref) => {
617
610
  const input = useThreadContext("Composer.Send", (s) => s.chat.input);
@@ -629,7 +622,9 @@ var ComposerSend = forwardRef7(
629
622
 
630
623
  // src/utils/createActionButton.tsx
631
624
  import { forwardRef as forwardRef8 } from "react";
632
- import { Primitive as Primitive6 } from "@radix-ui/react-primitive";
625
+ import {
626
+ Primitive as Primitive6
627
+ } from "@radix-ui/react-primitive";
633
628
  import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primitive";
634
629
  var createActionButton = (useActionButton) => {
635
630
  return forwardRef8(
@@ -671,41 +666,59 @@ __export(branchPicker_exports, {
671
666
  Root: () => BranchPickerRoot
672
667
  });
673
668
 
674
- // src/primitives/branchPicker/BranchPickerNext.tsx
675
- var useBranchPickerNext = () => {
669
+ // src/actions/useGoToNextBranch.tsx
670
+ var useGoToNextBranch = () => {
676
671
  const switchToBranch = useThreadContext(
677
672
  "BranchPicker.Next",
678
673
  (s) => s.chat.switchToBranch
679
674
  );
680
- const [message, { branchId, branchCount }] = useMessageContext(
681
- "BranchPicker.Next",
682
- (s) => [s.message, s.branchState]
683
- );
684
- if (branchCount <= 1 || branchId + 1 >= branchCount)
675
+ const context = useMessageContext("BranchPicker.Next", (s) => {
676
+ const {
677
+ message: message2,
678
+ editState: { isEditing },
679
+ branchState: { branchId: branchId2, branchCount }
680
+ } = s;
681
+ if (isEditing || branchCount <= 1 || branchId2 + 1 >= branchCount)
682
+ return null;
683
+ return { message: message2, branchId: branchId2 };
684
+ });
685
+ if (!context)
685
686
  return null;
687
+ const { message, branchId } = context;
686
688
  return () => {
687
689
  switchToBranch(message, branchId + 1);
688
690
  };
689
691
  };
690
- var BranchPickerNext = createActionButton(useBranchPickerNext);
691
692
 
692
- // src/primitives/branchPicker/BranchPickerPrevious.tsx
693
- var useBranchPickerPrevious = () => {
693
+ // src/primitives/branchPicker/BranchPickerNext.tsx
694
+ var BranchPickerNext = createActionButton(useGoToNextBranch);
695
+
696
+ // src/actions/useGoToPreviousBranch.tsx
697
+ var useGoToPreviousBranch = () => {
694
698
  const switchToBranch = useThreadContext(
695
699
  "BranchPicker.Previous",
696
700
  (s) => s.chat.switchToBranch
697
701
  );
698
- const [message, { branchId, branchCount }] = useMessageContext(
699
- "BranchPicker.Previous",
700
- (s) => [s.message, s.branchState]
701
- );
702
- if (branchCount <= 1 || branchId <= 0)
702
+ const context = useMessageContext("BranchPicker.Previous", (s) => {
703
+ const {
704
+ message: message2,
705
+ editState: { isEditing },
706
+ branchState: { branchId: branchId2, branchCount }
707
+ } = s;
708
+ if (isEditing || branchCount <= 1 || branchId2 <= 0)
709
+ return null;
710
+ return { message: message2, branchId: branchId2 };
711
+ });
712
+ if (!context)
703
713
  return null;
714
+ const { message, branchId } = context;
704
715
  return () => {
705
716
  switchToBranch(message, branchId - 1);
706
717
  };
707
718
  };
708
- var BranchPickerPrevious = createActionButton(useBranchPickerPrevious);
719
+
720
+ // src/primitives/branchPicker/BranchPickerPrevious.tsx
721
+ var BranchPickerPrevious = createActionButton(useGoToPreviousBranch);
709
722
 
710
723
  // src/primitives/branchPicker/BranchPickerCount.tsx
711
724
  var BranchPickerCount = () => {
@@ -726,10 +739,12 @@ var BranchPickerNumber = () => {
726
739
  };
727
740
 
728
741
  // src/primitives/branchPicker/BranchPickerRoot.tsx
742
+ import {
743
+ Primitive as Primitive7
744
+ } from "@radix-ui/react-primitive";
729
745
  import { forwardRef as forwardRef9 } from "react";
730
- import { Primitive as Primitive7 } from "@radix-ui/react-primitive";
731
- var BranchPickerRoot = forwardRef9(({ ...rest }, ref) => {
732
- return /* @__PURE__ */ React.createElement(Primitive7.div, { ...rest, ref });
746
+ var BranchPickerRoot = forwardRef9(({ hideWhenSingleBranch, ...rest }, ref) => {
747
+ return /* @__PURE__ */ React.createElement(MessageIf, { hasBranches: hideWhenSingleBranch ? true : void 0 }, /* @__PURE__ */ React.createElement(Primitive7.div, { ...rest, ref }));
733
748
  });
734
749
 
735
750
  // src/primitives/actionBar/index.ts
@@ -742,51 +757,81 @@ __export(actionBar_exports, {
742
757
  });
743
758
 
744
759
  // src/primitives/actionBar/ActionBarRoot.tsx
760
+ import {
761
+ Primitive as Primitive8
762
+ } from "@radix-ui/react-primitive";
745
763
  import { forwardRef as forwardRef10 } from "react";
746
- import { Primitive as Primitive8 } from "@radix-ui/react-primitive";
747
- var ActionBarRoot = forwardRef10(
748
- ({ ...rest }, ref) => {
749
- return /* @__PURE__ */ React.createElement(Primitive8.div, { ...rest, ref });
750
- }
751
- );
764
+ var ActionBarRoot = forwardRef10(({ ...rest }, ref) => {
765
+ return /* @__PURE__ */ React.createElement(Primitive8.div, { ...rest, ref });
766
+ });
752
767
 
753
- // src/primitives/actionBar/ActionBarCopy.tsx
754
- var useActionBarCopy = ({ copiedDuration = 3e3 }) => {
755
- const [messageContent, setIsCopied] = useMessageContext(
756
- "ActionBar.Copy",
757
- (s) => [s.message.content, s.setIsCopied]
758
- );
768
+ // src/actions/useCopyMessage.tsx
769
+ var useCopyMessage = ({ copiedDuration = 3e3 }) => {
770
+ const context = useMessageContext("ActionBar.Copy", (s) => {
771
+ const {
772
+ editState: { isEditing },
773
+ message: { content: content2 },
774
+ setIsCopied: setIsCopied2
775
+ } = s;
776
+ if (isEditing)
777
+ return null;
778
+ return { content: content2, setIsCopied: setIsCopied2 };
779
+ });
780
+ if (!context)
781
+ return null;
782
+ const { content, setIsCopied } = context;
759
783
  return () => {
760
- navigator.clipboard.writeText(messageContent);
784
+ navigator.clipboard.writeText(content);
761
785
  setIsCopied(true);
762
786
  setTimeout(() => setIsCopied(false), copiedDuration);
763
787
  };
764
788
  };
765
- var ActionBarCopy = createActionButton(useActionBarCopy);
766
789
 
767
- // src/primitives/actionBar/ActionBarReload.tsx
768
- var useActionBarReload = () => {
769
- const chat = useThreadContext("ActionBar.Reload", (s) => s.chat);
770
- const message = useMessageContext("ActionBar.Reload", (s) => s.message);
771
- if (message.role !== "assistant" || chat.isLoading)
790
+ // src/primitives/actionBar/ActionBarCopy.tsx
791
+ var ActionBarCopy = createActionButton(useCopyMessage);
792
+
793
+ // src/actions/useReloadMessage.tsx
794
+ var useReloadMessage = () => {
795
+ const [isLoading, reloadAt] = useThreadContext("ActionBar.Reload", (s) => [
796
+ s.chat.isLoading,
797
+ s.chat.reloadAt
798
+ ]);
799
+ const message = useMessageContext("ActionBar.Reload", (s) => {
800
+ const message2 = s.message;
801
+ if (message2.role !== "assistant" || isLoading)
802
+ return null;
803
+ return message2;
804
+ });
805
+ if (!message)
772
806
  return null;
773
- return () => chat.reloadAt(message);
807
+ return () => reloadAt(message);
774
808
  };
775
- var ActionBarReload = createActionButton(useActionBarReload);
776
809
 
777
- // src/primitives/actionBar/ActionBarEdit.tsx
778
- var useActionBarEdit = () => {
779
- const [editState, messageContent, setEditState] = useMessageContext(
780
- "ActionBar.Edit",
781
- (s) => [s.editState, s.message.content, s.setEditState]
782
- );
783
- if (editState.isEditing)
810
+ // src/primitives/actionBar/ActionBarReload.tsx
811
+ var ActionBarReload = createActionButton(useReloadMessage);
812
+
813
+ // src/actions/useBeginMessageEdit.tsx
814
+ var useBeginMessageEdit = () => {
815
+ const context = useMessageContext("ActionBar.Edit", (s) => {
816
+ const {
817
+ message: { content: content2 },
818
+ editState: { isEditing },
819
+ setEditState: setEditState2
820
+ } = s;
821
+ if (isEditing)
822
+ return null;
823
+ return { content: content2, setEditState: setEditState2 };
824
+ });
825
+ if (!context)
784
826
  return null;
827
+ const { content, setEditState } = context;
785
828
  return () => {
786
- setEditState({ isEditing: true, value: messageContent });
829
+ setEditState({ isEditing: true, value: content });
787
830
  };
788
831
  };
789
- var ActionBarEdit = createActionButton(useActionBarEdit);
832
+
833
+ // src/primitives/actionBar/ActionBarEdit.tsx
834
+ var ActionBarEdit = createActionButton(useBeginMessageEdit);
790
835
 
791
836
  // src/primitives/editBar/index.ts
792
837
  var editBar_exports = {};
@@ -797,56 +842,86 @@ __export(editBar_exports, {
797
842
  });
798
843
 
799
844
  // src/primitives/editBar/EditBarRoot.tsx
845
+ import {
846
+ Primitive as Primitive9
847
+ } from "@radix-ui/react-primitive";
800
848
  import { forwardRef as forwardRef11 } from "react";
801
- import { Primitive as Primitive9 } from "@radix-ui/react-primitive";
802
849
  var EditBarRoot = forwardRef11(
803
850
  ({ ...rest }, ref) => {
804
851
  return /* @__PURE__ */ React.createElement(Primitive9.div, { ...rest, ref });
805
852
  }
806
853
  );
807
854
 
808
- // src/primitives/editBar/EditBarSave.tsx
809
- var useEditBarSave = () => {
855
+ // src/actions/useSaveMessageEdit.tsx
856
+ var useSaveMessageEdit = () => {
810
857
  const chat = useThreadContext("EditBar.Save", (s) => s.chat);
811
- const [editState, message, setEditState] = useMessageContext(
812
- "EditBar.Save",
813
- (s) => [s.editState, s.message, s.setEditState]
814
- );
815
- if (!editState.isEditing)
858
+ const context = useMessageContext("EditBar.Save", (s) => {
859
+ const { message: message2, editState, setEditState: setEditState2 } = s;
860
+ if (!editState.isEditing)
861
+ return null;
862
+ return { message: message2, content: editState.value, setEditState: setEditState2 };
863
+ });
864
+ if (!context)
816
865
  return null;
866
+ const { message, content, setEditState } = context;
817
867
  return () => {
818
- if (!editState.isEditing)
819
- return;
820
868
  chat.editAt(message, {
821
869
  ...message,
822
870
  id: void 0,
823
871
  // remove id to create a new message
824
- content: editState.value
872
+ content
825
873
  });
826
874
  setEditState({ isEditing: false });
827
875
  };
828
876
  };
829
- var EditBarSave = createActionButton(useEditBarSave);
830
877
 
831
- // src/primitives/editBar/EditBarCancel.tsx
832
- var useEditBarCancel = () => {
833
- const [isEditing, setEditState] = useMessageContext("EditBar.Cancel", (s) => [
834
- s.editState.isEditing,
835
- s.setEditState
836
- ]);
837
- if (!isEditing)
878
+ // src/primitives/editBar/EditBarSave.tsx
879
+ var EditBarSave = createActionButton(useSaveMessageEdit);
880
+
881
+ // src/actions/useCancelMessageEdit.tsx
882
+ var useCancelMessageEdit = () => {
883
+ const context = useMessageContext("EditBar.Cancel", (s) => {
884
+ const {
885
+ editState: { isEditing },
886
+ setEditState: setEditState2
887
+ } = s;
888
+ if (!isEditing)
889
+ return null;
890
+ return { setEditState: setEditState2 };
891
+ });
892
+ if (!context)
838
893
  return null;
894
+ const { setEditState } = context;
839
895
  return () => {
840
896
  setEditState({ isEditing: false });
841
897
  };
842
898
  };
843
- var EditBarCancel = createActionButton(useEditBarCancel);
899
+
900
+ // src/primitives/editBar/EditBarCancel.tsx
901
+ var EditBarCancel = createActionButton(useCancelMessageEdit);
902
+
903
+ // src/vercel/VercelAIThreadProvider.tsx
904
+ var VercelAIThreadProvider = ({
905
+ chat,
906
+ children
907
+ }) => {
908
+ const branches = useChatWithBranches(chat);
909
+ return /* @__PURE__ */ React.createElement(ThreadContextProvider, { chat: branches }, children);
910
+ };
844
911
  export {
845
- actionBar_exports as ActionBar,
846
- branchPicker_exports as BranchPicker,
847
- composer_exports as Composer,
848
- editBar_exports as EditBar,
849
- message_exports as Message,
850
- thread_exports as Thread,
851
- useMessageContext as unstable_useMessageContext
912
+ actionBar_exports as ActionBarPrimitive,
913
+ branchPicker_exports as BranchPickerPrimitive,
914
+ composer_exports as ComposerPrimitive,
915
+ editBar_exports as EditBarPrimitive,
916
+ message_exports as MessagePrimitive,
917
+ thread_exports as ThreadPrimitive,
918
+ VercelAIThreadProvider,
919
+ useMessageContext as unstable_useMessageContext,
920
+ useBeginMessageEdit,
921
+ useCancelMessageEdit,
922
+ useCopyMessage,
923
+ useGoToNextBranch,
924
+ useGoToPreviousBranch,
925
+ useReloadMessage,
926
+ useSaveMessageEdit
852
927
  };