@assistant-ui/react 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.d.mts CHANGED
@@ -35,8 +35,13 @@ declare const ThreadViewport: react.ForwardRefExoticComponent<Pick<Omit<react.De
35
35
  type ThreadMessagesProps = {
36
36
  components: {
37
37
  Message: React.ComponentType;
38
+ UserMessage?: React.ComponentType;
39
+ EditingUserMessage?: React.ComponentType;
40
+ AssistantMessage?: React.ComponentType;
38
41
  } | {
42
+ Message?: React.ComponentType;
39
43
  UserMessage: React.ComponentType;
44
+ EditingUserMessage?: React.ComponentType;
40
45
  AssistantMessage: React.ComponentType;
41
46
  };
42
47
  };
@@ -90,7 +95,7 @@ type MessageIfFilters = {
90
95
  editing: boolean | undefined;
91
96
  hasBranches: boolean | undefined;
92
97
  copied: boolean | undefined;
93
- unstable_hoveringOrLast: boolean | undefined;
98
+ lastOrHover: boolean | undefined;
94
99
  };
95
100
  type MessageIfProps = RequireAtLeastOne<MessageIfFilters> & {
96
101
  children: React.ReactNode;
@@ -138,7 +143,8 @@ declare const ActionBarRoot: react.ForwardRefExoticComponent<Pick<Omit<react.Det
138
143
  } & {
139
144
  asChild?: boolean;
140
145
  }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & {
141
- hideWhenEditing?: boolean;
146
+ hideWhenBusy?: boolean;
147
+ hideWhenNotLastOrHover?: boolean;
142
148
  } & react.RefAttributes<HTMLDivElement>>;
143
149
 
144
150
  type ActionBarCopyProps = {
@@ -170,9 +176,7 @@ declare const EditBarRoot: react.ForwardRefExoticComponent<Pick<Omit<react.Detai
170
176
  ref?: ((instance: HTMLDivElement | null) => void) | react.RefObject<HTMLDivElement> | null | undefined;
171
177
  } & {
172
178
  asChild?: boolean;
173
- }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & {
174
- hideWhenNotEditing?: boolean;
175
- } & react.RefAttributes<HTMLDivElement>>;
179
+ }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & react.RefAttributes<HTMLDivElement>>;
176
180
 
177
181
  declare const EditBarSave: react.ForwardRefExoticComponent<Pick<Omit<react.DetailedHTMLProps<react.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
178
182
  ref?: ((instance: HTMLButtonElement | null) => void) | react.RefObject<HTMLButtonElement> | null | undefined;
@@ -221,7 +225,7 @@ declare const useMessageContext: <Selection>(consumerName: string, selector: (s:
221
225
 
222
226
  declare const useCopyMessage: ({ copiedDuration }: {
223
227
  copiedDuration?: number | undefined;
224
- }) => () => void;
228
+ }) => (() => void) | null;
225
229
 
226
230
  declare const useReloadMessage: () => (() => Promise<void>) | null;
227
231
 
package/dist/index.d.ts CHANGED
@@ -35,8 +35,13 @@ declare const ThreadViewport: react.ForwardRefExoticComponent<Pick<Omit<react.De
35
35
  type ThreadMessagesProps = {
36
36
  components: {
37
37
  Message: React.ComponentType;
38
+ UserMessage?: React.ComponentType;
39
+ EditingUserMessage?: React.ComponentType;
40
+ AssistantMessage?: React.ComponentType;
38
41
  } | {
42
+ Message?: React.ComponentType;
39
43
  UserMessage: React.ComponentType;
44
+ EditingUserMessage?: React.ComponentType;
40
45
  AssistantMessage: React.ComponentType;
41
46
  };
42
47
  };
@@ -90,7 +95,7 @@ type MessageIfFilters = {
90
95
  editing: boolean | undefined;
91
96
  hasBranches: boolean | undefined;
92
97
  copied: boolean | undefined;
93
- unstable_hoveringOrLast: boolean | undefined;
98
+ lastOrHover: boolean | undefined;
94
99
  };
95
100
  type MessageIfProps = RequireAtLeastOne<MessageIfFilters> & {
96
101
  children: React.ReactNode;
@@ -138,7 +143,8 @@ declare const ActionBarRoot: react.ForwardRefExoticComponent<Pick<Omit<react.Det
138
143
  } & {
139
144
  asChild?: boolean;
140
145
  }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & {
141
- hideWhenEditing?: boolean;
146
+ hideWhenBusy?: boolean;
147
+ hideWhenNotLastOrHover?: boolean;
142
148
  } & react.RefAttributes<HTMLDivElement>>;
143
149
 
144
150
  type ActionBarCopyProps = {
@@ -170,9 +176,7 @@ declare const EditBarRoot: react.ForwardRefExoticComponent<Pick<Omit<react.Detai
170
176
  ref?: ((instance: HTMLDivElement | null) => void) | react.RefObject<HTMLDivElement> | null | undefined;
171
177
  } & {
172
178
  asChild?: boolean;
173
- }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & {
174
- hideWhenNotEditing?: boolean;
175
- } & react.RefAttributes<HTMLDivElement>>;
179
+ }, "key" | keyof react.HTMLAttributes<HTMLDivElement> | "asChild"> & react.RefAttributes<HTMLDivElement>>;
176
180
 
177
181
  declare const EditBarSave: react.ForwardRefExoticComponent<Pick<Omit<react.DetailedHTMLProps<react.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
178
182
  ref?: ((instance: HTMLButtonElement | null) => void) | react.RefObject<HTMLButtonElement> | null | undefined;
@@ -221,7 +225,7 @@ declare const useMessageContext: <Selection>(consumerName: string, selector: (s:
221
225
 
222
226
  declare const useCopyMessage: ({ copiedDuration }: {
223
227
  copiedDuration?: number | undefined;
224
- }) => () => void;
228
+ }) => (() => void) | null;
225
229
 
226
230
  declare const useReloadMessage: () => (() => Promise<void>) | null;
227
231
 
package/dist/index.js CHANGED
@@ -186,7 +186,6 @@ var useOnResizeContent = (ref, callback) => {
186
186
  return;
187
187
  const resizeObserver = new ResizeObserver(() => {
188
188
  callbackRef.current();
189
- console.log("resize observed");
190
189
  });
191
190
  const mutationObserver = new MutationObserver((mutations) => {
192
191
  for (const mutation of mutations) {
@@ -203,6 +202,7 @@ var useOnResizeContent = (ref, callback) => {
203
202
  }
204
203
  callbackRef.current();
205
204
  });
205
+ resizeObserver.observe(el);
206
206
  mutationObserver.observe(el, { childList: true });
207
207
  for (const child of el.children) {
208
208
  resizeObserver.observe(child);
@@ -365,6 +365,9 @@ var useChatWithBranches = (chat) => {
365
365
  [chat, getBranchState, switchToBranch, editAt, reloadAt]
366
366
  );
367
367
  };
368
+ var hasUpcomingMessage = (thread) => {
369
+ return thread.isLoading && thread.messages[thread.messages.length - 1]?.role !== "assistant";
370
+ };
368
371
 
369
372
  // src/primitives/message/index.ts
370
373
  var message_exports = {};
@@ -445,6 +448,10 @@ var MessageRoot = (0, import_react7.forwardRef)(
445
448
  );
446
449
 
447
450
  // src/primitives/message/MessageIf.tsx
451
+ var isLast = (thread, message) => {
452
+ const hasUpcoming = hasUpcomingMessage(thread);
453
+ return hasUpcoming ? message.id === UPCOMING_MESSAGE_ID : thread.messages[thread.messages.length - 1]?.id === message.id;
454
+ };
448
455
  var useMessageIf = (props) => {
449
456
  const thread = useThreadContext("Message.If", (s) => s.chat);
450
457
  return useMessageContext(
@@ -461,7 +468,7 @@ var useMessageIf = (props) => {
461
468
  return false;
462
469
  if (props.editing === false && isEditing)
463
470
  return false;
464
- if (props.unstable_hoveringOrLast === true && !isHovering && thread.messages[thread.messages.length - 1]?.id !== message.id)
471
+ if (props.lastOrHover === true && !isHovering && !isLast(thread, message))
465
472
  return false;
466
473
  if (props.copied === true && !isCopied)
467
474
  return false;
@@ -514,23 +521,24 @@ var MessageEditableContent = (0, import_react8.forwardRef)(({ onChange, value, .
514
521
 
515
522
  // src/primitives/thread/ThreadMessages.tsx
516
523
  var getComponents = (components) => {
517
- if ("Message" in components) {
518
- return {
519
- UserMessage: components.Message,
520
- AssistantMessage: components.Message
521
- };
522
- }
523
- return components;
524
+ return {
525
+ EditingUserMessage: components.EditingUserMessage ?? components.UserMessage ?? components.Message,
526
+ UserMessage: components.UserMessage ?? components.Message,
527
+ AssistantMessage: components.AssistantMessage ?? components.Message
528
+ };
524
529
  };
525
530
  var ThreadMessages = ({ components }) => {
526
531
  const chat = useThreadContext("Thread.Messages", (s) => s.chat);
527
532
  const messages = chat.messages;
528
- const { UserMessage, AssistantMessage } = getComponents(components);
533
+ const { UserMessage, EditingUserMessage, AssistantMessage } = getComponents(components);
529
534
  if (messages.length === 0)
530
535
  return null;
531
- return /* @__PURE__ */ React.createElement(React.Fragment, null, messages.map((message) => {
532
- return /* @__PURE__ */ React.createElement(MessageProvider, { key: message.id, message }, message.role === "assistant" ? /* @__PURE__ */ React.createElement(AssistantMessage, null) : /* @__PURE__ */ React.createElement(UserMessage, null));
533
- }), chat.isLoading && chat.messages[chat.messages.length - 1]?.role !== "assistant" && /* @__PURE__ */ React.createElement(
536
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, messages.map((message, idx) => {
537
+ return (
538
+ // biome-ignore lint/suspicious/noArrayIndexKey: fixes a11y issues with branch navigation
539
+ /* @__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)))
540
+ );
541
+ }), hasUpcomingMessage(chat) && /* @__PURE__ */ React.createElement(
534
542
  MessageProvider,
535
543
  {
536
544
  message: {
@@ -698,12 +706,19 @@ var useGoToNextBranch = () => {
698
706
  "BranchPicker.Next",
699
707
  (s) => s.chat.switchToBranch
700
708
  );
701
- const [message, { branchId, branchCount }] = useMessageContext(
702
- "BranchPicker.Next",
703
- (s) => [s.message, s.branchState]
704
- );
705
- if (branchCount <= 1 || branchId + 1 >= branchCount)
709
+ const context = useMessageContext("BranchPicker.Next", (s) => {
710
+ const {
711
+ message: message2,
712
+ editState: { isEditing },
713
+ branchState: { branchId: branchId2, branchCount }
714
+ } = s;
715
+ if (isEditing || branchCount <= 1 || branchId2 + 1 >= branchCount)
716
+ return null;
717
+ return { message: message2, branchId: branchId2 };
718
+ });
719
+ if (!context)
706
720
  return null;
721
+ const { message, branchId } = context;
707
722
  return () => {
708
723
  switchToBranch(message, branchId + 1);
709
724
  };
@@ -718,12 +733,19 @@ var useGoToPreviousBranch = () => {
718
733
  "BranchPicker.Previous",
719
734
  (s) => s.chat.switchToBranch
720
735
  );
721
- const [message, { branchId, branchCount }] = useMessageContext(
722
- "BranchPicker.Previous",
723
- (s) => [s.message, s.branchState]
724
- );
725
- if (branchCount <= 1 || branchId <= 0)
736
+ const context = useMessageContext("BranchPicker.Previous", (s) => {
737
+ const {
738
+ message: message2,
739
+ editState: { isEditing },
740
+ branchState: { branchId: branchId2, branchCount }
741
+ } = s;
742
+ if (isEditing || branchCount <= 1 || branchId2 <= 0)
743
+ return null;
744
+ return { message: message2, branchId: branchId2 };
745
+ });
746
+ if (!context)
726
747
  return null;
748
+ const { message, branchId } = context;
727
749
  return () => {
728
750
  switchToBranch(message, branchId - 1);
729
751
  };
@@ -769,18 +791,27 @@ __export(actionBar_exports, {
769
791
  // src/primitives/actionBar/ActionBarRoot.tsx
770
792
  var import_react_primitive8 = require("@radix-ui/react-primitive");
771
793
  var import_react14 = require("react");
772
- var ActionBarRoot = (0, import_react14.forwardRef)(({ hideWhenEditing = false, ...rest }, ref) => {
773
- return /* @__PURE__ */ React.createElement(MessageIf, { editing: hideWhenEditing ? false : void 0 }, /* @__PURE__ */ React.createElement(import_react_primitive8.Primitive.div, { ...rest, ref }));
794
+ var ActionBarRoot = (0, import_react14.forwardRef)(({ hideWhenBusy, hideWhenNotLastOrHover, ...rest }, ref) => {
795
+ return /* @__PURE__ */ React.createElement(ThreadIf, { busy: hideWhenBusy ? false : void 0 }, /* @__PURE__ */ React.createElement(MessageIf, { lastOrHover: hideWhenNotLastOrHover ? true : void 0 }, /* @__PURE__ */ React.createElement(import_react_primitive8.Primitive.div, { ...rest, ref })));
774
796
  });
775
797
 
776
798
  // src/actions/useCopyMessage.tsx
777
799
  var useCopyMessage = ({ copiedDuration = 3e3 }) => {
778
- const [messageContent, setIsCopied] = useMessageContext(
779
- "ActionBar.Copy",
780
- (s) => [s.message.content, s.setIsCopied]
781
- );
800
+ const context = useMessageContext("ActionBar.Copy", (s) => {
801
+ const {
802
+ editState: { isEditing },
803
+ message: { content: content2 },
804
+ setIsCopied: setIsCopied2
805
+ } = s;
806
+ if (isEditing)
807
+ return null;
808
+ return { content: content2, setIsCopied: setIsCopied2 };
809
+ });
810
+ if (!context)
811
+ return null;
812
+ const { content, setIsCopied } = context;
782
813
  return () => {
783
- navigator.clipboard.writeText(messageContent);
814
+ navigator.clipboard.writeText(content);
784
815
  setIsCopied(true);
785
816
  setTimeout(() => setIsCopied(false), copiedDuration);
786
817
  };
@@ -795,8 +826,13 @@ var useReloadMessage = () => {
795
826
  s.chat.isLoading,
796
827
  s.chat.reloadAt
797
828
  ]);
798
- const message = useMessageContext("ActionBar.Reload", (s) => s.message);
799
- if (message.role !== "assistant" || isLoading)
829
+ const message = useMessageContext("ActionBar.Reload", (s) => {
830
+ const message2 = s.message;
831
+ if (message2.role !== "assistant" || isLoading)
832
+ return null;
833
+ return message2;
834
+ });
835
+ if (!message)
800
836
  return null;
801
837
  return () => reloadAt(message);
802
838
  };
@@ -806,14 +842,21 @@ var ActionBarReload = createActionButton(useReloadMessage);
806
842
 
807
843
  // src/actions/useBeginMessageEdit.tsx
808
844
  var useBeginMessageEdit = () => {
809
- const [editState, messageContent, setEditState] = useMessageContext(
810
- "ActionBar.Edit",
811
- (s) => [s.editState, s.message.content, s.setEditState]
812
- );
813
- if (editState.isEditing)
845
+ const context = useMessageContext("ActionBar.Edit", (s) => {
846
+ const {
847
+ message: { content: content2 },
848
+ editState: { isEditing },
849
+ setEditState: setEditState2
850
+ } = s;
851
+ if (isEditing)
852
+ return null;
853
+ return { content: content2, setEditState: setEditState2 };
854
+ });
855
+ if (!context)
814
856
  return null;
857
+ const { content, setEditState } = context;
815
858
  return () => {
816
- setEditState({ isEditing: true, value: messageContent });
859
+ setEditState({ isEditing: true, value: content });
817
860
  };
818
861
  };
819
862
 
@@ -832,28 +875,29 @@ __export(editBar_exports, {
832
875
  var import_react_primitive9 = require("@radix-ui/react-primitive");
833
876
  var import_react15 = require("react");
834
877
  var EditBarRoot = (0, import_react15.forwardRef)(
835
- ({ hideWhenNotEditing, ...rest }, ref) => {
836
- return /* @__PURE__ */ React.createElement(MessageIf, { editing: hideWhenNotEditing ? true : void 0 }, /* @__PURE__ */ React.createElement(import_react_primitive9.Primitive.div, { ...rest, ref }));
878
+ ({ ...rest }, ref) => {
879
+ return /* @__PURE__ */ React.createElement(import_react_primitive9.Primitive.div, { ...rest, ref });
837
880
  }
838
881
  );
839
882
 
840
883
  // src/actions/useSaveMessageEdit.tsx
841
884
  var useSaveMessageEdit = () => {
842
885
  const chat = useThreadContext("EditBar.Save", (s) => s.chat);
843
- const [editState, message, setEditState] = useMessageContext(
844
- "EditBar.Save",
845
- (s) => [s.editState, s.message, s.setEditState]
846
- );
847
- if (!editState.isEditing)
886
+ const context = useMessageContext("EditBar.Save", (s) => {
887
+ const { message: message2, editState, setEditState: setEditState2 } = s;
888
+ if (!editState.isEditing)
889
+ return null;
890
+ return { message: message2, content: editState.value, setEditState: setEditState2 };
891
+ });
892
+ if (!context)
848
893
  return null;
894
+ const { message, content, setEditState } = context;
849
895
  return () => {
850
- if (!editState.isEditing)
851
- return;
852
896
  chat.editAt(message, {
853
897
  ...message,
854
898
  id: void 0,
855
899
  // remove id to create a new message
856
- content: editState.value
900
+ content
857
901
  });
858
902
  setEditState({ isEditing: false });
859
903
  };
@@ -864,12 +908,18 @@ var EditBarSave = createActionButton(useSaveMessageEdit);
864
908
 
865
909
  // src/actions/useCancelMessageEdit.tsx
866
910
  var useCancelMessageEdit = () => {
867
- const [isEditing, setEditState] = useMessageContext("EditBar.Cancel", (s) => [
868
- s.editState.isEditing,
869
- s.setEditState
870
- ]);
871
- if (!isEditing)
911
+ const context = useMessageContext("EditBar.Cancel", (s) => {
912
+ const {
913
+ editState: { isEditing },
914
+ setEditState: setEditState2
915
+ } = s;
916
+ if (!isEditing)
917
+ return null;
918
+ return { setEditState: setEditState2 };
919
+ });
920
+ if (!context)
872
921
  return null;
922
+ const { setEditState } = context;
873
923
  return () => {
874
924
  setEditState({ isEditing: false });
875
925
  };
package/dist/index.mjs CHANGED
@@ -151,7 +151,6 @@ var useOnResizeContent = (ref, callback) => {
151
151
  return;
152
152
  const resizeObserver = new ResizeObserver(() => {
153
153
  callbackRef.current();
154
- console.log("resize observed");
155
154
  });
156
155
  const mutationObserver = new MutationObserver((mutations) => {
157
156
  for (const mutation of mutations) {
@@ -168,6 +167,7 @@ var useOnResizeContent = (ref, callback) => {
168
167
  }
169
168
  callbackRef.current();
170
169
  });
170
+ resizeObserver.observe(el);
171
171
  mutationObserver.observe(el, { childList: true });
172
172
  for (const child of el.children) {
173
173
  resizeObserver.observe(child);
@@ -330,6 +330,9 @@ var useChatWithBranches = (chat) => {
330
330
  [chat, getBranchState, switchToBranch, editAt, reloadAt]
331
331
  );
332
332
  };
333
+ var hasUpcomingMessage = (thread) => {
334
+ return thread.isLoading && thread.messages[thread.messages.length - 1]?.role !== "assistant";
335
+ };
333
336
 
334
337
  // src/primitives/message/index.ts
335
338
  var message_exports = {};
@@ -412,6 +415,10 @@ var MessageRoot = forwardRef3(
412
415
  );
413
416
 
414
417
  // src/primitives/message/MessageIf.tsx
418
+ var isLast = (thread, message) => {
419
+ const hasUpcoming = hasUpcomingMessage(thread);
420
+ return hasUpcoming ? message.id === UPCOMING_MESSAGE_ID : thread.messages[thread.messages.length - 1]?.id === message.id;
421
+ };
415
422
  var useMessageIf = (props) => {
416
423
  const thread = useThreadContext("Message.If", (s) => s.chat);
417
424
  return useMessageContext(
@@ -428,7 +435,7 @@ var useMessageIf = (props) => {
428
435
  return false;
429
436
  if (props.editing === false && isEditing)
430
437
  return false;
431
- if (props.unstable_hoveringOrLast === true && !isHovering && thread.messages[thread.messages.length - 1]?.id !== message.id)
438
+ if (props.lastOrHover === true && !isHovering && !isLast(thread, message))
432
439
  return false;
433
440
  if (props.copied === true && !isCopied)
434
441
  return false;
@@ -481,23 +488,24 @@ var MessageEditableContent = forwardRef4(({ onChange, value, ...rest }, forwarde
481
488
 
482
489
  // src/primitives/thread/ThreadMessages.tsx
483
490
  var getComponents = (components) => {
484
- if ("Message" in components) {
485
- return {
486
- UserMessage: components.Message,
487
- AssistantMessage: components.Message
488
- };
489
- }
490
- return components;
491
+ return {
492
+ EditingUserMessage: components.EditingUserMessage ?? components.UserMessage ?? components.Message,
493
+ UserMessage: components.UserMessage ?? components.Message,
494
+ AssistantMessage: components.AssistantMessage ?? components.Message
495
+ };
491
496
  };
492
497
  var ThreadMessages = ({ components }) => {
493
498
  const chat = useThreadContext("Thread.Messages", (s) => s.chat);
494
499
  const messages = chat.messages;
495
- const { UserMessage, AssistantMessage } = getComponents(components);
500
+ const { UserMessage, EditingUserMessage, AssistantMessage } = getComponents(components);
496
501
  if (messages.length === 0)
497
502
  return null;
498
- return /* @__PURE__ */ React.createElement(React.Fragment, null, messages.map((message) => {
499
- return /* @__PURE__ */ React.createElement(MessageProvider, { key: message.id, message }, message.role === "assistant" ? /* @__PURE__ */ React.createElement(AssistantMessage, null) : /* @__PURE__ */ React.createElement(UserMessage, null));
500
- }), chat.isLoading && chat.messages[chat.messages.length - 1]?.role !== "assistant" && /* @__PURE__ */ React.createElement(
503
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, messages.map((message, idx) => {
504
+ return (
505
+ // biome-ignore lint/suspicious/noArrayIndexKey: fixes a11y issues with branch navigation
506
+ /* @__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)))
507
+ );
508
+ }), hasUpcomingMessage(chat) && /* @__PURE__ */ React.createElement(
501
509
  MessageProvider,
502
510
  {
503
511
  message: {
@@ -671,12 +679,19 @@ var useGoToNextBranch = () => {
671
679
  "BranchPicker.Next",
672
680
  (s) => s.chat.switchToBranch
673
681
  );
674
- const [message, { branchId, branchCount }] = useMessageContext(
675
- "BranchPicker.Next",
676
- (s) => [s.message, s.branchState]
677
- );
678
- if (branchCount <= 1 || branchId + 1 >= branchCount)
682
+ const context = useMessageContext("BranchPicker.Next", (s) => {
683
+ const {
684
+ message: message2,
685
+ editState: { isEditing },
686
+ branchState: { branchId: branchId2, branchCount }
687
+ } = s;
688
+ if (isEditing || branchCount <= 1 || branchId2 + 1 >= branchCount)
689
+ return null;
690
+ return { message: message2, branchId: branchId2 };
691
+ });
692
+ if (!context)
679
693
  return null;
694
+ const { message, branchId } = context;
680
695
  return () => {
681
696
  switchToBranch(message, branchId + 1);
682
697
  };
@@ -691,12 +706,19 @@ var useGoToPreviousBranch = () => {
691
706
  "BranchPicker.Previous",
692
707
  (s) => s.chat.switchToBranch
693
708
  );
694
- const [message, { branchId, branchCount }] = useMessageContext(
695
- "BranchPicker.Previous",
696
- (s) => [s.message, s.branchState]
697
- );
698
- if (branchCount <= 1 || branchId <= 0)
709
+ const context = useMessageContext("BranchPicker.Previous", (s) => {
710
+ const {
711
+ message: message2,
712
+ editState: { isEditing },
713
+ branchState: { branchId: branchId2, branchCount }
714
+ } = s;
715
+ if (isEditing || branchCount <= 1 || branchId2 <= 0)
716
+ return null;
717
+ return { message: message2, branchId: branchId2 };
718
+ });
719
+ if (!context)
699
720
  return null;
721
+ const { message, branchId } = context;
700
722
  return () => {
701
723
  switchToBranch(message, branchId - 1);
702
724
  };
@@ -746,18 +768,27 @@ import {
746
768
  Primitive as Primitive8
747
769
  } from "@radix-ui/react-primitive";
748
770
  import { forwardRef as forwardRef10 } from "react";
749
- var ActionBarRoot = forwardRef10(({ hideWhenEditing = false, ...rest }, ref) => {
750
- return /* @__PURE__ */ React.createElement(MessageIf, { editing: hideWhenEditing ? false : void 0 }, /* @__PURE__ */ React.createElement(Primitive8.div, { ...rest, ref }));
771
+ var ActionBarRoot = forwardRef10(({ hideWhenBusy, hideWhenNotLastOrHover, ...rest }, ref) => {
772
+ return /* @__PURE__ */ React.createElement(ThreadIf, { busy: hideWhenBusy ? false : void 0 }, /* @__PURE__ */ React.createElement(MessageIf, { lastOrHover: hideWhenNotLastOrHover ? true : void 0 }, /* @__PURE__ */ React.createElement(Primitive8.div, { ...rest, ref })));
751
773
  });
752
774
 
753
775
  // src/actions/useCopyMessage.tsx
754
776
  var useCopyMessage = ({ copiedDuration = 3e3 }) => {
755
- const [messageContent, setIsCopied] = useMessageContext(
756
- "ActionBar.Copy",
757
- (s) => [s.message.content, s.setIsCopied]
758
- );
777
+ const context = useMessageContext("ActionBar.Copy", (s) => {
778
+ const {
779
+ editState: { isEditing },
780
+ message: { content: content2 },
781
+ setIsCopied: setIsCopied2
782
+ } = s;
783
+ if (isEditing)
784
+ return null;
785
+ return { content: content2, setIsCopied: setIsCopied2 };
786
+ });
787
+ if (!context)
788
+ return null;
789
+ const { content, setIsCopied } = context;
759
790
  return () => {
760
- navigator.clipboard.writeText(messageContent);
791
+ navigator.clipboard.writeText(content);
761
792
  setIsCopied(true);
762
793
  setTimeout(() => setIsCopied(false), copiedDuration);
763
794
  };
@@ -772,8 +803,13 @@ var useReloadMessage = () => {
772
803
  s.chat.isLoading,
773
804
  s.chat.reloadAt
774
805
  ]);
775
- const message = useMessageContext("ActionBar.Reload", (s) => s.message);
776
- if (message.role !== "assistant" || isLoading)
806
+ const message = useMessageContext("ActionBar.Reload", (s) => {
807
+ const message2 = s.message;
808
+ if (message2.role !== "assistant" || isLoading)
809
+ return null;
810
+ return message2;
811
+ });
812
+ if (!message)
777
813
  return null;
778
814
  return () => reloadAt(message);
779
815
  };
@@ -783,14 +819,21 @@ var ActionBarReload = createActionButton(useReloadMessage);
783
819
 
784
820
  // src/actions/useBeginMessageEdit.tsx
785
821
  var useBeginMessageEdit = () => {
786
- const [editState, messageContent, setEditState] = useMessageContext(
787
- "ActionBar.Edit",
788
- (s) => [s.editState, s.message.content, s.setEditState]
789
- );
790
- if (editState.isEditing)
822
+ const context = useMessageContext("ActionBar.Edit", (s) => {
823
+ const {
824
+ message: { content: content2 },
825
+ editState: { isEditing },
826
+ setEditState: setEditState2
827
+ } = s;
828
+ if (isEditing)
829
+ return null;
830
+ return { content: content2, setEditState: setEditState2 };
831
+ });
832
+ if (!context)
791
833
  return null;
834
+ const { content, setEditState } = context;
792
835
  return () => {
793
- setEditState({ isEditing: true, value: messageContent });
836
+ setEditState({ isEditing: true, value: content });
794
837
  };
795
838
  };
796
839
 
@@ -811,28 +854,29 @@ import {
811
854
  } from "@radix-ui/react-primitive";
812
855
  import { forwardRef as forwardRef11 } from "react";
813
856
  var EditBarRoot = forwardRef11(
814
- ({ hideWhenNotEditing, ...rest }, ref) => {
815
- return /* @__PURE__ */ React.createElement(MessageIf, { editing: hideWhenNotEditing ? true : void 0 }, /* @__PURE__ */ React.createElement(Primitive9.div, { ...rest, ref }));
857
+ ({ ...rest }, ref) => {
858
+ return /* @__PURE__ */ React.createElement(Primitive9.div, { ...rest, ref });
816
859
  }
817
860
  );
818
861
 
819
862
  // src/actions/useSaveMessageEdit.tsx
820
863
  var useSaveMessageEdit = () => {
821
864
  const chat = useThreadContext("EditBar.Save", (s) => s.chat);
822
- const [editState, message, setEditState] = useMessageContext(
823
- "EditBar.Save",
824
- (s) => [s.editState, s.message, s.setEditState]
825
- );
826
- if (!editState.isEditing)
865
+ const context = useMessageContext("EditBar.Save", (s) => {
866
+ const { message: message2, editState, setEditState: setEditState2 } = s;
867
+ if (!editState.isEditing)
868
+ return null;
869
+ return { message: message2, content: editState.value, setEditState: setEditState2 };
870
+ });
871
+ if (!context)
827
872
  return null;
873
+ const { message, content, setEditState } = context;
828
874
  return () => {
829
- if (!editState.isEditing)
830
- return;
831
875
  chat.editAt(message, {
832
876
  ...message,
833
877
  id: void 0,
834
878
  // remove id to create a new message
835
- content: editState.value
879
+ content
836
880
  });
837
881
  setEditState({ isEditing: false });
838
882
  };
@@ -843,12 +887,18 @@ var EditBarSave = createActionButton(useSaveMessageEdit);
843
887
 
844
888
  // src/actions/useCancelMessageEdit.tsx
845
889
  var useCancelMessageEdit = () => {
846
- const [isEditing, setEditState] = useMessageContext("EditBar.Cancel", (s) => [
847
- s.editState.isEditing,
848
- s.setEditState
849
- ]);
850
- if (!isEditing)
890
+ const context = useMessageContext("EditBar.Cancel", (s) => {
891
+ const {
892
+ editState: { isEditing },
893
+ setEditState: setEditState2
894
+ } = s;
895
+ if (!isEditing)
896
+ return null;
897
+ return { setEditState: setEditState2 };
898
+ });
899
+ if (!context)
851
900
  return null;
901
+ const { setEditState } = context;
852
902
  return () => {
853
903
  setEditState({ isEditing: false });
854
904
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": {
@@ -31,7 +31,7 @@
31
31
  "@radix-ui/react-compose-refs": "^1.0.1",
32
32
  "@radix-ui/react-primitive": "^1.0.3",
33
33
  "@radix-ui/react-slot": "^1.0.2",
34
- "ai": "^3.1.1",
34
+ "ai": "^3.1.8",
35
35
  "react-textarea-autosize": "^8.5.3",
36
36
  "use-sync-external-store": "^1.2.2"
37
37
  },