@assistant-ui/react-native 0.1.43 → 0.1.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/dist/context/AssistantContext.d.ts +2 -2
  2. package/dist/context/AssistantContext.d.ts.map +1 -0
  3. package/dist/context/providers/AttachmentByIndexProvider.d.ts +2 -2
  4. package/dist/context/providers/AttachmentByIndexProvider.d.ts.map +1 -0
  5. package/dist/context/providers/RuntimeAdapterProvider.d.ts +2 -2
  6. package/dist/context/providers/RuntimeAdapterProvider.d.ts.map +1 -0
  7. package/dist/context/providers/ThreadListItemRuntimeProvider.d.ts +2 -2
  8. package/dist/context/providers/ThreadListItemRuntimeProvider.d.ts.map +1 -0
  9. package/dist/index.d.ts +54 -23
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +4 -4
  12. package/dist/internal.d.ts +4 -3
  13. package/dist/internal.d.ts.map +1 -0
  14. package/dist/primitives/actionBar/ActionBarCopy.d.ts +7 -9
  15. package/dist/primitives/actionBar/ActionBarCopy.d.ts.map +1 -1
  16. package/dist/primitives/actionBar/ActionBarEdit.d.ts +5 -7
  17. package/dist/primitives/actionBar/ActionBarEdit.d.ts.map +1 -1
  18. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts +6 -8
  19. package/dist/primitives/actionBar/ActionBarFeedbackNegative.d.ts.map +1 -1
  20. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js +28 -20
  21. package/dist/primitives/actionBar/ActionBarFeedbackNegative.js.map +1 -1
  22. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts +6 -8
  23. package/dist/primitives/actionBar/ActionBarFeedbackPositive.d.ts.map +1 -1
  24. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js +28 -20
  25. package/dist/primitives/actionBar/ActionBarFeedbackPositive.js.map +1 -1
  26. package/dist/primitives/actionBar/ActionBarReload.d.ts +5 -7
  27. package/dist/primitives/actionBar/ActionBarReload.d.ts.map +1 -1
  28. package/dist/primitives/actionBar/ActionBarSpeak.d.ts +7 -9
  29. package/dist/primitives/actionBar/ActionBarSpeak.d.ts.map +1 -1
  30. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts +7 -9
  31. package/dist/primitives/actionBar/ActionBarStopSpeaking.d.ts.map +1 -1
  32. package/dist/primitives/actionBar.d.ts +7 -12
  33. package/dist/primitives/actionBar.d.ts.map +1 -1
  34. package/dist/primitives/attachment/AttachmentName.d.ts +2 -4
  35. package/dist/primitives/attachment/AttachmentName.d.ts.map +1 -1
  36. package/dist/primitives/attachment/AttachmentRemove.d.ts +2 -4
  37. package/dist/primitives/attachment/AttachmentRemove.d.ts.map +1 -1
  38. package/dist/primitives/attachment/AttachmentRoot.d.ts +3 -5
  39. package/dist/primitives/attachment/AttachmentRoot.d.ts.map +1 -1
  40. package/dist/primitives/attachment/AttachmentThumb.d.ts +2 -4
  41. package/dist/primitives/attachment/AttachmentThumb.d.ts.map +1 -1
  42. package/dist/primitives/attachment.d.ts +4 -9
  43. package/dist/primitives/attachment.d.ts.map +1 -1
  44. package/dist/primitives/branchPicker/BranchPickerCount.d.ts +1 -3
  45. package/dist/primitives/branchPicker/BranchPickerCount.d.ts.map +1 -1
  46. package/dist/primitives/branchPicker/BranchPickerNext.d.ts +5 -7
  47. package/dist/primitives/branchPicker/BranchPickerNext.d.ts.map +1 -1
  48. package/dist/primitives/branchPicker/BranchPickerNumber.d.ts +1 -3
  49. package/dist/primitives/branchPicker/BranchPickerNumber.d.ts.map +1 -1
  50. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts +5 -7
  51. package/dist/primitives/branchPicker/BranchPickerPrevious.d.ts.map +1 -1
  52. package/dist/primitives/branchPicker.d.ts +4 -9
  53. package/dist/primitives/branchPicker.d.ts.map +1 -1
  54. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts +2 -4
  55. package/dist/primitives/chainOfThought/ChainOfThoughtAccordionTrigger.d.ts.map +1 -1
  56. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts +3 -5
  57. package/dist/primitives/chainOfThought/ChainOfThoughtRoot.d.ts.map +1 -1
  58. package/dist/primitives/chainOfThought.d.ts +3 -8
  59. package/dist/primitives/chainOfThought.d.ts.map +1 -1
  60. package/dist/primitives/composer/ComposerAddAttachment.d.ts +2 -4
  61. package/dist/primitives/composer/ComposerAddAttachment.d.ts.map +1 -1
  62. package/dist/primitives/composer/ComposerAttachments.d.ts +1 -3
  63. package/dist/primitives/composer/ComposerAttachments.d.ts.map +1 -1
  64. package/dist/primitives/composer/ComposerCancel.d.ts +2 -4
  65. package/dist/primitives/composer/ComposerCancel.d.ts.map +1 -1
  66. package/dist/primitives/composer/ComposerIf.d.ts +2 -2
  67. package/dist/primitives/composer/ComposerIf.d.ts.map +1 -0
  68. package/dist/primitives/composer/ComposerInput.d.ts +8 -10
  69. package/dist/primitives/composer/ComposerInput.d.ts.map +1 -1
  70. package/dist/primitives/composer/ComposerInput.js +1 -1
  71. package/dist/primitives/composer/ComposerInput.js.map +1 -1
  72. package/dist/primitives/composer/ComposerQueue.d.ts +2 -2
  73. package/dist/primitives/composer/ComposerQueue.d.ts.map +1 -0
  74. package/dist/primitives/composer/ComposerQuote.d.ts +3 -5
  75. package/dist/primitives/composer/ComposerQuote.d.ts.map +1 -1
  76. package/dist/primitives/composer/ComposerQuoteDismiss.d.ts +2 -4
  77. package/dist/primitives/composer/ComposerQuoteDismiss.d.ts.map +1 -1
  78. package/dist/primitives/composer/ComposerQuoteText.d.ts +3 -5
  79. package/dist/primitives/composer/ComposerQuoteText.d.ts.map +1 -1
  80. package/dist/primitives/composer/ComposerRoot.d.ts +3 -5
  81. package/dist/primitives/composer/ComposerRoot.d.ts.map +1 -1
  82. package/dist/primitives/composer/ComposerSend.d.ts +2 -4
  83. package/dist/primitives/composer/ComposerSend.d.ts.map +1 -1
  84. package/dist/primitives/composer.d.ts +11 -16
  85. package/dist/primitives/composer.d.ts.map +1 -1
  86. package/dist/primitives/error/ErrorMessage.d.ts +5 -7
  87. package/dist/primitives/error/ErrorMessage.d.ts.map +1 -1
  88. package/dist/primitives/error/ErrorRoot.d.ts +5 -7
  89. package/dist/primitives/error/ErrorRoot.d.ts.map +1 -1
  90. package/dist/primitives/error/index.d.ts +2 -7
  91. package/dist/primitives/error/index.d.ts.map +1 -1
  92. package/dist/primitives/message/MessageAttachments.d.ts +1 -3
  93. package/dist/primitives/message/MessageAttachments.d.ts.map +1 -1
  94. package/dist/primitives/message/MessageContent.d.ts +46 -47
  95. package/dist/primitives/message/MessageContent.d.ts.map +1 -1
  96. package/dist/primitives/message/MessageContent.js +27 -21
  97. package/dist/primitives/message/MessageContent.js.map +1 -1
  98. package/dist/primitives/message/MessageIf.d.ts +7 -9
  99. package/dist/primitives/message/MessageIf.d.ts.map +1 -1
  100. package/dist/primitives/message/MessageParts.d.ts +4 -6
  101. package/dist/primitives/message/MessageParts.d.ts.map +1 -1
  102. package/dist/primitives/message/MessageRoot.d.ts +3 -5
  103. package/dist/primitives/message/MessageRoot.d.ts.map +1 -1
  104. package/dist/primitives/message.d.ts +6 -11
  105. package/dist/primitives/message.d.ts.map +1 -1
  106. package/dist/primitives/messagePart/MessagePartImage.d.ts +4 -6
  107. package/dist/primitives/messagePart/MessagePartImage.d.ts.map +1 -1
  108. package/dist/primitives/messagePart/MessagePartInProgress.d.ts +2 -2
  109. package/dist/primitives/messagePart/MessagePartInProgress.d.ts.map +1 -0
  110. package/dist/primitives/messagePart/MessagePartText.d.ts +4 -6
  111. package/dist/primitives/messagePart/MessagePartText.d.ts.map +1 -1
  112. package/dist/primitives/messagePart.d.ts +4 -9
  113. package/dist/primitives/messagePart.d.ts.map +1 -1
  114. package/dist/primitives/queueItem/QueueItemRemove.d.ts +2 -4
  115. package/dist/primitives/queueItem/QueueItemRemove.d.ts.map +1 -1
  116. package/dist/primitives/queueItem/QueueItemSteer.d.ts +2 -4
  117. package/dist/primitives/queueItem/QueueItemSteer.d.ts.map +1 -1
  118. package/dist/primitives/queueItem/QueueItemText.d.ts +3 -5
  119. package/dist/primitives/queueItem/QueueItemText.d.ts.map +1 -1
  120. package/dist/primitives/queueItem.d.ts +3 -8
  121. package/dist/primitives/queueItem.d.ts.map +1 -1
  122. package/dist/primitives/suggestion/SuggestionDescription.d.ts +3 -5
  123. package/dist/primitives/suggestion/SuggestionDescription.d.ts.map +1 -1
  124. package/dist/primitives/suggestion/SuggestionTitle.d.ts +3 -5
  125. package/dist/primitives/suggestion/SuggestionTitle.d.ts.map +1 -1
  126. package/dist/primitives/suggestion/SuggestionTrigger.d.ts +13 -15
  127. package/dist/primitives/suggestion/SuggestionTrigger.d.ts.map +1 -1
  128. package/dist/primitives/suggestion/SuggestionTrigger.js +1 -1
  129. package/dist/primitives/suggestion.d.ts +3 -8
  130. package/dist/primitives/suggestion.d.ts.map +1 -1
  131. package/dist/primitives/thread/ThreadEmpty.d.ts +2 -4
  132. package/dist/primitives/thread/ThreadEmpty.d.ts.map +1 -1
  133. package/dist/primitives/thread/ThreadIf.d.ts +4 -6
  134. package/dist/primitives/thread/ThreadIf.d.ts.map +1 -1
  135. package/dist/primitives/thread/ThreadMessages.d.ts +37 -37
  136. package/dist/primitives/thread/ThreadMessages.d.ts.map +1 -1
  137. package/dist/primitives/thread/ThreadMessages.js +70 -58
  138. package/dist/primitives/thread/ThreadMessages.js.map +1 -1
  139. package/dist/primitives/thread/ThreadRoot.d.ts +3 -5
  140. package/dist/primitives/thread/ThreadRoot.d.ts.map +1 -1
  141. package/dist/primitives/thread/ThreadSuggestion.d.ts +15 -17
  142. package/dist/primitives/thread/ThreadSuggestion.d.ts.map +1 -1
  143. package/dist/primitives/thread.d.ts +8 -11
  144. package/dist/primitives/thread.d.ts.map +1 -1
  145. package/dist/primitives/threadList/ThreadListItems.d.ts +6 -8
  146. package/dist/primitives/threadList/ThreadListItems.d.ts.map +1 -1
  147. package/dist/primitives/threadList/ThreadListItems.js +1 -1
  148. package/dist/primitives/threadList/ThreadListNew.d.ts +5 -7
  149. package/dist/primitives/threadList/ThreadListNew.d.ts.map +1 -1
  150. package/dist/primitives/threadList/ThreadListNew.js +21 -17
  151. package/dist/primitives/threadList/ThreadListNew.js.map +1 -1
  152. package/dist/primitives/threadList/ThreadListRoot.d.ts +3 -5
  153. package/dist/primitives/threadList/ThreadListRoot.d.ts.map +1 -1
  154. package/dist/primitives/threadList.d.ts +3 -8
  155. package/dist/primitives/threadList.d.ts.map +1 -1
  156. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts +2 -4
  157. package/dist/primitives/threadListItem/ThreadListItemArchive.d.ts.map +1 -1
  158. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts +2 -4
  159. package/dist/primitives/threadListItem/ThreadListItemDelete.d.ts.map +1 -1
  160. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts +3 -5
  161. package/dist/primitives/threadListItem/ThreadListItemRoot.d.ts.map +1 -1
  162. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts +5 -7
  163. package/dist/primitives/threadListItem/ThreadListItemTrigger.d.ts.map +1 -1
  164. package/dist/primitives/threadListItem/ThreadListItemTrigger.js +21 -17
  165. package/dist/primitives/threadListItem/ThreadListItemTrigger.js.map +1 -1
  166. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts +2 -4
  167. package/dist/primitives/threadListItem/ThreadListItemUnarchive.d.ts.map +1 -1
  168. package/dist/primitives/threadListItem.d.ts +6 -11
  169. package/dist/primitives/threadListItem.d.ts.map +1 -1
  170. package/dist/runtimes/useLocalRuntime.d.ts +2 -2
  171. package/dist/runtimes/useLocalRuntime.d.ts.map +1 -0
  172. package/dist/runtimes/useRemoteThreadListRuntime.d.ts +2 -2
  173. package/dist/runtimes/useRemoteThreadListRuntime.d.ts.map +1 -0
  174. package/package.json +7 -7
  175. package/src/index.ts +90 -1
  176. package/src/primitives/actionBar/ActionBar.test.tsx +76 -0
  177. package/src/primitives/actionBar/ActionBarFeedbackNegative.tsx +4 -1
  178. package/src/primitives/actionBar/ActionBarFeedbackPositive.tsx +4 -1
  179. package/src/primitives/composer/ComposerInput.test.tsx +17 -1
  180. package/src/primitives/composer/ComposerInput.tsx +6 -1
  181. package/src/primitives/message/MessageContent.test.tsx +64 -3
  182. package/src/primitives/message/MessageContent.tsx +5 -3
  183. package/src/primitives/thread/ThreadMessages.test.tsx +111 -5
  184. package/src/primitives/thread/ThreadMessages.tsx +41 -11
  185. package/src/primitives/threadList/ThreadListNew.test.tsx +35 -8
  186. package/src/primitives/threadList/ThreadListNew.tsx +4 -1
  187. package/src/primitives/threadListItem/ThreadListItemTrigger.test.tsx +32 -6
  188. package/src/primitives/threadListItem/ThreadListItemTrigger.tsx +4 -1
@@ -1,11 +1,11 @@
1
- import { useAuiState } from "@assistant-ui/store";
2
1
  import { useThreadListItemTrigger } from "@assistant-ui/core/react";
2
+ import { useAuiState } from "@assistant-ui/store";
3
3
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
4
- import { Pressable } from "react-native";
4
+ import { Platform, Pressable } from "react-native";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region src/primitives/threadListItem/ThreadListItemTrigger.tsx
7
7
  const ThreadListItemTrigger = (t0) => {
8
- const $ = c(15);
8
+ const $ = c(16);
9
9
  let accessibilityState;
10
10
  let children;
11
11
  let pressableProps;
@@ -22,42 +22,46 @@ const ThreadListItemTrigger = (t0) => {
22
22
  }
23
23
  const isActive = useAuiState(_temp);
24
24
  const { switchTo } = useThreadListItemTrigger();
25
+ const selected = accessibilityState?.selected ?? isActive;
25
26
  let t1;
26
- if ($[4] !== accessibilityState || $[5] !== isActive) {
27
+ if ($[4] !== accessibilityState || $[5] !== selected) {
27
28
  t1 = {
28
- selected: isActive,
29
- ...accessibilityState
29
+ ...accessibilityState,
30
+ selected
30
31
  };
31
32
  $[4] = accessibilityState;
32
- $[5] = isActive;
33
+ $[5] = selected;
33
34
  $[6] = t1;
34
35
  } else t1 = $[6];
35
- let t2;
36
+ const t2 = Platform.OS === "web" && selected ? "true" : void 0;
37
+ let t3;
36
38
  if ($[7] !== children || $[8] !== isActive) {
37
- t2 = typeof children === "function" ? (state) => children({
39
+ t3 = typeof children === "function" ? (state) => children({
38
40
  ...state,
39
41
  isActive
40
42
  }) : children;
41
43
  $[7] = children;
42
44
  $[8] = isActive;
43
- $[9] = t2;
44
- } else t2 = $[9];
45
- let t3;
46
- if ($[10] !== pressableProps || $[11] !== switchTo || $[12] !== t1 || $[13] !== t2) {
47
- t3 = /* @__PURE__ */ jsx(Pressable, {
45
+ $[9] = t3;
46
+ } else t3 = $[9];
47
+ let t4;
48
+ if ($[10] !== pressableProps || $[11] !== switchTo || $[12] !== t1 || $[13] !== t2 || $[14] !== t3) {
49
+ t4 = /* @__PURE__ */ jsx(Pressable, {
48
50
  onPress: switchTo,
49
51
  accessibilityRole: "button",
50
52
  accessibilityState: t1,
53
+ "aria-current": t2,
51
54
  ...pressableProps,
52
- children: t2
55
+ children: t3
53
56
  });
54
57
  $[10] = pressableProps;
55
58
  $[11] = switchTo;
56
59
  $[12] = t1;
57
60
  $[13] = t2;
58
61
  $[14] = t3;
59
- } else t3 = $[14];
60
- return t3;
62
+ $[15] = t4;
63
+ } else t4 = $[15];
64
+ return t4;
61
65
  };
62
66
  function _temp(s) {
63
67
  return s.threads.mainThreadId === s.threadListItem.id;
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadListItemTrigger.js","names":["ReactNode","Pressable","PressableProps","PressableStateCallbackType","useAuiState","useThreadListItemTrigger","ThreadListItemTriggerProps","Omit","children","state","isActive","ThreadListItemTrigger","t0","$","_c","accessibilityState","pressableProps","_temp","switchTo","t1","selected","t2","t3","s","threads","mainThreadId","threadListItem","id"],"sources":["../../../src/primitives/threadListItem/ThreadListItemTrigger.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport {\n Pressable,\n type PressableProps,\n type PressableStateCallbackType,\n} from \"react-native\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport { useThreadListItemTrigger } from \"@assistant-ui/core/react\";\n\nexport type ThreadListItemTriggerProps = Omit<\n PressableProps,\n \"onPress\" | \"children\"\n> & {\n children:\n | ReactNode\n | ((\n state: PressableStateCallbackType & { isActive: boolean },\n ) => ReactNode);\n};\n\nexport const ThreadListItemTrigger = ({\n children,\n accessibilityState,\n ...pressableProps\n}: ThreadListItemTriggerProps) => {\n const isActive = useAuiState(\n (s) => s.threads.mainThreadId === s.threadListItem.id,\n );\n const { switchTo } = useThreadListItemTrigger();\n\n return (\n <Pressable\n onPress={switchTo}\n accessibilityRole=\"button\"\n accessibilityState={{ selected: isActive, ...accessibilityState }}\n {...pressableProps}\n >\n {typeof children === \"function\"\n ? (state) => children({ ...state, isActive })\n : children}\n </Pressable>\n );\n};\n"],"mappings":";;;;;;AAoBA,MAAaW,yBAAwBC,OAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAAA,IAAAC;CAAA,IAAAP;CAAA,IAAAQ;CAAA,IAAAH,EAAA,OAAAD,IAAA;EAAC,CAAA,CAAAJ,UAAAO,oBAAA,GAAAC,kBAAAJ;EAITC,EAAA,KAAAD;EAAAC,EAAA,KAAAE;EAAAF,EAAA,KAAAL;EAAAK,EAAA,KAAAG;CAAA,OAAA;EAAAD,qBAAAF,EAAA;EAAAL,WAAAK,EAAA;EAAAG,iBAAAH,EAAA;CAAA;CAC3B,MAAAH,WAAiBN,YACfa,KACF;CACA,MAAA,EAAAC,aAAqBb,yBAAyB;CAAE,IAAAc;CAAA,IAAAN,EAAA,OAAAE,sBAAAF,EAAA,OAAAH,UAAA;EAMxBS,KAAA;GAAAC,UAAYV;GAAQ,GAAKK;EAAmB;EAACF,EAAA,KAAAE;EAAAF,EAAA,KAAAH;EAAAG,EAAA,KAAAM;CAAA,OAAAA,KAAAN,EAAA;CAAA,IAAAQ;CAAA,IAAAR,EAAA,OAAAL,YAAAK,EAAA,OAAAH,UAAA;EAGhEW,KAAA,OAAOb,aAAa,cAApBC,UACcD,SAAS;GAAA,GAAKC;GAAKC;EAAW,CAAC,IAD7CF;EAEWK,EAAA,KAAAL;EAAAK,EAAA,KAAAH;EAAAG,EAAA,KAAAQ;CAAA,OAAAA,KAAAR,EAAA;CAAA,IAAAS;CAAA,IAAAT,EAAA,QAAAG,kBAAAH,EAAA,QAAAK,YAAAL,EAAA,QAAAM,MAAAN,EAAA,QAAAQ,IAAA;EARdC,KAAA,oBAAC,WAAD;GACWJ,SAAAA;GACS,mBAAA;GACE,oBAAAC;GAA6C,GAC7DH;GAEHK,UAAAA;EANO,CAAA;EASER,EAAA,MAAAG;EAAAH,EAAA,MAAAK;EAAAL,EAAA,MAAAM;EAAAN,EAAA,MAAAQ;EAAAR,EAAA,MAAAS;CAAA,OAAAA,KAAAT,EAAA;CAAA,OATZS;AASY;AApBqB,SAAAL,MAAAM,GAAA;CAAA,OAM1BA,EAACC,QAAQC,iBAAkBF,EAACG,eAAeC;AAAG"}
1
+ {"version":3,"file":"ThreadListItemTrigger.js","names":["ReactNode","Platform","Pressable","PressableProps","PressableStateCallbackType","useAuiState","useThreadListItemTrigger","ThreadListItemTriggerProps","Omit","children","state","isActive","ThreadListItemTrigger","t0","$","_c","accessibilityState","pressableProps","_temp","switchTo","selected","t1","t2","OS","undefined","t3","t4","s","threads","mainThreadId","threadListItem","id"],"sources":["../../../src/primitives/threadListItem/ThreadListItemTrigger.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport {\n Platform,\n Pressable,\n type PressableProps,\n type PressableStateCallbackType,\n} from \"react-native\";\nimport { useAuiState } from \"@assistant-ui/store\";\nimport { useThreadListItemTrigger } from \"@assistant-ui/core/react\";\n\nexport type ThreadListItemTriggerProps = Omit<\n PressableProps,\n \"onPress\" | \"children\"\n> & {\n children:\n | ReactNode\n | ((\n state: PressableStateCallbackType & { isActive: boolean },\n ) => ReactNode);\n};\n\nexport const ThreadListItemTrigger = ({\n children,\n accessibilityState,\n ...pressableProps\n}: ThreadListItemTriggerProps) => {\n const isActive = useAuiState(\n (s) => s.threads.mainThreadId === s.threadListItem.id,\n );\n const { switchTo } = useThreadListItemTrigger();\n const selected = accessibilityState?.selected ?? isActive;\n\n return (\n <Pressable\n onPress={switchTo}\n accessibilityRole=\"button\"\n accessibilityState={{ ...accessibilityState, selected }}\n aria-current={Platform.OS === \"web\" && selected ? \"true\" : undefined}\n {...pressableProps}\n >\n {typeof children === \"function\"\n ? (state) => children({ ...state, isActive })\n : children}\n </Pressable>\n );\n};\n"],"mappings":";;;;;;AAqBA,MAAaY,yBAAwBC,OAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAAA,IAAAC;CAAA,IAAAP;CAAA,IAAAQ;CAAA,IAAAH,EAAA,OAAAD,IAAA;EAAC,CAAA,CAAAJ,UAAAO,oBAAA,GAAAC,kBAAAJ;EAITC,EAAA,KAAAD;EAAAC,EAAA,KAAAE;EAAAF,EAAA,KAAAL;EAAAK,EAAA,KAAAG;CAAA,OAAA;EAAAD,qBAAAF,EAAA;EAAAL,WAAAK,EAAA;EAAAG,iBAAAH,EAAA;CAAA;CAC3B,MAAAH,WAAiBN,YACfa,KACF;CACA,MAAA,EAAAC,aAAqBb,yBAAyB;CAC9C,MAAAc,WAAiBJ,oBAAkBI,YAAlBT;CAAyC,IAAAU;CAAA,IAAAP,EAAA,OAAAE,sBAAAF,EAAA,OAAAM,UAAA;EAMlCC,KAAA;GAAA,GAAKL;GAAkBI;EAAW;EAACN,EAAA,KAAAE;EAAAF,EAAA,KAAAM;EAAAN,EAAA,KAAAO;CAAA,OAAAA,KAAAP,EAAA;CACzC,MAAAQ,KAAArB,SAAQsB,OAAQ,SAAhBH,WAAA,SAAAI,KAAAA;CAAsD,IAAAC;CAAA,IAAAX,EAAA,OAAAL,YAAAK,EAAA,OAAAH,UAAA;EAGnEc,KAAA,OAAOhB,aAAa,cAApBC,UACcD,SAAS;GAAA,GAAKC;GAAKC;EAAW,CAAC,IAD7CF;EAEWK,EAAA,KAAAL;EAAAK,EAAA,KAAAH;EAAAG,EAAA,KAAAW;CAAA,OAAAA,KAAAX,EAAA;CAAA,IAAAY;CAAA,IAAAZ,EAAA,QAAAG,kBAAAH,EAAA,QAAAK,YAAAL,EAAA,QAAAO,MAAAP,EAAA,QAAAQ,MAAAR,EAAA,QAAAW,IAAA;EATdC,KAAA,oBAAC,WAAD;GACWP,SAAAA;GACS,mBAAA;GACE,oBAAAE;GACN,gBAAAC;GAAsD,GAChEL;GAEHQ,UAAAA;EAPO,CAAA;EAUEX,EAAA,MAAAG;EAAAH,EAAA,MAAAK;EAAAL,EAAA,MAAAO;EAAAP,EAAA,MAAAQ;EAAAR,EAAA,MAAAW;EAAAX,EAAA,MAAAY;CAAA,OAAAA,KAAAZ,EAAA;CAAA,OAVZY;AAUY;AAtBqB,SAAAR,MAAAS,GAAA;CAAA,OAM1BA,EAACC,QAAQC,iBAAkBF,EAACG,eAAeC;AAAG"}
@@ -1,8 +1,6 @@
1
- import { PressableProps } from "react-native";
2
- //#region src/primitives/threadListItem/ThreadListItemUnarchive.d.ts
1
+ import { type PressableProps } from "react-native";
3
2
  export type ThreadListItemUnarchiveProps = Omit<PressableProps, "onPress" | "children"> & {
4
- children: PressableProps["children"];
3
+ children: PressableProps["children"];
5
4
  };
6
5
  export declare const ThreadListItemUnarchive: ({ children, ...pressableProps }: ThreadListItemUnarchiveProps) => import("react").JSX.Element;
7
- //#endregion
8
6
  //# sourceMappingURL=ThreadListItemUnarchive.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadListItemUnarchive.d.ts","names":[],"sources":["../../../src/primitives/threadListItem/ThreadListItemUnarchive.tsx"],"mappings":";;YAGY,+BAA+B,KACzC;EAGA,UAAU;;qBAGC,4BAA2B,aAAA,kBAGrC,iDAA4B,IAAA"}
1
+ {"version":3,"file":"ThreadListItemUnarchive.d.ts","sourceRoot":"","sources":["../../../src/primitives/threadListItem/ThreadListItemUnarchive.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9D,MAAM,MAAM,4BAA4B,GAAG,IAAI,CAC7C,cAAc,EACd,SAAS,GAAG,UAAU,CACvB,GAAG;IACF,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;CACtC,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,iCAGrC,4BAA4B,gCAY9B,CAAC"}
@@ -1,12 +1,7 @@
1
- import { ThreadListItemRoot, ThreadListItemRootProps } from "./threadListItem/ThreadListItemRoot.js";
2
- import { ThreadListItemTrigger, ThreadListItemTriggerProps } from "./threadListItem/ThreadListItemTrigger.js";
3
- import { ThreadListItemDelete, ThreadListItemDeleteProps } from "./threadListItem/ThreadListItemDelete.js";
4
- import { ThreadListItemArchive, ThreadListItemArchiveProps } from "./threadListItem/ThreadListItemArchive.js";
5
- import { ThreadListItemUnarchive, ThreadListItemUnarchiveProps } from "./threadListItem/ThreadListItemUnarchive.js";
6
- import { ThreadListItemPrimitiveTitle as Title } from "@assistant-ui/core/react";
7
- declare namespace threadListItem_d_exports {
8
- export { ThreadListItemArchive as Archive, ThreadListItemArchiveProps as ArchiveProps, ThreadListItemDelete as Delete, ThreadListItemDeleteProps as DeleteProps, ThreadListItemRoot as Root, ThreadListItemRootProps as RootProps, Title, ThreadListItemTrigger as Trigger, ThreadListItemTriggerProps as TriggerProps, ThreadListItemUnarchive as Unarchive, ThreadListItemUnarchiveProps as UnarchiveProps };
9
- }
10
- //#endregion
11
- export { ThreadListItemArchive as Archive, type ThreadListItemArchiveProps as ArchiveProps, ThreadListItemDelete as Delete, type ThreadListItemDeleteProps as DeleteProps, ThreadListItemRoot as Root, type ThreadListItemRootProps as RootProps, Title, ThreadListItemTrigger as Trigger, type ThreadListItemTriggerProps as TriggerProps, ThreadListItemUnarchive as Unarchive, type ThreadListItemUnarchiveProps as UnarchiveProps, threadListItem_d_exports };
1
+ export { ThreadListItemRoot as Root, type ThreadListItemRootProps as RootProps, } from "./threadListItem/ThreadListItemRoot.js";
2
+ export { ThreadListItemPrimitiveTitle as Title } from "@assistant-ui/core/react";
3
+ export { ThreadListItemTrigger as Trigger, type ThreadListItemTriggerProps as TriggerProps, } from "./threadListItem/ThreadListItemTrigger.js";
4
+ export { ThreadListItemDelete as Delete, type ThreadListItemDeleteProps as DeleteProps, } from "./threadListItem/ThreadListItemDelete.js";
5
+ export { ThreadListItemArchive as Archive, type ThreadListItemArchiveProps as ArchiveProps, } from "./threadListItem/ThreadListItemArchive.js";
6
+ export { ThreadListItemUnarchive as Unarchive, type ThreadListItemUnarchiveProps as UnarchiveProps, } from "./threadListItem/ThreadListItemUnarchive.js";
12
7
  //# sourceMappingURL=threadListItem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"threadListItem.d.ts","names":[],"sources":["../../src/primitives/threadListItem.ts"],"mappings":""}
1
+ {"version":3,"file":"threadListItem.d.ts","sourceRoot":"","sources":["../../src/primitives/threadListItem.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,IAAI,IAAI,EAC1B,KAAK,uBAAuB,IAAI,SAAS,GAC1C,+CAA4C;AAC7C,OAAO,EAAE,4BAA4B,IAAI,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACjF,OAAO,EACL,qBAAqB,IAAI,OAAO,EAChC,KAAK,0BAA0B,IAAI,YAAY,GAChD,kDAA+C;AAChD,OAAO,EACL,oBAAoB,IAAI,MAAM,EAC9B,KAAK,yBAAyB,IAAI,WAAW,GAC9C,iDAA8C;AAC/C,OAAO,EACL,qBAAqB,IAAI,OAAO,EAChC,KAAK,0BAA0B,IAAI,YAAY,GAChD,kDAA+C;AAChD,OAAO,EACL,uBAAuB,IAAI,SAAS,EACpC,KAAK,4BAA4B,IAAI,cAAc,GACpD,oDAAiD"}
@@ -1,2 +1,2 @@
1
- import { LocalRuntimeOptions, useLocalRuntime } from "@assistant-ui/core/react";
2
- export { type LocalRuntimeOptions, useLocalRuntime };
1
+ export { useLocalRuntime, type LocalRuntimeOptions, } from "@assistant-ui/core/react";
2
+ //# sourceMappingURL=useLocalRuntime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLocalRuntime.d.ts","sourceRoot":"","sources":["../../src/runtimes/useLocalRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,GACzB,MAAM,0BAA0B,CAAC"}
@@ -1,2 +1,2 @@
1
- import { useRemoteThreadListRuntime } from "@assistant-ui/core/react";
2
- export { useRemoteThreadListRuntime };
1
+ export { useRemoteThreadListRuntime } from "@assistant-ui/core/react";
2
+ //# sourceMappingURL=useRemoteThreadListRuntime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRemoteThreadListRuntime.d.ts","sourceRoot":"","sources":["../../src/runtimes/useRemoteThreadListRuntime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assistant-ui/react-native",
3
- "version": "0.1.43",
3
+ "version": "0.1.44",
4
4
  "description": "React Native bindings for assistant-ui",
5
5
  "keywords": [
6
6
  "assistant",
@@ -31,11 +31,11 @@
31
31
  ],
32
32
  "sideEffects": false,
33
33
  "dependencies": {
34
- "@assistant-ui/core": "^0.3.20",
35
- "@assistant-ui/store": "^0.3.14",
36
- "@assistant-ui/tap": "^0.9.18",
37
- "assistant-cloud": "^0.2.2",
38
- "assistant-stream": "^0.3.44"
34
+ "@assistant-ui/core": "^0.3.21",
35
+ "@assistant-ui/store": "^0.3.15",
36
+ "@assistant-ui/tap": "^0.9.19",
37
+ "assistant-cloud": "^0.2.3",
38
+ "assistant-stream": "^0.3.45"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "@types/react": "*",
@@ -48,7 +48,7 @@
48
48
  }
49
49
  },
50
50
  "devDependencies": {
51
- "@assistant-ui/x-buildutils": "0.0.28",
51
+ "@assistant-ui/x-buildutils": "0.0.29",
52
52
  "@babel/core": "^7.29.7",
53
53
  "@types/react": "^19.3.0",
54
54
  "@types/react-dom": "^19.3.0",
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- /// <reference types="@assistant-ui/core/react" />
1
+ /// <reference types="@assistant-ui/core/react" preserve="true" />
2
2
 
3
3
  // Re-export core types
4
4
  export type {
@@ -22,6 +22,7 @@ export type {
22
22
  ToolApprovalOptionKind,
23
23
  ToolApprovalResponse,
24
24
  ToolCallMessagePart,
25
+ ToolCallMessagePartStatus,
25
26
  ToolCallTiming,
26
27
  ToolModelContentPart,
27
28
  ImageMessagePart,
@@ -33,12 +34,16 @@ export type {
33
34
  // Runtime types
34
35
  AssistantRuntime,
35
36
  ThreadRuntime,
37
+ ThreadRuntimeState,
36
38
  MessageRuntime,
39
+ MessageRuntimeState,
37
40
  ThreadComposerRuntime,
38
41
  EditComposerRuntime,
39
42
  ComposerRuntime,
43
+ ComposerRuntimeState,
40
44
  ThreadListRuntime,
41
45
  ThreadListItemRuntime,
46
+ ThreadListItemRuntimeState,
42
47
  // Runtime core types
43
48
  ChatModelAdapter,
44
49
  ChatModelRunOptions,
@@ -50,6 +55,7 @@ export type {
50
55
  CompleteAttachment,
51
56
  CreateAttachment,
52
57
  AttachmentRuntime,
58
+ AttachmentRuntimeState,
53
59
  // Adapter types
54
60
  AttachmentAdapter,
55
61
  ThreadHistoryAdapter,
@@ -187,6 +193,7 @@ export {
187
193
  TextMessagePartProvider,
188
194
  ChainOfThoughtPartByIndexProvider,
189
195
  SuggestionByIndexProvider,
196
+ ReadonlyThreadProvider,
190
197
  } from "@assistant-ui/core/react";
191
198
 
192
199
  // Model context, tools & clients (inlined from model-context)
@@ -321,3 +328,85 @@ export {
321
328
  useVoiceVolume,
322
329
  useVoiceControls,
323
330
  } from "@assistant-ui/core/react";
331
+
332
+ // Shared surface carried by every distribution (scripts/check-distribution-barrels.mjs)
333
+ export type {
334
+ AssistantTransportProtocol,
335
+ EnrichedPartState,
336
+ GenerativeUIComponentRegistry,
337
+ GenerativeUIMessagePartComponent,
338
+ GenerativeUIMessagePartProps,
339
+ GenerativeUIRenderProps,
340
+ McpAppResourceOutput,
341
+ PartState,
342
+ QuoteMessagePartComponent,
343
+ QuoteMessagePartProps,
344
+ TitleGenerationAdapter,
345
+ } from "@assistant-ui/core/react";
346
+ export {
347
+ CloudFileAttachmentAdapter,
348
+ createSimpleTitleAdapter,
349
+ GenerativeUIRender,
350
+ GenerativeUIRenderError,
351
+ useCloudThreadListAdapter,
352
+ useCloudThreadListRuntime,
353
+ } from "@assistant-ui/core/react";
354
+ export type {
355
+ ComposerSendOptions,
356
+ ExternalThreadMessage,
357
+ ExternalThreadProps,
358
+ InMemoryThreadListProps,
359
+ QueueItemMethods,
360
+ RemoteThreadListProps,
361
+ TaskMethods,
362
+ } from "@assistant-ui/core/store";
363
+ export {
364
+ ExternalThread,
365
+ InMemoryThreadList,
366
+ RemoteThreadList,
367
+ SingleThreadList,
368
+ } from "@assistant-ui/core/store";
369
+ export type {
370
+ AddToolResultOptions,
371
+ AttachmentStatus,
372
+ ChatModelRunUpdate,
373
+ CreateAppendMessage,
374
+ CreateResumeRunConfig,
375
+ CreateStartRunConfig,
376
+ ComposerSubmission,
377
+ DictationAdapter,
378
+ DictationState,
379
+ EditComposerState,
380
+ GenerativeUIMessagePart,
381
+ GenerativeUINode,
382
+ GenerativeUISpec,
383
+ GenericThreadHistoryAdapter,
384
+ LocalRuntimeOptionsBase,
385
+ McpAppMetadata,
386
+ MessageFormatAdapter,
387
+ MessageFormatItem,
388
+ MessageFormatRepository,
389
+ MessageModality,
390
+ MessagePartRuntime,
391
+ MessagePartState,
392
+ MessagePartStatus,
393
+ MessagePartStreamStatus,
394
+ MessageStorageEntry,
395
+ MessageTiming,
396
+ PartProviderMetadata,
397
+ QuoteInfo,
398
+ SourceProviderMetadata,
399
+ SpeechSynthesisAdapter,
400
+ SubmitFeedbackOptions,
401
+ ThreadComposerState,
402
+ ThreadListItemStatus,
403
+ ThreadListState,
404
+ ThreadSuggestion,
405
+ ToolCallMessagePartMcpMetadata,
406
+ ToolExecutionStatus,
407
+ Unstable_DirectiveFormatter,
408
+ Unstable_DirectiveSegment,
409
+ Unstable_TriggerItem,
410
+ VoiceSessionState,
411
+ } from "@assistant-ui/core";
412
+ export { unstable_defaultDirectiveFormatter } from "@assistant-ui/core";
@@ -17,6 +17,7 @@ const h = vi.hoisted(() => ({
17
17
  reload: vi.fn<() => void>(),
18
18
  speak: vi.fn<() => Promise<void>>(),
19
19
  stopSpeaking: vi.fn<() => void>(),
20
+ platform: { os: "web" },
20
21
  state: {
21
22
  copy: { disabled: false, isCopied: false },
22
23
  edit: { disabled: false },
@@ -62,6 +63,21 @@ vi.mock("@assistant-ui/core/react", async (importOriginal) => {
62
63
  };
63
64
  });
64
65
 
66
+ vi.mock("react-native", async (importOriginal) => {
67
+ const actual = (await importOriginal()) as Record<string, unknown> & {
68
+ Platform: Record<string, unknown>;
69
+ };
70
+ return {
71
+ ...actual,
72
+ Platform: {
73
+ ...actual.Platform,
74
+ get OS() {
75
+ return h.platform.os;
76
+ },
77
+ },
78
+ };
79
+ });
80
+
65
81
  (globalThis as Record<string, unknown>).IS_REACT_ACT_ENVIRONMENT = true;
66
82
 
67
83
  const click = (el: Element) =>
@@ -177,6 +193,7 @@ describe("ActionBar", () => {
177
193
  h.reload.mockReset();
178
194
  h.speak.mockReset();
179
195
  h.stopSpeaking.mockReset();
196
+ h.platform.os = "web";
180
197
  h.state.copy.disabled = false;
181
198
  h.state.copy.isCopied = false;
182
199
  h.state.edit.disabled = false;
@@ -251,6 +268,65 @@ describe("ActionBar", () => {
251
268
  });
252
269
  }
253
270
 
271
+ const feedbackActionBars = [
272
+ {
273
+ name: "ActionBarFeedbackNegative",
274
+ state: h.state.feedbackNegative,
275
+ render: (extra: { "aria-selected"?: boolean }) => (
276
+ <ActionBarFeedbackNegative testID="t" {...extra}>
277
+ x
278
+ </ActionBarFeedbackNegative>
279
+ ),
280
+ },
281
+ {
282
+ name: "ActionBarFeedbackPositive",
283
+ state: h.state.feedbackPositive,
284
+ render: (extra: { "aria-selected"?: boolean }) => (
285
+ <ActionBarFeedbackPositive testID="t" {...extra}>
286
+ x
287
+ </ActionBarFeedbackPositive>
288
+ ),
289
+ },
290
+ ];
291
+
292
+ for (const { name, state, render } of feedbackActionBars) {
293
+ describe(name, () => {
294
+ it("marks submitted feedback pressed on the web", async () => {
295
+ state.isSubmitted = true;
296
+
297
+ const el = await mount(render({}));
298
+
299
+ expect(el.getAttribute("aria-pressed")).toBe("true");
300
+ expect(el.hasAttribute("aria-selected")).toBe(false);
301
+ });
302
+
303
+ it("does not mark unsubmitted feedback pressed on the web", async () => {
304
+ const el = await mount(render({}));
305
+
306
+ expect(el.getAttribute("aria-pressed")).toBe("false");
307
+ });
308
+
309
+ it("marks submitted feedback selected on native", async () => {
310
+ h.platform.os = "ios";
311
+ state.isSubmitted = true;
312
+
313
+ const el = await mount(render({}));
314
+
315
+ expect(el.getAttribute("aria-selected")).toBe("true");
316
+ expect(el.hasAttribute("aria-pressed")).toBe(false);
317
+ });
318
+
319
+ it("keeps a caller selected override on native", async () => {
320
+ h.platform.os = "ios";
321
+ state.isSubmitted = true;
322
+
323
+ const el = await mount(render({ "aria-selected": false }));
324
+
325
+ expect(el.getAttribute("aria-selected")).toBe("false");
326
+ });
327
+ });
328
+ }
329
+
254
330
  it("calls speak on press", async () => {
255
331
  const el = await mount(<ActionBarSpeak testID="t">speak</ActionBarSpeak>);
256
332
 
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from "react";
2
- import { Pressable, type PressableProps } from "react-native";
2
+ import { Platform, Pressable, type PressableProps } from "react-native";
3
3
  import { useActionBarFeedbackNegative } from "@assistant-ui/core/react";
4
4
 
5
5
  export type ActionBarFeedbackNegativeProps = Omit<
@@ -24,6 +24,9 @@ export const ActionBarFeedbackNegative = ({
24
24
  onPress={submit}
25
25
  disabled={disabledProp}
26
26
  accessibilityRole="button"
27
+ {...(Platform.OS === "web"
28
+ ? { "aria-pressed": isSubmitted }
29
+ : { "aria-selected": isSubmitted })}
27
30
  {...pressableProps}
28
31
  >
29
32
  {typeof children === "function"
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from "react";
2
- import { Pressable, type PressableProps } from "react-native";
2
+ import { Platform, Pressable, type PressableProps } from "react-native";
3
3
  import { useActionBarFeedbackPositive } from "@assistant-ui/core/react";
4
4
 
5
5
  export type ActionBarFeedbackPositiveProps = Omit<
@@ -24,6 +24,9 @@ export const ActionBarFeedbackPositive = ({
24
24
  onPress={submit}
25
25
  disabled={disabledProp}
26
26
  accessibilityRole="button"
27
+ {...(Platform.OS === "web"
28
+ ? { "aria-pressed": isSubmitted }
29
+ : { "aria-selected": isSubmitted })}
27
30
  {...pressableProps}
28
31
  >
29
32
  {typeof children === "function"
@@ -8,7 +8,7 @@ const h = vi.hoisted(() => ({
8
8
  sendSpy: vi.fn<() => void>(),
9
9
  flushTapSyncSpy: vi.fn(<T,>(fn: () => T) => fn()),
10
10
  composerState: { text: "" },
11
- threadState: { isRunning: false, queue: false },
11
+ threadState: { isRunning: false, queue: false, voice: false },
12
12
  platform: { os: "web" as "web" | "ios" | "android" },
13
13
  }));
14
14
 
@@ -21,6 +21,7 @@ vi.mock("@assistant-ui/store", () => {
21
21
  getState: () => ({
22
22
  isRunning: h.threadState.isRunning,
23
23
  capabilities: { queue: h.threadState.queue },
24
+ voice: h.threadState.voice ? { status: { type: "running" } } : undefined,
24
25
  }),
25
26
  };
26
27
  const aui = { composer, thread };
@@ -109,6 +110,7 @@ describe("ComposerInput", () => {
109
110
  h.composerState.text = "";
110
111
  h.threadState.isRunning = false;
111
112
  h.threadState.queue = false;
113
+ h.threadState.voice = false;
112
114
  h.platform.os = "web";
113
115
 
114
116
  container = document.createElement("div");
@@ -203,6 +205,20 @@ describe("ComposerInput", () => {
203
205
  expect(h.sendSpy).toHaveBeenCalledTimes(1);
204
206
  });
205
207
 
208
+ it("submits while a spoken reply runs during a voice session", async () => {
209
+ h.threadState.isRunning = true;
210
+ h.threadState.voice = true;
211
+ const input = await mount();
212
+
213
+ let event!: KeyboardEvent;
214
+ await act(async () => {
215
+ event = fireKeyDown(input, { key: "Enter" });
216
+ });
217
+
218
+ expect(h.sendSpy).toHaveBeenCalledTimes(1);
219
+ expect(event.defaultPrevented).toBe(true);
220
+ });
221
+
206
222
  it("blocks submission when the thread starts running after mount", async () => {
207
223
  const input = await mount();
208
224
 
@@ -103,7 +103,12 @@ export const ComposerInput = ({
103
103
  if (nativeEvent.isComposing || nativeEvent.keyCode === 229) return;
104
104
  if (nativeEvent.key === "Enter" && !nativeEvent.shiftKey) {
105
105
  const threadState = aui.thread.getState();
106
- if (threadState.isRunning && !threadState.capabilities.queue) return;
106
+ if (
107
+ threadState.isRunning &&
108
+ !threadState.capabilities.queue &&
109
+ threadState.voice === undefined
110
+ )
111
+ return;
107
112
  (e as unknown as Event).preventDefault?.();
108
113
  aui.composer.send();
109
114
  }
@@ -9,6 +9,7 @@ const h = vi.hoisted(() => ({
9
9
  addToolResult: vi.fn(),
10
10
  resumeToolCall: vi.fn(),
11
11
  respondToToolApproval: vi.fn(),
12
+ unstable_recordInteraction: vi.fn(),
12
13
  state: {
13
14
  message: {
14
15
  content: [] as AnyPart[],
@@ -17,7 +18,10 @@ const h = vi.hoisted(() => ({
17
18
  },
18
19
  },
19
20
  tools: { toolUIs: {} as Record<string, unknown> },
20
- dataRenderers: { renderers: {} as Record<string, unknown> },
21
+ dataRenderers: {
22
+ renderers: {} as Record<string, unknown>,
23
+ fallbacks: [] as unknown[],
24
+ },
21
25
  },
22
26
  }));
23
27
 
@@ -28,6 +32,8 @@ vi.mock("@assistant-ui/store", () => {
28
32
  resumeToolCall: (...args: unknown[]) => h.resumeToolCall(index, ...args),
29
33
  respondToToolApproval: (...args: unknown[]) =>
30
34
  h.respondToToolApproval(index, ...args),
35
+ unstable_recordInteraction: (...args: unknown[]) =>
36
+ h.unstable_recordInteraction(index, ...args),
31
37
  }),
32
38
  });
33
39
  const aui = { message };
@@ -47,9 +53,11 @@ describe("MessageContent", () => {
47
53
  h.addToolResult.mockReset();
48
54
  h.resumeToolCall.mockReset();
49
55
  h.respondToToolApproval.mockReset();
56
+ h.unstable_recordInteraction.mockReset();
50
57
  h.state.message.content = [];
51
58
  h.state.tools.toolUIs = {};
52
59
  h.state.dataRenderers.renderers = {};
60
+ h.state.dataRenderers.fallbacks = [];
53
61
 
54
62
  container = document.createElement("div");
55
63
  document.body.appendChild(container);
@@ -152,6 +160,10 @@ describe("MessageContent", () => {
152
160
  (props.addResult as () => void)();
153
161
  (props.resume as () => void)();
154
162
  (props.respondToApproval as () => void)();
163
+ (props.unstable_recordInteraction as (input: unknown) => void)({
164
+ type: "action",
165
+ payload: { choice: "retry" },
166
+ });
155
167
  return <span data-testid="tool">tool:{String(props.toolName)}</span>;
156
168
  });
157
169
  h.state.tools.toolUIs = { search: [{ render: ToolRender }] };
@@ -163,6 +175,10 @@ describe("MessageContent", () => {
163
175
  expect(h.addToolResult).toHaveBeenCalledWith(0);
164
176
  expect(h.resumeToolCall).toHaveBeenCalledWith(0);
165
177
  expect(h.respondToToolApproval).toHaveBeenCalledWith(0);
178
+ expect(h.unstable_recordInteraction).toHaveBeenCalledWith(0, {
179
+ type: "action",
180
+ payload: { choice: "retry" },
181
+ });
166
182
  });
167
183
 
168
184
  it("picks the first registration when multiple are registered", async () => {
@@ -218,7 +234,7 @@ describe("MessageContent", () => {
218
234
  const DataRender = vi.fn((props: Record<string, unknown>) => (
219
235
  <span data-testid="data">data:{String(props.name)}</span>
220
236
  ));
221
- h.state.dataRenderers.renderers = { chart: DataRender };
237
+ h.state.dataRenderers.renderers = { chart: [DataRender] };
222
238
 
223
239
  await mount();
224
240
 
@@ -251,6 +267,51 @@ describe("MessageContent", () => {
251
267
  expect(el?.textContent).toBe("fallback:chart:0");
252
268
  });
253
269
 
270
+ it("uses dataRenderers.fallbacks[0] before renderData when no named renderer matches", async () => {
271
+ h.state.message.content = [{ type: "data", name: "chart", data: {} }];
272
+ const DataFallback = vi.fn((props: Record<string, unknown>) => (
273
+ <span data-testid="gfallback">global:{String(props.name)}</span>
274
+ ));
275
+ h.state.dataRenderers.fallbacks = [DataFallback];
276
+ const renderData = vi.fn(({ part, index }): ReactElement => (
277
+ <span data-testid="dfallback">
278
+ fallback:{String(part.name)}:{index}
279
+ </span>
280
+ ));
281
+ await mount({ renderData });
282
+
283
+ expect(
284
+ container.querySelector('[data-testid="gfallback"]')?.textContent,
285
+ ).toBe("global:chart");
286
+ expect(DataFallback.mock.calls[0]?.[0]).toEqual({
287
+ type: "data",
288
+ name: "chart",
289
+ data: {},
290
+ });
291
+ expect(renderData).not.toHaveBeenCalled();
292
+ });
293
+
294
+ it("prefers a named data renderer over dataRenderers.fallbacks", async () => {
295
+ h.state.message.content = [{ type: "data", name: "chart", data: {} }];
296
+ const DataRender = vi.fn((props: Record<string, unknown>) => (
297
+ <span data-testid="data">data:{String(props.name)}</span>
298
+ ));
299
+ const DataFallback = vi.fn(() => (
300
+ <span data-testid="gfallback">global-fallback</span>
301
+ ));
302
+ h.state.dataRenderers.renderers = { chart: [DataRender] };
303
+ h.state.dataRenderers.fallbacks = [DataFallback];
304
+ await mount({
305
+ renderData: () => <span data-testid="dfallback">render prop</span>,
306
+ });
307
+
308
+ expect(container.querySelector('[data-testid="data"]')?.textContent).toBe(
309
+ "data:chart",
310
+ );
311
+ expect(DataFallback).not.toHaveBeenCalled();
312
+ expect(container.querySelector('[data-testid="dfallback"]')).toBeNull();
313
+ });
314
+
254
315
  it("renders null when no data renderer is registered and no fallback is given", async () => {
255
316
  h.state.message.content = [{ type: "data", name: "chart", data: {} }];
256
317
  await mount();
@@ -268,7 +329,7 @@ describe("MessageContent", () => {
268
329
  t: [{ render: () => <span>[tool]</span> }],
269
330
  };
270
331
  h.state.dataRenderers.renderers = {
271
- d: () => <span>[data]</span>,
332
+ d: [() => <span>[data]</span>],
272
333
  };
273
334
  await mount();
274
335