stream-chat-react-native-core 10.0.0-rc.2 → 10.0.0-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (500) hide show
  1. package/lib/commonjs/ai-components/README.md +50 -2
  2. package/lib/commonjs/ai-components/index.js +24 -0
  3. package/lib/commonjs/ai-components/index.js.map +1 -1
  4. package/lib/commonjs/ai-components/message-composer/ComposerView.js +4 -2
  5. package/lib/commonjs/ai-components/message-composer/ComposerView.js.map +1 -1
  6. package/lib/commonjs/ai-components/message-composer/SpeechToTextButton.js +4 -1
  7. package/lib/commonjs/ai-components/message-composer/SpeechToTextButton.js.map +1 -1
  8. package/lib/commonjs/ai-components/native/AIDictation.js +6 -0
  9. package/lib/commonjs/ai-components/native/AIDictation.js.map +1 -1
  10. package/lib/commonjs/ai-components/store/dictation/store.js +4 -2
  11. package/lib/commonjs/ai-components/store/dictation/store.js.map +1 -1
  12. package/lib/commonjs/ai-components/store/dictation/useDictationState.js +4 -2
  13. package/lib/commonjs/ai-components/store/dictation/useDictationState.js.map +1 -1
  14. package/lib/commonjs/ai-components/store/index.js +22 -0
  15. package/lib/commonjs/ai-components/store/index.js.map +1 -1
  16. package/lib/commonjs/ai-components/theme.js +3 -0
  17. package/lib/commonjs/ai-components/theme.js.map +1 -1
  18. package/lib/commonjs/ai-components/transcription/useDictation.js +7 -3
  19. package/lib/commonjs/ai-components/transcription/useDictation.js.map +1 -1
  20. package/lib/commonjs/ai-components/transcription/useDictationAudioLevel.js +32 -0
  21. package/lib/commonjs/ai-components/transcription/useDictationAudioLevel.js.map +1 -0
  22. package/lib/commonjs/ai-components/voice-visualization/VoiceGlow.js +79 -0
  23. package/lib/commonjs/ai-components/voice-visualization/VoiceGlow.js.map +1 -0
  24. package/lib/commonjs/ai-components/voice-visualization/VoiceVisualizationView.js +147 -0
  25. package/lib/commonjs/ai-components/voice-visualization/VoiceVisualizationView.js.map +1 -0
  26. package/lib/commonjs/ai-components/voice-visualization/VoiceWave.js +58 -0
  27. package/lib/commonjs/ai-components/voice-visualization/VoiceWave.js.map +1 -0
  28. package/lib/commonjs/ai-components/voice-visualization/bounce.js +60 -0
  29. package/lib/commonjs/ai-components/voice-visualization/bounce.js.map +1 -0
  30. package/lib/commonjs/ai-components/voice-visualization/driver.js +208 -0
  31. package/lib/commonjs/ai-components/voice-visualization/driver.js.map +1 -0
  32. package/lib/commonjs/ai-components/voice-visualization/glowShader.js +218 -0
  33. package/lib/commonjs/ai-components/voice-visualization/glowShader.js.map +1 -0
  34. package/lib/commonjs/ai-components/voice-visualization/index.js +18 -0
  35. package/lib/commonjs/ai-components/voice-visualization/index.js.map +1 -0
  36. package/lib/commonjs/ai-components/voice-visualization/math.js +70 -0
  37. package/lib/commonjs/ai-components/voice-visualization/math.js.map +1 -0
  38. package/lib/commonjs/ai-components/voice-visualization/palette.js +47 -0
  39. package/lib/commonjs/ai-components/voice-visualization/palette.js.map +1 -0
  40. package/lib/commonjs/ai-components/voice-visualization/simplex.js +77 -0
  41. package/lib/commonjs/ai-components/voice-visualization/simplex.js.map +1 -0
  42. package/lib/commonjs/ai-components/voice-visualization/styles.js +33 -0
  43. package/lib/commonjs/ai-components/voice-visualization/styles.js.map +1 -0
  44. package/lib/commonjs/ai-components/voice-visualization/types.js +4 -0
  45. package/lib/commonjs/ai-components/voice-visualization/types.js.map +1 -0
  46. package/lib/commonjs/ai-components/voice-visualization/useReduceMotion.js +28 -0
  47. package/lib/commonjs/ai-components/voice-visualization/useReduceMotion.js.map +1 -0
  48. package/lib/commonjs/ai-components/voice-visualization/useVoiceVisualization.js +129 -0
  49. package/lib/commonjs/ai-components/voice-visualization/useVoiceVisualization.js.map +1 -0
  50. package/lib/commonjs/ai-components/voice-visualization/waveGeometry.js +124 -0
  51. package/lib/commonjs/ai-components/voice-visualization/waveGeometry.js.map +1 -0
  52. package/lib/commonjs/components/Channel/hooks/useChannelLifecycle.js +2 -1
  53. package/lib/commonjs/components/Channel/hooks/useChannelLifecycle.js.map +1 -1
  54. package/lib/commonjs/components/ChannelDetails/components/members/ChannelMemberItem.js +1 -1
  55. package/lib/commonjs/components/ChannelDetails/components/members/ChannelMemberItem.js.map +1 -1
  56. package/lib/commonjs/components/ChannelDetails/hooks/useChannelDetailsMemberStatusText.js +1 -1
  57. package/lib/commonjs/components/ChannelDetails/hooks/useChannelDetailsMemberStatusText.js.map +1 -1
  58. package/lib/commonjs/components/ChannelList/ChannelListView.js +0 -2
  59. package/lib/commonjs/components/ChannelList/ChannelListView.js.map +1 -1
  60. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js +1 -1
  61. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  62. package/lib/commonjs/components/ChannelPreview/ChannelDetailsBottomSheet.js +1 -1
  63. package/lib/commonjs/components/ChannelPreview/ChannelDetailsBottomSheet.js.map +1 -1
  64. package/lib/commonjs/components/ChannelPreview/ChannelLastMessagePreview.js +1 -0
  65. package/lib/commonjs/components/ChannelPreview/ChannelLastMessagePreview.js.map +1 -1
  66. package/lib/commonjs/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js +2 -0
  67. package/lib/commonjs/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js.map +1 -1
  68. package/lib/commonjs/components/ChannelPreview/ChannelPreviewTitle.js +1 -0
  69. package/lib/commonjs/components/ChannelPreview/ChannelPreviewTitle.js.map +1 -1
  70. package/lib/commonjs/components/ChannelPreview/ChannelPreviewView.js +1 -1
  71. package/lib/commonjs/components/ChannelPreview/ChannelPreviewView.js.map +1 -1
  72. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewData.js +5 -5
  73. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewData.js.map +1 -1
  74. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js +1 -1
  75. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js.map +1 -1
  76. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.js +1 -1
  77. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.js.map +1 -1
  78. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js +4 -1
  79. package/lib/commonjs/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js.map +1 -1
  80. package/lib/commonjs/components/Chat/hooks/useConnectionLifecycle.js +6 -2
  81. package/lib/commonjs/components/Chat/hooks/useConnectionLifecycle.js.map +1 -1
  82. package/lib/commonjs/components/Indicators/LoadingErrorIndicator.js +5 -0
  83. package/lib/commonjs/components/Indicators/LoadingErrorIndicator.js.map +1 -1
  84. package/lib/commonjs/components/Message/Message.js +1 -1
  85. package/lib/commonjs/components/Message/Message.js.map +1 -1
  86. package/lib/commonjs/components/Message/MessageItemView/MessageStatus.js +4 -0
  87. package/lib/commonjs/components/Message/MessageItemView/MessageStatus.js.map +1 -1
  88. package/lib/commonjs/components/Message/MessageItemView/MessageWrapper.js +7 -4
  89. package/lib/commonjs/components/Message/MessageItemView/MessageWrapper.js.map +1 -1
  90. package/lib/commonjs/components/Message/hooks/useCreateMessageActionHandlers.js +3 -3
  91. package/lib/commonjs/components/Message/hooks/useCreateMessageActionHandlers.js.map +1 -1
  92. package/lib/commonjs/components/Message/hooks/useProcessReactions.js +2 -2
  93. package/lib/commonjs/components/Message/hooks/useProcessReactions.js.map +1 -1
  94. package/lib/commonjs/components/Message/hooks/useUserMuteActive.js +1 -1
  95. package/lib/commonjs/components/Message/hooks/useUserMuteActive.js.map +1 -1
  96. package/lib/commonjs/components/MessageInput/MessageComposer.js +2 -1
  97. package/lib/commonjs/components/MessageInput/MessageComposer.js.map +1 -1
  98. package/lib/commonjs/components/MessageList/MessageFlashList.js +2 -2
  99. package/lib/commonjs/components/MessageList/MessageFlashList.js.map +1 -1
  100. package/lib/commonjs/components/MessageList/MessageList.js +2 -2
  101. package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
  102. package/lib/commonjs/components/MessageList/hooks/useOwnUnreadCount.js +1 -1
  103. package/lib/commonjs/components/MessageList/hooks/useOwnUnreadCount.js.map +1 -1
  104. package/lib/commonjs/components/MessageMenu/MessageUserReactionsItem.js +1 -1
  105. package/lib/commonjs/components/MessageMenu/MessageUserReactionsItem.js.map +1 -1
  106. package/lib/commonjs/components/MessageMenu/hooks/useMessageOwnReactions.js +2 -2
  107. package/lib/commonjs/components/MessageMenu/hooks/useMessageOwnReactions.js.map +1 -1
  108. package/lib/commonjs/components/Poll/components/PollAnswersList.js +1 -1
  109. package/lib/commonjs/components/Poll/components/PollAnswersList.js.map +1 -1
  110. package/lib/commonjs/components/Poll/components/PollButtons.js +1 -1
  111. package/lib/commonjs/components/Poll/components/PollButtons.js.map +1 -1
  112. package/lib/commonjs/components/Poll/hook/useIsPollCreatedByCurrentUser.js +1 -1
  113. package/lib/commonjs/components/Poll/hook/useIsPollCreatedByCurrentUser.js.map +1 -1
  114. package/lib/commonjs/components/Thread/Thread.js +1 -1
  115. package/lib/commonjs/components/Thread/Thread.js.map +1 -1
  116. package/lib/commonjs/components/ThreadList/ThreadListItem.js +1 -1
  117. package/lib/commonjs/components/ThreadList/ThreadListItem.js.map +1 -1
  118. package/lib/commonjs/components/ThreadList/ThreadListUnreadBanner.js +9 -2
  119. package/lib/commonjs/components/ThreadList/ThreadListUnreadBanner.js.map +1 -1
  120. package/lib/commonjs/components/index.js +24 -0
  121. package/lib/commonjs/components/index.js.map +1 -1
  122. package/lib/commonjs/contexts/componentsContext/defaultComponents.js +0 -2
  123. package/lib/commonjs/contexts/componentsContext/defaultComponents.js.map +1 -1
  124. package/lib/commonjs/contexts/liveLocationManagerContext/LiveLocationManagerContext.js +1 -1
  125. package/lib/commonjs/contexts/liveLocationManagerContext/LiveLocationManagerContext.js.map +1 -1
  126. package/lib/commonjs/hooks/actions/useChannelActionItems.js +1 -1
  127. package/lib/commonjs/hooks/actions/useChannelActionItems.js.map +1 -1
  128. package/lib/commonjs/hooks/actions/useChannelActions.js +2 -2
  129. package/lib/commonjs/hooks/actions/useChannelActions.js.map +1 -1
  130. package/lib/commonjs/hooks/actions/useChannelMemberActionItems.js +1 -1
  131. package/lib/commonjs/hooks/actions/useChannelMemberActionItems.js.map +1 -1
  132. package/lib/commonjs/hooks/index.js +11 -0
  133. package/lib/commonjs/hooks/index.js.map +1 -1
  134. package/lib/commonjs/hooks/messagePreview/useMessageDeliveryStatus.js +6 -6
  135. package/lib/commonjs/hooks/messagePreview/useMessageDeliveryStatus.js.map +1 -1
  136. package/lib/commonjs/hooks/useIsDirectChat.js +1 -1
  137. package/lib/commonjs/hooks/useIsDirectChat.js.map +1 -1
  138. package/lib/commonjs/i18n/runtimeDefaults.js +1 -0
  139. package/lib/commonjs/i18n/runtimeDefaults.js.map +1 -1
  140. package/lib/commonjs/store/apis/getChannelMessages.js +5 -3
  141. package/lib/commonjs/store/apis/getChannelMessages.js.map +1 -1
  142. package/lib/commonjs/store/apis/getChannels.js +6 -3
  143. package/lib/commonjs/store/apis/getChannels.js.map +1 -1
  144. package/lib/commonjs/store/apis/getChannelsForFilterSort.js +2 -1
  145. package/lib/commonjs/store/apis/getChannelsForFilterSort.js.map +1 -1
  146. package/lib/commonjs/store/apis/queries/selectMessagesForChannels.js +7 -5
  147. package/lib/commonjs/store/apis/queries/selectMessagesForChannels.js.map +1 -1
  148. package/lib/commonjs/utils/installNativeMultipartAdapter.js.map +1 -1
  149. package/lib/commonjs/version.json +1 -1
  150. package/lib/module/ai-components/README.md +50 -2
  151. package/lib/module/ai-components/index.js +24 -0
  152. package/lib/module/ai-components/index.js.map +1 -1
  153. package/lib/module/ai-components/message-composer/ComposerView.js +4 -2
  154. package/lib/module/ai-components/message-composer/ComposerView.js.map +1 -1
  155. package/lib/module/ai-components/message-composer/SpeechToTextButton.js +4 -1
  156. package/lib/module/ai-components/message-composer/SpeechToTextButton.js.map +1 -1
  157. package/lib/module/ai-components/native/AIDictation.js +6 -0
  158. package/lib/module/ai-components/native/AIDictation.js.map +1 -1
  159. package/lib/module/ai-components/store/dictation/store.js +4 -2
  160. package/lib/module/ai-components/store/dictation/store.js.map +1 -1
  161. package/lib/module/ai-components/store/dictation/useDictationState.js +4 -2
  162. package/lib/module/ai-components/store/dictation/useDictationState.js.map +1 -1
  163. package/lib/module/ai-components/store/index.js +22 -0
  164. package/lib/module/ai-components/store/index.js.map +1 -1
  165. package/lib/module/ai-components/theme.js +3 -0
  166. package/lib/module/ai-components/theme.js.map +1 -1
  167. package/lib/module/ai-components/transcription/useDictation.js +7 -3
  168. package/lib/module/ai-components/transcription/useDictation.js.map +1 -1
  169. package/lib/module/ai-components/transcription/useDictationAudioLevel.js +32 -0
  170. package/lib/module/ai-components/transcription/useDictationAudioLevel.js.map +1 -0
  171. package/lib/module/ai-components/voice-visualization/VoiceGlow.js +79 -0
  172. package/lib/module/ai-components/voice-visualization/VoiceGlow.js.map +1 -0
  173. package/lib/module/ai-components/voice-visualization/VoiceVisualizationView.js +147 -0
  174. package/lib/module/ai-components/voice-visualization/VoiceVisualizationView.js.map +1 -0
  175. package/lib/module/ai-components/voice-visualization/VoiceWave.js +58 -0
  176. package/lib/module/ai-components/voice-visualization/VoiceWave.js.map +1 -0
  177. package/lib/module/ai-components/voice-visualization/bounce.js +60 -0
  178. package/lib/module/ai-components/voice-visualization/bounce.js.map +1 -0
  179. package/lib/module/ai-components/voice-visualization/driver.js +208 -0
  180. package/lib/module/ai-components/voice-visualization/driver.js.map +1 -0
  181. package/lib/module/ai-components/voice-visualization/glowShader.js +218 -0
  182. package/lib/module/ai-components/voice-visualization/glowShader.js.map +1 -0
  183. package/lib/module/ai-components/voice-visualization/index.js +18 -0
  184. package/lib/module/ai-components/voice-visualization/index.js.map +1 -0
  185. package/lib/module/ai-components/voice-visualization/math.js +70 -0
  186. package/lib/module/ai-components/voice-visualization/math.js.map +1 -0
  187. package/lib/module/ai-components/voice-visualization/palette.js +47 -0
  188. package/lib/module/ai-components/voice-visualization/palette.js.map +1 -0
  189. package/lib/module/ai-components/voice-visualization/simplex.js +77 -0
  190. package/lib/module/ai-components/voice-visualization/simplex.js.map +1 -0
  191. package/lib/module/ai-components/voice-visualization/styles.js +33 -0
  192. package/lib/module/ai-components/voice-visualization/styles.js.map +1 -0
  193. package/lib/module/ai-components/voice-visualization/types.js +4 -0
  194. package/lib/module/ai-components/voice-visualization/types.js.map +1 -0
  195. package/lib/module/ai-components/voice-visualization/useReduceMotion.js +28 -0
  196. package/lib/module/ai-components/voice-visualization/useReduceMotion.js.map +1 -0
  197. package/lib/module/ai-components/voice-visualization/useVoiceVisualization.js +129 -0
  198. package/lib/module/ai-components/voice-visualization/useVoiceVisualization.js.map +1 -0
  199. package/lib/module/ai-components/voice-visualization/waveGeometry.js +124 -0
  200. package/lib/module/ai-components/voice-visualization/waveGeometry.js.map +1 -0
  201. package/lib/module/components/Channel/hooks/useChannelLifecycle.js +2 -1
  202. package/lib/module/components/Channel/hooks/useChannelLifecycle.js.map +1 -1
  203. package/lib/module/components/ChannelDetails/components/members/ChannelMemberItem.js +1 -1
  204. package/lib/module/components/ChannelDetails/components/members/ChannelMemberItem.js.map +1 -1
  205. package/lib/module/components/ChannelDetails/hooks/useChannelDetailsMemberStatusText.js +1 -1
  206. package/lib/module/components/ChannelDetails/hooks/useChannelDetailsMemberStatusText.js.map +1 -1
  207. package/lib/module/components/ChannelList/ChannelListView.js +0 -2
  208. package/lib/module/components/ChannelList/ChannelListView.js.map +1 -1
  209. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js +1 -1
  210. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  211. package/lib/module/components/ChannelPreview/ChannelDetailsBottomSheet.js +1 -1
  212. package/lib/module/components/ChannelPreview/ChannelDetailsBottomSheet.js.map +1 -1
  213. package/lib/module/components/ChannelPreview/ChannelLastMessagePreview.js +1 -0
  214. package/lib/module/components/ChannelPreview/ChannelLastMessagePreview.js.map +1 -1
  215. package/lib/module/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js +2 -0
  216. package/lib/module/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js.map +1 -1
  217. package/lib/module/components/ChannelPreview/ChannelPreviewTitle.js +1 -0
  218. package/lib/module/components/ChannelPreview/ChannelPreviewTitle.js.map +1 -1
  219. package/lib/module/components/ChannelPreview/ChannelPreviewView.js +1 -1
  220. package/lib/module/components/ChannelPreview/ChannelPreviewView.js.map +1 -1
  221. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewData.js +5 -5
  222. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewData.js.map +1 -1
  223. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js +1 -1
  224. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayName.js.map +1 -1
  225. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.js +1 -1
  226. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.js.map +1 -1
  227. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js +4 -1
  228. package/lib/module/components/ChannelPreview/hooks/useChannelPreviewPollLabel.js.map +1 -1
  229. package/lib/module/components/Chat/hooks/useConnectionLifecycle.js +6 -2
  230. package/lib/module/components/Chat/hooks/useConnectionLifecycle.js.map +1 -1
  231. package/lib/module/components/Indicators/LoadingErrorIndicator.js +5 -0
  232. package/lib/module/components/Indicators/LoadingErrorIndicator.js.map +1 -1
  233. package/lib/module/components/Message/Message.js +1 -1
  234. package/lib/module/components/Message/Message.js.map +1 -1
  235. package/lib/module/components/Message/MessageItemView/MessageStatus.js +4 -0
  236. package/lib/module/components/Message/MessageItemView/MessageStatus.js.map +1 -1
  237. package/lib/module/components/Message/MessageItemView/MessageWrapper.js +7 -4
  238. package/lib/module/components/Message/MessageItemView/MessageWrapper.js.map +1 -1
  239. package/lib/module/components/Message/hooks/useCreateMessageActionHandlers.js +3 -3
  240. package/lib/module/components/Message/hooks/useCreateMessageActionHandlers.js.map +1 -1
  241. package/lib/module/components/Message/hooks/useProcessReactions.js +2 -2
  242. package/lib/module/components/Message/hooks/useProcessReactions.js.map +1 -1
  243. package/lib/module/components/Message/hooks/useUserMuteActive.js +1 -1
  244. package/lib/module/components/Message/hooks/useUserMuteActive.js.map +1 -1
  245. package/lib/module/components/MessageInput/MessageComposer.js +2 -1
  246. package/lib/module/components/MessageInput/MessageComposer.js.map +1 -1
  247. package/lib/module/components/MessageList/MessageFlashList.js +2 -2
  248. package/lib/module/components/MessageList/MessageFlashList.js.map +1 -1
  249. package/lib/module/components/MessageList/MessageList.js +2 -2
  250. package/lib/module/components/MessageList/MessageList.js.map +1 -1
  251. package/lib/module/components/MessageList/hooks/useOwnUnreadCount.js +1 -1
  252. package/lib/module/components/MessageList/hooks/useOwnUnreadCount.js.map +1 -1
  253. package/lib/module/components/MessageMenu/MessageUserReactionsItem.js +1 -1
  254. package/lib/module/components/MessageMenu/MessageUserReactionsItem.js.map +1 -1
  255. package/lib/module/components/MessageMenu/hooks/useMessageOwnReactions.js +2 -2
  256. package/lib/module/components/MessageMenu/hooks/useMessageOwnReactions.js.map +1 -1
  257. package/lib/module/components/Poll/components/PollAnswersList.js +1 -1
  258. package/lib/module/components/Poll/components/PollAnswersList.js.map +1 -1
  259. package/lib/module/components/Poll/components/PollButtons.js +1 -1
  260. package/lib/module/components/Poll/components/PollButtons.js.map +1 -1
  261. package/lib/module/components/Poll/hook/useIsPollCreatedByCurrentUser.js +1 -1
  262. package/lib/module/components/Poll/hook/useIsPollCreatedByCurrentUser.js.map +1 -1
  263. package/lib/module/components/Thread/Thread.js +1 -1
  264. package/lib/module/components/Thread/Thread.js.map +1 -1
  265. package/lib/module/components/ThreadList/ThreadListItem.js +1 -1
  266. package/lib/module/components/ThreadList/ThreadListItem.js.map +1 -1
  267. package/lib/module/components/ThreadList/ThreadListUnreadBanner.js +9 -2
  268. package/lib/module/components/ThreadList/ThreadListUnreadBanner.js.map +1 -1
  269. package/lib/module/components/index.js +24 -0
  270. package/lib/module/components/index.js.map +1 -1
  271. package/lib/module/contexts/componentsContext/defaultComponents.js +0 -2
  272. package/lib/module/contexts/componentsContext/defaultComponents.js.map +1 -1
  273. package/lib/module/contexts/liveLocationManagerContext/LiveLocationManagerContext.js +1 -1
  274. package/lib/module/contexts/liveLocationManagerContext/LiveLocationManagerContext.js.map +1 -1
  275. package/lib/module/hooks/actions/useChannelActionItems.js +1 -1
  276. package/lib/module/hooks/actions/useChannelActionItems.js.map +1 -1
  277. package/lib/module/hooks/actions/useChannelActions.js +2 -2
  278. package/lib/module/hooks/actions/useChannelActions.js.map +1 -1
  279. package/lib/module/hooks/actions/useChannelMemberActionItems.js +1 -1
  280. package/lib/module/hooks/actions/useChannelMemberActionItems.js.map +1 -1
  281. package/lib/module/hooks/index.js +11 -0
  282. package/lib/module/hooks/index.js.map +1 -1
  283. package/lib/module/hooks/messagePreview/useMessageDeliveryStatus.js +6 -6
  284. package/lib/module/hooks/messagePreview/useMessageDeliveryStatus.js.map +1 -1
  285. package/lib/module/hooks/useIsDirectChat.js +1 -1
  286. package/lib/module/hooks/useIsDirectChat.js.map +1 -1
  287. package/lib/module/i18n/runtimeDefaults.js +1 -0
  288. package/lib/module/i18n/runtimeDefaults.js.map +1 -1
  289. package/lib/module/store/apis/getChannelMessages.js +5 -3
  290. package/lib/module/store/apis/getChannelMessages.js.map +1 -1
  291. package/lib/module/store/apis/getChannels.js +6 -3
  292. package/lib/module/store/apis/getChannels.js.map +1 -1
  293. package/lib/module/store/apis/getChannelsForFilterSort.js +2 -1
  294. package/lib/module/store/apis/getChannelsForFilterSort.js.map +1 -1
  295. package/lib/module/store/apis/queries/selectMessagesForChannels.js +7 -5
  296. package/lib/module/store/apis/queries/selectMessagesForChannels.js.map +1 -1
  297. package/lib/module/utils/installNativeMultipartAdapter.js.map +1 -1
  298. package/lib/module/version.json +1 -1
  299. package/lib/typescript/ai-components/index.d.ts +3 -1
  300. package/lib/typescript/ai-components/index.d.ts.map +1 -1
  301. package/lib/typescript/ai-components/message-composer/ComposerView.d.ts.map +1 -1
  302. package/lib/typescript/ai-components/native/AIDictation.d.ts +6 -0
  303. package/lib/typescript/ai-components/native/AIDictation.d.ts.map +1 -1
  304. package/lib/typescript/ai-components/store/dictation/store.d.ts +7 -0
  305. package/lib/typescript/ai-components/store/dictation/store.d.ts.map +1 -1
  306. package/lib/typescript/ai-components/store/dictation/useDictationState.d.ts +1 -0
  307. package/lib/typescript/ai-components/store/dictation/useDictationState.d.ts.map +1 -1
  308. package/lib/typescript/ai-components/store/index.d.ts +2 -0
  309. package/lib/typescript/ai-components/store/index.d.ts.map +1 -1
  310. package/lib/typescript/ai-components/theme.d.ts +13 -0
  311. package/lib/typescript/ai-components/theme.d.ts.map +1 -1
  312. package/lib/typescript/ai-components/transcription/useDictation.d.ts +9 -1
  313. package/lib/typescript/ai-components/transcription/useDictation.d.ts.map +1 -1
  314. package/lib/typescript/ai-components/transcription/useDictationAudioLevel.d.ts +11 -0
  315. package/lib/typescript/ai-components/transcription/useDictationAudioLevel.d.ts.map +1 -0
  316. package/lib/typescript/ai-components/voice-visualization/VoiceGlow.d.ts +13 -0
  317. package/lib/typescript/ai-components/voice-visualization/VoiceGlow.d.ts.map +1 -0
  318. package/lib/typescript/ai-components/voice-visualization/VoiceVisualizationView.d.ts +26 -0
  319. package/lib/typescript/ai-components/voice-visualization/VoiceVisualizationView.d.ts.map +1 -0
  320. package/lib/typescript/ai-components/voice-visualization/VoiceWave.d.ts +13 -0
  321. package/lib/typescript/ai-components/voice-visualization/VoiceWave.d.ts.map +1 -0
  322. package/lib/typescript/ai-components/voice-visualization/bounce.d.ts +20 -0
  323. package/lib/typescript/ai-components/voice-visualization/bounce.d.ts.map +1 -0
  324. package/lib/typescript/ai-components/voice-visualization/driver.d.ts +96 -0
  325. package/lib/typescript/ai-components/voice-visualization/driver.d.ts.map +1 -0
  326. package/lib/typescript/ai-components/voice-visualization/glowShader.d.ts +7 -0
  327. package/lib/typescript/ai-components/voice-visualization/glowShader.d.ts.map +1 -0
  328. package/lib/typescript/ai-components/voice-visualization/index.d.ts +4 -0
  329. package/lib/typescript/ai-components/voice-visualization/index.d.ts.map +1 -0
  330. package/lib/typescript/ai-components/voice-visualization/math.d.ts +26 -0
  331. package/lib/typescript/ai-components/voice-visualization/math.d.ts.map +1 -0
  332. package/lib/typescript/ai-components/voice-visualization/palette.d.ts +18 -0
  333. package/lib/typescript/ai-components/voice-visualization/palette.d.ts.map +1 -0
  334. package/lib/typescript/ai-components/voice-visualization/simplex.d.ts +11 -0
  335. package/lib/typescript/ai-components/voice-visualization/simplex.d.ts.map +1 -0
  336. package/lib/typescript/ai-components/voice-visualization/styles.d.ts +24 -0
  337. package/lib/typescript/ai-components/voice-visualization/styles.d.ts.map +1 -0
  338. package/lib/typescript/ai-components/voice-visualization/types.d.ts +45 -0
  339. package/lib/typescript/ai-components/voice-visualization/types.d.ts.map +1 -0
  340. package/lib/typescript/ai-components/voice-visualization/useReduceMotion.d.ts +10 -0
  341. package/lib/typescript/ai-components/voice-visualization/useReduceMotion.d.ts.map +1 -0
  342. package/lib/typescript/ai-components/voice-visualization/useVoiceVisualization.d.ts +18 -0
  343. package/lib/typescript/ai-components/voice-visualization/useVoiceVisualization.d.ts.map +1 -0
  344. package/lib/typescript/ai-components/voice-visualization/waveGeometry.d.ts +25 -0
  345. package/lib/typescript/ai-components/voice-visualization/waveGeometry.d.ts.map +1 -0
  346. package/lib/typescript/components/Channel/hooks/useChannelLifecycle.d.ts.map +1 -1
  347. package/lib/typescript/components/ChannelList/ChannelListView.d.ts +1 -1
  348. package/lib/typescript/components/ChannelList/ChannelListView.d.ts.map +1 -1
  349. package/lib/typescript/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.d.ts.map +1 -1
  350. package/lib/typescript/components/ChannelPreview/hooks/useChannelPreviewData.d.ts.map +1 -1
  351. package/lib/typescript/components/Chat/hooks/useConnectionLifecycle.d.ts +5 -4
  352. package/lib/typescript/components/Chat/hooks/useConnectionLifecycle.d.ts.map +1 -1
  353. package/lib/typescript/components/Indicators/LoadingErrorIndicator.d.ts +1 -1
  354. package/lib/typescript/components/Indicators/LoadingErrorIndicator.d.ts.map +1 -1
  355. package/lib/typescript/components/Message/MessageItemView/MessageStatus.d.ts.map +1 -1
  356. package/lib/typescript/components/Message/MessageItemView/MessageWrapper.d.ts.map +1 -1
  357. package/lib/typescript/components/MessageInput/MessageComposer.d.ts.map +1 -1
  358. package/lib/typescript/components/ThreadList/ThreadListUnreadBanner.d.ts.map +1 -1
  359. package/lib/typescript/components/index.d.ts +2 -0
  360. package/lib/typescript/components/index.d.ts.map +1 -1
  361. package/lib/typescript/contexts/componentsContext/defaultComponents.d.ts +0 -1
  362. package/lib/typescript/contexts/componentsContext/defaultComponents.d.ts.map +1 -1
  363. package/lib/typescript/hooks/index.d.ts +1 -0
  364. package/lib/typescript/hooks/index.d.ts.map +1 -1
  365. package/lib/typescript/hooks/messagePreview/useMessageDeliveryStatus.d.ts +3 -0
  366. package/lib/typescript/hooks/messagePreview/useMessageDeliveryStatus.d.ts.map +1 -1
  367. package/lib/typescript/i18n/keys.d.ts +3 -1
  368. package/lib/typescript/i18n/keys.d.ts.map +1 -1
  369. package/lib/typescript/i18n/runtimeDefaults.d.ts +1 -0
  370. package/lib/typescript/i18n/runtimeDefaults.d.ts.map +1 -1
  371. package/lib/typescript/store/apis/getChannelMessages.d.ts +2 -1
  372. package/lib/typescript/store/apis/getChannelMessages.d.ts.map +1 -1
  373. package/lib/typescript/store/apis/getChannels.d.ts +3 -1
  374. package/lib/typescript/store/apis/getChannels.d.ts.map +1 -1
  375. package/lib/typescript/store/apis/getChannelsForFilterSort.d.ts.map +1 -1
  376. package/lib/typescript/store/apis/queries/selectMessagesForChannels.d.ts +3 -1
  377. package/lib/typescript/store/apis/queries/selectMessagesForChannels.d.ts.map +1 -1
  378. package/lib/typescript/utils/installNativeMultipartAdapter.d.ts +5 -3
  379. package/lib/typescript/utils/installNativeMultipartAdapter.d.ts.map +1 -1
  380. package/package.json +4 -4
  381. package/src/__tests__/offline-support/offline-feature.tsx +7 -7
  382. package/src/__tests__/offline-support/optimistic-update.tsx +5 -5
  383. package/src/ai-components/README.md +50 -2
  384. package/src/ai-components/__tests__/VoiceVisualization.test.tsx +208 -0
  385. package/src/ai-components/__tests__/dictation.test.tsx +58 -1
  386. package/src/ai-components/__tests__/voiceDriver.test.ts +317 -0
  387. package/src/ai-components/__tests__/voicePalette.test.ts +124 -0
  388. package/src/ai-components/index.ts +3 -1
  389. package/src/ai-components/message-composer/ComposerView.tsx +6 -3
  390. package/src/ai-components/message-composer/SpeechToTextButton.tsx +5 -2
  391. package/src/ai-components/native/AIDictation.ts +11 -0
  392. package/src/ai-components/store/dictation/store.ts +9 -0
  393. package/src/ai-components/store/dictation/useDictationState.ts +2 -1
  394. package/src/ai-components/store/index.ts +2 -0
  395. package/src/ai-components/theme.ts +16 -0
  396. package/src/ai-components/transcription/useDictation.ts +16 -3
  397. package/src/ai-components/transcription/useDictationAudioLevel.ts +38 -0
  398. package/src/ai-components/voice-visualization/VoiceGlow.tsx +79 -0
  399. package/src/ai-components/voice-visualization/VoiceVisualizationView.tsx +179 -0
  400. package/src/ai-components/voice-visualization/VoiceWave.tsx +67 -0
  401. package/src/ai-components/voice-visualization/bounce.ts +61 -0
  402. package/src/ai-components/voice-visualization/driver.ts +240 -0
  403. package/src/ai-components/voice-visualization/glowShader.ts +227 -0
  404. package/src/ai-components/voice-visualization/index.ts +3 -0
  405. package/src/ai-components/voice-visualization/math.ts +73 -0
  406. package/src/ai-components/voice-visualization/palette.ts +59 -0
  407. package/src/ai-components/voice-visualization/simplex.ts +92 -0
  408. package/src/ai-components/voice-visualization/styles.ts +42 -0
  409. package/src/ai-components/voice-visualization/types.ts +44 -0
  410. package/src/ai-components/voice-visualization/useReduceMotion.ts +34 -0
  411. package/src/ai-components/voice-visualization/useVoiceVisualization.ts +153 -0
  412. package/src/ai-components/voice-visualization/waveGeometry.ts +137 -0
  413. package/src/components/Channel/__tests__/Channel.test.tsx +44 -5
  414. package/src/components/Channel/hooks/useChannelLifecycle.ts +4 -1
  415. package/src/components/ChannelDetails/__tests__/ChannelDetails.test.tsx +1 -1
  416. package/src/components/ChannelDetails/__tests__/ChannelDetailsActionsSection.test.tsx +1 -1
  417. package/src/components/ChannelDetails/__tests__/ChannelDetailsEditButton.test.tsx +1 -1
  418. package/src/components/ChannelDetails/__tests__/ChannelDetailsMemberSection.test.tsx +1 -1
  419. package/src/components/ChannelDetails/__tests__/ChannelDetailsNavHeader.test.tsx +1 -1
  420. package/src/components/ChannelDetails/__tests__/ChannelDetailsProfile.test.tsx +2 -2
  421. package/src/components/ChannelDetails/__tests__/ChannelEditDetailsForm.test.tsx +1 -1
  422. package/src/components/ChannelDetails/__tests__/ChannelEditDetailsFormContent.test.tsx +2 -2
  423. package/src/components/ChannelDetails/__tests__/ChannelEditName.test.tsx +1 -1
  424. package/src/components/ChannelDetails/__tests__/members/ChannelAddMembersForm.test.tsx +1 -1
  425. package/src/components/ChannelDetails/__tests__/members/ChannelMemberActionsSheet.test.tsx +2 -2
  426. package/src/components/ChannelDetails/__tests__/members/ChannelMemberItem.test.tsx +1 -1
  427. package/src/components/ChannelDetails/__tests__/useChannelDetailsMemberStatusText.test.tsx +1 -1
  428. package/src/components/ChannelDetails/components/members/ChannelMemberItem.tsx +1 -1
  429. package/src/components/ChannelDetails/hooks/useChannelDetailsMemberStatusText.ts +1 -1
  430. package/src/components/ChannelList/ChannelListView.tsx +1 -3
  431. package/src/components/ChannelList/__tests__/ChannelList.test.tsx +44 -0
  432. package/src/components/ChannelList/hooks/usePaginatedChannels.ts +1 -1
  433. package/src/components/ChannelPreview/ChannelDetailsBottomSheet.tsx +1 -1
  434. package/src/components/ChannelPreview/ChannelLastMessagePreview.tsx +1 -1
  435. package/src/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.tsx +8 -2
  436. package/src/components/ChannelPreview/ChannelPreviewTitle.tsx +1 -1
  437. package/src/components/ChannelPreview/ChannelPreviewView.tsx +1 -1
  438. package/src/components/ChannelPreview/__tests__/ChannelPreview.test.tsx +4 -4
  439. package/src/components/ChannelPreview/__tests__/ChannelPreviewView.test.tsx +40 -0
  440. package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewData.test.tsx +51 -0
  441. package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayName.test.tsx +1 -1
  442. package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayPresence.test.tsx +1 -1
  443. package/src/components/ChannelPreview/hooks/__tests__/useChannelPreviewPollLabel.test.tsx +87 -0
  444. package/src/components/ChannelPreview/hooks/useChannelPreviewData.ts +3 -4
  445. package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayName.ts +1 -1
  446. package/src/components/ChannelPreview/hooks/useChannelPreviewDisplayPresence.ts +1 -1
  447. package/src/components/ChannelPreview/hooks/useChannelPreviewPollLabel.ts +1 -1
  448. package/src/components/Chat/__tests__/Chat.test.tsx +31 -1
  449. package/src/components/Chat/hooks/useConnectionLifecycle.ts +12 -6
  450. package/src/components/Indicators/LoadingErrorIndicator.tsx +8 -1
  451. package/src/components/Message/Message.tsx +1 -1
  452. package/src/components/Message/MessageItemView/MessageStatus.tsx +16 -2
  453. package/src/components/Message/MessageItemView/MessageWrapper.tsx +14 -4
  454. package/src/components/Message/MessageItemView/__tests__/MessageStatus.test.tsx +21 -0
  455. package/src/components/Message/hooks/__tests__/useCreateMessageActionHandlers.test.tsx +1 -1
  456. package/src/components/Message/hooks/__tests__/useUserMuteActive.test.tsx +1 -1
  457. package/src/components/Message/hooks/useCreateMessageActionHandlers.ts +3 -3
  458. package/src/components/Message/hooks/useProcessReactions.ts +2 -2
  459. package/src/components/Message/hooks/useUserMuteActive.ts +1 -1
  460. package/src/components/MessageInput/MessageComposer.tsx +4 -2
  461. package/src/components/MessageList/MessageFlashList.tsx +2 -2
  462. package/src/components/MessageList/MessageList.tsx +2 -2
  463. package/src/components/MessageList/__tests__/MessageList.test.tsx +26 -8
  464. package/src/components/MessageList/__tests__/ScrollToBottomButton.test.tsx +3 -3
  465. package/src/components/MessageList/hooks/useOwnUnreadCount.ts +1 -1
  466. package/src/components/MessageMenu/MessageUserReactionsItem.tsx +1 -1
  467. package/src/components/MessageMenu/hooks/useMessageOwnReactions.ts +2 -2
  468. package/src/components/Poll/components/PollAnswersList.tsx +1 -1
  469. package/src/components/Poll/components/PollButtons.tsx +1 -1
  470. package/src/components/Poll/hook/useIsPollCreatedByCurrentUser.ts +1 -1
  471. package/src/components/Thread/Thread.tsx +1 -1
  472. package/src/components/Thread/__tests__/Thread.test.tsx +4 -2
  473. package/src/components/ThreadList/ThreadListItem.tsx +1 -1
  474. package/src/components/ThreadList/ThreadListUnreadBanner.tsx +6 -2
  475. package/src/components/ThreadList/__tests__/ThreadList.test.tsx +21 -0
  476. package/src/components/index.ts +2 -0
  477. package/src/contexts/componentsContext/defaultComponents.ts +0 -2
  478. package/src/contexts/liveLocationManagerContext/LiveLocationManagerContext.tsx +1 -1
  479. package/src/hooks/__tests__/useChannelMuteActive.test.tsx +1 -1
  480. package/src/hooks/__tests__/useIsDirectChat.test.tsx +1 -1
  481. package/src/hooks/actions/__tests__/useChannelActionItems.test.tsx +1 -1
  482. package/src/hooks/actions/__tests__/useChannelActions.test.tsx +1 -1
  483. package/src/hooks/actions/__tests__/useChannelMemberActionItems.test.tsx +6 -6
  484. package/src/hooks/actions/useChannelActionItems.tsx +1 -1
  485. package/src/hooks/actions/useChannelActions.ts +2 -2
  486. package/src/hooks/actions/useChannelMemberActionItems.tsx +1 -1
  487. package/src/hooks/index.ts +1 -0
  488. package/src/hooks/messagePreview/__tests__/useMessageDeliveryStatus.test.tsx +57 -32
  489. package/src/hooks/messagePreview/useMessageDeliveryStatus.ts +13 -7
  490. package/src/hooks/useIsDirectChat.ts +1 -1
  491. package/src/i18n/__tests__/catalog.fixture.json +2 -0
  492. package/src/i18n/keys.ts +3 -0
  493. package/src/i18n/runtimeDefaults.ts +1 -0
  494. package/src/store/__tests__/selectMessagesForChannels.test.ts +34 -12
  495. package/src/store/apis/getChannelMessages.ts +4 -1
  496. package/src/store/apis/getChannels.ts +5 -1
  497. package/src/store/apis/getChannelsForFilterSort.ts +1 -0
  498. package/src/store/apis/queries/selectMessagesForChannels.ts +7 -2
  499. package/src/utils/installNativeMultipartAdapter.ts +5 -3
  500. package/src/version.json +1 -1
@@ -0,0 +1,317 @@
1
+ import {
2
+ bounceScale,
3
+ createBounce,
4
+ easeOut,
5
+ scaleAt,
6
+ startBounce,
7
+ } from '../voice-visualization/bounce';
8
+ import {
9
+ advanceDriver,
10
+ createDriverState,
11
+ driverReact,
12
+ driverScale,
13
+ ease,
14
+ hoverDriver,
15
+ LEVEL_RESPONSE,
16
+ type LevelResponse,
17
+ NO_TAP,
18
+ tapDriver,
19
+ type VoiceDriverInput,
20
+ type VoiceDriverState,
21
+ } from '../voice-visualization/driver';
22
+ import type { Hsv, VoiceAgentState } from '../voice-visualization/types';
23
+
24
+ // Ported from stream-chat-android's VoiceVisualizationDriverTest and VoiceVisualizationBounceTest,
25
+ // so the platforms keep moving alike.
26
+
27
+ const blue: Hsv = { hue: 218 / 360, saturation: 1, value: 1 };
28
+ const red: Hsv = { hue: 0, saturation: 1, value: 1 };
29
+ const FRAME = 1 / 60;
30
+
31
+ const input = (
32
+ state: VoiceAgentState,
33
+ overrides: Partial<Omit<VoiceDriverInput, 'state'>> = {},
34
+ ): VoiceDriverInput => ({
35
+ audioLevel: null,
36
+ colors: [blue],
37
+ expressivity: 1,
38
+ reduceMotion: false,
39
+ state,
40
+ ...overrides,
41
+ });
42
+
43
+ /** A driver with the input it reads each frame, as the view keeps them. */
44
+ const createDriver = (initial: VoiceDriverInput, response?: LevelResponse) => {
45
+ const driver = { input: initial, state: createDriverState(initial, response) };
46
+ return {
47
+ ...driver,
48
+ advance: (seconds: number) => advanceDriver(driver.state, driver.input, seconds),
49
+ run: (seconds: number) => {
50
+ for (let i = 0; i < Math.floor(seconds / FRAME); i++) {
51
+ advanceDriver(driver.state, driver.input, FRAME);
52
+ }
53
+ },
54
+ setInput: (next: VoiceDriverInput) => {
55
+ driver.input = next;
56
+ },
57
+ get d(): VoiceDriverState {
58
+ return driver.state;
59
+ },
60
+ get input() {
61
+ return driver.input;
62
+ },
63
+ };
64
+ };
65
+
66
+ const expectNear = (actual: number, expected: number, tolerance: number) =>
67
+ expect(Math.abs(actual - expected)).toBeLessThanOrEqual(tolerance);
68
+
69
+ describe('voice visualization driver', () => {
70
+ it('starts settled on the state', () => {
71
+ const { d } = createDriver(input('speaking'));
72
+
73
+ expect(driverReact(d)).toBe(1);
74
+ expect(d.load).toBe(0);
75
+ expect(d.flow).toBe(0);
76
+ expect(d.bright).toBe(1);
77
+ expect(d.time).toBe(0);
78
+ expect(d.count).toBe(1);
79
+ expect(driverScale(d)).toBe(1);
80
+ expect(d.tapAge).toBe(NO_TAP);
81
+ expect(d.colors[0]).toEqual(blue);
82
+ expect(d.colors[4]).toEqual(blue);
83
+ });
84
+
85
+ it('does not share its colors with the caller’s palette', () => {
86
+ const palette = [{ ...blue }];
87
+ const driver = createDriver(input('idle', { colors: palette }));
88
+ driver.setInput(input('idle', { colors: [red] }));
89
+
90
+ driver.run(1);
91
+
92
+ expect(palette[0]).toEqual(blue);
93
+ });
94
+
95
+ it('eases toward the motion of a new state', () => {
96
+ const driver = createDriver(input('idle'));
97
+ driver.setInput(input('connecting'));
98
+
99
+ driver.advance(FRAME);
100
+ expectNear(driver.d.load, 0.08, 1e-4);
101
+ driver.run(2);
102
+ expectNear(driver.d.load, 1, 1e-3);
103
+ expectNear(driverReact(driver.d), 0, 1e-3);
104
+ });
105
+
106
+ it('eases the same at any frame rate', () => {
107
+ const at60 = createDriver(input('idle'));
108
+ const at120 = createDriver(input('idle'));
109
+ at60.setInput(input('speaking'));
110
+ at120.setInput(input('speaking'));
111
+
112
+ for (let i = 0; i < 30; i++) at60.advance(1 / 60);
113
+ for (let i = 0; i < 60; i++) at120.advance(1 / 120);
114
+
115
+ expectNear(driverReact(at60.d), driverReact(at120.d), 1e-4);
116
+ expectNear(at60.d.time, at120.d.time, 1e-2);
117
+ });
118
+
119
+ it('clamps a long frame', () => {
120
+ const driver = createDriver(input('idle'));
121
+
122
+ driver.advance(5);
123
+
124
+ expectNear(driver.d.time, 0.05 * 0.4, 1e-5);
125
+ });
126
+
127
+ it('turns the flow only while thinking', () => {
128
+ const driver = createDriver(input('speaking'));
129
+ driver.run(1);
130
+ expect(driver.d.flowSpin).toBe(0);
131
+
132
+ driver.setInput(input('thinking'));
133
+ driver.run(1);
134
+ expect(driver.d.flowSpin).toBeGreaterThan(0);
135
+ });
136
+
137
+ it('keeps the colors turning in every state', () => {
138
+ const driver = createDriver(input('idle'));
139
+
140
+ driver.run(1);
141
+
142
+ expect(driver.d.orbSpin).toBeGreaterThan(0);
143
+ });
144
+
145
+ it('scales amplitude and speed with expressivity', () => {
146
+ const lively = createDriver(input('speaking', { expressivity: 2 }));
147
+ const still = createDriver(input('speaking', { expressivity: 0 }));
148
+
149
+ expectNear(driverReact(lively.d), 1.85, 1e-5);
150
+ expectNear(driverReact(still.d), 0.15, 1e-5);
151
+ lively.advance(0.05);
152
+ expectNear(lively.d.time, 0.05 * 1.25 * 1.4, 1e-5);
153
+ });
154
+
155
+ it('slows time and ignores the pointer under reduced motion', () => {
156
+ const driver = createDriver(input('idle', { reduceMotion: true }));
157
+
158
+ tapDriver(driver.d, driver.input, 0.1, 0.1);
159
+ hoverDriver(driver.d, driver.input, 0.1, 0.1);
160
+ driver.advance(0.05);
161
+
162
+ expectNear(driver.d.time, 0.05 * 0.07 * 0.4, 1e-6);
163
+ expect(driver.d.tapAge).toBeGreaterThan(NO_TAP);
164
+ expect(driverScale(driver.d)).toBe(1);
165
+ expect(driver.d.hoverAmount).toBe(0);
166
+ });
167
+
168
+ it('stops hovering once motion is reduced', () => {
169
+ const driver = createDriver(input('idle'));
170
+ hoverDriver(driver.d, driver.input, 0.1, 0.1);
171
+ driver.run(1);
172
+
173
+ driver.setInput(input('idle', { reduceMotion: true }));
174
+ driver.run(1);
175
+
176
+ expectNear(driver.d.hoverAmount, 0, 1e-3);
177
+ });
178
+
179
+ it('ripples from a tap and bounces', () => {
180
+ const driver = createDriver(input('idle'));
181
+
182
+ tapDriver(driver.d, driver.input, 0.1, -0.2);
183
+ expect(driver.d.tapX).toBe(0.1);
184
+ expect(driver.d.tapY).toBe(-0.2);
185
+ expect(driver.d.tapAge).toBe(0);
186
+
187
+ driver.advance(0.05);
188
+ expectNear(driver.d.tapAge, 0.05, 1e-6);
189
+ expect(driverScale(driver.d)).toBeLessThan(1);
190
+ driver.run(0.5);
191
+ expect(driverScale(driver.d)).toBe(1);
192
+ });
193
+
194
+ it('eases hovering in and out', () => {
195
+ const driver = createDriver(input('idle'));
196
+
197
+ hoverDriver(driver.d, driver.input, 0.2, 0.1);
198
+ driver.run(1);
199
+ expectNear(driver.d.hoverAmount, 1, 1e-3);
200
+ expect(driver.d.hoverX).toBe(0.2);
201
+
202
+ hoverDriver(driver.d, driver.input, null, null);
203
+ driver.run(1);
204
+ expectNear(driver.d.hoverAmount, 0, 1e-3);
205
+ expect(driver.d.hoverX).toBe(0.2);
206
+ });
207
+
208
+ it('lifts the motion to a live audio level', () => {
209
+ const driver = createDriver(input('idle', { audioLevel: 0.8 }));
210
+
211
+ driver.run(2);
212
+ expectNear(driver.d.mic, 0.8, 1e-3);
213
+ expectNear(driver.d.voice, 1, 1e-3);
214
+ expectNear(driverReact(driver.d), 0.8, 1e-3);
215
+
216
+ driver.setInput(input('idle'));
217
+ driver.run(2);
218
+ expectNear(driver.d.voice, 0, 1e-3);
219
+ expectNear(driverReact(driver.d), 0.12, 1e-3);
220
+ });
221
+
222
+ const settled = (response: LevelResponse, audioLevel: number) => {
223
+ const driver = createDriver(input('idle', { audioLevel }), response);
224
+ driver.run(1);
225
+ return driver;
226
+ };
227
+
228
+ it('catches up with a louder level within a word when smooth', () => {
229
+ const driver = settled(LEVEL_RESPONSE.smooth, 0);
230
+
231
+ driver.setInput(input('idle', { audioLevel: 1 }));
232
+ driver.run(0.1);
233
+ expect(driver.d.mic).toBeGreaterThanOrEqual(0.5);
234
+ expect(driver.d.mic).toBeLessThanOrEqual(0.8);
235
+ driver.run(0.3);
236
+ expect(driver.d.mic).toBeGreaterThan(0.95);
237
+ });
238
+
239
+ it('lets a quieter level fall away over a pause, not a syllable, when smooth', () => {
240
+ const driver = settled(LEVEL_RESPONSE.smooth, 1);
241
+
242
+ driver.setInput(input('idle', { audioLevel: 0 }));
243
+ driver.run(0.1);
244
+ expect(driver.d.mic).toBeGreaterThan(0.7);
245
+ driver.run(0.9);
246
+ expect(driver.d.mic).toBeLessThan(0.1);
247
+ });
248
+
249
+ it('follows a quieter level within a syllable when steady', () => {
250
+ const driver = settled(LEVEL_RESPONSE.steady, 1);
251
+
252
+ driver.setInput(input('idle', { audioLevel: 0 }));
253
+ driver.run(0.1);
254
+ expect(driver.d.mic).toBeLessThan(0.1);
255
+ });
256
+
257
+ it('eases a hue the short way round', () => {
258
+ const driver = createDriver(
259
+ input('idle', { colors: [{ hue: 0.95, saturation: 1, value: 1 }] }),
260
+ );
261
+ driver.setInput(input('idle', { colors: [{ hue: 0.05, saturation: 1, value: 1 }] }));
262
+
263
+ driver.advance(FRAME);
264
+ expectNear(driver.d.colors[0].hue, 0.962, 1e-4);
265
+ driver.run(2);
266
+ expectNear(driver.d.colors[0].hue, 0.05, 1e-3);
267
+ });
268
+
269
+ it('repeats the first color in empty slots and crossfades the count', () => {
270
+ const driver = createDriver(input('idle', { colors: [blue, red] }));
271
+ expect(driver.d.colors[1]).toEqual(red);
272
+ expect(driver.d.colors[2]).toEqual(blue);
273
+
274
+ driver.setInput(input('idle', { colors: [blue, red, red] }));
275
+ driver.advance(FRAME);
276
+ expectNear(driver.d.count, 2.12, 1e-4);
277
+ });
278
+
279
+ it('moves the per-frame share at 60 Hz', () => {
280
+ expectNear(ease(0.08, 1 / 60), 0.08, 1e-5);
281
+ expect(ease(0.08, 0)).toBe(0);
282
+ });
283
+ });
284
+
285
+ describe('voice visualization bounce', () => {
286
+ it('follows the keyframes', () => {
287
+ expect(scaleAt(0)).toBe(1);
288
+ expectNear(scaleAt(0.15), 0.965, 1e-5);
289
+ expectNear(scaleAt(0.3), 0.93, 1e-5);
290
+ expectNear(scaleAt(0.62), 1.03, 1e-5);
291
+ expectNear(scaleAt(1), 1, 1e-5);
292
+ });
293
+
294
+ it('times them with the CSS ease-out', () => {
295
+ expectNear(easeOut(0), 0, 1e-4);
296
+ expectNear(easeOut(0.5), 0.684, 2e-3);
297
+ expectNear(easeOut(1), 1, 1e-4);
298
+ });
299
+
300
+ it('dips, overshoots and settles', () => {
301
+ const bounce = createBounce();
302
+ expect(bounceScale(bounce)).toBe(1);
303
+
304
+ startBounce(bounce);
305
+ const scales = Array.from({ length: 21 }, () => {
306
+ const scale = bounceScale(bounce);
307
+ bounce.age += 1 / 60;
308
+ return scale;
309
+ });
310
+
311
+ expectNear(scales[0], 1, 1e-9);
312
+ expectNear(Math.min(...scales), 0.93, 0.01);
313
+ expectNear(Math.max(...scales), 1.03, 0.01);
314
+ expect(scales.indexOf(Math.min(...scales))).toBeLessThan(scales.indexOf(Math.max(...scales)));
315
+ expect(bounceScale(bounce)).toBe(1);
316
+ });
317
+ });
@@ -0,0 +1,124 @@
1
+ import { audioLevelInput, expressivityInput, speechEnv } from '../voice-visualization/math';
2
+ import { luminance, parseColor, rgbToHsv, toHsvPalette } from '../voice-visualization/palette';
3
+ import { snoise } from '../voice-visualization/simplex';
4
+ import { GLOW_STYLE, WAVE_STYLE } from '../voice-visualization/styles';
5
+
6
+ describe('voice visualization palette', () => {
7
+ it('keeps a color’s full hue, saturation and value', () => {
8
+ const hsv = rgbToHsv([0, 95 / 255, 1]);
9
+
10
+ expect(hsv.hue * 360).toBeCloseTo(217.6, 1);
11
+ expect(hsv.saturation).toBeCloseTo(1, 4);
12
+ expect(hsv.value).toBeCloseTo(1, 4);
13
+ });
14
+
15
+ it('keeps a muted color muted', () => {
16
+ // hsv(108°, 25%, 60%)
17
+ const hsv = rgbToHsv([0.48, 0.6, 0.45]);
18
+
19
+ expect(hsv.hue).toBeCloseTo(0.3, 2);
20
+ expect(hsv.saturation).toBeCloseTo(0.25, 2);
21
+ expect(hsv.value).toBeCloseTo(0.6, 4);
22
+ });
23
+
24
+ it('gives a gray no saturation', () => {
25
+ const hsv = rgbToHsv([0.5, 0.5, 0.5]);
26
+
27
+ expect(hsv.saturation).toBe(0);
28
+ expect(hsv.value).toBe(0.5);
29
+ });
30
+
31
+ it.each([
32
+ ['#005fff', [0, 95 / 255, 1]],
33
+ ['#0af', [0, 170 / 255, 1]],
34
+ ['#005fff80', [0, 95 / 255, 1]],
35
+ ['rgb(0, 95, 255)', [0, 95 / 255, 1]],
36
+ ['rgba(0, 95, 255, 0.5)', [0, 95 / 255, 1]],
37
+ ['hsl(0, 100%, 50%)', [1, 0, 0]],
38
+ ['rebeccapurple', [0.4, 0.2, 0.6]],
39
+ ['#000000', [0, 0, 0]],
40
+ ])('reads %s', (color, expected) => {
41
+ const rgb = parseColor(color);
42
+ expect(rgb).not.toBeNull();
43
+ rgb?.forEach((channel, i) => expect(channel).toBeCloseTo(expected[i], 2));
44
+ });
45
+
46
+ it('skips colors it cannot read', () => {
47
+ expect(parseColor('not-a-color')).toBeNull();
48
+ expect(parseColor('#12345')).toBeNull();
49
+ expect(parseColor('')).toBeNull();
50
+ expect(toHsvPalette(['nope', '#ff0000'])).toHaveLength(1);
51
+ });
52
+
53
+ it('keeps only the first five colors', () => {
54
+ expect(toHsvPalette(Array.from({ length: 7 }, () => '#ff0000'))).toHaveLength(5);
55
+ });
56
+
57
+ it('measures luminance for the light or dark look', () => {
58
+ expect(luminance('#ffffff')).toBeCloseTo(1, 4);
59
+ expect(luminance('#000000')).toBe(0);
60
+ expect(luminance('#1c1e22')).toBeLessThan(0.5);
61
+ expect(luminance('')).toBeNull();
62
+ });
63
+ });
64
+
65
+ describe('voice visualization inputs', () => {
66
+ it('clamps expressivity to 0-2 and replaces one that is not a number', () => {
67
+ expect(expressivityInput(3)).toBe(2);
68
+ expect(expressivityInput(-1)).toBe(0);
69
+ expect(expressivityInput(0.5)).toBe(0.5);
70
+ expect(expressivityInput(Number.NaN)).toBe(1);
71
+ expect(expressivityInput(Number.POSITIVE_INFINITY)).toBe(1);
72
+ expect(expressivityInput(undefined)).toBe(1);
73
+ });
74
+
75
+ it('clamps the audio level to 0-1 and treats one that is not a number as no audio', () => {
76
+ expect(audioLevelInput(2)).toBe(1);
77
+ expect(audioLevelInput(-1)).toBe(0);
78
+ expect(audioLevelInput(0.4)).toBe(0.4);
79
+ expect(audioLevelInput(Number.NaN)).toBeNull();
80
+ expect(audioLevelInput(null)).toBeNull();
81
+ expect(audioLevelInput(undefined)).toBeNull();
82
+ });
83
+ });
84
+
85
+ describe('voice visualization noise', () => {
86
+ it('matches the shader’s simplex noise as a GPU computes it', () => {
87
+ // Read back from the shader's own snoise on a GPU (stream-chat-react's fixtures).
88
+ const gpu: Array<[number, number, number, number]> = [
89
+ [0.3, 21, 0, 0.7696],
90
+ [1.7, 5, 0, 0.208],
91
+ [0.12, 0, 0, 0.049],
92
+ [2.5, 9, 0, 0.3869],
93
+ [10.2, 14, 0, 0.603],
94
+ [3.3, 1.1, 0.9, -0.7541],
95
+ [0.05, 0.05, 0.05, -0.5481],
96
+ ];
97
+ for (const [x, y, z, expected] of gpu) {
98
+ expect(snoise(x, y, z)).toBeCloseTo(expected, 2);
99
+ }
100
+ });
101
+
102
+ it('gives speech phrases and pauses', () => {
103
+ const samples = Array.from({ length: 2000 }, (_, i) => speechEnv(i * 0.01));
104
+
105
+ expect(Math.min(...samples)).toBe(0);
106
+ expect(Math.max(...samples)).toBeGreaterThan(0.6);
107
+ expect(Math.max(...samples)).toBeLessThanOrEqual(1);
108
+ });
109
+ });
110
+
111
+ describe('voice visualization hit areas', () => {
112
+ it('takes the globe within a third of the shorter side', () => {
113
+ expect(GLOW_STYLE.contains(0, 0)).toBe(true);
114
+ expect(GLOW_STYLE.contains(0.2, 0.2)).toBe(true);
115
+ expect(GLOW_STYLE.contains(0.3, 0.3)).toBe(false);
116
+ });
117
+
118
+ it('takes the string across, and only near its line', () => {
119
+ expect(WAVE_STYLE.contains(0.45, 0)).toBe(true);
120
+ expect(WAVE_STYLE.contains(0, 0.1)).toBe(true);
121
+ expect(WAVE_STYLE.contains(0, 0.2)).toBe(false);
122
+ expect(WAVE_STYLE.contains(0.55, 0)).toBe(false);
123
+ });
124
+ });
@@ -4,6 +4,7 @@ export * from './charts';
4
4
  export * from './message-composer';
5
5
  export * from './StreamingMessageView';
6
6
  export * from './AITypingIndicatorView';
7
+ export * from './voice-visualization';
7
8
 
8
9
  export * from './components';
9
10
 
@@ -11,7 +12,8 @@ export * from './contexts';
11
12
 
12
13
  export * from './services';
13
14
  export * from './transcription/useDictation';
14
- export { isDictationAvailable } from './native/AIDictation';
15
+ export * from './transcription/useDictationAudioLevel';
16
+ export { isDictationAvailable, type DictationLevel } from './native/AIDictation';
15
17
 
16
18
  export * from './store';
17
19
 
@@ -19,7 +19,7 @@ import type {
19
19
  AbstractMediaPickerService,
20
20
  MediaPickerState,
21
21
  } from '../services/media-picker-service/AbstractMediaPickerService';
22
- import { useComposerText } from '../store';
22
+ import { COMPOSER_DICTATION_SOURCE, useComposerText } from '../store';
23
23
  import type { ComposerState } from '../store';
24
24
  import { useDictationState } from '../store/dictation/useDictationState';
25
25
  import { useDictationTranscript } from '../store/dictation/useDictationTranscript';
@@ -100,7 +100,7 @@ export const AIMessageInput = () => {
100
100
  } = useTheme();
101
101
  const styles = useStyles();
102
102
 
103
- const { error, isRecording } = useDictationState();
103
+ const { error, isRecording, source } = useDictationState();
104
104
  const { text } = useComposerText();
105
105
  const { transcript } = useDictationTranscript();
106
106
  const { setText } = useMessageComposerContext();
@@ -109,10 +109,13 @@ export const AIMessageInput = () => {
109
109
  useEffect(() => {
110
110
  const transcriptChanged = transcript !== previousTranscript.current;
111
111
  previousTranscript.current = transcript;
112
+ // Only dictation from the composer's own button fills the input; dictation started elsewhere
113
+ // (a voice mode, say) must not overwrite what the user typed.
114
+ if (source !== COMPOSER_DICTATION_SOURCE) return;
112
115
  if (!error && (isRecording || transcriptChanged)) {
113
116
  setText(transcript);
114
117
  }
115
- }, [isRecording, transcript, error, setText]);
118
+ }, [isRecording, transcript, error, setText, source]);
116
119
 
117
120
  return (
118
121
  <TextInput
@@ -9,7 +9,7 @@ import { Mic } from '../internal/icons/Mic';
9
9
 
10
10
  import { isDictationAvailable, warnIfDictationUnavailable } from '../native/AIDictation';
11
11
  import type { DictationStartOptions } from '../native-specs/NativeAIDictation';
12
- import { dictationStore, type DictationStoreState } from '../store';
12
+ import { COMPOSER_DICTATION_SOURCE, dictationStore, type DictationStoreState } from '../store';
13
13
  import { useDictation } from '../transcription/useDictation';
14
14
 
15
15
  const selector = ({ isRecording }: DictationStoreState) => ({
@@ -30,6 +30,9 @@ export const SpeechToTextButton = (props: SpeechToTextButtonProps) => {
30
30
  return <AvailableSpeechToTextButton {...props} />;
31
31
  };
32
32
 
33
+ // Marks this button's dictation as the composer's, so `ComposerView` fills its input with it.
34
+ const DICTATION_OPTIONS = { source: COMPOSER_DICTATION_SOURCE };
35
+
33
36
  const AvailableSpeechToTextButton = ({ options }: SpeechToTextButtonProps) => {
34
37
  const {
35
38
  theme: {
@@ -38,7 +41,7 @@ const AvailableSpeechToTextButton = ({ options }: SpeechToTextButtonProps) => {
38
41
  },
39
42
  } = useTheme();
40
43
 
41
- const { cancel, toggle } = useDictation(options);
44
+ const { cancel, toggle } = useDictation(options, DICTATION_OPTIONS);
42
45
  const { isRecording } = useStateStore(dictationStore, selector);
43
46
 
44
47
  useEffect(() => {
@@ -11,6 +11,10 @@ import NativeAIDictation, {
11
11
  const ON_STATE_EVENT = 'AIDictationOnState';
12
12
  const ON_RESULT_EVENT = 'AIDictationOnResult';
13
13
  const ON_ERROR_EVENT = 'AIDictationOnError';
14
+ const ON_LEVEL_EVENT = 'AIDictationOnLevel';
15
+
16
+ /** The microphone's level while dictation listens, from 0 to 1. */
17
+ export type DictationLevel = { level: number };
14
18
 
15
19
  let eventEmitter: NativeEventEmitter | undefined;
16
20
  const getEventEmitter = () => {
@@ -75,4 +79,11 @@ export const AIDictation = {
75
79
  );
76
80
  return sub ? () => sub.remove() : noop;
77
81
  },
82
+ /** The microphone's level while dictation listens, about 10 to 30 times a second. */
83
+ addLevelListener(listener: (payload: DictationLevel) => void) {
84
+ const sub = getEventEmitter()?.addListener(ON_LEVEL_EVENT, (event) =>
85
+ listener(event as DictationLevel),
86
+ );
87
+ return sub ? () => sub.remove() : noop;
88
+ },
78
89
  };
@@ -7,6 +7,11 @@ export type DictationStoreState = {
7
7
  transcript: string;
8
8
  isRecording: boolean;
9
9
  error?: DictationError | null;
10
+ /**
11
+ * Who started the current dictation, as passed to `useDictation`, or `null`. Lets a consumer
12
+ * such as `ComposerView` pick up only the transcripts meant for it.
13
+ */
14
+ source?: string | null;
10
15
  };
11
16
 
12
17
  const DEFAULT_STATE: DictationStoreState = {
@@ -14,8 +19,12 @@ const DEFAULT_STATE: DictationStoreState = {
14
19
  transcript: '',
15
20
  isRecording: false,
16
21
  error: null,
22
+ source: null,
17
23
  };
18
24
 
25
+ /** The `source` of dictation started by the composer's own `SpeechToTextButton`. */
26
+ export const COMPOSER_DICTATION_SOURCE = 'composer';
27
+
19
28
  export const dictationStore = new StateStore<DictationStoreState>(DEFAULT_STATE);
20
29
 
21
30
  const reset = () => dictationStore.next(DEFAULT_STATE);
@@ -2,10 +2,11 @@ import { useStateStore } from '@stream-io/state-store/react-bindings';
2
2
 
3
3
  import { dictationStore, type DictationStoreState } from './store';
4
4
 
5
- const selector = ({ state, isRecording, error }: DictationStoreState) => ({
5
+ const selector = ({ state, isRecording, error, source }: DictationStoreState) => ({
6
6
  state,
7
7
  isRecording,
8
8
  error,
9
+ source,
9
10
  });
10
11
 
11
12
  export const useDictationState = () => useStateStore(dictationStore, selector);
@@ -6,3 +6,5 @@ export * from './composer/useComposerHasText';
6
6
  export * from './composer/useComposerText';
7
7
 
8
8
  export * from './dictation/store';
9
+ export * from './dictation/useDictationState';
10
+ export * from './dictation/useDictationTranscript';
@@ -56,6 +56,19 @@ export type Theme = {
56
56
  aiTypingIndicatorView: {
57
57
  text: TextStyle;
58
58
  };
59
+ /**
60
+ * `VoiceGlow` and `VoiceWave`. Optional, so a hand-built `Theme` without it keeps type-checking;
61
+ * the visualizations fall back to the default accent then.
62
+ */
63
+ voiceVisualization?: {
64
+ /** One to five colors, used when a visualization is given no `colors` of its own. */
65
+ colors: string[];
66
+ /**
67
+ * The color the visualizations sit on, which tells them to draw for a light or a dark
68
+ * background. Defaults to the system's color scheme.
69
+ */
70
+ backdropColor?: string;
71
+ };
59
72
  };
60
73
 
61
74
  export const defaultTheme: Theme = {
@@ -135,4 +148,7 @@ export const defaultTheme: Theme = {
135
148
  aiTypingIndicatorView: {
136
149
  text: {},
137
150
  },
151
+ voiceVisualization: {
152
+ colors: [colors.accent_blue],
153
+ },
138
154
  };
@@ -27,7 +27,19 @@ const selector = ({ isRecording }: DictationStoreState) => ({
27
27
  });
28
28
 
29
29
  // TODO: add proper jsdocs
30
- export const useDictation = (defaultOptions: DictationStartOptions = DEFAULT_OPTIONS) => {
30
+ export type UseDictationOptions = {
31
+ /**
32
+ * Who is dictating, stored as the dictation store's `source` when dictation starts. The
33
+ * `ComposerView` only fills its input with dictation whose source is the composer's own, so
34
+ * dictation started elsewhere (a voice mode, say) leaves the composer's text alone.
35
+ */
36
+ source?: string;
37
+ };
38
+
39
+ export const useDictation = (
40
+ defaultOptions: DictationStartOptions = DEFAULT_OPTIONS,
41
+ { source }: UseDictationOptions = {},
42
+ ) => {
31
43
  const { isRecording } = useStateStore(dictationStore, selector);
32
44
 
33
45
  useEffect(() => {
@@ -65,11 +77,12 @@ export const useDictation = (defaultOptions: DictationStartOptions = DEFAULT_OPT
65
77
  code: 'NO_PERMISSION',
66
78
  message: 'Microphone permission not granted',
67
79
  },
80
+ source: source ?? null,
68
81
  });
69
82
  return;
70
83
  }
71
84
 
72
- dictationStore.partialNext({ error: null, transcript: '' });
85
+ dictationStore.partialNext({ error: null, source: source ?? null, transcript: '' });
73
86
 
74
87
  const opts: DictationStartOptions = {
75
88
  ...defaultOptions,
@@ -78,7 +91,7 @@ export const useDictation = (defaultOptions: DictationStartOptions = DEFAULT_OPT
78
91
 
79
92
  AIDictation.start(opts);
80
93
  },
81
- [defaultOptions],
94
+ [defaultOptions, source],
82
95
  );
83
96
 
84
97
  const stop = useCallback(() => {