@assistant-ui/react 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs ADDED
@@ -0,0 +1,852 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/primitives/thread/index.ts
8
+ var thread_exports = {};
9
+ __export(thread_exports, {
10
+ Empty: () => ThreadEmpty,
11
+ If: () => ThreadIf,
12
+ Messages: () => ThreadMessages,
13
+ Provider: () => ThreadProvider,
14
+ Root: () => ThreadRoot,
15
+ Viewport: () => ThreadViewport
16
+ });
17
+
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;
43
+ }
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
+ };
138
+
139
+ // src/utils/context/createStoreContext.tsx
140
+ import {
141
+ createContext,
142
+ useContext,
143
+ useMemo as useMemo2,
144
+ useState
145
+ } from "react";
146
+ import { useSyncExternalStoreWithSelector } from "use-sync-external-store/with-selector";
147
+
148
+ // src/utils/context/shallow.ts
149
+ function shallow(objA, objB) {
150
+ if (Object.is(objA, objB)) {
151
+ return true;
152
+ }
153
+ if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) {
154
+ return false;
155
+ }
156
+ const keysA = Object.keys(objA);
157
+ if (keysA.length !== Object.keys(objB).length) {
158
+ return false;
159
+ }
160
+ for (const keyA of keysA) {
161
+ if (!Object.prototype.hasOwnProperty.call(objB, keyA) || !Object.is(objA[keyA], objB[keyA])) {
162
+ return false;
163
+ }
164
+ }
165
+ return true;
166
+ }
167
+
168
+ // src/utils/context/createStoreContext.tsx
169
+ var createStoreContext = (providerName) => {
170
+ const context = createContext(null);
171
+ const StoreProvider = ({ children, ...rest }) => {
172
+ const unstableContext = rest;
173
+ const [store] = useState(() => {
174
+ let state = unstableContext;
175
+ const listeners = /* @__PURE__ */ new Set();
176
+ return {
177
+ subscribe: (cb) => {
178
+ listeners.add(cb);
179
+ return () => listeners.delete(cb);
180
+ },
181
+ emit: () => {
182
+ listeners.forEach((l) => l());
183
+ },
184
+ snapshot: () => {
185
+ return state;
186
+ },
187
+ setState: (value) => {
188
+ state = value;
189
+ store.emit();
190
+ }
191
+ };
192
+ });
193
+ useMemo2(
194
+ () => store.setState(unstableContext),
195
+ Object.values(unstableContext)
196
+ );
197
+ return /* @__PURE__ */ React.createElement(context.Provider, { value: store }, children);
198
+ };
199
+ const useStoreContext = (consumerName, selector) => {
200
+ const store = useContext(context);
201
+ if (!store)
202
+ throw new Error(
203
+ `${consumerName} can only be used inside ${providerName}.`
204
+ );
205
+ return useSyncExternalStoreWithSelector(
206
+ store.subscribe,
207
+ store.snapshot,
208
+ store.snapshot,
209
+ selector,
210
+ shallow
211
+ );
212
+ };
213
+ return [StoreProvider, useStoreContext];
214
+ };
215
+
216
+ // src/utils/context/ThreadContext.ts
217
+ var [ThreadContextProvider, useThreadContext] = createStoreContext("Thread.Provider");
218
+
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
+ // src/primitives/thread/ThreadIf.tsx
235
+ var useThreadIf = (props) => {
236
+ return useThreadContext("Thread.If", (s) => {
237
+ const thread = s.chat;
238
+ if (props.empty === true && thread.messages.length !== 0)
239
+ return false;
240
+ if (props.empty === false && thread.messages.length === 0)
241
+ return false;
242
+ if (props.busy === true && !thread.isLoading)
243
+ return false;
244
+ if (props.busy === false && thread.isLoading)
245
+ return false;
246
+ return true;
247
+ });
248
+ };
249
+ var ThreadIf = ({ children, ...query }) => {
250
+ const result = useThreadIf(query);
251
+ return result ? children : null;
252
+ };
253
+
254
+ // src/primitives/thread/ThreadEmpty.tsx
255
+ var ThreadEmpty = ({ children }) => {
256
+ return /* @__PURE__ */ React.createElement(ThreadIf, { empty: true }, children);
257
+ };
258
+
259
+ // 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";
262
+ import { useComposedRefs } from "@radix-ui/react-compose-refs";
263
+ import { composeEventHandlers } from "@radix-ui/primitive";
264
+
265
+ // src/utils/hooks/useOnResizeContent.tsx
266
+ import { useLayoutEffect, useRef as useRef2 } from "react";
267
+ var useOnResizeContent = (ref, callback) => {
268
+ const callbackRef = useRef2(callback);
269
+ callbackRef.current = callback;
270
+ useLayoutEffect(() => {
271
+ const el = ref.current;
272
+ if (!el)
273
+ return;
274
+ const resizeObserver = new ResizeObserver(() => {
275
+ callbackRef.current();
276
+ });
277
+ const mutationObserver = new MutationObserver((mutations) => {
278
+ mutations.forEach((mutation) => {
279
+ mutation.addedNodes.forEach((node) => {
280
+ if (node instanceof HTMLElement) {
281
+ resizeObserver.observe(node);
282
+ }
283
+ });
284
+ mutation.removedNodes.forEach((node) => {
285
+ if (node instanceof HTMLElement) {
286
+ resizeObserver.unobserve(node);
287
+ }
288
+ });
289
+ });
290
+ callbackRef.current();
291
+ });
292
+ mutationObserver.observe(el, { childList: true });
293
+ return () => {
294
+ resizeObserver.disconnect();
295
+ mutationObserver.disconnect();
296
+ };
297
+ }, []);
298
+ };
299
+
300
+ // src/primitives/thread/ThreadViewport.tsx
301
+ var ThreadViewport = forwardRef2(({ onScroll, children, ...rest }, forwardedRef) => {
302
+ const divRef = useRef3(null);
303
+ const ref = useComposedRefs(forwardedRef, divRef);
304
+ const [isAtBottom, setIsAtBottom] = useState2(true);
305
+ useOnResizeContent(divRef, () => {
306
+ const div = divRef.current;
307
+ if (!div || !isAtBottom)
308
+ return;
309
+ div.scrollTop = div.scrollHeight;
310
+ });
311
+ const handleScroll = () => {
312
+ const div = divRef.current;
313
+ if (!div)
314
+ return;
315
+ setIsAtBottom(div.scrollHeight - div.scrollTop <= div.clientHeight);
316
+ };
317
+ return /* @__PURE__ */ React.createElement(
318
+ Primitive2.div,
319
+ {
320
+ ...rest,
321
+ onScroll: composeEventHandlers(onScroll, handleScroll),
322
+ ref
323
+ },
324
+ children
325
+ );
326
+ });
327
+
328
+ // src/primitives/message/index.ts
329
+ var message_exports = {};
330
+ __export(message_exports, {
331
+ Content: () => MessageContent,
332
+ EditableContent: () => MessageEditableContent,
333
+ If: () => MessageIf,
334
+ Provider: () => MessageProvider,
335
+ Root: () => MessageRoot
336
+ });
337
+
338
+ // src/primitives/message/MessageProvider.tsx
339
+ import { useMemo as useMemo3, useState as useState3 } from "react";
340
+
341
+ // src/utils/context/MessageContext.ts
342
+ var [MessageContextProvider, useMessageContext] = createStoreContext("Thread.Provider");
343
+
344
+ // src/primitives/message/MessageProvider.tsx
345
+ var MessageProvider = ({
346
+ message,
347
+ children
348
+ }) => {
349
+ const getBranchState = useThreadContext(
350
+ "Message.Provider",
351
+ (s) => s.chat.getBranchState
352
+ );
353
+ const [editState, setEditState] = useState3({
354
+ isEditing: false
355
+ });
356
+ const [isCopied, setIsCopied] = useState3(false);
357
+ const [isHovering, setIsHovering] = useState3(false);
358
+ const branchState = useMemo3(
359
+ () => getBranchState(message),
360
+ [getBranchState, message]
361
+ );
362
+ return /* @__PURE__ */ React.createElement(
363
+ MessageContextProvider,
364
+ {
365
+ message,
366
+ editState,
367
+ setEditState,
368
+ branchState,
369
+ isCopied,
370
+ setIsCopied,
371
+ isHovering,
372
+ setIsHovering
373
+ },
374
+ children
375
+ );
376
+ };
377
+
378
+ // src/primitives/message/MessageRoot.tsx
379
+ import { forwardRef as forwardRef3 } from "react";
380
+ import { Primitive as Primitive3 } from "@radix-ui/react-primitive";
381
+ import { composeEventHandlers as composeEventHandlers2 } from "@radix-ui/primitive";
382
+ var MessageRoot = forwardRef3(
383
+ ({ onMouseEnter, onMouseLeave, ...rest }, ref) => {
384
+ const setIsHovering = useMessageContext(
385
+ "Message.Root",
386
+ (s) => s.setIsHovering
387
+ );
388
+ const handleMouseEnter = () => {
389
+ setIsHovering(true);
390
+ };
391
+ const handleMouseLeave = () => {
392
+ setIsHovering(false);
393
+ };
394
+ return /* @__PURE__ */ React.createElement(
395
+ Primitive3.div,
396
+ {
397
+ ...rest,
398
+ ref,
399
+ onMouseEnter: composeEventHandlers2(onMouseEnter, handleMouseEnter),
400
+ onMouseLeave: composeEventHandlers2(onMouseLeave, handleMouseLeave)
401
+ }
402
+ );
403
+ }
404
+ );
405
+
406
+ // src/primitives/message/MessageIf.tsx
407
+ var useMessageIf = (props) => {
408
+ const thread = useThreadContext("Message.If", (s) => s.chat);
409
+ return useMessageContext(
410
+ "Message.If",
411
+ ({ message, editState: { isEditing }, isCopied, isHovering }) => {
412
+ const { branchCount } = thread.getBranchState(message);
413
+ if (props.hasBranches === true && branchCount < 2)
414
+ return false;
415
+ if (props.user && message.role !== "user")
416
+ return false;
417
+ if (props.assistant && message.role !== "assistant")
418
+ return false;
419
+ if (props.editing === true && !isEditing)
420
+ return false;
421
+ if (props.editing === false && isEditing)
422
+ return false;
423
+ if (props.unstable_hoveringOrLast === true && !isHovering && thread.messages[thread.messages.length - 1]?.id !== message.id)
424
+ return false;
425
+ if (props.copied === true && !isCopied)
426
+ return false;
427
+ if (props.copied === false && isCopied)
428
+ return false;
429
+ return true;
430
+ }
431
+ );
432
+ };
433
+ var MessageIf = ({ children, ...query }) => {
434
+ const result = useMessageIf(query);
435
+ return result ? children : null;
436
+ };
437
+
438
+ // src/primitives/message/MessageContent.tsx
439
+ var MessageContent = () => {
440
+ const content = useMessageContext(
441
+ "Message.Content",
442
+ (s) => s.message.content
443
+ );
444
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, content);
445
+ };
446
+
447
+ // 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
472
+ import { composeEventHandlers as composeEventHandlers3 } from "@radix-ui/primitive";
473
+ var MessageEditableContent = forwardRef4(({ onChange, value, ...rest }, forwardedRef) => {
474
+ const textareaRef = useRef4(null);
475
+ const ref = useComposedRefs2(forwardedRef, textareaRef);
476
+ useAutosize(textareaRef);
477
+ const [editState, setEditState] = useMessageContext(
478
+ "Message.EditableContent",
479
+ (s) => [s.editState, s.setEditState]
480
+ );
481
+ const handleChange = (e) => {
482
+ setEditState({ isEditing: true, value: e.target.value });
483
+ };
484
+ if (!editState.isEditing)
485
+ throw new Error(
486
+ "Message.EditableContent may only be rendered when edit mode is enabled. Consider wrapping the component in <Message.If editing>."
487
+ );
488
+ return /* @__PURE__ */ React.createElement(
489
+ "textarea",
490
+ {
491
+ ...rest,
492
+ ref,
493
+ onChange: composeEventHandlers3(onChange, handleChange),
494
+ value: editState.value || value
495
+ }
496
+ );
497
+ });
498
+
499
+ // src/primitives/thread/ThreadMessages.tsx
500
+ var ThreadMessages = ({
501
+ components: { Message }
502
+ }) => {
503
+ const chat = useThreadContext("Thread.Messages", (s) => s.chat);
504
+ const messages = chat.messages;
505
+ if (messages.length === 0)
506
+ 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));
509
+ }), chat.isLoading && chat.messages[chat.messages.length - 1]?.role !== "assistant" && /* @__PURE__ */ React.createElement(
510
+ MessageProvider,
511
+ {
512
+ message: {
513
+ id: UPCOMING_MESSAGE_ID,
514
+ role: "assistant",
515
+ content: "..."
516
+ }
517
+ },
518
+ /* @__PURE__ */ React.createElement(Message, null)
519
+ ));
520
+ };
521
+
522
+ // src/primitives/composer/index.ts
523
+ var composer_exports = {};
524
+ __export(composer_exports, {
525
+ Input: () => ComposerInput,
526
+ Root: () => ComposerRoot,
527
+ Send: () => ComposerSend,
528
+ Stop: () => ComposerStop
529
+ });
530
+
531
+ // 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";
534
+ import { composeEventHandlers as composeEventHandlers4 } from "@radix-ui/primitive";
535
+ import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
536
+ var ComposerContext = createContext2(null);
537
+ var useComposerContext = () => {
538
+ const context = useContext2(ComposerContext);
539
+ if (!context) {
540
+ throw new Error(
541
+ "Composer compound components cannot be rendered outside the Composer component"
542
+ );
543
+ }
544
+ return context;
545
+ };
546
+ var ComposerRoot = forwardRef5(
547
+ ({ onSubmit, ...rest }, forwardedRef) => {
548
+ const handleSubmit = useThreadContext(
549
+ "Composer.Root",
550
+ (s) => s.chat.handleSubmit
551
+ );
552
+ const formRef = useRef5(null);
553
+ const ref = useComposedRefs3(forwardedRef, formRef);
554
+ const composerContextValue = useMemo4(
555
+ () => ({
556
+ submit: () => formRef.current?.dispatchEvent(
557
+ new Event("submit", { cancelable: true, bubbles: true })
558
+ )
559
+ }),
560
+ []
561
+ );
562
+ return /* @__PURE__ */ React.createElement(ComposerContext.Provider, { value: composerContextValue }, /* @__PURE__ */ React.createElement(
563
+ Primitive4.form,
564
+ {
565
+ ...rest,
566
+ ref,
567
+ onSubmit: composeEventHandlers4(onSubmit, handleSubmit)
568
+ }
569
+ ));
570
+ }
571
+ );
572
+
573
+ // src/primitives/composer/ComposerInput.tsx
574
+ import { forwardRef as forwardRef6, useRef as useRef6 } from "react";
575
+ import { Slot } from "@radix-ui/react-slot";
576
+ import { composeEventHandlers as composeEventHandlers5 } from "@radix-ui/primitive";
577
+ import { useComposedRefs as useComposedRefs4 } from "@radix-ui/react-compose-refs";
578
+ var ComposerInput = forwardRef6(({ asChild, onChange, onKeyDown, ...rest }, forwardedRef) => {
579
+ const chat = useThreadContext(
580
+ "Composer.Input",
581
+ ({ chat: { input, handleInputChange, isLoading } }) => ({
582
+ input,
583
+ handleInputChange,
584
+ isLoading
585
+ })
586
+ );
587
+ const Component = asChild ? Slot : "textarea";
588
+ const textareaRef = useRef6(null);
589
+ const ref = useComposedRefs4(forwardedRef, textareaRef);
590
+ useAutosize(textareaRef);
591
+ const composer = useComposerContext();
592
+ const handleKeyPress = (e) => {
593
+ if (chat.isLoading || rest.disabled)
594
+ return;
595
+ if (e.key === "Enter" && e.shiftKey == false) {
596
+ e.preventDefault();
597
+ composer.submit();
598
+ }
599
+ };
600
+ return /* @__PURE__ */ React.createElement(
601
+ Component,
602
+ {
603
+ value: chat.input,
604
+ ...rest,
605
+ ref,
606
+ onChange: composeEventHandlers5(onChange, chat.handleInputChange),
607
+ onKeyDown: composeEventHandlers5(onKeyDown, handleKeyPress)
608
+ }
609
+ );
610
+ });
611
+
612
+ // src/primitives/composer/ComposerSend.tsx
613
+ import { forwardRef as forwardRef7 } from "react";
614
+ import { Primitive as Primitive5 } from "@radix-ui/react-primitive";
615
+ var ComposerSend = forwardRef7(
616
+ ({ disabled, ...rest }, ref) => {
617
+ const input = useThreadContext("Composer.Send", (s) => s.chat.input);
618
+ return /* @__PURE__ */ React.createElement(
619
+ Primitive5.button,
620
+ {
621
+ type: "submit",
622
+ ...rest,
623
+ ref,
624
+ disabled: disabled || input.length === 0
625
+ }
626
+ );
627
+ }
628
+ );
629
+
630
+ // src/utils/createActionButton.tsx
631
+ import { forwardRef as forwardRef8 } from "react";
632
+ import { Primitive as Primitive6 } from "@radix-ui/react-primitive";
633
+ import { composeEventHandlers as composeEventHandlers6 } from "@radix-ui/primitive";
634
+ var createActionButton = (useActionButton) => {
635
+ return forwardRef8(
636
+ (props, forwardedRef) => {
637
+ const onClick = useActionButton(props);
638
+ return /* @__PURE__ */ React.createElement(
639
+ Primitive6.button,
640
+ {
641
+ type: "button",
642
+ disabled: !onClick,
643
+ ...props,
644
+ ref: forwardedRef,
645
+ onClick: composeEventHandlers6(props.onClick, onClick ?? void 0)
646
+ }
647
+ );
648
+ }
649
+ );
650
+ };
651
+
652
+ // src/primitives/composer/ComposerStop.tsx
653
+ var useComposerStop = () => {
654
+ const [isLoading, stop] = useThreadContext("Composer.Stop", (s) => [
655
+ s.chat.isLoading,
656
+ s.chat.stop
657
+ ]);
658
+ if (!isLoading)
659
+ return null;
660
+ return stop;
661
+ };
662
+ var ComposerStop = createActionButton(useComposerStop);
663
+
664
+ // src/primitives/branchPicker/index.ts
665
+ var branchPicker_exports = {};
666
+ __export(branchPicker_exports, {
667
+ Count: () => BranchPickerCount,
668
+ Next: () => BranchPickerNext,
669
+ Number: () => BranchPickerNumber,
670
+ Previous: () => BranchPickerPrevious,
671
+ Root: () => BranchPickerRoot
672
+ });
673
+
674
+ // src/primitives/branchPicker/BranchPickerNext.tsx
675
+ var useBranchPickerNext = () => {
676
+ const switchToBranch = useThreadContext(
677
+ "BranchPicker.Next",
678
+ (s) => s.chat.switchToBranch
679
+ );
680
+ const [message, { branchId, branchCount }] = useMessageContext(
681
+ "BranchPicker.Next",
682
+ (s) => [s.message, s.branchState]
683
+ );
684
+ if (branchCount <= 1 || branchId + 1 >= branchCount)
685
+ return null;
686
+ return () => {
687
+ switchToBranch(message, branchId + 1);
688
+ };
689
+ };
690
+ var BranchPickerNext = createActionButton(useBranchPickerNext);
691
+
692
+ // src/primitives/branchPicker/BranchPickerPrevious.tsx
693
+ var useBranchPickerPrevious = () => {
694
+ const switchToBranch = useThreadContext(
695
+ "BranchPicker.Previous",
696
+ (s) => s.chat.switchToBranch
697
+ );
698
+ const [message, { branchId, branchCount }] = useMessageContext(
699
+ "BranchPicker.Previous",
700
+ (s) => [s.message, s.branchState]
701
+ );
702
+ if (branchCount <= 1 || branchId <= 0)
703
+ return null;
704
+ return () => {
705
+ switchToBranch(message, branchId - 1);
706
+ };
707
+ };
708
+ var BranchPickerPrevious = createActionButton(useBranchPickerPrevious);
709
+
710
+ // src/primitives/branchPicker/BranchPickerCount.tsx
711
+ var BranchPickerCount = () => {
712
+ const branchCount = useMessageContext(
713
+ "BranchPicker.Count",
714
+ (s) => s.branchState.branchCount
715
+ );
716
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, branchCount);
717
+ };
718
+
719
+ // src/primitives/branchPicker/BranchPickerNumber.tsx
720
+ var BranchPickerNumber = () => {
721
+ const branchId = useMessageContext(
722
+ "BranchPicker.Number",
723
+ (s) => s.branchState.branchId
724
+ );
725
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, branchId + 1);
726
+ };
727
+
728
+ // src/primitives/branchPicker/BranchPickerRoot.tsx
729
+ 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 });
733
+ });
734
+
735
+ // src/primitives/actionBar/index.ts
736
+ var actionBar_exports = {};
737
+ __export(actionBar_exports, {
738
+ Copy: () => ActionBarCopy,
739
+ Edit: () => ActionBarEdit,
740
+ Reload: () => ActionBarReload,
741
+ Root: () => ActionBarRoot
742
+ });
743
+
744
+ // src/primitives/actionBar/ActionBarRoot.tsx
745
+ 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
+ );
752
+
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
+ );
759
+ return () => {
760
+ navigator.clipboard.writeText(messageContent);
761
+ setIsCopied(true);
762
+ setTimeout(() => setIsCopied(false), copiedDuration);
763
+ };
764
+ };
765
+ var ActionBarCopy = createActionButton(useActionBarCopy);
766
+
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)
772
+ return null;
773
+ return () => chat.reloadAt(message);
774
+ };
775
+ var ActionBarReload = createActionButton(useActionBarReload);
776
+
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)
784
+ return null;
785
+ return () => {
786
+ setEditState({ isEditing: true, value: messageContent });
787
+ };
788
+ };
789
+ var ActionBarEdit = createActionButton(useActionBarEdit);
790
+
791
+ // src/primitives/editBar/index.ts
792
+ var editBar_exports = {};
793
+ __export(editBar_exports, {
794
+ Cancel: () => EditBarCancel,
795
+ Root: () => EditBarRoot,
796
+ Save: () => EditBarSave
797
+ });
798
+
799
+ // src/primitives/editBar/EditBarRoot.tsx
800
+ import { forwardRef as forwardRef11 } from "react";
801
+ import { Primitive as Primitive9 } from "@radix-ui/react-primitive";
802
+ var EditBarRoot = forwardRef11(
803
+ ({ ...rest }, ref) => {
804
+ return /* @__PURE__ */ React.createElement(Primitive9.div, { ...rest, ref });
805
+ }
806
+ );
807
+
808
+ // src/primitives/editBar/EditBarSave.tsx
809
+ var useEditBarSave = () => {
810
+ 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)
816
+ return null;
817
+ return () => {
818
+ if (!editState.isEditing)
819
+ return;
820
+ chat.editAt(message, {
821
+ ...message,
822
+ id: void 0,
823
+ // remove id to create a new message
824
+ content: editState.value
825
+ });
826
+ setEditState({ isEditing: false });
827
+ };
828
+ };
829
+ var EditBarSave = createActionButton(useEditBarSave);
830
+
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)
838
+ return null;
839
+ return () => {
840
+ setEditState({ isEditing: false });
841
+ };
842
+ };
843
+ var EditBarCancel = createActionButton(useEditBarCancel);
844
+ 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
852
+ };