@assistant-ui/react 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  };