stream-chat-react-native-core 9.1.3 → 9.2.0-beta.2

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 (466) hide show
  1. package/lib/commonjs/a11y/a11yUtils.js +40 -0
  2. package/lib/commonjs/a11y/a11yUtils.js.map +1 -0
  3. package/lib/commonjs/a11y/hooks/useA11yLabel.js +16 -0
  4. package/lib/commonjs/a11y/hooks/useA11yLabel.js.map +1 -0
  5. package/lib/commonjs/a11y/hooks/useAccessibilityActivateAction.js +25 -0
  6. package/lib/commonjs/a11y/hooks/useAccessibilityActivateAction.js.map +1 -0
  7. package/lib/commonjs/a11y/hooks/useAnnounceOnStateChange.js +36 -0
  8. package/lib/commonjs/a11y/hooks/useAnnounceOnStateChange.js.map +1 -0
  9. package/lib/commonjs/a11y/hooks/useReducedMotionPreference.js +34 -0
  10. package/lib/commonjs/a11y/hooks/useReducedMotionPreference.js.map +1 -0
  11. package/lib/commonjs/a11y/hooks/useResolvedModalAccessibilityProps.js +20 -0
  12. package/lib/commonjs/a11y/hooks/useResolvedModalAccessibilityProps.js.map +1 -0
  13. package/lib/commonjs/a11y/hooks/useScreenReaderEnabled.js +37 -0
  14. package/lib/commonjs/a11y/hooks/useScreenReaderEnabled.js.map +1 -0
  15. package/lib/commonjs/a11y/index.js +81 -0
  16. package/lib/commonjs/a11y/index.js.map +1 -0
  17. package/lib/commonjs/components/AITypingIndicatorView/AITypingIndicatorView.js +10 -0
  18. package/lib/commonjs/components/AITypingIndicatorView/AITypingIndicatorView.js.map +1 -1
  19. package/lib/commonjs/components/Accessibility/NotificationAnnouncer.js +37 -0
  20. package/lib/commonjs/components/Accessibility/NotificationAnnouncer.js.map +1 -0
  21. package/lib/commonjs/components/Accessibility/hooks/useIncomingMessageAnnouncements.js +109 -0
  22. package/lib/commonjs/components/Accessibility/hooks/useIncomingMessageAnnouncements.js.map +1 -0
  23. package/lib/commonjs/components/Accessibility/index.js +37 -0
  24. package/lib/commonjs/components/Accessibility/index.js.map +1 -0
  25. package/lib/commonjs/components/Accessibility/useAccessibilityAnnouncer.js +15 -0
  26. package/lib/commonjs/components/Accessibility/useAccessibilityAnnouncer.js.map +1 -0
  27. package/lib/commonjs/components/AttachmentPicker/AttachmentPicker.js +20 -0
  28. package/lib/commonjs/components/AttachmentPicker/AttachmentPicker.js.map +1 -1
  29. package/lib/commonjs/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentMediaPicker.js +1 -0
  30. package/lib/commonjs/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentMediaPicker.js.map +1 -1
  31. package/lib/commonjs/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js +19 -2
  32. package/lib/commonjs/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js.map +1 -1
  33. package/lib/commonjs/components/AttachmentPicker/components/AttachmentPickerContent.js +2 -1
  34. package/lib/commonjs/components/AttachmentPicker/components/AttachmentPickerContent.js.map +1 -1
  35. package/lib/commonjs/components/AttachmentPicker/components/AttachmentTypePickerButton.js +9 -1
  36. package/lib/commonjs/components/AttachmentPicker/components/AttachmentTypePickerButton.js.map +1 -1
  37. package/lib/commonjs/components/Channel/Channel.js +2 -1
  38. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  39. package/lib/commonjs/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js +4 -0
  40. package/lib/commonjs/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js.map +1 -1
  41. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js +2 -2
  42. package/lib/commonjs/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  43. package/lib/commonjs/components/ImageGallery/components/ImageGalleryHeader.js +1 -1
  44. package/lib/commonjs/components/ImageGallery/components/ImageGalleryHeader.js.map +1 -1
  45. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js +1 -1
  46. package/lib/commonjs/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  47. package/lib/commonjs/components/Indicators/LoadingDots.js +2 -0
  48. package/lib/commonjs/components/Indicators/LoadingDots.js.map +1 -1
  49. package/lib/commonjs/components/Indicators/LoadingErrorIndicator.js +3 -0
  50. package/lib/commonjs/components/Indicators/LoadingErrorIndicator.js.map +1 -1
  51. package/lib/commonjs/components/Indicators/LoadingIndicator.js +2 -0
  52. package/lib/commonjs/components/Indicators/LoadingIndicator.js.map +1 -1
  53. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AttachmentRemoveControl.js +16 -4
  54. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AttachmentRemoveControl.js.map +1 -1
  55. package/lib/commonjs/components/MessageInput/components/AudioRecorder/AudioRecorder.js +3 -0
  56. package/lib/commonjs/components/MessageInput/components/AudioRecorder/AudioRecorder.js.map +1 -1
  57. package/lib/commonjs/components/MessageInput/components/AudioRecorder/AudioRecordingButton.js +5 -0
  58. package/lib/commonjs/components/MessageInput/components/AudioRecorder/AudioRecordingButton.js.map +1 -1
  59. package/lib/commonjs/components/MessageInput/components/InputButtons/AttachButton.js +12 -3
  60. package/lib/commonjs/components/MessageInput/components/InputButtons/AttachButton.js.map +1 -1
  61. package/lib/commonjs/components/MessageInput/components/OutputButtons/EditButton.js +1 -0
  62. package/lib/commonjs/components/MessageInput/components/OutputButtons/EditButton.js.map +1 -1
  63. package/lib/commonjs/components/MessageInput/components/OutputButtons/SendButton.js +1 -0
  64. package/lib/commonjs/components/MessageInput/components/OutputButtons/SendButton.js.map +1 -1
  65. package/lib/commonjs/components/MessageList/MessageFlashList.js +19 -2
  66. package/lib/commonjs/components/MessageList/MessageFlashList.js.map +1 -1
  67. package/lib/commonjs/components/MessageList/MessageList.js +32 -8
  68. package/lib/commonjs/components/MessageList/MessageList.js.map +1 -1
  69. package/lib/commonjs/components/MessageList/ScrollToBottomButton.js +12 -1
  70. package/lib/commonjs/components/MessageList/ScrollToBottomButton.js.map +1 -1
  71. package/lib/commonjs/components/MessageList/UnreadMessagesNotification.js +1 -0
  72. package/lib/commonjs/components/MessageList/UnreadMessagesNotification.js.map +1 -1
  73. package/lib/commonjs/components/MessageList/hooks/useScrollToBottomAccessibilityAction.js +47 -0
  74. package/lib/commonjs/components/MessageList/hooks/useScrollToBottomAccessibilityAction.js.map +1 -0
  75. package/lib/commonjs/components/MessageMenu/MessageActionList.js +4 -1
  76. package/lib/commonjs/components/MessageMenu/MessageActionList.js.map +1 -1
  77. package/lib/commonjs/components/MessageMenu/MessageActionListItem.js +12 -3
  78. package/lib/commonjs/components/MessageMenu/MessageActionListItem.js.map +1 -1
  79. package/lib/commonjs/components/MessageMenu/MessageReactionPicker.js +2 -0
  80. package/lib/commonjs/components/MessageMenu/MessageReactionPicker.js.map +1 -1
  81. package/lib/commonjs/components/MessageMenu/ReactionButton.js +9 -1
  82. package/lib/commonjs/components/MessageMenu/ReactionButton.js.map +1 -1
  83. package/lib/commonjs/components/Poll/components/CreatePollHeader.js +2 -0
  84. package/lib/commonjs/components/Poll/components/CreatePollHeader.js.map +1 -1
  85. package/lib/commonjs/components/Poll/components/MultipleVotesSettings.js +2 -0
  86. package/lib/commonjs/components/Poll/components/MultipleVotesSettings.js.map +1 -1
  87. package/lib/commonjs/components/Poll/components/PollModalHeader.js +1 -0
  88. package/lib/commonjs/components/Poll/components/PollModalHeader.js.map +1 -1
  89. package/lib/commonjs/components/Poll/components/PollOption.js +15 -0
  90. package/lib/commonjs/components/Poll/components/PollOption.js.map +1 -1
  91. package/lib/commonjs/components/ProgressControl/ProgressControl.js +10 -0
  92. package/lib/commonjs/components/ProgressControl/ProgressControl.js.map +1 -1
  93. package/lib/commonjs/components/Reply/Reply.js +3 -0
  94. package/lib/commonjs/components/Reply/Reply.js.map +1 -1
  95. package/lib/commonjs/components/UIComponents/BottomSheetModal.js +6 -3
  96. package/lib/commonjs/components/UIComponents/BottomSheetModal.js.map +1 -1
  97. package/lib/commonjs/components/index.js +11 -0
  98. package/lib/commonjs/components/index.js.map +1 -1
  99. package/lib/commonjs/components/ui/Avatar/Avatar.js +17 -2
  100. package/lib/commonjs/components/ui/Avatar/Avatar.js.map +1 -1
  101. package/lib/commonjs/components/ui/Avatar/ChannelAvatar.js +3 -1
  102. package/lib/commonjs/components/ui/Avatar/ChannelAvatar.js.map +1 -1
  103. package/lib/commonjs/components/ui/Avatar/UserAvatar.js +1 -0
  104. package/lib/commonjs/components/ui/Avatar/UserAvatar.js.map +1 -1
  105. package/lib/commonjs/components/ui/Button/Button.js +64 -21
  106. package/lib/commonjs/components/ui/Button/Button.js.map +1 -1
  107. package/lib/commonjs/components/ui/Input/Input.js +63 -21
  108. package/lib/commonjs/components/ui/Input/Input.js.map +1 -1
  109. package/lib/commonjs/contexts/accessibilityContext/AccessibilityContext.js +134 -0
  110. package/lib/commonjs/contexts/accessibilityContext/AccessibilityContext.js.map +1 -0
  111. package/lib/commonjs/contexts/accessibilityContext/index.js +15 -0
  112. package/lib/commonjs/contexts/accessibilityContext/index.js.map +1 -0
  113. package/lib/commonjs/contexts/index.js +11 -0
  114. package/lib/commonjs/contexts/index.js.map +1 -1
  115. package/lib/commonjs/contexts/overlayContext/OverlayContext.js.map +1 -1
  116. package/lib/commonjs/contexts/overlayContext/OverlayProvider.js +19 -14
  117. package/lib/commonjs/contexts/overlayContext/OverlayProvider.js.map +1 -1
  118. package/lib/commonjs/hooks/index.js +11 -0
  119. package/lib/commonjs/hooks/index.js.map +1 -1
  120. package/lib/commonjs/i18n/en.json +57 -1
  121. package/lib/commonjs/i18n/es.json +57 -1
  122. package/lib/commonjs/i18n/fr.json +57 -1
  123. package/lib/commonjs/i18n/he.json +57 -1
  124. package/lib/commonjs/i18n/hi.json +57 -1
  125. package/lib/commonjs/i18n/it.json +57 -1
  126. package/lib/commonjs/i18n/ja.json +57 -1
  127. package/lib/commonjs/i18n/ko.json +57 -1
  128. package/lib/commonjs/i18n/nl.json +57 -1
  129. package/lib/commonjs/i18n/pt-br.json +57 -1
  130. package/lib/commonjs/i18n/ru.json +57 -1
  131. package/lib/commonjs/i18n/tr.json +57 -1
  132. package/lib/commonjs/mock-builders/DB/mock.js +3 -1
  133. package/lib/commonjs/mock-builders/DB/mock.js.map +1 -1
  134. package/lib/commonjs/test-utils/BetterSqlite.js +3 -2
  135. package/lib/commonjs/test-utils/BetterSqlite.js.map +1 -1
  136. package/lib/commonjs/version.json +1 -1
  137. package/lib/module/a11y/a11yUtils.js +40 -0
  138. package/lib/module/a11y/a11yUtils.js.map +1 -0
  139. package/lib/module/a11y/hooks/useA11yLabel.js +16 -0
  140. package/lib/module/a11y/hooks/useA11yLabel.js.map +1 -0
  141. package/lib/module/a11y/hooks/useAccessibilityActivateAction.js +25 -0
  142. package/lib/module/a11y/hooks/useAccessibilityActivateAction.js.map +1 -0
  143. package/lib/module/a11y/hooks/useAnnounceOnStateChange.js +36 -0
  144. package/lib/module/a11y/hooks/useAnnounceOnStateChange.js.map +1 -0
  145. package/lib/module/a11y/hooks/useReducedMotionPreference.js +34 -0
  146. package/lib/module/a11y/hooks/useReducedMotionPreference.js.map +1 -0
  147. package/lib/module/a11y/hooks/useResolvedModalAccessibilityProps.js +20 -0
  148. package/lib/module/a11y/hooks/useResolvedModalAccessibilityProps.js.map +1 -0
  149. package/lib/module/a11y/hooks/useScreenReaderEnabled.js +37 -0
  150. package/lib/module/a11y/hooks/useScreenReaderEnabled.js.map +1 -0
  151. package/lib/module/a11y/index.js +81 -0
  152. package/lib/module/a11y/index.js.map +1 -0
  153. package/lib/module/components/AITypingIndicatorView/AITypingIndicatorView.js +10 -0
  154. package/lib/module/components/AITypingIndicatorView/AITypingIndicatorView.js.map +1 -1
  155. package/lib/module/components/Accessibility/NotificationAnnouncer.js +37 -0
  156. package/lib/module/components/Accessibility/NotificationAnnouncer.js.map +1 -0
  157. package/lib/module/components/Accessibility/hooks/useIncomingMessageAnnouncements.js +109 -0
  158. package/lib/module/components/Accessibility/hooks/useIncomingMessageAnnouncements.js.map +1 -0
  159. package/lib/module/components/Accessibility/index.js +37 -0
  160. package/lib/module/components/Accessibility/index.js.map +1 -0
  161. package/lib/module/components/Accessibility/useAccessibilityAnnouncer.js +15 -0
  162. package/lib/module/components/Accessibility/useAccessibilityAnnouncer.js.map +1 -0
  163. package/lib/module/components/AttachmentPicker/AttachmentPicker.js +20 -0
  164. package/lib/module/components/AttachmentPicker/AttachmentPicker.js.map +1 -1
  165. package/lib/module/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentMediaPicker.js +1 -0
  166. package/lib/module/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentMediaPicker.js.map +1 -1
  167. package/lib/module/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js +19 -2
  168. package/lib/module/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js.map +1 -1
  169. package/lib/module/components/AttachmentPicker/components/AttachmentPickerContent.js +2 -1
  170. package/lib/module/components/AttachmentPicker/components/AttachmentPickerContent.js.map +1 -1
  171. package/lib/module/components/AttachmentPicker/components/AttachmentTypePickerButton.js +9 -1
  172. package/lib/module/components/AttachmentPicker/components/AttachmentTypePickerButton.js.map +1 -1
  173. package/lib/module/components/Channel/Channel.js +2 -1
  174. package/lib/module/components/Channel/Channel.js.map +1 -1
  175. package/lib/module/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js +4 -0
  176. package/lib/module/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.js.map +1 -1
  177. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js +2 -2
  178. package/lib/module/components/ImageGallery/components/ImageGalleryFooter.js.map +1 -1
  179. package/lib/module/components/ImageGallery/components/ImageGalleryHeader.js +1 -1
  180. package/lib/module/components/ImageGallery/components/ImageGalleryHeader.js.map +1 -1
  181. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js +1 -1
  182. package/lib/module/components/ImageGallery/components/ImageGalleryVideoControl.js.map +1 -1
  183. package/lib/module/components/Indicators/LoadingDots.js +2 -0
  184. package/lib/module/components/Indicators/LoadingDots.js.map +1 -1
  185. package/lib/module/components/Indicators/LoadingErrorIndicator.js +3 -0
  186. package/lib/module/components/Indicators/LoadingErrorIndicator.js.map +1 -1
  187. package/lib/module/components/Indicators/LoadingIndicator.js +2 -0
  188. package/lib/module/components/Indicators/LoadingIndicator.js.map +1 -1
  189. package/lib/module/components/MessageInput/components/AttachmentPreview/AttachmentRemoveControl.js +16 -4
  190. package/lib/module/components/MessageInput/components/AttachmentPreview/AttachmentRemoveControl.js.map +1 -1
  191. package/lib/module/components/MessageInput/components/AudioRecorder/AudioRecorder.js +3 -0
  192. package/lib/module/components/MessageInput/components/AudioRecorder/AudioRecorder.js.map +1 -1
  193. package/lib/module/components/MessageInput/components/AudioRecorder/AudioRecordingButton.js +5 -0
  194. package/lib/module/components/MessageInput/components/AudioRecorder/AudioRecordingButton.js.map +1 -1
  195. package/lib/module/components/MessageInput/components/InputButtons/AttachButton.js +12 -3
  196. package/lib/module/components/MessageInput/components/InputButtons/AttachButton.js.map +1 -1
  197. package/lib/module/components/MessageInput/components/OutputButtons/EditButton.js +1 -0
  198. package/lib/module/components/MessageInput/components/OutputButtons/EditButton.js.map +1 -1
  199. package/lib/module/components/MessageInput/components/OutputButtons/SendButton.js +1 -0
  200. package/lib/module/components/MessageInput/components/OutputButtons/SendButton.js.map +1 -1
  201. package/lib/module/components/MessageList/MessageFlashList.js +19 -2
  202. package/lib/module/components/MessageList/MessageFlashList.js.map +1 -1
  203. package/lib/module/components/MessageList/MessageList.js +32 -8
  204. package/lib/module/components/MessageList/MessageList.js.map +1 -1
  205. package/lib/module/components/MessageList/ScrollToBottomButton.js +12 -1
  206. package/lib/module/components/MessageList/ScrollToBottomButton.js.map +1 -1
  207. package/lib/module/components/MessageList/UnreadMessagesNotification.js +1 -0
  208. package/lib/module/components/MessageList/UnreadMessagesNotification.js.map +1 -1
  209. package/lib/module/components/MessageList/hooks/useScrollToBottomAccessibilityAction.js +47 -0
  210. package/lib/module/components/MessageList/hooks/useScrollToBottomAccessibilityAction.js.map +1 -0
  211. package/lib/module/components/MessageMenu/MessageActionList.js +4 -1
  212. package/lib/module/components/MessageMenu/MessageActionList.js.map +1 -1
  213. package/lib/module/components/MessageMenu/MessageActionListItem.js +12 -3
  214. package/lib/module/components/MessageMenu/MessageActionListItem.js.map +1 -1
  215. package/lib/module/components/MessageMenu/MessageReactionPicker.js +2 -0
  216. package/lib/module/components/MessageMenu/MessageReactionPicker.js.map +1 -1
  217. package/lib/module/components/MessageMenu/ReactionButton.js +9 -1
  218. package/lib/module/components/MessageMenu/ReactionButton.js.map +1 -1
  219. package/lib/module/components/Poll/components/CreatePollHeader.js +2 -0
  220. package/lib/module/components/Poll/components/CreatePollHeader.js.map +1 -1
  221. package/lib/module/components/Poll/components/MultipleVotesSettings.js +2 -0
  222. package/lib/module/components/Poll/components/MultipleVotesSettings.js.map +1 -1
  223. package/lib/module/components/Poll/components/PollModalHeader.js +1 -0
  224. package/lib/module/components/Poll/components/PollModalHeader.js.map +1 -1
  225. package/lib/module/components/Poll/components/PollOption.js +15 -0
  226. package/lib/module/components/Poll/components/PollOption.js.map +1 -1
  227. package/lib/module/components/ProgressControl/ProgressControl.js +10 -0
  228. package/lib/module/components/ProgressControl/ProgressControl.js.map +1 -1
  229. package/lib/module/components/Reply/Reply.js +3 -0
  230. package/lib/module/components/Reply/Reply.js.map +1 -1
  231. package/lib/module/components/UIComponents/BottomSheetModal.js +6 -3
  232. package/lib/module/components/UIComponents/BottomSheetModal.js.map +1 -1
  233. package/lib/module/components/index.js +11 -0
  234. package/lib/module/components/index.js.map +1 -1
  235. package/lib/module/components/ui/Avatar/Avatar.js +17 -2
  236. package/lib/module/components/ui/Avatar/Avatar.js.map +1 -1
  237. package/lib/module/components/ui/Avatar/ChannelAvatar.js +3 -1
  238. package/lib/module/components/ui/Avatar/ChannelAvatar.js.map +1 -1
  239. package/lib/module/components/ui/Avatar/UserAvatar.js +1 -0
  240. package/lib/module/components/ui/Avatar/UserAvatar.js.map +1 -1
  241. package/lib/module/components/ui/Button/Button.js +64 -21
  242. package/lib/module/components/ui/Button/Button.js.map +1 -1
  243. package/lib/module/components/ui/Input/Input.js +63 -21
  244. package/lib/module/components/ui/Input/Input.js.map +1 -1
  245. package/lib/module/contexts/accessibilityContext/AccessibilityContext.js +134 -0
  246. package/lib/module/contexts/accessibilityContext/AccessibilityContext.js.map +1 -0
  247. package/lib/module/contexts/accessibilityContext/index.js +15 -0
  248. package/lib/module/contexts/accessibilityContext/index.js.map +1 -0
  249. package/lib/module/contexts/index.js +11 -0
  250. package/lib/module/contexts/index.js.map +1 -1
  251. package/lib/module/contexts/overlayContext/OverlayContext.js.map +1 -1
  252. package/lib/module/contexts/overlayContext/OverlayProvider.js +19 -14
  253. package/lib/module/contexts/overlayContext/OverlayProvider.js.map +1 -1
  254. package/lib/module/hooks/index.js +11 -0
  255. package/lib/module/hooks/index.js.map +1 -1
  256. package/lib/module/i18n/en.json +57 -1
  257. package/lib/module/i18n/es.json +57 -1
  258. package/lib/module/i18n/fr.json +57 -1
  259. package/lib/module/i18n/he.json +57 -1
  260. package/lib/module/i18n/hi.json +57 -1
  261. package/lib/module/i18n/it.json +57 -1
  262. package/lib/module/i18n/ja.json +57 -1
  263. package/lib/module/i18n/ko.json +57 -1
  264. package/lib/module/i18n/nl.json +57 -1
  265. package/lib/module/i18n/pt-br.json +57 -1
  266. package/lib/module/i18n/ru.json +57 -1
  267. package/lib/module/i18n/tr.json +57 -1
  268. package/lib/module/mock-builders/DB/mock.js +3 -1
  269. package/lib/module/mock-builders/DB/mock.js.map +1 -1
  270. package/lib/module/test-utils/BetterSqlite.js +3 -2
  271. package/lib/module/test-utils/BetterSqlite.js.map +1 -1
  272. package/lib/module/version.json +1 -1
  273. package/lib/typescript/a11y/a11yUtils.d.ts +31 -0
  274. package/lib/typescript/a11y/a11yUtils.d.ts.map +1 -0
  275. package/lib/typescript/a11y/hooks/useA11yLabel.d.ts +13 -0
  276. package/lib/typescript/a11y/hooks/useA11yLabel.d.ts.map +1 -0
  277. package/lib/typescript/a11y/hooks/useAccessibilityActivateAction.d.ts +17 -0
  278. package/lib/typescript/a11y/hooks/useAccessibilityActivateAction.d.ts.map +1 -0
  279. package/lib/typescript/a11y/hooks/useAnnounceOnStateChange.d.ts +14 -0
  280. package/lib/typescript/a11y/hooks/useAnnounceOnStateChange.d.ts.map +1 -0
  281. package/lib/typescript/a11y/hooks/useReducedMotionPreference.d.ts +6 -0
  282. package/lib/typescript/a11y/hooks/useReducedMotionPreference.d.ts.map +1 -0
  283. package/lib/typescript/a11y/hooks/useResolvedModalAccessibilityProps.d.ts +18 -0
  284. package/lib/typescript/a11y/hooks/useResolvedModalAccessibilityProps.d.ts.map +1 -0
  285. package/lib/typescript/a11y/hooks/useScreenReaderEnabled.d.ts +10 -0
  286. package/lib/typescript/a11y/hooks/useScreenReaderEnabled.d.ts.map +1 -0
  287. package/lib/typescript/a11y/index.d.ts +8 -0
  288. package/lib/typescript/a11y/index.d.ts.map +1 -0
  289. package/lib/typescript/components/AITypingIndicatorView/AITypingIndicatorView.d.ts.map +1 -1
  290. package/lib/typescript/components/Accessibility/NotificationAnnouncer.d.ts +12 -0
  291. package/lib/typescript/components/Accessibility/NotificationAnnouncer.d.ts.map +1 -0
  292. package/lib/typescript/components/Accessibility/hooks/useIncomingMessageAnnouncements.d.ts +20 -0
  293. package/lib/typescript/components/Accessibility/hooks/useIncomingMessageAnnouncements.d.ts.map +1 -0
  294. package/lib/typescript/components/Accessibility/index.d.ts +4 -0
  295. package/lib/typescript/components/Accessibility/index.d.ts.map +1 -0
  296. package/lib/typescript/components/Accessibility/useAccessibilityAnnouncer.d.ts +15 -0
  297. package/lib/typescript/components/Accessibility/useAccessibilityAnnouncer.d.ts.map +1 -0
  298. package/lib/typescript/components/AttachmentPicker/AttachmentPicker.d.ts.map +1 -1
  299. package/lib/typescript/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentMediaPicker.d.ts.map +1 -1
  300. package/lib/typescript/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.d.ts.map +1 -1
  301. package/lib/typescript/components/AttachmentPicker/components/AttachmentPickerContent.d.ts.map +1 -1
  302. package/lib/typescript/components/AttachmentPicker/components/AttachmentTypePickerButton.d.ts +2 -1
  303. package/lib/typescript/components/AttachmentPicker/components/AttachmentTypePickerButton.d.ts.map +1 -1
  304. package/lib/typescript/components/Channel/Channel.d.ts.map +1 -1
  305. package/lib/typescript/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.d.ts.map +1 -1
  306. package/lib/typescript/components/Indicators/LoadingDots.d.ts.map +1 -1
  307. package/lib/typescript/components/Indicators/LoadingErrorIndicator.d.ts.map +1 -1
  308. package/lib/typescript/components/MessageInput/components/AttachmentPreview/AttachmentRemoveControl.d.ts +5 -2
  309. package/lib/typescript/components/MessageInput/components/AttachmentPreview/AttachmentRemoveControl.d.ts.map +1 -1
  310. package/lib/typescript/components/MessageInput/components/AudioRecorder/AudioRecorder.d.ts.map +1 -1
  311. package/lib/typescript/components/MessageInput/components/AudioRecorder/AudioRecordingButton.d.ts.map +1 -1
  312. package/lib/typescript/components/MessageInput/components/InputButtons/AttachButton.d.ts +1 -0
  313. package/lib/typescript/components/MessageInput/components/InputButtons/AttachButton.d.ts.map +1 -1
  314. package/lib/typescript/components/MessageInput/components/OutputButtons/EditButton.d.ts.map +1 -1
  315. package/lib/typescript/components/MessageInput/components/OutputButtons/SendButton.d.ts.map +1 -1
  316. package/lib/typescript/components/MessageList/MessageFlashList.d.ts.map +1 -1
  317. package/lib/typescript/components/MessageList/MessageList.d.ts.map +1 -1
  318. package/lib/typescript/components/MessageList/ScrollToBottomButton.d.ts +2 -0
  319. package/lib/typescript/components/MessageList/ScrollToBottomButton.d.ts.map +1 -1
  320. package/lib/typescript/components/MessageList/UnreadMessagesNotification.d.ts.map +1 -1
  321. package/lib/typescript/components/MessageList/hooks/useScrollToBottomAccessibilityAction.d.ts +20 -0
  322. package/lib/typescript/components/MessageList/hooks/useScrollToBottomAccessibilityAction.d.ts.map +1 -0
  323. package/lib/typescript/components/MessageMenu/MessageActionList.d.ts.map +1 -1
  324. package/lib/typescript/components/MessageMenu/MessageActionListItem.d.ts.map +1 -1
  325. package/lib/typescript/components/MessageMenu/MessageReactionPicker.d.ts.map +1 -1
  326. package/lib/typescript/components/MessageMenu/ReactionButton.d.ts.map +1 -1
  327. package/lib/typescript/components/Poll/components/CreatePollHeader.d.ts.map +1 -1
  328. package/lib/typescript/components/Poll/components/MultipleVotesSettings.d.ts.map +1 -1
  329. package/lib/typescript/components/Poll/components/PollModalHeader.d.ts.map +1 -1
  330. package/lib/typescript/components/Poll/components/PollOption.d.ts.map +1 -1
  331. package/lib/typescript/components/ProgressControl/ProgressControl.d.ts.map +1 -1
  332. package/lib/typescript/components/Reply/Reply.d.ts.map +1 -1
  333. package/lib/typescript/components/UIComponents/BottomSheetModal.d.ts.map +1 -1
  334. package/lib/typescript/components/index.d.ts +1 -0
  335. package/lib/typescript/components/index.d.ts.map +1 -1
  336. package/lib/typescript/components/ui/Avatar/Avatar.d.ts +12 -1
  337. package/lib/typescript/components/ui/Avatar/Avatar.d.ts.map +1 -1
  338. package/lib/typescript/components/ui/Avatar/ChannelAvatar.d.ts.map +1 -1
  339. package/lib/typescript/components/ui/Avatar/UserAvatar.d.ts.map +1 -1
  340. package/lib/typescript/components/ui/Button/Button.d.ts +10 -1
  341. package/lib/typescript/components/ui/Button/Button.d.ts.map +1 -1
  342. package/lib/typescript/components/ui/Input/Input.d.ts.map +1 -1
  343. package/lib/typescript/contexts/accessibilityContext/AccessibilityContext.d.ts +34 -0
  344. package/lib/typescript/contexts/accessibilityContext/AccessibilityContext.d.ts.map +1 -0
  345. package/lib/typescript/contexts/accessibilityContext/index.d.ts +2 -0
  346. package/lib/typescript/contexts/accessibilityContext/index.d.ts.map +1 -0
  347. package/lib/typescript/contexts/index.d.ts +1 -0
  348. package/lib/typescript/contexts/index.d.ts.map +1 -1
  349. package/lib/typescript/contexts/overlayContext/OverlayContext.d.ts +7 -0
  350. package/lib/typescript/contexts/overlayContext/OverlayContext.d.ts.map +1 -1
  351. package/lib/typescript/contexts/overlayContext/OverlayProvider.d.ts.map +1 -1
  352. package/lib/typescript/hooks/index.d.ts +1 -0
  353. package/lib/typescript/hooks/index.d.ts.map +1 -1
  354. package/lib/typescript/hooks/useTranslatedMessage.d.ts +2 -2
  355. package/lib/typescript/i18n/en.json +57 -1
  356. package/lib/typescript/i18n/es.json +57 -1
  357. package/lib/typescript/i18n/fr.json +57 -1
  358. package/lib/typescript/i18n/he.json +57 -1
  359. package/lib/typescript/i18n/hi.json +57 -1
  360. package/lib/typescript/i18n/it.json +57 -1
  361. package/lib/typescript/i18n/ja.json +57 -1
  362. package/lib/typescript/i18n/ko.json +57 -1
  363. package/lib/typescript/i18n/nl.json +57 -1
  364. package/lib/typescript/i18n/pt-br.json +57 -1
  365. package/lib/typescript/i18n/ru.json +57 -1
  366. package/lib/typescript/i18n/tr.json +57 -1
  367. package/lib/typescript/test-utils/BetterSqlite.d.ts.map +1 -1
  368. package/lib/typescript/utils/i18n/Streami18n.d.ts +56 -0
  369. package/lib/typescript/utils/i18n/Streami18n.d.ts.map +1 -1
  370. package/package.json +1 -1
  371. package/src/__tests__/offline-support/offline-feature.tsx +40 -34
  372. package/src/a11y/__tests__/a11yUtils.test.ts +70 -0
  373. package/src/a11y/a11yUtils.ts +50 -0
  374. package/src/a11y/hooks/useA11yLabel.ts +22 -0
  375. package/src/a11y/hooks/useAccessibilityActivateAction.ts +44 -0
  376. package/src/a11y/hooks/useAnnounceOnStateChange.ts +47 -0
  377. package/src/a11y/hooks/useReducedMotionPreference.ts +38 -0
  378. package/src/a11y/hooks/useResolvedModalAccessibilityProps.ts +30 -0
  379. package/src/a11y/hooks/useScreenReaderEnabled.ts +44 -0
  380. package/src/a11y/index.ts +7 -0
  381. package/src/components/AITypingIndicatorView/AITypingIndicatorView.tsx +17 -2
  382. package/src/components/AITypingIndicatorView/__tests__/AITypingIndicatorView.test.tsx +73 -0
  383. package/src/components/Accessibility/NotificationAnnouncer.tsx +43 -0
  384. package/src/components/Accessibility/__tests__/AccessibilityAnnouncer.test.tsx +75 -0
  385. package/src/components/Accessibility/hooks/useIncomingMessageAnnouncements.ts +157 -0
  386. package/src/components/Accessibility/index.ts +3 -0
  387. package/src/components/Accessibility/useAccessibilityAnnouncer.ts +30 -0
  388. package/src/components/AttachmentPicker/AttachmentPicker.tsx +23 -1
  389. package/src/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentMediaPicker.tsx +1 -0
  390. package/src/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.tsx +15 -2
  391. package/src/components/AttachmentPicker/components/AttachmentPickerContent.tsx +1 -0
  392. package/src/components/AttachmentPicker/components/AttachmentTypePickerButton.tsx +9 -0
  393. package/src/components/Channel/Channel.tsx +3 -0
  394. package/src/components/ChannelList/__tests__/ChannelListView.test.tsx +16 -5
  395. package/src/components/ChannelPreview/ChannelMessagePreviewDeliveryStatus.tsx +14 -1
  396. package/src/components/ImageGallery/__tests__/ImageGalleryFooter.test.tsx +9 -3
  397. package/src/components/ImageGallery/__tests__/ImageGalleryHeader.test.tsx +4 -1
  398. package/src/components/ImageGallery/components/ImageGalleryFooter.tsx +2 -2
  399. package/src/components/ImageGallery/components/ImageGalleryHeader.tsx +1 -1
  400. package/src/components/ImageGallery/components/ImageGalleryVideoControl.tsx +1 -1
  401. package/src/components/Indicators/LoadingDots.tsx +5 -1
  402. package/src/components/Indicators/LoadingErrorIndicator.tsx +7 -1
  403. package/src/components/Indicators/LoadingIndicator.tsx +1 -1
  404. package/src/components/Message/MessageItemView/__tests__/__snapshots__/MessageAuthor.test.tsx.snap +2 -0
  405. package/src/components/MessageInput/__tests__/__snapshots__/AttachButton.test.tsx.snap +30 -15
  406. package/src/components/MessageInput/__tests__/__snapshots__/SendButton.test.tsx.snap +20 -10
  407. package/src/components/MessageInput/components/AttachmentPreview/AttachmentRemoveControl.tsx +18 -2
  408. package/src/components/MessageInput/components/AudioRecorder/AudioRecorder.tsx +3 -0
  409. package/src/components/MessageInput/components/AudioRecorder/AudioRecordingButton.tsx +8 -1
  410. package/src/components/MessageInput/components/InputButtons/AttachButton.tsx +13 -3
  411. package/src/components/MessageInput/components/OutputButtons/EditButton.tsx +1 -0
  412. package/src/components/MessageInput/components/OutputButtons/SendButton.tsx +1 -0
  413. package/src/components/MessageList/MessageFlashList.tsx +23 -2
  414. package/src/components/MessageList/MessageList.tsx +32 -2
  415. package/src/components/MessageList/ScrollToBottomButton.tsx +19 -1
  416. package/src/components/MessageList/UnreadMessagesNotification.tsx +1 -0
  417. package/src/components/MessageList/__tests__/MessageList.test.tsx +186 -0
  418. package/src/components/MessageList/__tests__/ScrollToBottomButton.test.tsx +2 -2
  419. package/src/components/MessageList/__tests__/__snapshots__/ScrollToBottomButton.test.tsx.snap +4 -1
  420. package/src/components/MessageList/__tests__/__snapshots__/TypingIndicator.test.tsx.snap +6 -0
  421. package/src/components/MessageList/hooks/useScrollToBottomAccessibilityAction.ts +74 -0
  422. package/src/components/MessageMenu/MessageActionList.tsx +4 -1
  423. package/src/components/MessageMenu/MessageActionListItem.tsx +11 -4
  424. package/src/components/MessageMenu/MessageReactionPicker.tsx +2 -0
  425. package/src/components/MessageMenu/ReactionButton.tsx +7 -1
  426. package/src/components/MessageMenu/__tests__/MessageReactionPicker.test.tsx +13 -15
  427. package/src/components/MessageMenu/__tests__/MessageUserReactions.test.tsx +20 -18
  428. package/src/components/MessageMenu/__tests__/ReactionButton.test.tsx +18 -5
  429. package/src/components/Poll/components/CreatePollHeader.tsx +2 -0
  430. package/src/components/Poll/components/MultipleVotesSettings.tsx +2 -0
  431. package/src/components/Poll/components/PollModalHeader.tsx +1 -0
  432. package/src/components/Poll/components/PollOption.tsx +11 -0
  433. package/src/components/ProgressControl/ProgressControl.tsx +8 -0
  434. package/src/components/Reply/Reply.tsx +9 -2
  435. package/src/components/Thread/__tests__/__snapshots__/Thread.test.tsx.snap +23 -6
  436. package/src/components/UIComponents/BottomSheetModal.tsx +4 -0
  437. package/src/components/index.ts +2 -0
  438. package/src/components/ui/Avatar/Avatar.tsx +24 -2
  439. package/src/components/ui/Avatar/ChannelAvatar.tsx +3 -0
  440. package/src/components/ui/Avatar/UserAvatar.tsx +1 -0
  441. package/src/components/ui/Button/Button.tsx +50 -0
  442. package/src/components/ui/Button/__tests__/Button.test.tsx +44 -0
  443. package/src/components/ui/Input/Input.tsx +35 -0
  444. package/src/contexts/accessibilityContext/AccessibilityContext.tsx +199 -0
  445. package/src/contexts/accessibilityContext/__tests__/AccessibilityContext.test.tsx +65 -0
  446. package/src/contexts/accessibilityContext/index.ts +1 -0
  447. package/src/contexts/index.ts +1 -0
  448. package/src/contexts/overlayContext/OverlayContext.tsx +7 -0
  449. package/src/contexts/overlayContext/OverlayProvider.tsx +18 -14
  450. package/src/contexts/overlayContext/__tests__/OverlayProvider.test.tsx +51 -0
  451. package/src/hooks/index.ts +1 -0
  452. package/src/i18n/en.json +57 -1
  453. package/src/i18n/es.json +57 -1
  454. package/src/i18n/fr.json +57 -1
  455. package/src/i18n/he.json +57 -1
  456. package/src/i18n/hi.json +57 -1
  457. package/src/i18n/it.json +57 -1
  458. package/src/i18n/ja.json +57 -1
  459. package/src/i18n/ko.json +57 -1
  460. package/src/i18n/nl.json +57 -1
  461. package/src/i18n/pt-br.json +57 -1
  462. package/src/i18n/ru.json +57 -1
  463. package/src/i18n/tr.json +57 -1
  464. package/src/mock-builders/DB/mock.ts +2 -1
  465. package/src/test-utils/BetterSqlite.ts +3 -1
  466. package/src/version.json +1 -1
@@ -0,0 +1,38 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { AccessibilityInfo } from 'react-native';
3
+
4
+ import { useAccessibilityContext } from '../../contexts/accessibilityContext/AccessibilityContext';
5
+
6
+ /**
7
+ * Subscribes to AccessibilityInfo reduce-motion changes and returns the live state.
8
+ * Returns false when the AccessibilityContext is disabled.
9
+ */
10
+ export const useReducedMotionPreference = (): boolean => {
11
+ const { enabled } = useAccessibilityContext();
12
+ const [reduceMotion, setReduceMotion] = useState<boolean>(false);
13
+
14
+ useEffect(() => {
15
+ if (!enabled) {
16
+ setReduceMotion(false);
17
+ return;
18
+ }
19
+
20
+ let cancelled = false;
21
+ AccessibilityInfo.isReduceMotionEnabled?.()
22
+ .then((value) => {
23
+ if (!cancelled) setReduceMotion(value);
24
+ })
25
+ .catch(() => {
26
+ // Older RN or platforms without the API.
27
+ });
28
+
29
+ const subscription = AccessibilityInfo.addEventListener('reduceMotionChanged', setReduceMotion);
30
+
31
+ return () => {
32
+ cancelled = true;
33
+ subscription?.remove?.();
34
+ };
35
+ }, [enabled]);
36
+
37
+ return enabled && reduceMotion;
38
+ };
@@ -0,0 +1,30 @@
1
+ import { Platform } from 'react-native';
2
+
3
+ import { useAccessibilityContext } from '../../contexts/accessibilityContext/AccessibilityContext';
4
+
5
+ export type ResolvedModalAccessibilityProps = {
6
+ accessibilityViewIsModal?: boolean;
7
+ importantForAccessibility?: 'auto' | 'yes' | 'no' | 'no-hide-descendants';
8
+ accessibilityRole?: 'none' | 'button' | 'image' | 'text' | 'alert' | 'menu' | 'menuitem';
9
+ };
10
+
11
+ /**
12
+ * Returns the platform-appropriate set of a11y props for a modal/sheet root.
13
+ * Equivalent of stream-chat-react's `useResolvedModalAriaProps` — but aware of
14
+ * RN's iOS-vs-Android split:
15
+ * - iOS uses `accessibilityViewIsModal` to trap focus.
16
+ * - Android uses `importantForAccessibility="yes"` on the modal root and
17
+ * `"no-hide-descendants"` on background siblings (caller's responsibility).
18
+ *
19
+ * Returns an empty object when AccessibilityContext is disabled, so the modal
20
+ * stays a no-op for integrators that haven't opted in.
21
+ */
22
+ export const useResolvedModalAccessibilityProps = (): ResolvedModalAccessibilityProps => {
23
+ const { enabled } = useAccessibilityContext();
24
+ if (!enabled) return {};
25
+
26
+ if (Platform.OS === 'ios') {
27
+ return { accessibilityViewIsModal: true };
28
+ }
29
+ return { importantForAccessibility: 'yes' };
30
+ };
@@ -0,0 +1,44 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { AccessibilityInfo } from 'react-native';
3
+
4
+ import { useAccessibilityContext } from '../../contexts/accessibilityContext/AccessibilityContext';
5
+
6
+ /**
7
+ * Subscribes to AccessibilityInfo screen-reader changes and returns the live state.
8
+ * Returns false when the AccessibilityContext is disabled, regardless of the OS state,
9
+ * so consumers don't pay the listener cost when the SDK's a11y is opted out.
10
+ *
11
+ * `forceScreenReaderMode: true` in the config short-circuits to true (used in tests
12
+ * and for integrator preview).
13
+ */
14
+ export const useScreenReaderEnabled = (): boolean => {
15
+ const { enabled, forceScreenReaderMode } = useAccessibilityContext();
16
+ const [isEnabled, setIsEnabled] = useState<boolean>(false);
17
+
18
+ useEffect(() => {
19
+ if (!enabled) {
20
+ setIsEnabled(false);
21
+ return;
22
+ }
23
+
24
+ let cancelled = false;
25
+ AccessibilityInfo.isScreenReaderEnabled()
26
+ .then((value) => {
27
+ if (!cancelled) setIsEnabled(value);
28
+ })
29
+ .catch(() => {
30
+ // Some platforms / environments may not implement this; fall back to false.
31
+ });
32
+
33
+ const subscription = AccessibilityInfo.addEventListener('screenReaderChanged', setIsEnabled);
34
+
35
+ return () => {
36
+ cancelled = true;
37
+ subscription?.remove?.();
38
+ };
39
+ }, [enabled]);
40
+
41
+ if (!enabled) return false;
42
+ if (forceScreenReaderMode) return true;
43
+ return isEnabled;
44
+ };
@@ -0,0 +1,7 @@
1
+ export * from './a11yUtils';
2
+ export * from './hooks/useScreenReaderEnabled';
3
+ export * from './hooks/useReducedMotionPreference';
4
+ export * from './hooks/useResolvedModalAccessibilityProps';
5
+ export * from './hooks/useAnnounceOnStateChange';
6
+ export * from './hooks/useA11yLabel';
7
+ export * from './hooks/useAccessibilityActivateAction';
@@ -6,7 +6,13 @@ import { Channel } from 'stream-chat';
6
6
 
7
7
  import { AIStates, useAIState } from './hooks/useAIState';
8
8
 
9
- import { useChannelContext, useTheme, useTranslationContext } from '../../contexts';
9
+ import { useAnnounceOnStateChange } from '../../a11y/hooks/useAnnounceOnStateChange';
10
+ import {
11
+ useAccessibilityContext,
12
+ useChannelContext,
13
+ useTheme,
14
+ useTranslationContext,
15
+ } from '../../contexts';
10
16
  import { primitives } from '../../theme';
11
17
 
12
18
  export type AITypingIndicatorViewProps = {
@@ -20,15 +26,24 @@ export const AITypingIndicatorView = ({
20
26
  const { channel: channelFromContext } = useChannelContext();
21
27
  const channel = channelFromProps || channelFromContext;
22
28
  const { aiState } = useAIState(channel);
29
+ const { announceTypingIndicator, enabled } = useAccessibilityContext();
23
30
  const allowedStates = {
24
31
  [AIStates.Thinking]: t('Thinking...'),
25
32
  [AIStates.Generating]: t('Generating...'),
26
33
  };
27
34
 
28
35
  const styles = useStyles();
36
+ const announceableState = aiState in allowedStates ? allowedStates[aiState] : null;
37
+ const shouldAnnounceTypingIndicator = enabled && announceTypingIndicator;
38
+ const typingAnnouncement = announceTypingIndicator ? announceableState : null;
39
+ useAnnounceOnStateChange(typingAnnouncement);
29
40
 
30
41
  return aiState in allowedStates ? (
31
- <View style={styles.container}>
42
+ <View
43
+ accessibilityLiveRegion={shouldAnnounceTypingIndicator ? 'polite' : undefined}
44
+ accessibilityRole='text'
45
+ style={styles.container}
46
+ >
32
47
  <Text style={styles.text}>{allowedStates[aiState]}</Text>
33
48
  </View>
34
49
  ) : null;
@@ -0,0 +1,73 @@
1
+ import React from 'react';
2
+
3
+ import { render } from '@testing-library/react-native';
4
+ import type { Channel } from 'stream-chat';
5
+
6
+ import { useAnnounceOnStateChange } from '../../../a11y/hooks/useAnnounceOnStateChange';
7
+ import { AccessibilityProvider } from '../../../contexts/accessibilityContext/AccessibilityContext';
8
+ import { ThemeProvider } from '../../../contexts/themeContext/ThemeContext';
9
+ import { defaultTheme } from '../../../contexts/themeContext/utils/theme';
10
+ import { AITypingIndicatorView } from '../AITypingIndicatorView';
11
+ import { AIStates, useAIState } from '../hooks/useAIState';
12
+
13
+ jest.mock('../../../a11y/hooks/useAnnounceOnStateChange', () => ({
14
+ useAnnounceOnStateChange: jest.fn(),
15
+ }));
16
+
17
+ jest.mock('../hooks/useAIState', () => {
18
+ const actual = jest.requireActual('../hooks/useAIState');
19
+ return {
20
+ ...actual,
21
+ useAIState: jest.fn(),
22
+ };
23
+ });
24
+
25
+ const mockUseAIState = useAIState as jest.MockedFunction<typeof useAIState>;
26
+ const mockUseAnnounceOnStateChange = useAnnounceOnStateChange as jest.MockedFunction<
27
+ typeof useAnnounceOnStateChange
28
+ >;
29
+
30
+ const renderComponent = (
31
+ accessibility?: React.ComponentProps<typeof AccessibilityProvider>['value'],
32
+ ) =>
33
+ render(
34
+ <ThemeProvider theme={defaultTheme}>
35
+ <AccessibilityProvider value={accessibility}>
36
+ <AITypingIndicatorView channel={{} as Channel} />
37
+ </AccessibilityProvider>
38
+ </ThemeProvider>,
39
+ );
40
+
41
+ describe('AITypingIndicatorView', () => {
42
+ beforeEach(() => {
43
+ mockUseAIState.mockReturnValue({ aiState: AIStates.Thinking });
44
+ jest.clearAllMocks();
45
+ });
46
+
47
+ it('does not announce typing state by default', () => {
48
+ const { UNSAFE_queryByProps } = renderComponent();
49
+
50
+ expect(mockUseAnnounceOnStateChange).toHaveBeenCalledWith(null);
51
+ expect(UNSAFE_queryByProps({ accessibilityLiveRegion: 'polite' })).toBeNull();
52
+ });
53
+
54
+ it('does not announce typing state when a11y is enabled but typing announcements are off', () => {
55
+ const { UNSAFE_queryByProps } = renderComponent({
56
+ announceTypingIndicator: false,
57
+ enabled: true,
58
+ });
59
+
60
+ expect(mockUseAnnounceOnStateChange).toHaveBeenCalledWith(null);
61
+ expect(UNSAFE_queryByProps({ accessibilityLiveRegion: 'polite' })).toBeNull();
62
+ });
63
+
64
+ it('announces typing state when the typing announcement toggle is enabled', () => {
65
+ const { UNSAFE_queryByProps } = renderComponent({
66
+ announceTypingIndicator: true,
67
+ enabled: true,
68
+ });
69
+
70
+ expect(mockUseAnnounceOnStateChange).toHaveBeenCalledWith('Thinking...');
71
+ expect(UNSAFE_queryByProps({ accessibilityLiveRegion: 'polite' })).toBeTruthy();
72
+ });
73
+ });
@@ -0,0 +1,43 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ import { useAccessibilityAnnouncer } from './useAccessibilityAnnouncer';
4
+
5
+ import { useAccessibilityContext } from '../../contexts/accessibilityContext/AccessibilityContext';
6
+ import { useChatContext } from '../../contexts/chatContext/ChatContext';
7
+ import { useTranslationContext } from '../../contexts/translationContext/TranslationContext';
8
+
9
+ /**
10
+ * Mirrors stream-chat-react's `<NotificationAnnouncer />`. RN does not yet have a
11
+ * unified Notification queue, so this component currently announces only
12
+ * connection-state transitions (offline → online and back) gated on
13
+ * `accessibility.announceConnectionState`. Per-channel error announcements can
14
+ * be wired in by a future PR via `useChannelContext().error`.
15
+ *
16
+ * Renders nothing. Mount once inside `<Channel>` (or wherever the active chat
17
+ * surface lives).
18
+ */
19
+ export const NotificationAnnouncer = () => {
20
+ const { announceConnectionState, enabled } = useAccessibilityContext();
21
+ const { connectionRecovering, isOnline } = useChatContext();
22
+ const announce = useAccessibilityAnnouncer();
23
+ const { t } = useTranslationContext();
24
+ const previousIsOnlineRef = useRef<boolean | null | undefined>(undefined);
25
+
26
+ useEffect(() => {
27
+ if (!enabled || !announceConnectionState) return;
28
+ if (previousIsOnlineRef.current === undefined) {
29
+ previousIsOnlineRef.current = isOnline;
30
+ return;
31
+ }
32
+ if (previousIsOnlineRef.current === isOnline) return;
33
+ previousIsOnlineRef.current = isOnline;
34
+
35
+ if (isOnline) {
36
+ announce(t('a11y/Connected'), 'polite');
37
+ } else {
38
+ announce(connectionRecovering ? t('a11y/Reconnecting') : t('a11y/Offline'), 'assertive');
39
+ }
40
+ }, [announce, announceConnectionState, connectionRecovering, enabled, isOnline, t]);
41
+
42
+ return null;
43
+ };
@@ -0,0 +1,75 @@
1
+ import React from 'react';
2
+ import { AccessibilityInfo } from 'react-native';
3
+
4
+ import { renderHook, waitFor } from '@testing-library/react-native';
5
+
6
+ import { AccessibilityProvider } from '../../../contexts/accessibilityContext/AccessibilityContext';
7
+ import { useAccessibilityAnnouncer } from '../useAccessibilityAnnouncer';
8
+
9
+ jest.mock('react-native/Libraries/Components/AccessibilityInfo/AccessibilityInfo', () => ({
10
+ __esModule: true,
11
+ default: {
12
+ announceForAccessibility: jest.fn(),
13
+ addEventListener: jest.fn().mockReturnValue({ remove: jest.fn() }),
14
+ isScreenReaderEnabled: jest.fn().mockResolvedValue(false),
15
+ isReduceMotionEnabled: jest.fn().mockResolvedValue(false),
16
+ },
17
+ }));
18
+
19
+ const wrapper =
20
+ (enabled: boolean) =>
21
+ ({ children }: { children: React.ReactNode }) => (
22
+ <AccessibilityProvider value={{ enabled }}>{children}</AccessibilityProvider>
23
+ );
24
+
25
+ describe('AccessibilityProvider announcer', () => {
26
+ beforeEach(() => {
27
+ (AccessibilityInfo.announceForAccessibility as jest.Mock).mockClear();
28
+ });
29
+
30
+ it('returns a no-op when enabled is false', async () => {
31
+ const { result } = renderHook(() => useAccessibilityAnnouncer(), { wrapper: wrapper(false) });
32
+ result.current('hello');
33
+ await new Promise((r) => setTimeout(r, 80));
34
+ expect(AccessibilityInfo.announceForAccessibility).not.toHaveBeenCalled();
35
+ });
36
+
37
+ it('announces via AccessibilityInfo when enabled', async () => {
38
+ const { result } = renderHook(() => useAccessibilityAnnouncer(), { wrapper: wrapper(true) });
39
+ result.current('hello');
40
+ await waitFor(() =>
41
+ expect(AccessibilityInfo.announceForAccessibility).toHaveBeenCalledWith('hello'),
42
+ );
43
+ });
44
+
45
+ it('flushes only the latest message per priority within the debounce window', async () => {
46
+ const { result } = renderHook(() => useAccessibilityAnnouncer(), { wrapper: wrapper(true) });
47
+ result.current('first');
48
+ result.current('second');
49
+ result.current('third');
50
+ await waitFor(() =>
51
+ expect(AccessibilityInfo.announceForAccessibility).toHaveBeenCalledWith('third'),
52
+ );
53
+ expect(AccessibilityInfo.announceForAccessibility).not.toHaveBeenCalledWith('first');
54
+ expect(AccessibilityInfo.announceForAccessibility).not.toHaveBeenCalledWith('second');
55
+ });
56
+
57
+ it('ignores empty messages', async () => {
58
+ const { result } = renderHook(() => useAccessibilityAnnouncer(), { wrapper: wrapper(true) });
59
+ result.current('');
60
+ await new Promise((r) => setTimeout(r, 80));
61
+ expect(AccessibilityInfo.announceForAccessibility).not.toHaveBeenCalled();
62
+ });
63
+
64
+ it('clears pending announcements on unmount', async () => {
65
+ const { result, unmount } = renderHook(() => useAccessibilityAnnouncer(), {
66
+ wrapper: wrapper(true),
67
+ });
68
+
69
+ result.current('hello');
70
+ unmount();
71
+
72
+ await new Promise((r) => setTimeout(r, 80));
73
+ expect(AccessibilityInfo.announceForAccessibility).not.toHaveBeenCalled();
74
+ });
75
+ });
@@ -0,0 +1,157 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+
3
+ import type { Channel, Event, MessageResponse } from 'stream-chat';
4
+
5
+ import { useAccessibilityContext } from '../../../contexts/accessibilityContext/AccessibilityContext';
6
+ import { useTranslationContext } from '../../../contexts/translationContext/TranslationContext';
7
+ import { useAccessibilityAnnouncer } from '../useAccessibilityAnnouncer';
8
+
9
+ const MESSAGE_ANNOUNCEMENT_THROTTLE_MS = 1000;
10
+
11
+ const isAnnounceableIncomingMessage = (message: MessageResponse, ownUserId?: string): boolean => {
12
+ const messageUserId = message.user?.id;
13
+ if (!message.id || !messageUserId || messageUserId === ownUserId) return false;
14
+ return (
15
+ message.type !== 'deleted' &&
16
+ message.type !== 'ephemeral' &&
17
+ message.type !== 'error' &&
18
+ message.type !== 'system' &&
19
+ message.status !== 'failed' &&
20
+ message.status !== 'sending'
21
+ );
22
+ };
23
+
24
+ const getSenderName = (
25
+ message: MessageResponse,
26
+ t: ReturnType<typeof useTranslationContext>['t'],
27
+ ) => message.user?.name?.trim() || message.user?.id || t('Anonymous');
28
+
29
+ export type UseIncomingMessageAnnouncementsParams = {
30
+ activeThreadId?: string;
31
+ channel?: Channel;
32
+ ownUserId?: string;
33
+ threadList?: boolean;
34
+ };
35
+
36
+ /**
37
+ * Mirrors stream-chat-react's `useIncomingMessageAnnouncements`:
38
+ * - 1 message → "New message from {{user}}"
39
+ * - >1 messages within throttle window → "{{count}} new messages"
40
+ * - Throttled to one announcement per second
41
+ * - Bounded `announcedMessageIds` set so a long-running session does not leak.
42
+ *
43
+ * Subscribes to `channel.on('message.new')`. When AccessibilityContext.enabled
44
+ * is false OR `announceNewMessages` is false, the hook is a no-op (no
45
+ * subscription is opened, no listener cost is paid).
46
+ */
47
+ export const useIncomingMessageAnnouncements = ({
48
+ activeThreadId,
49
+ channel,
50
+ ownUserId,
51
+ threadList = false,
52
+ }: UseIncomingMessageAnnouncementsParams) => {
53
+ const { announceNewMessages, enabled } = useAccessibilityContext();
54
+ const announce = useAccessibilityAnnouncer();
55
+ const { t } = useTranslationContext();
56
+ const lastAnnouncementTimestampRef = useRef(0);
57
+ const flushTimeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
58
+ const announcedMessageIdsRef = useRef(new Set<string>());
59
+ const pendingAnnouncementBatchRef = useRef<{ count: number; firstSender: string | null }>({
60
+ count: 0,
61
+ firstSender: null,
62
+ });
63
+
64
+ const flushPendingAnnouncements = useCallback(() => {
65
+ const pending = pendingAnnouncementBatchRef.current;
66
+ if (pending.count <= 0) return;
67
+
68
+ if (pending.count === 1) {
69
+ announce(
70
+ t('a11y/New message from {{user}}', {
71
+ user: pending.firstSender || t('Anonymous'),
72
+ }),
73
+ );
74
+ } else {
75
+ announce(t('a11y/{{count}} new messages', { count: pending.count }));
76
+ }
77
+
78
+ pending.count = 0;
79
+ pending.firstSender = null;
80
+ lastAnnouncementTimestampRef.current = Date.now();
81
+ }, [announce, t]);
82
+
83
+ const scheduleFlush = useCallback(() => {
84
+ if (flushTimeoutRef.current) return;
85
+ const now = Date.now();
86
+ const elapsed = now - lastAnnouncementTimestampRef.current;
87
+ if (elapsed >= MESSAGE_ANNOUNCEMENT_THROTTLE_MS) {
88
+ flushPendingAnnouncements();
89
+ return;
90
+ }
91
+ flushTimeoutRef.current = setTimeout(() => {
92
+ flushTimeoutRef.current = undefined;
93
+ flushPendingAnnouncements();
94
+ }, MESSAGE_ANNOUNCEMENT_THROTTLE_MS - elapsed);
95
+ }, [flushPendingAnnouncements]);
96
+
97
+ useEffect(
98
+ () => () => {
99
+ if (flushTimeoutRef.current) clearTimeout(flushTimeoutRef.current);
100
+ },
101
+ [],
102
+ );
103
+
104
+ useEffect(() => {
105
+ if (!enabled || !announceNewMessages || !channel) return;
106
+
107
+ const handleMessageNew = (event: Event) => {
108
+ const message = event.message;
109
+ if (!message) return;
110
+ if (
111
+ (event.cid && event.cid !== channel.cid) ||
112
+ !isAnnounceableIncomingMessage(message, ownUserId)
113
+ ) {
114
+ return;
115
+ }
116
+
117
+ const isReply = !!message.parent_id;
118
+ const belongsToActiveThread = !!activeThreadId && message.parent_id === activeThreadId;
119
+ const shouldAnnounceInThreadList = threadList && belongsToActiveThread;
120
+ const shouldAnnounceInMainList = !threadList && !isReply;
121
+ if (!shouldAnnounceInThreadList && !shouldAnnounceInMainList) return;
122
+
123
+ if (announcedMessageIdsRef.current.has(message.id || '')) return;
124
+ if (message.id) {
125
+ if (announcedMessageIdsRef.current.size > 500) {
126
+ announcedMessageIdsRef.current.clear();
127
+ }
128
+ announcedMessageIdsRef.current.add(message.id);
129
+ }
130
+
131
+ pendingAnnouncementBatchRef.current.count += 1;
132
+ if (!pendingAnnouncementBatchRef.current.firstSender) {
133
+ pendingAnnouncementBatchRef.current.firstSender = getSenderName(message, t);
134
+ }
135
+
136
+ scheduleFlush();
137
+ };
138
+
139
+ const subscription = channel.on('message.new', handleMessageNew);
140
+ return () => {
141
+ subscription.unsubscribe();
142
+ if (flushTimeoutRef.current) {
143
+ clearTimeout(flushTimeoutRef.current);
144
+ flushTimeoutRef.current = undefined;
145
+ }
146
+ };
147
+ }, [
148
+ activeThreadId,
149
+ announceNewMessages,
150
+ channel,
151
+ enabled,
152
+ ownUserId,
153
+ scheduleFlush,
154
+ t,
155
+ threadList,
156
+ ]);
157
+ };
@@ -0,0 +1,3 @@
1
+ export * from './NotificationAnnouncer';
2
+ export * from './useAccessibilityAnnouncer';
3
+ export * from './hooks/useIncomingMessageAnnouncements';
@@ -0,0 +1,30 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ export type AccessibilityAnnouncePriority = 'assertive' | 'polite';
4
+ export type AccessibilityAnnounce = (
5
+ message: string,
6
+ priority?: AccessibilityAnnouncePriority,
7
+ ) => void;
8
+
9
+ export type AccessibilityAnnouncerContextValue = {
10
+ announce: AccessibilityAnnounce;
11
+ };
12
+
13
+ const noopAnnounce: AccessibilityAnnounce = () => undefined;
14
+
15
+ export const AccessibilityAnnouncerContext = createContext<
16
+ AccessibilityAnnouncerContextValue | undefined
17
+ >(undefined);
18
+
19
+ /**
20
+ * Returns the imperative announcer. When called outside the AccessibilityProvider's
21
+ * announcer context (which happens any time the SDK's a11y is disabled), this
22
+ * returns a no-op.
23
+ *
24
+ * Mirrors the React SDK's `useAriaLiveAnnouncer` so cross-SDK code reads the same.
25
+ */
26
+ export const useAccessibilityAnnouncer = (): AccessibilityAnnounce => {
27
+ const contextValue = useContext(AccessibilityAnnouncerContext);
28
+ if (!contextValue) return noopAnnounce;
29
+ return contextValue.announce;
30
+ };
@@ -6,11 +6,13 @@ import {
6
6
  Platform,
7
7
  View,
8
8
  LayoutChangeEvent,
9
+ useWindowDimensions,
9
10
  } from 'react-native';
10
11
 
11
12
  import { runOnJS, useAnimatedReaction, useSharedValue } from 'react-native-reanimated';
12
13
 
13
14
  import { useBottomSheetSpringConfigs } from '@gorhom/bottom-sheet';
15
+ import type { BottomSheetBackgroundProps } from '@gorhom/bottom-sheet';
14
16
  import dayjs from 'dayjs';
15
17
  import duration from 'dayjs/plugin/duration';
16
18
 
@@ -38,13 +40,14 @@ export const AttachmentPicker = () => {
38
40
  attachmentPickerStore,
39
41
  attachmentPickerBottomSheetHeight,
40
42
  bottomSheetRef: ref,
43
+ bottomInset,
41
44
  disableAttachmentPicker,
42
45
  } = useAttachmentPickerContext();
43
46
  const { AttachmentPickerContent, AttachmentPickerSelectionBar } = useComponentsContext();
44
47
  const {
45
48
  theme: { semantics },
46
49
  } = useTheme();
47
-
50
+ const { height: windowHeight } = useWindowDimensions();
48
51
  const [currentIndex, setCurrentIndexInternal] = useState(-1);
49
52
  const currentIndexRef = useRef<number>(currentIndex);
50
53
  const setCurrentIndex = useStableCallback((_: number, toIndex: number) => {
@@ -99,6 +102,10 @@ export const AttachmentPicker = () => {
99
102
  const selectionBarRef = useRef<number | null>(null);
100
103
 
101
104
  const initialSnapPoint = attachmentPickerBottomSheetHeight;
105
+ const pickerTopInset = Math.max(
106
+ 0,
107
+ windowHeight - attachmentPickerBottomSheetHeight - bottomInset,
108
+ );
102
109
 
103
110
  /**
104
111
  * Snap points changing cause a rerender of the position,
@@ -150,8 +157,13 @@ export const AttachmentPicker = () => {
150
157
 
151
158
  return (
152
159
  <BottomSheet
160
+ accessible={false}
161
+ accessibilityLabel={null}
162
+ accessibilityRole={null}
153
163
  android_keyboardInputMode='adjustResize'
164
+ backgroundComponent={AttachmentPickerBackground}
154
165
  backgroundStyle={backgroundStyle}
166
+ bottomInset={bottomInset}
155
167
  enablePanDownToClose={false}
156
168
  enableContentPanningGesture={false}
157
169
  enableDynamicSizing={false}
@@ -162,6 +174,7 @@ export const AttachmentPicker = () => {
162
174
  // @ts-ignore
163
175
  ref={ref}
164
176
  snapPoints={snapPoints}
177
+ topInset={pickerTopInset}
165
178
  animationConfigs={animationConfigs}
166
179
  >
167
180
  <View onLayout={onAttachmentPickerSelectionBarLayout}>
@@ -178,4 +191,13 @@ export const AttachmentPicker = () => {
178
191
 
179
192
  const RenderNull = () => null;
180
193
 
194
+ const AttachmentPickerBackground = ({ pointerEvents, style }: BottomSheetBackgroundProps) => (
195
+ <View
196
+ accessible={false}
197
+ importantForAccessibility='no'
198
+ pointerEvents={pointerEvents}
199
+ style={style}
200
+ />
201
+ );
202
+
181
203
  AttachmentPicker.displayName = 'AttachmentPicker';
@@ -172,6 +172,7 @@ export const AttachmentMediaPicker = (props: AttachmentPickerContentProps) => {
172
172
  numColumns={numberOfColumns}
173
173
  onEndReached={photoError ? undefined : getMorePhotos}
174
174
  renderItem={renderAttachmentPickerItem}
175
+ showsVerticalScrollIndicator={false}
175
176
  testID={'attachment-picker-list'}
176
177
  updateCellsBatchingPeriod={16}
177
178
  />