stream-chat-react 14.11.1 → 14.12.0

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 (1102) hide show
  1. package/dist/cjs/{NotificationList.6abbee1c.js → NotificationList.4ce251ea.js} +127 -34
  2. package/dist/cjs/NotificationList.4ce251ea.js.map +1 -0
  3. package/dist/cjs/{ReactPlayerWrapper.a94a0cd1.js → ReactPlayerWrapper.7cc7b0d8.js} +4 -4
  4. package/dist/cjs/{ReactPlayerWrapper.a94a0cd1.js.map → ReactPlayerWrapper.7cc7b0d8.js.map} +1 -1
  5. package/dist/cjs/channel-detail.js +2 -2
  6. package/dist/cjs/emojis.js +2 -2
  7. package/dist/cjs/index.js +232 -55
  8. package/dist/cjs/index.js.map +1 -1
  9. package/dist/cjs/{useChannelHeaderOnlineStatus.7e17671e.js → useChannelHeaderOnlineStatus.64c443f5.js} +2 -2
  10. package/dist/cjs/{useChannelHeaderOnlineStatus.7e17671e.js.map → useChannelHeaderOnlineStatus.64c443f5.js.map} +1 -1
  11. package/dist/cjs/{useInertWhenHidden.22151beb.js → useInertWhenHidden.1a2a6a2b.js} +200 -53
  12. package/dist/cjs/useInertWhenHidden.1a2a6a2b.js.map +1 -0
  13. package/dist/css/index.css +71 -12
  14. package/dist/css/index.css.map +1 -1
  15. package/dist/es/_virtual/_rolldown/runtime.mjs +13 -0
  16. package/dist/es/a11y/a11yUtils.mjs +42 -0
  17. package/dist/es/a11y/a11yUtils.mjs.map +1 -0
  18. package/dist/es/a11y/accessibleLabel.mjs +27 -0
  19. package/dist/es/a11y/accessibleLabel.mjs.map +1 -0
  20. package/dist/es/a11y/hooks/useAriaIdentifiers.mjs +25 -0
  21. package/dist/es/a11y/hooks/useAriaIdentifiers.mjs.map +1 -0
  22. package/dist/es/a11y/hooks/useListboxKeyboardNavigation.mjs +85 -0
  23. package/dist/es/a11y/hooks/useListboxKeyboardNavigation.mjs.map +1 -0
  24. package/dist/es/a11y/hooks/useResolvedModalAriaProps.mjs +32 -0
  25. package/dist/es/a11y/hooks/useResolvedModalAriaProps.mjs.map +1 -0
  26. package/dist/es/a11y/hooks/useVirtualizedListboxKeyboardNavigation.mjs +68 -0
  27. package/dist/es/a11y/hooks/useVirtualizedListboxKeyboardNavigation.mjs.map +1 -0
  28. package/dist/es/channel-detail.mjs +29 -3020
  29. package/dist/es/components/AIStateIndicator/AIStateIndicator.mjs +26 -0
  30. package/dist/es/components/AIStateIndicator/AIStateIndicator.mjs.map +1 -0
  31. package/dist/es/components/AIStateIndicator/hooks/useAIState.mjs +44 -0
  32. package/dist/es/components/AIStateIndicator/hooks/useAIState.mjs.map +1 -0
  33. package/dist/es/components/Accessibility/AriaLiveAnnouncerProvider.mjs +144 -0
  34. package/dist/es/components/Accessibility/AriaLiveAnnouncerProvider.mjs.map +1 -0
  35. package/dist/es/components/Accessibility/AriaLiveOutlet.mjs +58 -0
  36. package/dist/es/components/Accessibility/AriaLiveOutlet.mjs.map +1 -0
  37. package/dist/es/components/Accessibility/AriaLiveOutletContext.mjs +8 -0
  38. package/dist/es/components/Accessibility/AriaLiveOutletContext.mjs.map +1 -0
  39. package/dist/es/components/Accessibility/NotificationAnnouncer.mjs +87 -0
  40. package/dist/es/components/Accessibility/NotificationAnnouncer.mjs.map +1 -0
  41. package/dist/es/components/Accessibility/hooks/useAudioPlaybackChangeAnnouncements.mjs +20 -0
  42. package/dist/es/components/Accessibility/hooks/useAudioPlaybackChangeAnnouncements.mjs.map +1 -0
  43. package/dist/es/components/Accessibility/hooks/useFocusReturn.mjs +37 -0
  44. package/dist/es/components/Accessibility/hooks/useFocusReturn.mjs.map +1 -0
  45. package/dist/es/components/Accessibility/hooks/useIncomingMessageAnnouncements.mjs +84 -0
  46. package/dist/es/components/Accessibility/hooks/useIncomingMessageAnnouncements.mjs.map +1 -0
  47. package/dist/es/components/Accessibility/hooks/useInertWhenHidden.mjs +85 -0
  48. package/dist/es/components/Accessibility/hooks/useInertWhenHidden.mjs.map +1 -0
  49. package/dist/es/components/Accessibility/hooks/useInteractionAnnouncements.mjs +155 -0
  50. package/dist/es/components/Accessibility/hooks/useInteractionAnnouncements.mjs.map +1 -0
  51. package/dist/es/components/Accessibility/scheduling/useAnnouncementQueue.mjs +43 -0
  52. package/dist/es/components/Accessibility/scheduling/useAnnouncementQueue.mjs.map +1 -0
  53. package/dist/es/components/Accessibility/scheduling/useDebouncedAnnounce.mjs +78 -0
  54. package/dist/es/components/Accessibility/scheduling/useDebouncedAnnounce.mjs.map +1 -0
  55. package/dist/es/components/Accessibility/scheduling/useSettledAnnouncement.mjs +90 -0
  56. package/dist/es/components/Accessibility/scheduling/useSettledAnnouncement.mjs.map +1 -0
  57. package/dist/es/components/Accessibility/useAriaLiveAnnouncer.mjs +16 -0
  58. package/dist/es/components/Accessibility/useAriaLiveAnnouncer.mjs.map +1 -0
  59. package/dist/es/components/Attachment/Attachment.mjs +74 -0
  60. package/dist/es/components/Attachment/Attachment.mjs.map +1 -0
  61. package/dist/es/components/Attachment/AttachmentActions.mjs +109 -0
  62. package/dist/es/components/Attachment/AttachmentActions.mjs.map +1 -0
  63. package/dist/es/components/Attachment/AttachmentContainer.mjs +265 -0
  64. package/dist/es/components/Attachment/AttachmentContainer.mjs.map +1 -0
  65. package/dist/es/components/Attachment/Audio.mjs +104 -0
  66. package/dist/es/components/Attachment/Audio.mjs.map +1 -0
  67. package/dist/es/components/Attachment/FileAttachment.mjs +47 -0
  68. package/dist/es/components/Attachment/FileAttachment.mjs.map +1 -0
  69. package/dist/es/components/Attachment/Geolocation.mjs +77 -0
  70. package/dist/es/components/Attachment/Geolocation.mjs.map +1 -0
  71. package/dist/es/components/Attachment/Giphy.mjs +62 -0
  72. package/dist/es/components/Attachment/Giphy.mjs.map +1 -0
  73. package/dist/es/components/Attachment/Image.mjs +19 -0
  74. package/dist/es/components/Attachment/Image.mjs.map +1 -0
  75. package/dist/es/components/Attachment/LinkPreview/Card.mjs +93 -0
  76. package/dist/es/components/Attachment/LinkPreview/Card.mjs.map +1 -0
  77. package/dist/es/components/Attachment/LinkPreview/UnableToRenderCard.mjs +22 -0
  78. package/dist/es/components/Attachment/LinkPreview/UnableToRenderCard.mjs.map +1 -0
  79. package/dist/es/components/Attachment/ModalGallery.mjs +166 -0
  80. package/dist/es/components/Attachment/ModalGallery.mjs.map +1 -0
  81. package/dist/es/components/Attachment/UnsupportedAttachment.mjs +25 -0
  82. package/dist/es/components/Attachment/UnsupportedAttachment.mjs.map +1 -0
  83. package/dist/es/components/Attachment/VideoAttachment.mjs +56 -0
  84. package/dist/es/components/Attachment/VideoAttachment.mjs.map +1 -0
  85. package/dist/es/components/Attachment/VisibilityDisclaimer.mjs +17 -0
  86. package/dist/es/components/Attachment/VisibilityDisclaimer.mjs.map +1 -0
  87. package/dist/es/components/Attachment/VoiceRecording.mjs +134 -0
  88. package/dist/es/components/Attachment/VoiceRecording.mjs.map +1 -0
  89. package/dist/es/components/Attachment/attachment-sizing.mjs +73 -0
  90. package/dist/es/components/Attachment/attachment-sizing.mjs.map +1 -0
  91. package/dist/es/components/Attachment/audioSampling.mjs +74 -0
  92. package/dist/es/components/Attachment/audioSampling.mjs.map +1 -0
  93. package/dist/es/components/Attachment/components/AttachmentUploadProgressIndicator.mjs +38 -0
  94. package/dist/es/components/Attachment/components/AttachmentUploadProgressIndicator.mjs.map +1 -0
  95. package/dist/es/components/Attachment/components/DownloadButton.mjs +35 -0
  96. package/dist/es/components/Attachment/components/DownloadButton.mjs.map +1 -0
  97. package/dist/es/components/Attachment/components/FileSizeIndicator.mjs +17 -0
  98. package/dist/es/components/Attachment/components/FileSizeIndicator.mjs.map +1 -0
  99. package/dist/es/components/Attachment/giphyAccessibility.mjs +15 -0
  100. package/dist/es/components/Attachment/giphyAccessibility.mjs.map +1 -0
  101. package/dist/es/components/Attachment/hooks/useAttachmentUploadState.mjs +106 -0
  102. package/dist/es/components/Attachment/hooks/useAttachmentUploadState.mjs.map +1 -0
  103. package/dist/es/components/Attachment/hooks/useLocalVideoDimensions.mjs +79 -0
  104. package/dist/es/components/Attachment/hooks/useLocalVideoDimensions.mjs.map +1 -0
  105. package/dist/es/components/Attachment/icons.mjs +13 -0
  106. package/dist/es/components/Attachment/icons.mjs.map +1 -0
  107. package/dist/es/components/Attachment/utils.mjs +41 -0
  108. package/dist/es/components/Attachment/utils.mjs.map +1 -0
  109. package/dist/es/components/AudioPlayback/AudioPlayer.mjs +457 -0
  110. package/dist/es/components/AudioPlayback/AudioPlayer.mjs.map +1 -0
  111. package/dist/es/components/AudioPlayback/AudioPlayerPool.mjs +109 -0
  112. package/dist/es/components/AudioPlayback/AudioPlayerPool.mjs.map +1 -0
  113. package/dist/es/components/AudioPlayback/WithAudioPlayback.mjs +72 -0
  114. package/dist/es/components/AudioPlayback/WithAudioPlayback.mjs.map +1 -0
  115. package/dist/es/components/AudioPlayback/components/DurationDisplay.mjs +33 -0
  116. package/dist/es/components/AudioPlayback/components/DurationDisplay.mjs.map +1 -0
  117. package/dist/es/components/AudioPlayback/components/PlaybackRateButton.mjs +15 -0
  118. package/dist/es/components/AudioPlayback/components/PlaybackRateButton.mjs.map +1 -0
  119. package/dist/es/components/AudioPlayback/components/ProgressBar.mjs +56 -0
  120. package/dist/es/components/AudioPlayback/components/ProgressBar.mjs.map +1 -0
  121. package/dist/es/components/AudioPlayback/components/WaveProgressBar.mjs +107 -0
  122. package/dist/es/components/AudioPlayback/components/WaveProgressBar.mjs.map +1 -0
  123. package/dist/es/components/AudioPlayback/components/formatTime.mjs +14 -0
  124. package/dist/es/components/AudioPlayback/components/formatTime.mjs.map +1 -0
  125. package/dist/es/components/AudioPlayback/components/keyboardSeek.mjs +36 -0
  126. package/dist/es/components/AudioPlayback/components/keyboardSeek.mjs.map +1 -0
  127. package/dist/es/components/AudioPlayback/components/progressBarA11y.mjs +19 -0
  128. package/dist/es/components/AudioPlayback/components/progressBarA11y.mjs.map +1 -0
  129. package/dist/es/components/AudioPlayback/components/useInteractiveProgressBar.mjs +77 -0
  130. package/dist/es/components/AudioPlayback/components/useInteractiveProgressBar.mjs.map +1 -0
  131. package/dist/es/components/AudioPlayback/plugins/AudioPlayerNotificationsPlugin.mjs +33 -0
  132. package/dist/es/components/AudioPlayback/plugins/AudioPlayerNotificationsPlugin.mjs.map +1 -0
  133. package/dist/es/components/Avatar/Avatar.mjs +62 -0
  134. package/dist/es/components/Avatar/Avatar.mjs.map +1 -0
  135. package/dist/es/components/Avatar/AvatarStack.mjs +32 -0
  136. package/dist/es/components/Avatar/AvatarStack.mjs.map +1 -0
  137. package/dist/es/components/Avatar/ChannelAvatar.mjs +25 -0
  138. package/dist/es/components/Avatar/ChannelAvatar.mjs.map +1 -0
  139. package/dist/es/components/Avatar/GroupAvatar.mjs +53 -0
  140. package/dist/es/components/Avatar/GroupAvatar.mjs.map +1 -0
  141. package/dist/es/components/Avatar/utils.mjs +10 -0
  142. package/dist/es/components/Avatar/utils.mjs.map +1 -0
  143. package/dist/es/components/Badge/Badge.mjs +28 -0
  144. package/dist/es/components/Badge/Badge.mjs.map +1 -0
  145. package/dist/es/components/Badge/MediaBadge.mjs +20 -0
  146. package/dist/es/components/Badge/MediaBadge.mjs.map +1 -0
  147. package/dist/es/components/BaseImage/BaseImage.mjs +35 -0
  148. package/dist/es/components/BaseImage/BaseImage.mjs.map +1 -0
  149. package/dist/es/components/BaseImage/ImagePlaceholder.mjs +21 -0
  150. package/dist/es/components/BaseImage/ImagePlaceholder.mjs.map +1 -0
  151. package/dist/es/components/BaseImage/toBaseImageDescriptors.mjs +57 -0
  152. package/dist/es/components/BaseImage/toBaseImageDescriptors.mjs.map +1 -0
  153. package/dist/es/components/Button/Button.mjs +36 -0
  154. package/dist/es/components/Button/Button.mjs.map +1 -0
  155. package/dist/es/components/Button/PlayButton.mjs +26 -0
  156. package/dist/es/components/Button/PlayButton.mjs.map +1 -0
  157. package/dist/es/components/Channel/Channel.mjs +752 -0
  158. package/dist/es/components/Channel/Channel.mjs.map +1 -0
  159. package/dist/es/components/Channel/channelState.mjs +195 -0
  160. package/dist/es/components/Channel/channelState.mjs.map +1 -0
  161. package/dist/es/components/Channel/constants.mjs +6 -0
  162. package/dist/es/components/Channel/constants.mjs.map +1 -0
  163. package/dist/es/components/Channel/hooks/useChannelContainerClasses.mjs +20 -0
  164. package/dist/es/components/Channel/hooks/useChannelContainerClasses.mjs.map +1 -0
  165. package/dist/es/components/Channel/hooks/useCreateChannelStateContext.mjs +86 -0
  166. package/dist/es/components/Channel/hooks/useCreateChannelStateContext.mjs.map +1 -0
  167. package/dist/es/components/Channel/hooks/useCreateTypingContext.mjs +10 -0
  168. package/dist/es/components/Channel/hooks/useCreateTypingContext.mjs.map +1 -0
  169. package/dist/es/components/Channel/hooks/useEditMessageHandler.mjs +13 -0
  170. package/dist/es/components/Channel/hooks/useEditMessageHandler.mjs.map +1 -0
  171. package/dist/es/components/Channel/hooks/useIsMounted.mjs +16 -0
  172. package/dist/es/components/Channel/hooks/useIsMounted.mjs.map +1 -0
  173. package/dist/es/components/Channel/hooks/useMentionsHandlers.mjs +18 -0
  174. package/dist/es/components/Channel/hooks/useMentionsHandlers.mjs.map +1 -0
  175. package/dist/es/components/Channel/utils.mjs +156 -0
  176. package/dist/es/components/Channel/utils.mjs.map +1 -0
  177. package/dist/es/components/ChannelHeader/ChannelHeader.mjs +70 -0
  178. package/dist/es/components/ChannelHeader/ChannelHeader.mjs.map +1 -0
  179. package/dist/es/components/ChannelHeader/hooks/useChannelHasMembersOnline.mjs +51 -0
  180. package/dist/es/components/ChannelHeader/hooks/useChannelHasMembersOnline.mjs.map +1 -0
  181. package/dist/es/components/ChannelHeader/hooks/useChannelHeaderOnlineStatus.mjs +33 -0
  182. package/dist/es/components/ChannelHeader/hooks/useChannelHeaderOnlineStatus.mjs.map +1 -0
  183. package/dist/es/components/ChannelList/ChannelList.mjs +143 -0
  184. package/dist/es/components/ChannelList/ChannelList.mjs.map +1 -0
  185. package/dist/es/components/ChannelList/ChannelListHeader.mjs +22 -0
  186. package/dist/es/components/ChannelList/ChannelListHeader.mjs.map +1 -0
  187. package/dist/es/components/ChannelList/ChannelListUI.mjs +35 -0
  188. package/dist/es/components/ChannelList/ChannelListUI.mjs.map +1 -0
  189. package/dist/es/components/ChannelList/hooks/useChannelListKeyboardNavigation.mjs +82 -0
  190. package/dist/es/components/ChannelList/hooks/useChannelListKeyboardNavigation.mjs.map +1 -0
  191. package/dist/es/components/ChannelList/hooks/useChannelListShape.mjs +310 -0
  192. package/dist/es/components/ChannelList/hooks/useChannelListShape.mjs.map +1 -0
  193. package/dist/es/components/ChannelList/hooks/useChannelMembersState.mjs +23 -0
  194. package/dist/es/components/ChannelList/hooks/useChannelMembersState.mjs.map +1 -0
  195. package/dist/es/components/ChannelList/hooks/useChannelMembershipState.mjs +15 -0
  196. package/dist/es/components/ChannelList/hooks/useChannelMembershipState.mjs.map +1 -0
  197. package/dist/es/components/ChannelList/hooks/useConnectionRecoveredListener.mjs +19 -0
  198. package/dist/es/components/ChannelList/hooks/useConnectionRecoveredListener.mjs.map +1 -0
  199. package/dist/es/components/ChannelList/hooks/usePaginatedChannels.mjs +110 -0
  200. package/dist/es/components/ChannelList/hooks/usePaginatedChannels.mjs.map +1 -0
  201. package/dist/es/components/ChannelList/hooks/useSelectedChannelState.mjs +24 -0
  202. package/dist/es/components/ChannelList/hooks/useSelectedChannelState.mjs.map +1 -0
  203. package/dist/es/components/ChannelList/utils.mjs +86 -0
  204. package/dist/es/components/ChannelList/utils.mjs.map +1 -0
  205. package/dist/es/components/ChannelListItem/ChannelListItem.mjs +116 -0
  206. package/dist/es/components/ChannelListItem/ChannelListItem.mjs.map +1 -0
  207. package/dist/es/components/ChannelListItem/ChannelListItemActionButtons.defaults.mjs +432 -0
  208. package/dist/es/components/ChannelListItem/ChannelListItemActionButtons.defaults.mjs.map +1 -0
  209. package/dist/es/components/ChannelListItem/ChannelListItemActionButtons.mjs +67 -0
  210. package/dist/es/components/ChannelListItem/ChannelListItemActionButtons.mjs.map +1 -0
  211. package/dist/es/components/ChannelListItem/ChannelListItemTimestamp.mjs +30 -0
  212. package/dist/es/components/ChannelListItem/ChannelListItemTimestamp.mjs.map +1 -0
  213. package/dist/es/components/ChannelListItem/ChannelListItemUI.mjs +118 -0
  214. package/dist/es/components/ChannelListItem/ChannelListItemUI.mjs.map +1 -0
  215. package/dist/es/components/ChannelListItem/hooks/useChannelDisplayName.mjs +56 -0
  216. package/dist/es/components/ChannelListItem/hooks/useChannelDisplayName.mjs.map +1 -0
  217. package/dist/es/components/ChannelListItem/hooks/useChannelPreviewInfo.mjs +51 -0
  218. package/dist/es/components/ChannelListItem/hooks/useChannelPreviewInfo.mjs.map +1 -0
  219. package/dist/es/components/ChannelListItem/hooks/useIsChannelMuted.mjs +33 -0
  220. package/dist/es/components/ChannelListItem/hooks/useIsChannelMuted.mjs.map +1 -0
  221. package/dist/es/components/ChannelListItem/hooks/useIsUserMuted.mjs +11 -0
  222. package/dist/es/components/ChannelListItem/hooks/useIsUserMuted.mjs.map +1 -0
  223. package/dist/es/components/ChannelListItem/hooks/useMessageDeliveryStatus.mjs +68 -0
  224. package/dist/es/components/ChannelListItem/hooks/useMessageDeliveryStatus.mjs.map +1 -0
  225. package/dist/es/components/ChannelListItem/utils.a11y.mjs +121 -0
  226. package/dist/es/components/ChannelListItem/utils.a11y.mjs.map +1 -0
  227. package/dist/es/components/ChannelListItem/utils.mjs +195 -0
  228. package/dist/es/components/ChannelListItem/utils.mjs.map +1 -0
  229. package/dist/es/components/Chat/Chat.mjs +88 -0
  230. package/dist/es/components/Chat/Chat.mjs.map +1 -0
  231. package/dist/es/components/Chat/hooks/useChannelsQueryState.mjs +16 -0
  232. package/dist/es/components/Chat/hooks/useChannelsQueryState.mjs.map +1 -0
  233. package/dist/es/components/Chat/hooks/useChat.mjs +86 -0
  234. package/dist/es/components/Chat/hooks/useChat.mjs.map +1 -0
  235. package/dist/es/components/Chat/hooks/useCreateChatClient.mjs +36 -0
  236. package/dist/es/components/Chat/hooks/useCreateChatClient.mjs.map +1 -0
  237. package/dist/es/components/Chat/hooks/useCreateChatContext.mjs +38 -0
  238. package/dist/es/components/Chat/hooks/useCreateChatContext.mjs.map +1 -0
  239. package/dist/es/components/Chat/hooks/useReportLostConnectionSystemNotification.mjs +51 -0
  240. package/dist/es/components/Chat/hooks/useReportLostConnectionSystemNotification.mjs.map +1 -0
  241. package/dist/es/components/Chat/hooks/useSplitActionSet.mjs +21 -0
  242. package/dist/es/components/Chat/hooks/useSplitActionSet.mjs.map +1 -0
  243. package/dist/es/components/ChatView/ChatView.a11y.utility.mjs +13 -0
  244. package/dist/es/components/ChatView/ChatView.a11y.utility.mjs.map +1 -0
  245. package/dist/es/components/ChatView/ChatView.mjs +224 -0
  246. package/dist/es/components/ChatView/ChatView.mjs.map +1 -0
  247. package/dist/es/components/DateSeparator/DateSeparator.mjs +36 -0
  248. package/dist/es/components/DateSeparator/DateSeparator.mjs.map +1 -0
  249. package/dist/es/components/Dialog/components/Alert.mjs +53 -0
  250. package/dist/es/components/Dialog/components/Alert.mjs.map +1 -0
  251. package/dist/es/components/Dialog/components/Callout.mjs +57 -0
  252. package/dist/es/components/Dialog/components/Callout.mjs.map +1 -0
  253. package/dist/es/components/Dialog/components/ContextMenu.mjs +550 -0
  254. package/dist/es/components/Dialog/components/ContextMenu.mjs.map +1 -0
  255. package/dist/es/components/Dialog/components/Prompt.mjs +112 -0
  256. package/dist/es/components/Dialog/components/Prompt.mjs.map +1 -0
  257. package/dist/es/components/Dialog/components/Viewer.mjs +100 -0
  258. package/dist/es/components/Dialog/components/Viewer.mjs.map +1 -0
  259. package/dist/es/components/Dialog/hooks/useDialog.mjs +53 -0
  260. package/dist/es/components/Dialog/hooks/useDialog.mjs.map +1 -0
  261. package/dist/es/components/Dialog/hooks/usePopoverPosition.mjs +49 -0
  262. package/dist/es/components/Dialog/hooks/usePopoverPosition.mjs.map +1 -0
  263. package/dist/es/components/Dialog/service/DialogAnchor.mjs +175 -0
  264. package/dist/es/components/Dialog/service/DialogAnchor.mjs.map +1 -0
  265. package/dist/es/components/Dialog/service/DialogManager.mjs +169 -0
  266. package/dist/es/components/Dialog/service/DialogManager.mjs.map +1 -0
  267. package/dist/es/components/Dialog/service/DialogPortal.mjs +63 -0
  268. package/dist/es/components/Dialog/service/DialogPortal.mjs.map +1 -0
  269. package/dist/es/components/DragAndDrop/DragAndDropContainer.mjs +90 -0
  270. package/dist/es/components/DragAndDrop/DragAndDropContainer.mjs.map +1 -0
  271. package/dist/es/components/EmptyStateIndicator/EmptyStateIndicator.mjs +38 -0
  272. package/dist/es/components/EmptyStateIndicator/EmptyStateIndicator.mjs.map +1 -0
  273. package/dist/es/components/EventComponent/EventComponent.mjs +27 -0
  274. package/dist/es/components/EventComponent/EventComponent.mjs.map +1 -0
  275. package/dist/es/components/FileIcon/FileIcon.mjs +43 -0
  276. package/dist/es/components/FileIcon/FileIcon.mjs.map +1 -0
  277. package/dist/es/components/FileIcon/FileIconSet.mjs +407 -0
  278. package/dist/es/components/FileIcon/FileIconSet.mjs.map +1 -0
  279. package/dist/es/components/FileIcon/iconMap.mjs +41 -0
  280. package/dist/es/components/FileIcon/iconMap.mjs.map +1 -0
  281. package/dist/es/components/FileIcon/mimeTypes.mjs +242 -0
  282. package/dist/es/components/FileIcon/mimeTypes.mjs.map +1 -0
  283. package/dist/es/components/Form/Checkbox.mjs +15 -0
  284. package/dist/es/components/Form/Checkbox.mjs.map +1 -0
  285. package/dist/es/components/Form/Dropdown.mjs +132 -0
  286. package/dist/es/components/Form/Dropdown.mjs.map +1 -0
  287. package/dist/es/components/Form/FieldError.mjs +13 -0
  288. package/dist/es/components/Form/FieldError.mjs.map +1 -0
  289. package/dist/es/components/Form/NumericInput.mjs +125 -0
  290. package/dist/es/components/Form/NumericInput.mjs.map +1 -0
  291. package/dist/es/components/Form/SwitchField.mjs +103 -0
  292. package/dist/es/components/Form/SwitchField.mjs.map +1 -0
  293. package/dist/es/components/Form/TextInput.mjs +113 -0
  294. package/dist/es/components/Form/TextInput.mjs.map +1 -0
  295. package/dist/es/components/Form/TextInputFieldSet.mjs +21 -0
  296. package/dist/es/components/Form/TextInputFieldSet.mjs.map +1 -0
  297. package/dist/es/components/Form/hooks/useFormState.mjs +54 -0
  298. package/dist/es/components/Form/hooks/useFormState.mjs.map +1 -0
  299. package/dist/es/components/Gallery/Gallery.mjs +60 -0
  300. package/dist/es/components/Gallery/Gallery.mjs.map +1 -0
  301. package/dist/es/components/Gallery/GalleryContext.mjs +21 -0
  302. package/dist/es/components/Gallery/GalleryContext.mjs.map +1 -0
  303. package/dist/es/components/Gallery/GalleryHeader.mjs +65 -0
  304. package/dist/es/components/Gallery/GalleryHeader.mjs.map +1 -0
  305. package/dist/es/components/Gallery/GalleryUI.mjs +206 -0
  306. package/dist/es/components/Gallery/GalleryUI.mjs.map +1 -0
  307. package/dist/es/components/Icons/BaseIcon.mjs +20 -0
  308. package/dist/es/components/Icons/BaseIcon.mjs.map +1 -0
  309. package/dist/es/components/Icons/createIcon.mjs +23 -0
  310. package/dist/es/components/Icons/createIcon.mjs.map +1 -0
  311. package/dist/es/components/Icons/icons.mjs +802 -0
  312. package/dist/es/components/Icons/icons.mjs.map +1 -0
  313. package/dist/es/components/InfiniteScrollPaginator/InfiniteScroll.mjs +81 -0
  314. package/dist/es/components/InfiniteScrollPaginator/InfiniteScroll.mjs.map +1 -0
  315. package/dist/es/components/InfiniteScrollPaginator/InfiniteScrollPaginator.mjs +73 -0
  316. package/dist/es/components/InfiniteScrollPaginator/InfiniteScrollPaginator.mjs.map +1 -0
  317. package/dist/es/components/InfiniteScrollPaginator/hooks/useCursorPaginator.mjs +47 -0
  318. package/dist/es/components/InfiniteScrollPaginator/hooks/useCursorPaginator.mjs.map +1 -0
  319. package/dist/es/components/ListItemLayout/ListItemLayout.mjs +62 -0
  320. package/dist/es/components/ListItemLayout/ListItemLayout.mjs.map +1 -0
  321. package/dist/es/components/LoadMore/LoadMoreButton.mjs +28 -0
  322. package/dist/es/components/LoadMore/LoadMoreButton.mjs.map +1 -0
  323. package/dist/es/components/LoadMore/LoadMorePaginator.mjs +20 -0
  324. package/dist/es/components/LoadMore/LoadMorePaginator.mjs.map +1 -0
  325. package/dist/es/components/Loading/AttachmentUploadedSizeIndicator.mjs +33 -0
  326. package/dist/es/components/Loading/AttachmentUploadedSizeIndicator.mjs.map +1 -0
  327. package/dist/es/components/Loading/LoadingChannel.mjs +59 -0
  328. package/dist/es/components/Loading/LoadingChannel.mjs.map +1 -0
  329. package/dist/es/components/Loading/LoadingChannels.mjs +28 -0
  330. package/dist/es/components/Loading/LoadingChannels.mjs.map +1 -0
  331. package/dist/es/components/Loading/LoadingErrorIndicator.mjs +17 -0
  332. package/dist/es/components/Loading/LoadingErrorIndicator.mjs.map +1 -0
  333. package/dist/es/components/Loading/LoadingIndicator.mjs +15 -0
  334. package/dist/es/components/Loading/LoadingIndicator.mjs.map +1 -0
  335. package/dist/es/components/Loading/UploadProgressIndicator.mjs +15 -0
  336. package/dist/es/components/Loading/UploadProgressIndicator.mjs.map +1 -0
  337. package/dist/es/components/Loading/UploadedSizeIndicator.mjs +22 -0
  338. package/dist/es/components/Loading/UploadedSizeIndicator.mjs.map +1 -0
  339. package/dist/es/components/Loading/progress-indicators.mjs +50 -0
  340. package/dist/es/components/Loading/progress-indicators.mjs.map +1 -0
  341. package/dist/es/components/Location/ShareLocationDialog.mjs +206 -0
  342. package/dist/es/components/Location/ShareLocationDialog.mjs.map +1 -0
  343. package/dist/es/components/Location/hooks/useLiveLocationSharingManager.mjs +57 -0
  344. package/dist/es/components/Location/hooks/useLiveLocationSharingManager.mjs.map +1 -0
  345. package/dist/es/components/MediaRecorder/AudioRecorder/AudioRecorder.mjs +32 -0
  346. package/dist/es/components/MediaRecorder/AudioRecorder/AudioRecorder.mjs.map +1 -0
  347. package/dist/es/components/MediaRecorder/AudioRecorder/AudioRecorderRecordingControls.mjs +77 -0
  348. package/dist/es/components/MediaRecorder/AudioRecorder/AudioRecorderRecordingControls.mjs.map +1 -0
  349. package/dist/es/components/MediaRecorder/AudioRecorder/AudioRecordingButtonWithNotification.mjs +58 -0
  350. package/dist/es/components/MediaRecorder/AudioRecorder/AudioRecordingButtonWithNotification.mjs.map +1 -0
  351. package/dist/es/components/MediaRecorder/AudioRecorder/AudioRecordingPlayback.mjs +71 -0
  352. package/dist/es/components/MediaRecorder/AudioRecorder/AudioRecordingPlayback.mjs.map +1 -0
  353. package/dist/es/components/MediaRecorder/AudioRecorder/AudioRecordingPreview.mjs +65 -0
  354. package/dist/es/components/MediaRecorder/AudioRecorder/AudioRecordingPreview.mjs.map +1 -0
  355. package/dist/es/components/MediaRecorder/AudioRecorder/RecordingTimer.mjs +13 -0
  356. package/dist/es/components/MediaRecorder/AudioRecorder/RecordingTimer.mjs.map +1 -0
  357. package/dist/es/components/MediaRecorder/AudioRecorder/hooks/useTimeElapsed.mjs +40 -0
  358. package/dist/es/components/MediaRecorder/AudioRecorder/hooks/useTimeElapsed.mjs.map +1 -0
  359. package/dist/es/components/MediaRecorder/AudioRecorder/recordingStateIdentity.mjs +8 -0
  360. package/dist/es/components/MediaRecorder/AudioRecorder/recordingStateIdentity.mjs.map +1 -0
  361. package/dist/es/components/MediaRecorder/RecordingPermissionDeniedNotification.mjs +31 -0
  362. package/dist/es/components/MediaRecorder/RecordingPermissionDeniedNotification.mjs.map +1 -0
  363. package/dist/es/components/MediaRecorder/classes/AmplitudeRecorder.mjs +75 -0
  364. package/dist/es/components/MediaRecorder/classes/AmplitudeRecorder.mjs.map +1 -0
  365. package/dist/es/components/MediaRecorder/classes/BrowserPermission.mjs +62 -0
  366. package/dist/es/components/MediaRecorder/classes/BrowserPermission.mjs.map +1 -0
  367. package/dist/es/components/MediaRecorder/classes/MediaRecorderController.mjs +237 -0
  368. package/dist/es/components/MediaRecorder/classes/MediaRecorderController.mjs.map +1 -0
  369. package/dist/es/components/MediaRecorder/hooks/useMediaRecorder.mjs +79 -0
  370. package/dist/es/components/MediaRecorder/hooks/useMediaRecorder.mjs.map +1 -0
  371. package/dist/es/components/MediaRecorder/observable/BehaviorSubject.mjs +27 -0
  372. package/dist/es/components/MediaRecorder/observable/BehaviorSubject.mjs.map +1 -0
  373. package/dist/es/components/MediaRecorder/observable/Observable.mjs +23 -0
  374. package/dist/es/components/MediaRecorder/observable/Observable.mjs.map +1 -0
  375. package/dist/es/components/MediaRecorder/observable/Observer.mjs +8 -0
  376. package/dist/es/components/MediaRecorder/observable/Observer.mjs.map +1 -0
  377. package/dist/es/components/MediaRecorder/observable/Subject.mjs +54 -0
  378. package/dist/es/components/MediaRecorder/observable/Subject.mjs.map +1 -0
  379. package/dist/es/components/MediaRecorder/observable/Subscription.mjs +15 -0
  380. package/dist/es/components/MediaRecorder/observable/Subscription.mjs.map +1 -0
  381. package/dist/es/components/MediaRecorder/transcode/audioProcessing.mjs +34 -0
  382. package/dist/es/components/MediaRecorder/transcode/audioProcessing.mjs.map +1 -0
  383. package/dist/es/components/MediaRecorder/transcode/index.mjs +12 -0
  384. package/dist/es/components/MediaRecorder/transcode/index.mjs.map +1 -0
  385. package/dist/es/components/MediaRecorder/transcode/wav.mjs +99 -0
  386. package/dist/es/components/MediaRecorder/transcode/wav.mjs.map +1 -0
  387. package/dist/es/components/Message/Message.mjs +154 -0
  388. package/dist/es/components/Message/Message.mjs.map +1 -0
  389. package/dist/es/components/Message/MessageAlsoSentInChannelIndicator.mjs +79 -0
  390. package/dist/es/components/Message/MessageAlsoSentInChannelIndicator.mjs.map +1 -0
  391. package/dist/es/components/Message/MessageBlocked.mjs +27 -0
  392. package/dist/es/components/Message/MessageBlocked.mjs.map +1 -0
  393. package/dist/es/components/Message/MessageBubble.mjs +12 -0
  394. package/dist/es/components/Message/MessageBubble.mjs.map +1 -0
  395. package/dist/es/components/Message/MessageDeletedBubble.mjs +21 -0
  396. package/dist/es/components/Message/MessageDeletedBubble.mjs.map +1 -0
  397. package/dist/es/components/Message/MessageEditedIndicator.mjs +41 -0
  398. package/dist/es/components/Message/MessageEditedIndicator.mjs.map +1 -0
  399. package/dist/es/components/Message/MessageRepliesCountButton.mjs +37 -0
  400. package/dist/es/components/Message/MessageRepliesCountButton.mjs.map +1 -0
  401. package/dist/es/components/Message/MessageStatus.mjs +85 -0
  402. package/dist/es/components/Message/MessageStatus.mjs.map +1 -0
  403. package/dist/es/components/Message/MessageText.mjs +101 -0
  404. package/dist/es/components/Message/MessageText.mjs.map +1 -0
  405. package/dist/es/components/Message/MessageTimestamp.mjs +20 -0
  406. package/dist/es/components/Message/MessageTimestamp.mjs.map +1 -0
  407. package/dist/es/components/Message/MessageTranslationIndicator.mjs +53 -0
  408. package/dist/es/components/Message/MessageTranslationIndicator.mjs.map +1 -0
  409. package/dist/es/components/Message/MessageUI.mjs +185 -0
  410. package/dist/es/components/Message/MessageUI.mjs.map +1 -0
  411. package/dist/es/components/Message/PinIndicator.mjs +34 -0
  412. package/dist/es/components/Message/PinIndicator.mjs.map +1 -0
  413. package/dist/es/components/Message/QuotedMessage.mjs +26 -0
  414. package/dist/es/components/Message/QuotedMessage.mjs.map +1 -0
  415. package/dist/es/components/Message/ReminderNotification.mjs +57 -0
  416. package/dist/es/components/Message/ReminderNotification.mjs.map +1 -0
  417. package/dist/es/components/Message/StreamedMessageText.mjs +35 -0
  418. package/dist/es/components/Message/StreamedMessageText.mjs.map +1 -0
  419. package/dist/es/components/Message/Timestamp.mjs +41 -0
  420. package/dist/es/components/Message/Timestamp.mjs.map +1 -0
  421. package/dist/es/components/Message/emojiRegex.mjs +20 -0
  422. package/dist/es/components/Message/emojiRegex.mjs.map +1 -0
  423. package/dist/es/components/Message/hooks/useActionHandler.mjs +30 -0
  424. package/dist/es/components/Message/hooks/useActionHandler.mjs.map +1 -0
  425. package/dist/es/components/Message/hooks/useDeleteHandler.mjs +21 -0
  426. package/dist/es/components/Message/hooks/useDeleteHandler.mjs.map +1 -0
  427. package/dist/es/components/Message/hooks/useFlagHandler.mjs +20 -0
  428. package/dist/es/components/Message/hooks/useFlagHandler.mjs.map +1 -0
  429. package/dist/es/components/Message/hooks/useMarkUnreadHandler.mjs +17 -0
  430. package/dist/es/components/Message/hooks/useMarkUnreadHandler.mjs.map +1 -0
  431. package/dist/es/components/Message/hooks/useMentionsHandler.mjs +22 -0
  432. package/dist/es/components/Message/hooks/useMentionsHandler.mjs.map +1 -0
  433. package/dist/es/components/Message/hooks/useMessageReminder.mjs +14 -0
  434. package/dist/es/components/Message/hooks/useMessageReminder.mjs.map +1 -0
  435. package/dist/es/components/Message/hooks/useMessageTextStreaming.mjs +48 -0
  436. package/dist/es/components/Message/hooks/useMessageTextStreaming.mjs.map +1 -0
  437. package/dist/es/components/Message/hooks/useMuteHandler.mjs +24 -0
  438. package/dist/es/components/Message/hooks/useMuteHandler.mjs.map +1 -0
  439. package/dist/es/components/Message/hooks/useOpenThreadHandler.mjs +17 -0
  440. package/dist/es/components/Message/hooks/useOpenThreadHandler.mjs.map +1 -0
  441. package/dist/es/components/Message/hooks/usePinHandler.mjs +45 -0
  442. package/dist/es/components/Message/hooks/usePinHandler.mjs.map +1 -0
  443. package/dist/es/components/Message/hooks/useReactionHandler.mjs +90 -0
  444. package/dist/es/components/Message/hooks/useReactionHandler.mjs.map +1 -0
  445. package/dist/es/components/Message/hooks/useReactionsFetcher.mjs +28 -0
  446. package/dist/es/components/Message/hooks/useReactionsFetcher.mjs.map +1 -0
  447. package/dist/es/components/Message/hooks/useRetryHandler.mjs +13 -0
  448. package/dist/es/components/Message/hooks/useRetryHandler.mjs.map +1 -0
  449. package/dist/es/components/Message/hooks/useUserHandler.mjs +15 -0
  450. package/dist/es/components/Message/hooks/useUserHandler.mjs.map +1 -0
  451. package/dist/es/components/Message/hooks/useUserRole.mjs +47 -0
  452. package/dist/es/components/Message/hooks/useUserRole.mjs.map +1 -0
  453. package/dist/es/components/Message/renderText/componentRenderers/Anchor.mjs +20 -0
  454. package/dist/es/components/Message/renderText/componentRenderers/Anchor.mjs.map +1 -0
  455. package/dist/es/components/Message/renderText/componentRenderers/Emoji.mjs +12 -0
  456. package/dist/es/components/Message/renderText/componentRenderers/Emoji.mjs.map +1 -0
  457. package/dist/es/components/Message/renderText/componentRenderers/Mention.mjs +14 -0
  458. package/dist/es/components/Message/renderText/componentRenderers/Mention.mjs.map +1 -0
  459. package/dist/es/components/Message/renderText/regex.mjs +22 -0
  460. package/dist/es/components/Message/renderText/regex.mjs.map +1 -0
  461. package/dist/es/components/Message/renderText/rehypePlugins/emojiMarkdownPlugin.mjs +16 -0
  462. package/dist/es/components/Message/renderText/rehypePlugins/emojiMarkdownPlugin.mjs.map +1 -0
  463. package/dist/es/components/Message/renderText/rehypePlugins/mentionsMarkdownPlugin.mjs +111 -0
  464. package/dist/es/components/Message/renderText/rehypePlugins/mentionsMarkdownPlugin.mjs.map +1 -0
  465. package/dist/es/components/Message/renderText/remarkPlugins/htmlToTextPlugin.mjs +14 -0
  466. package/dist/es/components/Message/renderText/remarkPlugins/htmlToTextPlugin.mjs.map +1 -0
  467. package/dist/es/components/Message/renderText/remarkPlugins/imageToLink.mjs +33 -0
  468. package/dist/es/components/Message/renderText/remarkPlugins/imageToLink.mjs.map +1 -0
  469. package/dist/es/components/Message/renderText/remarkPlugins/keepLineBreaksPlugin.mjs +44 -0
  470. package/dist/es/components/Message/renderText/remarkPlugins/keepLineBreaksPlugin.mjs.map +1 -0
  471. package/dist/es/components/Message/renderText/remarkPlugins/plusPlusToEmphasis.mjs +68 -0
  472. package/dist/es/components/Message/renderText/remarkPlugins/plusPlusToEmphasis.mjs.map +1 -0
  473. package/dist/es/components/Message/renderText/remarkPlugins/remarkIgnoreMarkdown.mjs +19 -0
  474. package/dist/es/components/Message/renderText/remarkPlugins/remarkIgnoreMarkdown.mjs.map +1 -0
  475. package/dist/es/components/Message/renderText/renderText.mjs +131 -0
  476. package/dist/es/components/Message/renderText/renderText.mjs.map +1 -0
  477. package/dist/es/components/Message/utils.mjs +151 -0
  478. package/dist/es/components/Message/utils.mjs.map +1 -0
  479. package/dist/es/components/MessageActions/DeleteMessageAlert.mjs +43 -0
  480. package/dist/es/components/MessageActions/DeleteMessageAlert.mjs.map +1 -0
  481. package/dist/es/components/MessageActions/DownloadSubmenu.mjs +52 -0
  482. package/dist/es/components/MessageActions/DownloadSubmenu.mjs.map +1 -0
  483. package/dist/es/components/MessageActions/MessageActions.defaults.mjs +644 -0
  484. package/dist/es/components/MessageActions/MessageActions.defaults.mjs.map +1 -0
  485. package/dist/es/components/MessageActions/MessageActions.mjs +61 -0
  486. package/dist/es/components/MessageActions/MessageActions.mjs.map +1 -0
  487. package/dist/es/components/MessageActions/QuickMessageActionButton.mjs +20 -0
  488. package/dist/es/components/MessageActions/QuickMessageActionButton.mjs.map +1 -0
  489. package/dist/es/components/MessageActions/RemindMeSubmenu.mjs +71 -0
  490. package/dist/es/components/MessageActions/RemindMeSubmenu.mjs.map +1 -0
  491. package/dist/es/components/MessageActions/downloadUtils.mjs +65 -0
  492. package/dist/es/components/MessageActions/downloadUtils.mjs.map +1 -0
  493. package/dist/es/components/MessageActions/hooks/useBaseMessageActionSetFilter.mjs +64 -0
  494. package/dist/es/components/MessageActions/hooks/useBaseMessageActionSetFilter.mjs.map +1 -0
  495. package/dist/es/components/MessageBounce/MessageBounceModal.mjs +18 -0
  496. package/dist/es/components/MessageBounce/MessageBounceModal.mjs.map +1 -0
  497. package/dist/es/components/MessageBounce/MessageBouncePrompt.mjs +67 -0
  498. package/dist/es/components/MessageBounce/MessageBouncePrompt.mjs.map +1 -0
  499. package/dist/es/components/MessageComposer/AttachmentPreviewList/AttachmentPreviewList.mjs +91 -0
  500. package/dist/es/components/MessageComposer/AttachmentPreviewList/AttachmentPreviewList.mjs.map +1 -0
  501. package/dist/es/components/MessageComposer/AttachmentPreviewList/AudioAttachmentPreview.mjs +131 -0
  502. package/dist/es/components/MessageComposer/AttachmentPreviewList/AudioAttachmentPreview.mjs.map +1 -0
  503. package/dist/es/components/MessageComposer/AttachmentPreviewList/FileAttachmentPreview.mjs +82 -0
  504. package/dist/es/components/MessageComposer/AttachmentPreviewList/FileAttachmentPreview.mjs.map +1 -0
  505. package/dist/es/components/MessageComposer/AttachmentPreviewList/GeolocationPreview.mjs +53 -0
  506. package/dist/es/components/MessageComposer/AttachmentPreviewList/GeolocationPreview.mjs.map +1 -0
  507. package/dist/es/components/MessageComposer/AttachmentPreviewList/MediaAttachmentPreview.mjs +97 -0
  508. package/dist/es/components/MessageComposer/AttachmentPreviewList/MediaAttachmentPreview.mjs.map +1 -0
  509. package/dist/es/components/MessageComposer/AttachmentPreviewList/UnsupportedAttachmentPreview.mjs +36 -0
  510. package/dist/es/components/MessageComposer/AttachmentPreviewList/UnsupportedAttachmentPreview.mjs.map +1 -0
  511. package/dist/es/components/MessageComposer/AttachmentPreviewList/VoiceRecordingPreviewSlot.mjs +29 -0
  512. package/dist/es/components/MessageComposer/AttachmentPreviewList/VoiceRecordingPreviewSlot.mjs.map +1 -0
  513. package/dist/es/components/MessageComposer/AttachmentPreviewList/utils/AttachmentPreviewRoot.mjs +53 -0
  514. package/dist/es/components/MessageComposer/AttachmentPreviewList/utils/AttachmentPreviewRoot.mjs.map +1 -0
  515. package/dist/es/components/MessageComposer/AttachmentSelector/AttachmentSelector.mjs +308 -0
  516. package/dist/es/components/MessageComposer/AttachmentSelector/AttachmentSelector.mjs.map +1 -0
  517. package/dist/es/components/MessageComposer/AttachmentSelector/CommandsMenu.mjs +104 -0
  518. package/dist/es/components/MessageComposer/AttachmentSelector/CommandsMenu.mjs.map +1 -0
  519. package/dist/es/components/MessageComposer/CommandChip.mjs +37 -0
  520. package/dist/es/components/MessageComposer/CommandChip.mjs.map +1 -0
  521. package/dist/es/components/MessageComposer/CooldownTimer.mjs +15 -0
  522. package/dist/es/components/MessageComposer/CooldownTimer.mjs.map +1 -0
  523. package/dist/es/components/MessageComposer/EditedMessagePreview.mjs +17 -0
  524. package/dist/es/components/MessageComposer/EditedMessagePreview.mjs.map +1 -0
  525. package/dist/es/components/MessageComposer/LinkPreviewList.mjs +78 -0
  526. package/dist/es/components/MessageComposer/LinkPreviewList.mjs.map +1 -0
  527. package/dist/es/components/MessageComposer/MessageComposer.mjs +66 -0
  528. package/dist/es/components/MessageComposer/MessageComposer.mjs.map +1 -0
  529. package/dist/es/components/MessageComposer/MessageComposerActions.mjs +71 -0
  530. package/dist/es/components/MessageComposer/MessageComposerActions.mjs.map +1 -0
  531. package/dist/es/components/MessageComposer/MessageComposerUI.mjs +100 -0
  532. package/dist/es/components/MessageComposer/MessageComposerUI.mjs.map +1 -0
  533. package/dist/es/components/MessageComposer/QuotedMessageIndicator.mjs +9 -0
  534. package/dist/es/components/MessageComposer/QuotedMessageIndicator.mjs.map +1 -0
  535. package/dist/es/components/MessageComposer/QuotedMessagePreview.mjs +325 -0
  536. package/dist/es/components/MessageComposer/QuotedMessagePreview.mjs.map +1 -0
  537. package/dist/es/components/MessageComposer/RemoveAttachmentPreviewButton.mjs +25 -0
  538. package/dist/es/components/MessageComposer/RemoveAttachmentPreviewButton.mjs.map +1 -0
  539. package/dist/es/components/MessageComposer/SendButton.mjs +29 -0
  540. package/dist/es/components/MessageComposer/SendButton.mjs.map +1 -0
  541. package/dist/es/components/MessageComposer/SendToChannelCheckbox.mjs +51 -0
  542. package/dist/es/components/MessageComposer/SendToChannelCheckbox.mjs.map +1 -0
  543. package/dist/es/components/MessageComposer/StopAIGenerationButton.mjs +18 -0
  544. package/dist/es/components/MessageComposer/StopAIGenerationButton.mjs.map +1 -0
  545. package/dist/es/components/MessageComposer/WithDragAndDropUpload.mjs +109 -0
  546. package/dist/es/components/MessageComposer/WithDragAndDropUpload.mjs.map +1 -0
  547. package/dist/es/components/MessageComposer/hooks/useAttachmentManagerState.mjs +24 -0
  548. package/dist/es/components/MessageComposer/hooks/useAttachmentManagerState.mjs.map +1 -0
  549. package/dist/es/components/MessageComposer/hooks/useAttachmentsForPreview.mjs +21 -0
  550. package/dist/es/components/MessageComposer/hooks/useAttachmentsForPreview.mjs.map +1 -0
  551. package/dist/es/components/MessageComposer/hooks/useCanCreatePoll.mjs +15 -0
  552. package/dist/es/components/MessageComposer/hooks/useCanCreatePoll.mjs.map +1 -0
  553. package/dist/es/components/MessageComposer/hooks/useCooldownRemaining.mjs +19 -0
  554. package/dist/es/components/MessageComposer/hooks/useCooldownRemaining.mjs.map +1 -0
  555. package/dist/es/components/MessageComposer/hooks/useCreateMessageComposerContext.mjs +35 -0
  556. package/dist/es/components/MessageComposer/hooks/useCreateMessageComposerContext.mjs.map +1 -0
  557. package/dist/es/components/MessageComposer/hooks/useIsCooldownActive.mjs +12 -0
  558. package/dist/es/components/MessageComposer/hooks/useIsCooldownActive.mjs.map +1 -0
  559. package/dist/es/components/MessageComposer/hooks/useMessageComposerBindings.mjs +27 -0
  560. package/dist/es/components/MessageComposer/hooks/useMessageComposerBindings.mjs.map +1 -0
  561. package/dist/es/components/MessageComposer/hooks/useMessageComposerCommands.mjs +27 -0
  562. package/dist/es/components/MessageComposer/hooks/useMessageComposerCommands.mjs.map +1 -0
  563. package/dist/es/components/MessageComposer/hooks/useMessageComposerController.mjs +56 -0
  564. package/dist/es/components/MessageComposer/hooks/useMessageComposerController.mjs.map +1 -0
  565. package/dist/es/components/MessageComposer/hooks/useMessageComposerHasSendableData.mjs +13 -0
  566. package/dist/es/components/MessageComposer/hooks/useMessageComposerHasSendableData.mjs.map +1 -0
  567. package/dist/es/components/MessageComposer/hooks/useMessageContentIsEmpty.mjs +13 -0
  568. package/dist/es/components/MessageComposer/hooks/useMessageContentIsEmpty.mjs.map +1 -0
  569. package/dist/es/components/MessageComposer/hooks/usePasteHandler.mjs +34 -0
  570. package/dist/es/components/MessageComposer/hooks/usePasteHandler.mjs.map +1 -0
  571. package/dist/es/components/MessageComposer/hooks/useSubmitHandler.mjs +98 -0
  572. package/dist/es/components/MessageComposer/hooks/useSubmitHandler.mjs.map +1 -0
  573. package/dist/es/components/MessageComposer/hooks/useTextareaRef.mjs +14 -0
  574. package/dist/es/components/MessageComposer/hooks/useTextareaRef.mjs.map +1 -0
  575. package/dist/es/components/MessageComposer/hooks/utils.mjs +16 -0
  576. package/dist/es/components/MessageComposer/hooks/utils.mjs.map +1 -0
  577. package/dist/es/components/MessageComposer/icons.mjs +62 -0
  578. package/dist/es/components/MessageComposer/icons.mjs.map +1 -0
  579. package/dist/es/components/MessageComposer/preEditSnapshot.mjs +45 -0
  580. package/dist/es/components/MessageComposer/preEditSnapshot.mjs.map +1 -0
  581. package/dist/es/components/MessageList/FloatingDateSeparator.mjs +46 -0
  582. package/dist/es/components/MessageList/FloatingDateSeparator.mjs.map +1 -0
  583. package/dist/es/components/MessageList/GiphyPreviewMessage.mjs +15 -0
  584. package/dist/es/components/MessageList/GiphyPreviewMessage.mjs.map +1 -0
  585. package/dist/es/components/MessageList/MessageList.mjs +329 -0
  586. package/dist/es/components/MessageList/MessageList.mjs.map +1 -0
  587. package/dist/es/components/MessageList/MessageListMainPanel.mjs +12 -0
  588. package/dist/es/components/MessageList/MessageListMainPanel.mjs.map +1 -0
  589. package/dist/es/components/MessageList/NewMessageNotification.mjs +32 -0
  590. package/dist/es/components/MessageList/NewMessageNotification.mjs.map +1 -0
  591. package/dist/es/components/MessageList/ScrollToLatestMessageButton.mjs +78 -0
  592. package/dist/es/components/MessageList/ScrollToLatestMessageButton.mjs.map +1 -0
  593. package/dist/es/components/MessageList/UnreadMessagesNotification.mjs +33 -0
  594. package/dist/es/components/MessageList/UnreadMessagesNotification.mjs.map +1 -0
  595. package/dist/es/components/MessageList/UnreadMessagesSeparator.mjs +33 -0
  596. package/dist/es/components/MessageList/UnreadMessagesSeparator.mjs.map +1 -0
  597. package/dist/es/components/MessageList/VirtualizedMessageList.mjs +339 -0
  598. package/dist/es/components/MessageList/VirtualizedMessageList.mjs.map +1 -0
  599. package/dist/es/components/MessageList/VirtualizedMessageListComponents.mjs +93 -0
  600. package/dist/es/components/MessageList/VirtualizedMessageListComponents.mjs.map +1 -0
  601. package/dist/es/components/MessageList/hooks/MessageList/useEnrichedMessages.mjs +39 -0
  602. package/dist/es/components/MessageList/hooks/MessageList/useEnrichedMessages.mjs.map +1 -0
  603. package/dist/es/components/MessageList/hooks/MessageList/useFloatingDateSeparatorMessageList.mjs +78 -0
  604. package/dist/es/components/MessageList/hooks/MessageList/useFloatingDateSeparatorMessageList.mjs.map +1 -0
  605. package/dist/es/components/MessageList/hooks/MessageList/useMessageListElements.mjs +58 -0
  606. package/dist/es/components/MessageList/hooks/MessageList/useMessageListElements.mjs.map +1 -0
  607. package/dist/es/components/MessageList/hooks/MessageList/useMessageListScrollManager.mjs +141 -0
  608. package/dist/es/components/MessageList/hooks/MessageList/useMessageListScrollManager.mjs.map +1 -0
  609. package/dist/es/components/MessageList/hooks/MessageList/useScrollLocationLogic.mjs +275 -0
  610. package/dist/es/components/MessageList/hooks/MessageList/useScrollLocationLogic.mjs.map +1 -0
  611. package/dist/es/components/MessageList/hooks/MessageList/useUnreadMessagesNotification.mjs +81 -0
  612. package/dist/es/components/MessageList/hooks/MessageList/useUnreadMessagesNotification.mjs.map +1 -0
  613. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useFloatingDateSeparator.mjs +69 -0
  614. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useFloatingDateSeparator.mjs.map +1 -0
  615. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useGiphyPreview.mjs +24 -0
  616. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useGiphyPreview.mjs.map +1 -0
  617. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useMessageSetKey.mjs +18 -0
  618. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useMessageSetKey.mjs.map +1 -0
  619. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useNewMessageNotification.mjs +41 -0
  620. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useNewMessageNotification.mjs.map +1 -0
  621. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/usePrependMessagesCount.mjs +41 -0
  622. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/usePrependMessagesCount.mjs.map +1 -0
  623. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useScrollToBottomOnNewMessage.mjs +33 -0
  624. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useScrollToBottomOnNewMessage.mjs.map +1 -0
  625. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useShouldForceScrollToBottom.mjs +27 -0
  626. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useShouldForceScrollToBottom.mjs.map +1 -0
  627. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useUnreadMessagesNotificationVirtualized.mjs +43 -0
  628. package/dist/es/components/MessageList/hooks/VirtualizedMessageList/useUnreadMessagesNotificationVirtualized.mjs.map +1 -0
  629. package/dist/es/components/MessageList/hooks/useLastDeliveredData.mjs +43 -0
  630. package/dist/es/components/MessageList/hooks/useLastDeliveredData.mjs.map +1 -0
  631. package/dist/es/components/MessageList/hooks/useLastOwnMessage.mjs +8 -0
  632. package/dist/es/components/MessageList/hooks/useLastOwnMessage.mjs.map +1 -0
  633. package/dist/es/components/MessageList/hooks/useLastReadData.mjs +28 -0
  634. package/dist/es/components/MessageList/hooks/useLastReadData.mjs.map +1 -0
  635. package/dist/es/components/MessageList/hooks/useMarkRead.mjs +75 -0
  636. package/dist/es/components/MessageList/hooks/useMarkRead.mjs.map +1 -0
  637. package/dist/es/components/MessageList/hooks/useReducedMotionPreference.mjs +23 -0
  638. package/dist/es/components/MessageList/hooks/useReducedMotionPreference.mjs.map +1 -0
  639. package/dist/es/components/MessageList/renderMessages.mjs +76 -0
  640. package/dist/es/components/MessageList/renderMessages.mjs.map +1 -0
  641. package/dist/es/components/MessageList/utils.mjs +155 -0
  642. package/dist/es/components/MessageList/utils.mjs.map +1 -0
  643. package/dist/es/components/Modal/GlobalModal.mjs +157 -0
  644. package/dist/es/components/Modal/GlobalModal.mjs.map +1 -0
  645. package/dist/es/components/Notifications/Notification.mjs +91 -0
  646. package/dist/es/components/Notifications/Notification.mjs.map +1 -0
  647. package/dist/es/components/Notifications/NotificationConfigurationContext.mjs +19 -0
  648. package/dist/es/components/Notifications/NotificationConfigurationContext.mjs.map +1 -0
  649. package/dist/es/components/Notifications/NotificationList.mjs +314 -0
  650. package/dist/es/components/Notifications/NotificationList.mjs.map +1 -0
  651. package/dist/es/components/Notifications/hooks/useNotificationApi.mjs +107 -0
  652. package/dist/es/components/Notifications/hooks/useNotificationApi.mjs.map +1 -0
  653. package/dist/es/components/Notifications/hooks/useNotificationTarget.mjs +25 -0
  654. package/dist/es/components/Notifications/hooks/useNotificationTarget.mjs.map +1 -0
  655. package/dist/es/components/Notifications/hooks/useNotifications.mjs +39 -0
  656. package/dist/es/components/Notifications/hooks/useNotifications.mjs.map +1 -0
  657. package/dist/es/components/Notifications/hooks/useSystemNotifications.mjs +22 -0
  658. package/dist/es/components/Notifications/hooks/useSystemNotifications.mjs.map +1 -0
  659. package/dist/es/components/Notifications/notificationTarget.mjs +38 -0
  660. package/dist/es/components/Notifications/notificationTarget.mjs.map +1 -0
  661. package/dist/es/components/Poll/Poll.mjs +18 -0
  662. package/dist/es/components/Poll/Poll.mjs.map +1 -0
  663. package/dist/es/components/Poll/PollActions/AddCommentPrompt.mjs +79 -0
  664. package/dist/es/components/Poll/PollActions/AddCommentPrompt.mjs.map +1 -0
  665. package/dist/es/components/Poll/PollActions/EndPollAlert.mjs +61 -0
  666. package/dist/es/components/Poll/PollActions/EndPollAlert.mjs.map +1 -0
  667. package/dist/es/components/Poll/PollActions/PollAction.mjs +27 -0
  668. package/dist/es/components/Poll/PollActions/PollAction.mjs.map +1 -0
  669. package/dist/es/components/Poll/PollActions/PollActions.mjs +92 -0
  670. package/dist/es/components/Poll/PollActions/PollActions.mjs.map +1 -0
  671. package/dist/es/components/Poll/PollActions/PollAnswerList.mjs +70 -0
  672. package/dist/es/components/Poll/PollActions/PollAnswerList.mjs.map +1 -0
  673. package/dist/es/components/Poll/PollActions/PollOptionsFullList.mjs +32 -0
  674. package/dist/es/components/Poll/PollActions/PollOptionsFullList.mjs.map +1 -0
  675. package/dist/es/components/Poll/PollActions/PollQuestion.mjs +20 -0
  676. package/dist/es/components/Poll/PollActions/PollQuestion.mjs.map +1 -0
  677. package/dist/es/components/Poll/PollActions/PollResults/PollOptionWithVotes.mjs +49 -0
  678. package/dist/es/components/Poll/PollActions/PollResults/PollOptionWithVotes.mjs.map +1 -0
  679. package/dist/es/components/Poll/PollActions/PollResults/PollOptionWithVotesHeader.mjs +44 -0
  680. package/dist/es/components/Poll/PollActions/PollResults/PollOptionWithVotesHeader.mjs.map +1 -0
  681. package/dist/es/components/Poll/PollActions/PollResults/PollOptionWithVotesList.mjs +39 -0
  682. package/dist/es/components/Poll/PollActions/PollResults/PollOptionWithVotesList.mjs.map +1 -0
  683. package/dist/es/components/Poll/PollActions/PollResults/PollResults.mjs +75 -0
  684. package/dist/es/components/Poll/PollActions/PollResults/PollResults.mjs.map +1 -0
  685. package/dist/es/components/Poll/PollActions/SuggestPollOptionPrompt.mjs +79 -0
  686. package/dist/es/components/Poll/PollActions/SuggestPollOptionPrompt.mjs.map +1 -0
  687. package/dist/es/components/Poll/PollContent.mjs +28 -0
  688. package/dist/es/components/Poll/PollContent.mjs.map +1 -0
  689. package/dist/es/components/Poll/PollCreationDialog/MultipleAnswersField.mjs +84 -0
  690. package/dist/es/components/Poll/PollCreationDialog/MultipleAnswersField.mjs.map +1 -0
  691. package/dist/es/components/Poll/PollCreationDialog/NameField.mjs +41 -0
  692. package/dist/es/components/Poll/PollCreationDialog/NameField.mjs.map +1 -0
  693. package/dist/es/components/Poll/PollCreationDialog/OptionFieldSet.mjs +193 -0
  694. package/dist/es/components/Poll/PollCreationDialog/OptionFieldSet.mjs.map +1 -0
  695. package/dist/es/components/Poll/PollCreationDialog/PollCreationDialog.mjs +78 -0
  696. package/dist/es/components/Poll/PollCreationDialog/PollCreationDialog.mjs.map +1 -0
  697. package/dist/es/components/Poll/PollCreationDialog/PollCreationDialogControls.mjs +62 -0
  698. package/dist/es/components/Poll/PollCreationDialog/PollCreationDialogControls.mjs.map +1 -0
  699. package/dist/es/components/Poll/PollCreationDialog/PollOptionReorderHandle.mjs +79 -0
  700. package/dist/es/components/Poll/PollCreationDialog/PollOptionReorderHandle.mjs.map +1 -0
  701. package/dist/es/components/Poll/PollHeader.mjs +46 -0
  702. package/dist/es/components/Poll/PollHeader.mjs.map +1 -0
  703. package/dist/es/components/Poll/PollOptionList.mjs +41 -0
  704. package/dist/es/components/Poll/PollOptionList.mjs.map +1 -0
  705. package/dist/es/components/Poll/PollOptionSelector.mjs +99 -0
  706. package/dist/es/components/Poll/PollOptionSelector.mjs.map +1 -0
  707. package/dist/es/components/Poll/PollVote.mjs +59 -0
  708. package/dist/es/components/Poll/PollVote.mjs.map +1 -0
  709. package/dist/es/components/Poll/hooks/useManagePollVotesRealtime.mjs +36 -0
  710. package/dist/es/components/Poll/hooks/useManagePollVotesRealtime.mjs.map +1 -0
  711. package/dist/es/components/Poll/hooks/usePollAnswerPagination.mjs +44 -0
  712. package/dist/es/components/Poll/hooks/usePollAnswerPagination.mjs.map +1 -0
  713. package/dist/es/components/Poll/hooks/usePollOptionVotesPagination.mjs +44 -0
  714. package/dist/es/components/Poll/hooks/usePollOptionVotesPagination.mjs.map +1 -0
  715. package/dist/es/components/Portal/Portal.mjs +17 -0
  716. package/dist/es/components/Portal/Portal.mjs.map +1 -0
  717. package/dist/es/components/ReactFileUtilities/UploadButton.mjs +54 -0
  718. package/dist/es/components/ReactFileUtilities/UploadButton.mjs.map +1 -0
  719. package/dist/es/{audioProcessing.766ca76c.mjs → components/ReactFileUtilities/utils.mjs} +2 -32
  720. package/dist/es/components/ReactFileUtilities/utils.mjs.map +1 -0
  721. package/dist/es/components/Reactions/MessageReactions.mjs +150 -0
  722. package/dist/es/components/Reactions/MessageReactions.mjs.map +1 -0
  723. package/dist/es/components/Reactions/MessageReactionsDetail.mjs +150 -0
  724. package/dist/es/components/Reactions/MessageReactionsDetail.mjs.map +1 -0
  725. package/dist/es/components/Reactions/ReactionSelector.mjs +140 -0
  726. package/dist/es/components/Reactions/ReactionSelector.mjs.map +1 -0
  727. package/dist/es/components/Reactions/ReactionSelectorWithButton.mjs +51 -0
  728. package/dist/es/components/Reactions/ReactionSelectorWithButton.mjs.map +1 -0
  729. package/dist/es/components/Reactions/SpriteImage.mjs +34 -0
  730. package/dist/es/components/Reactions/SpriteImage.mjs.map +1 -0
  731. package/dist/es/components/Reactions/hooks/useFetchReactions.mjs +61 -0
  732. package/dist/es/components/Reactions/hooks/useFetchReactions.mjs.map +1 -0
  733. package/dist/es/components/Reactions/hooks/useProcessReactions.mjs +82 -0
  734. package/dist/es/components/Reactions/hooks/useProcessReactions.mjs.map +1 -0
  735. package/dist/es/components/Reactions/reactionOptions.mjs +79 -0
  736. package/dist/es/components/Reactions/reactionOptions.mjs.map +1 -0
  737. package/dist/es/components/Reactions/utils/utils.mjs +13 -0
  738. package/dist/es/components/Reactions/utils/utils.mjs.map +1 -0
  739. package/dist/es/components/SafeAnchor/SafeAnchor.mjs +21 -0
  740. package/dist/es/components/SafeAnchor/SafeAnchor.mjs.map +1 -0
  741. package/dist/es/components/Search/Search.mjs +40 -0
  742. package/dist/es/components/Search/Search.mjs.map +1 -0
  743. package/dist/es/components/Search/SearchBar/SearchBar.mjs +113 -0
  744. package/dist/es/components/Search/SearchBar/SearchBar.mjs.map +1 -0
  745. package/dist/es/components/Search/SearchContext.mjs +18 -0
  746. package/dist/es/components/Search/SearchContext.mjs.map +1 -0
  747. package/dist/es/components/Search/SearchResults/SearchResultItem.mjs +113 -0
  748. package/dist/es/components/Search/SearchResults/SearchResultItem.mjs.map +1 -0
  749. package/dist/es/components/Search/SearchResults/SearchResults.mjs +37 -0
  750. package/dist/es/components/Search/SearchResults/SearchResults.mjs.map +1 -0
  751. package/dist/es/components/Search/SearchResults/SearchResultsHeader.mjs +54 -0
  752. package/dist/es/components/Search/SearchResults/SearchResultsHeader.mjs.map +1 -0
  753. package/dist/es/components/Search/SearchResults/SearchResultsPresearch.mjs +15 -0
  754. package/dist/es/components/Search/SearchResults/SearchResultsPresearch.mjs.map +1 -0
  755. package/dist/es/components/Search/SearchResults/SearchSourceResultList.mjs +31 -0
  756. package/dist/es/components/Search/SearchResults/SearchSourceResultList.mjs.map +1 -0
  757. package/dist/es/components/Search/SearchResults/SearchSourceResultListFooter.mjs +31 -0
  758. package/dist/es/components/Search/SearchResults/SearchSourceResultListFooter.mjs.map +1 -0
  759. package/dist/es/components/Search/SearchResults/SearchSourceResults.mjs +30 -0
  760. package/dist/es/components/Search/SearchResults/SearchSourceResults.mjs.map +1 -0
  761. package/dist/es/components/Search/SearchResults/SearchSourceResultsEmpty.mjs +15 -0
  762. package/dist/es/components/Search/SearchResults/SearchSourceResultsEmpty.mjs.map +1 -0
  763. package/dist/es/components/Search/SearchResults/SearchSourceResultsHeader.mjs +6 -0
  764. package/dist/es/components/Search/SearchResults/SearchSourceResultsHeader.mjs.map +1 -0
  765. package/dist/es/components/Search/SearchResults/SearchSourceResultsLoadingIndicator.mjs +18 -0
  766. package/dist/es/components/Search/SearchResults/SearchSourceResultsLoadingIndicator.mjs.map +1 -0
  767. package/dist/es/components/Search/SearchSourceResultsContext.mjs +18 -0
  768. package/dist/es/components/Search/SearchSourceResultsContext.mjs.map +1 -0
  769. package/dist/es/components/Search/hooks/useAnnounceSearchResultCount.mjs +57 -0
  770. package/dist/es/components/Search/hooks/useAnnounceSearchResultCount.mjs.map +1 -0
  771. package/dist/es/components/Search/hooks/useSearchFocusedMessage.mjs +13 -0
  772. package/dist/es/components/Search/hooks/useSearchFocusedMessage.mjs.map +1 -0
  773. package/dist/es/components/Search/hooks/useSearchQueriesInProgress.mjs +24 -0
  774. package/dist/es/components/Search/hooks/useSearchQueriesInProgress.mjs.map +1 -0
  775. package/dist/es/components/Search/hooks/useSearchResultsKeyboardNavigation.mjs +28 -0
  776. package/dist/es/components/Search/hooks/useSearchResultsKeyboardNavigation.mjs.map +1 -0
  777. package/dist/es/components/SkipNavigation/SkipNavigation.mjs +64 -0
  778. package/dist/es/components/SkipNavigation/SkipNavigation.mjs.map +1 -0
  779. package/dist/es/components/SummarizedMessagePreview/SummarizedMessagePreview.mjs +55 -0
  780. package/dist/es/components/SummarizedMessagePreview/SummarizedMessagePreview.mjs.map +1 -0
  781. package/dist/es/components/SummarizedMessagePreview/hooks/useLatestMessagePreview.mjs +116 -0
  782. package/dist/es/components/SummarizedMessagePreview/hooks/useLatestMessagePreview.mjs.map +1 -0
  783. package/dist/es/components/TextareaComposer/SuggestionList/CommandItem.mjs +26 -0
  784. package/dist/es/components/TextareaComposer/SuggestionList/CommandItem.mjs.map +1 -0
  785. package/dist/es/components/TextareaComposer/SuggestionList/EmoticonItem.mjs +26 -0
  786. package/dist/es/components/TextareaComposer/SuggestionList/EmoticonItem.mjs.map +1 -0
  787. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/BroadcastMentionItem.mjs +32 -0
  788. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/BroadcastMentionItem.mjs.map +1 -0
  789. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/MentionItem.mjs +39 -0
  790. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/MentionItem.mjs.map +1 -0
  791. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/MentionSuggestionTitle.mjs +7 -0
  792. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/MentionSuggestionTitle.mjs.map +1 -0
  793. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/RoleItem.mjs +34 -0
  794. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/RoleItem.mjs.map +1 -0
  795. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/SpecialMentionItem.mjs +6 -0
  796. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/SpecialMentionItem.mjs.map +1 -0
  797. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/UserGroupItem.mjs +31 -0
  798. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/UserGroupItem.mjs.map +1 -0
  799. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/UserItem.mjs +50 -0
  800. package/dist/es/components/TextareaComposer/SuggestionList/MentionItem/UserItem.mjs.map +1 -0
  801. package/dist/es/components/TextareaComposer/SuggestionList/SuggestionList.mjs +198 -0
  802. package/dist/es/components/TextareaComposer/SuggestionList/SuggestionList.mjs.map +1 -0
  803. package/dist/es/components/TextareaComposer/SuggestionList/SuggestionListItem.mjs +46 -0
  804. package/dist/es/components/TextareaComposer/SuggestionList/SuggestionListItem.mjs.map +1 -0
  805. package/dist/es/components/TextareaComposer/SuggestionList/TokenizedSuggestionParts.mjs +30 -0
  806. package/dist/es/components/TextareaComposer/SuggestionList/TokenizedSuggestionParts.mjs.map +1 -0
  807. package/dist/es/components/TextareaComposer/TextareaComposer.mjs +288 -0
  808. package/dist/es/components/TextareaComposer/TextareaComposer.mjs.map +1 -0
  809. package/dist/es/components/TextareaComposer/hooks/useTextareaPlaceholder.mjs +30 -0
  810. package/dist/es/components/TextareaComposer/hooks/useTextareaPlaceholder.mjs.map +1 -0
  811. package/dist/es/components/Thread/LegacyThreadContext.mjs +8 -0
  812. package/dist/es/components/Thread/LegacyThreadContext.mjs.map +1 -0
  813. package/dist/es/components/Thread/Thread.mjs +106 -0
  814. package/dist/es/components/Thread/Thread.mjs.map +1 -0
  815. package/dist/es/components/Thread/ThreadHead.mjs +26 -0
  816. package/dist/es/components/Thread/ThreadHead.mjs.map +1 -0
  817. package/dist/es/components/Thread/ThreadHeader.mjs +88 -0
  818. package/dist/es/components/Thread/ThreadHeader.mjs.map +1 -0
  819. package/dist/es/components/Thread/ThreadStart.mjs +24 -0
  820. package/dist/es/components/Thread/ThreadStart.mjs.map +1 -0
  821. package/dist/es/components/Threads/ThreadContext.mjs +17 -0
  822. package/dist/es/components/Threads/ThreadContext.mjs.map +1 -0
  823. package/dist/es/components/Threads/ThreadList/ThreadList.mjs +120 -0
  824. package/dist/es/components/Threads/ThreadList/ThreadList.mjs.map +1 -0
  825. package/dist/es/components/Threads/ThreadList/ThreadListEmptyPlaceholder.mjs +17 -0
  826. package/dist/es/components/Threads/ThreadList/ThreadListEmptyPlaceholder.mjs.map +1 -0
  827. package/dist/es/components/Threads/ThreadList/ThreadListHeader.mjs +22 -0
  828. package/dist/es/components/Threads/ThreadList/ThreadListHeader.mjs.map +1 -0
  829. package/dist/es/components/Threads/ThreadList/ThreadListItem.mjs +18 -0
  830. package/dist/es/components/Threads/ThreadList/ThreadListItem.mjs.map +1 -0
  831. package/dist/es/components/Threads/ThreadList/ThreadListItemUI.mjs +160 -0
  832. package/dist/es/components/Threads/ThreadList/ThreadListItemUI.mjs.map +1 -0
  833. package/dist/es/components/Threads/ThreadList/ThreadListLoadingIndicator.mjs +22 -0
  834. package/dist/es/components/Threads/ThreadList/ThreadListLoadingIndicator.mjs.map +1 -0
  835. package/dist/es/components/Threads/ThreadList/ThreadListUnseenThreadsBanner.mjs +30 -0
  836. package/dist/es/components/Threads/ThreadList/ThreadListUnseenThreadsBanner.mjs.map +1 -0
  837. package/dist/es/components/Threads/ThreadList/utils.a11y.mjs +86 -0
  838. package/dist/es/components/Threads/ThreadList/utils.a11y.mjs.map +1 -0
  839. package/dist/es/components/Threads/UnreadCountBadge.mjs +16 -0
  840. package/dist/es/components/Threads/UnreadCountBadge.mjs.map +1 -0
  841. package/dist/es/components/Tooltip/Tooltip.mjs +39 -0
  842. package/dist/es/components/Tooltip/Tooltip.mjs.map +1 -0
  843. package/dist/es/components/Tooltip/hooks/useEnterLeaveHandlers.mjs +20 -0
  844. package/dist/es/components/Tooltip/hooks/useEnterLeaveHandlers.mjs.map +1 -0
  845. package/dist/es/components/TypingIndicator/TypingIndicator.mjs +79 -0
  846. package/dist/es/components/TypingIndicator/TypingIndicator.mjs.map +1 -0
  847. package/dist/es/components/TypingIndicator/TypingIndicatorDots.mjs +33 -0
  848. package/dist/es/components/TypingIndicator/TypingIndicatorDots.mjs.map +1 -0
  849. package/dist/es/components/TypingIndicator/TypingIndicatorHeader.mjs +44 -0
  850. package/dist/es/components/TypingIndicator/TypingIndicatorHeader.mjs.map +1 -0
  851. package/dist/es/components/TypingIndicator/hooks/useDebouncedTypingActive.mjs +53 -0
  852. package/dist/es/components/TypingIndicator/hooks/useDebouncedTypingActive.mjs.map +1 -0
  853. package/dist/es/components/TypingIndicator/utils/getTypingStatusMessage.mjs +15 -0
  854. package/dist/es/components/TypingIndicator/utils/getTypingStatusMessage.mjs.map +1 -0
  855. package/dist/es/components/UtilityComponents/ErrorBoundary.mjs +22 -0
  856. package/dist/es/components/UtilityComponents/ErrorBoundary.mjs.map +1 -0
  857. package/dist/es/components/UtilityComponents/NullComponent.mjs +6 -0
  858. package/dist/es/components/UtilityComponents/NullComponent.mjs.map +1 -0
  859. package/dist/es/components/UtilityComponents/hooks/useMutationObserver.mjs +45 -0
  860. package/dist/es/components/UtilityComponents/hooks/useMutationObserver.mjs.map +1 -0
  861. package/dist/es/components/UtilityComponents/useStableId.mjs +20 -0
  862. package/dist/es/components/UtilityComponents/useStableId.mjs.map +1 -0
  863. package/dist/es/{ReactPlayerWrapper.d2ae5941.mjs → components/VideoPlayer/ReactPlayerWrapper.mjs} +3 -3
  864. package/dist/es/components/VideoPlayer/ReactPlayerWrapper.mjs.map +1 -0
  865. package/dist/es/components/VideoPlayer/VideoPlayer.mjs +30 -0
  866. package/dist/es/components/VideoPlayer/VideoPlayer.mjs.map +1 -0
  867. package/dist/es/components/VideoPlayer/VideoThumbnail.mjs +35 -0
  868. package/dist/es/components/VideoPlayer/VideoThumbnail.mjs.map +1 -0
  869. package/dist/es/components/VisuallyHidden/VisuallyHidden.mjs +29 -0
  870. package/dist/es/components/VisuallyHidden/VisuallyHidden.mjs.map +1 -0
  871. package/dist/es/components/Window/Window.mjs +21 -0
  872. package/dist/es/components/Window/Window.mjs.map +1 -0
  873. package/dist/es/constants/messageTypes.mjs +9 -0
  874. package/dist/es/constants/messageTypes.mjs.map +1 -0
  875. package/dist/es/context/AttachmentSelectorContext.mjs +13 -0
  876. package/dist/es/context/AttachmentSelectorContext.mjs.map +1 -0
  877. package/dist/es/context/ChannelActionContext.mjs +20 -0
  878. package/dist/es/context/ChannelActionContext.mjs.map +1 -0
  879. package/dist/es/context/ChannelListContext.mjs +20 -0
  880. package/dist/es/context/ChannelListContext.mjs.map +1 -0
  881. package/dist/es/context/ChannelStateContext.mjs +24 -0
  882. package/dist/es/context/ChannelStateContext.mjs.map +1 -0
  883. package/dist/es/context/ChatContext.mjs +20 -0
  884. package/dist/es/context/ChatContext.mjs.map +1 -0
  885. package/dist/es/context/ComponentContext.mjs +13 -0
  886. package/dist/es/context/ComponentContext.mjs.map +1 -0
  887. package/dist/es/context/DialogManagerContext.mjs +119 -0
  888. package/dist/es/context/DialogManagerContext.mjs.map +1 -0
  889. package/dist/es/context/MessageBounceContext.mjs +53 -0
  890. package/dist/es/context/MessageBounceContext.mjs.map +1 -0
  891. package/dist/es/context/MessageComposerContext.mjs +17 -0
  892. package/dist/es/context/MessageComposerContext.mjs.map +1 -0
  893. package/dist/es/context/MessageContext.mjs +17 -0
  894. package/dist/es/context/MessageContext.mjs.map +1 -0
  895. package/dist/es/context/MessageListContext.mjs +23 -0
  896. package/dist/es/context/MessageListContext.mjs.map +1 -0
  897. package/dist/es/context/MessageTranslationViewContext.mjs +76 -0
  898. package/dist/es/context/MessageTranslationViewContext.mjs.map +1 -0
  899. package/dist/es/context/ModalContext.mjs +20 -0
  900. package/dist/es/context/ModalContext.mjs.map +1 -0
  901. package/dist/es/context/PollContext.mjs +15 -0
  902. package/dist/es/context/PollContext.mjs.map +1 -0
  903. package/dist/es/context/TranslationContext.mjs +30 -0
  904. package/dist/es/context/TranslationContext.mjs.map +1 -0
  905. package/dist/es/context/TypingContext.mjs +20 -0
  906. package/dist/es/context/TypingContext.mjs.map +1 -0
  907. package/dist/es/context/VirtualizedMessageListContext.mjs +16 -0
  908. package/dist/es/context/VirtualizedMessageListContext.mjs.map +1 -0
  909. package/dist/es/context/WithComponents.mjs +23 -0
  910. package/dist/es/context/WithComponents.mjs.map +1 -0
  911. package/dist/es/context/useComponentContextIcons.mjs +31 -0
  912. package/dist/es/context/useComponentContextIcons.mjs.map +1 -0
  913. package/dist/es/emojis.mjs +2 -229
  914. package/dist/es/i18n/Streami18n.mjs +545 -0
  915. package/dist/es/i18n/Streami18n.mjs.map +1 -0
  916. package/dist/es/i18n/TranslationBuilder/TranslationBuilder.mjs +86 -0
  917. package/dist/es/i18n/TranslationBuilder/TranslationBuilder.mjs.map +1 -0
  918. package/dist/es/i18n/TranslationBuilder/notifications/NotificationTranslationTopic.mjs +51 -0
  919. package/dist/es/i18n/TranslationBuilder/notifications/NotificationTranslationTopic.mjs.map +1 -0
  920. package/dist/es/i18n/TranslationBuilder/notifications/translators.mjs +47 -0
  921. package/dist/es/i18n/TranslationBuilder/notifications/translators.mjs.map +1 -0
  922. package/dist/es/i18n/TranslationBuilder/notifications/translatorsByNotificationType.mjs +24 -0
  923. package/dist/es/i18n/TranslationBuilder/notifications/translatorsByNotificationType.mjs.map +1 -0
  924. package/dist/es/i18n/de.mjs +782 -0
  925. package/dist/es/i18n/de.mjs.map +1 -0
  926. package/dist/es/i18n/en.mjs +779 -0
  927. package/dist/es/i18n/en.mjs.map +1 -0
  928. package/dist/es/i18n/es.mjs +821 -0
  929. package/dist/es/i18n/es.mjs.map +1 -0
  930. package/dist/es/i18n/fr.mjs +822 -0
  931. package/dist/es/i18n/fr.mjs.map +1 -0
  932. package/dist/es/i18n/hi.mjs +786 -0
  933. package/dist/es/i18n/hi.mjs.map +1 -0
  934. package/dist/es/i18n/it.mjs +821 -0
  935. package/dist/es/i18n/it.mjs.map +1 -0
  936. package/dist/es/i18n/ja.mjs +760 -0
  937. package/dist/es/i18n/ja.mjs.map +1 -0
  938. package/dist/es/i18n/ko.mjs +760 -0
  939. package/dist/es/i18n/ko.mjs.map +1 -0
  940. package/dist/es/i18n/nl.mjs +786 -0
  941. package/dist/es/i18n/nl.mjs.map +1 -0
  942. package/dist/es/i18n/pt.mjs +819 -0
  943. package/dist/es/i18n/pt.mjs.map +1 -0
  944. package/dist/es/i18n/ru.mjs +868 -0
  945. package/dist/es/i18n/ru.mjs.map +1 -0
  946. package/dist/es/i18n/tr.mjs +781 -0
  947. package/dist/es/i18n/tr.mjs.map +1 -0
  948. package/dist/es/i18n/utils.mjs +132 -0
  949. package/dist/es/i18n/utils.mjs.map +1 -0
  950. package/dist/es/index.mjs +323 -20870
  951. package/dist/es/mp3-encoder.mjs +1 -1
  952. package/dist/es/plugins/ChannelDetail/AvatarWithChannelDetail.mjs +40 -0
  953. package/dist/es/plugins/ChannelDetail/AvatarWithChannelDetail.mjs.map +1 -0
  954. package/dist/es/plugins/ChannelDetail/ChannelDetail.mjs +105 -0
  955. package/dist/es/plugins/ChannelDetail/ChannelDetail.mjs.map +1 -0
  956. package/dist/es/plugins/ChannelDetail/ChannelDetailContext.mjs +20 -0
  957. package/dist/es/plugins/ChannelDetail/ChannelDetailContext.mjs.map +1 -0
  958. package/dist/es/plugins/ChannelDetail/ChannelDetailEmptyList.mjs +14 -0
  959. package/dist/es/plugins/ChannelDetail/ChannelDetailEmptyList.mjs.map +1 -0
  960. package/dist/es/plugins/ChannelDetail/ChannelDetailListLoadingIndicator.mjs +20 -0
  961. package/dist/es/plugins/ChannelDetail/ChannelDetailListLoadingIndicator.mjs.map +1 -0
  962. package/dist/es/plugins/ChannelDetail/ChannelDetailNavButton.mjs +26 -0
  963. package/dist/es/plugins/ChannelDetail/ChannelDetailNavButton.mjs.map +1 -0
  964. package/dist/es/plugins/ChannelDetail/ChannelDetailSearchInput.mjs +35 -0
  965. package/dist/es/plugins/ChannelDetail/ChannelDetailSearchInput.mjs.map +1 -0
  966. package/dist/es/plugins/ChannelDetail/SectionNavigator/SectionNavigator.mjs +164 -0
  967. package/dist/es/plugins/ChannelDetail/SectionNavigator/SectionNavigator.mjs.map +1 -0
  968. package/dist/es/plugins/ChannelDetail/SectionNavigator/SectionNavigatorHeader.mjs +50 -0
  969. package/dist/es/plugins/ChannelDetail/SectionNavigator/SectionNavigatorHeader.mjs.map +1 -0
  970. package/dist/es/plugins/ChannelDetail/Views/ChannelFilesView/ChannelFilesEmptyList.mjs +25 -0
  971. package/dist/es/plugins/ChannelDetail/Views/ChannelFilesView/ChannelFilesEmptyList.mjs.map +1 -0
  972. package/dist/es/plugins/ChannelDetail/Views/ChannelFilesView/ChannelFilesView.mjs +130 -0
  973. package/dist/es/plugins/ChannelDetail/Views/ChannelFilesView/ChannelFilesView.mjs.map +1 -0
  974. package/dist/es/plugins/ChannelDetail/Views/ChannelFilesView/ChannelFilesView.utils.mjs +63 -0
  975. package/dist/es/plugins/ChannelDetail/Views/ChannelFilesView/ChannelFilesView.utils.mjs.map +1 -0
  976. package/dist/es/plugins/ChannelDetail/Views/ChannelFilesView/useChannelFilesSearch.mjs +47 -0
  977. package/dist/es/plugins/ChannelDetail/Views/ChannelFilesView/useChannelFilesSearch.mjs.map +1 -0
  978. package/dist/es/plugins/ChannelDetail/Views/ChannelManagementView/ChannelManagementActions.defaults.mjs +568 -0
  979. package/dist/es/plugins/ChannelDetail/Views/ChannelManagementView/ChannelManagementActions.defaults.mjs.map +1 -0
  980. package/dist/es/plugins/ChannelDetail/Views/ChannelManagementView/ChannelManagementView.mjs +324 -0
  981. package/dist/es/plugins/ChannelDetail/Views/ChannelManagementView/ChannelManagementView.mjs.map +1 -0
  982. package/dist/es/plugins/ChannelDetail/Views/ChannelMediaView/ChannelMediaEmptyList.mjs +25 -0
  983. package/dist/es/plugins/ChannelDetail/Views/ChannelMediaView/ChannelMediaEmptyList.mjs.map +1 -0
  984. package/dist/es/plugins/ChannelDetail/Views/ChannelMediaView/ChannelMediaView.mjs +215 -0
  985. package/dist/es/plugins/ChannelDetail/Views/ChannelMediaView/ChannelMediaView.mjs.map +1 -0
  986. package/dist/es/plugins/ChannelDetail/Views/ChannelMediaView/ChannelMediaView.utils.mjs +37 -0
  987. package/dist/es/plugins/ChannelDetail/Views/ChannelMediaView/ChannelMediaView.utils.mjs.map +1 -0
  988. package/dist/es/plugins/ChannelDetail/Views/ChannelMediaView/useChannelMediaSearch.mjs +47 -0
  989. package/dist/es/plugins/ChannelDetail/Views/ChannelMediaView/useChannelMediaSearch.mjs.map +1 -0
  990. package/dist/es/plugins/ChannelDetail/Views/ChannelMemberDetailView/ChannelMemberActions.defaults.mjs +451 -0
  991. package/dist/es/plugins/ChannelDetail/Views/ChannelMemberDetailView/ChannelMemberActions.defaults.mjs.map +1 -0
  992. package/dist/es/plugins/ChannelDetail/Views/ChannelMemberDetailView/ChannelMemberDetail.mjs +76 -0
  993. package/dist/es/plugins/ChannelDetail/Views/ChannelMemberDetailView/ChannelMemberDetail.mjs.map +1 -0
  994. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersAddView.mjs +182 -0
  995. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersAddView.mjs.map +1 -0
  996. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersBrowseView.mjs +110 -0
  997. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersBrowseView.mjs.map +1 -0
  998. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersHeaderActions.defaults.mjs +120 -0
  999. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersHeaderActions.defaults.mjs.map +1 -0
  1000. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersView.mjs +91 -0
  1001. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersView.mjs.map +1 -0
  1002. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersView.utils.mjs +11 -0
  1003. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/ChannelMembersView.utils.mjs.map +1 -0
  1004. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/useChannelMemberCount.mjs +22 -0
  1005. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/useChannelMemberCount.mjs.map +1 -0
  1006. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/useChannelMemberIds.mjs +23 -0
  1007. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/useChannelMemberIds.mjs.map +1 -0
  1008. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/useChannelMembersSearch.mjs +52 -0
  1009. package/dist/es/plugins/ChannelDetail/Views/ChannelMembersView/useChannelMembersSearch.mjs.map +1 -0
  1010. package/dist/es/plugins/ChannelDetail/Views/PinnedMessagesView/PinnedMessagesEmptyList.mjs +25 -0
  1011. package/dist/es/plugins/ChannelDetail/Views/PinnedMessagesView/PinnedMessagesEmptyList.mjs.map +1 -0
  1012. package/dist/es/plugins/ChannelDetail/Views/PinnedMessagesView/PinnedMessagesView.mjs +140 -0
  1013. package/dist/es/plugins/ChannelDetail/Views/PinnedMessagesView/PinnedMessagesView.mjs.map +1 -0
  1014. package/dist/es/plugins/ChannelDetail/Views/PinnedMessagesView/usePinnedMessagesCount.mjs +24 -0
  1015. package/dist/es/plugins/ChannelDetail/Views/PinnedMessagesView/usePinnedMessagesCount.mjs.map +1 -0
  1016. package/dist/es/plugins/ChannelDetail/Views/PinnedMessagesView/usePinnedMessagesSearch.mjs +68 -0
  1017. package/dist/es/plugins/ChannelDetail/Views/PinnedMessagesView/usePinnedMessagesSearch.mjs.map +1 -0
  1018. package/dist/es/plugins/ChannelDetail/VirtualizedList/VirtualizedList.mjs +42 -0
  1019. package/dist/es/plugins/ChannelDetail/VirtualizedList/VirtualizedList.mjs.map +1 -0
  1020. package/dist/es/plugins/Emojis/EmojiPicker.mjs +95 -0
  1021. package/dist/es/plugins/Emojis/EmojiPicker.mjs.map +1 -0
  1022. package/dist/es/plugins/Emojis/Picker.mjs +23 -0
  1023. package/dist/es/plugins/Emojis/Picker.mjs.map +1 -0
  1024. package/dist/es/plugins/Emojis/middleware/textComposerEmojiMiddleware.mjs +126 -0
  1025. package/dist/es/plugins/Emojis/middleware/textComposerEmojiMiddleware.mjs.map +1 -0
  1026. package/dist/es/store/hooks/useStateStore.mjs +32 -0
  1027. package/dist/es/store/hooks/useStateStore.mjs.map +1 -0
  1028. package/dist/es/utils/findReverse.mjs +8 -0
  1029. package/dist/es/utils/findReverse.mjs.map +1 -0
  1030. package/dist/es/utils/getChannel.mjs +38 -0
  1031. package/dist/es/utils/getChannel.mjs.map +1 -0
  1032. package/dist/es/utils/getChannelConfig.mjs +11 -0
  1033. package/dist/es/utils/getChannelConfig.mjs.map +1 -0
  1034. package/dist/es/utils/getTextareaCaretRect.mjs +45 -0
  1035. package/dist/es/utils/getTextareaCaretRect.mjs.map +1 -0
  1036. package/dist/es/utils/getWholeChar.mjs +20 -0
  1037. package/dist/es/utils/getWholeChar.mjs.map +1 -0
  1038. package/dist/es/utils/isDmChannel.mjs +9 -0
  1039. package/dist/es/utils/isDmChannel.mjs.map +1 -0
  1040. package/dist/es/utils/mergeDeep.mjs +8 -0
  1041. package/dist/es/utils/mergeDeep.mjs.map +1 -0
  1042. package/dist/es/utils/useStableCallback.mjs +34 -0
  1043. package/dist/es/utils/useStableCallback.mjs.map +1 -0
  1044. package/dist/types/components/Attachment/AttachmentContainer.d.ts.map +1 -1
  1045. package/dist/types/components/Attachment/Audio.d.ts.map +1 -1
  1046. package/dist/types/components/Attachment/FileAttachment.d.ts.map +1 -1
  1047. package/dist/types/components/Attachment/VideoAttachment.d.ts.map +1 -1
  1048. package/dist/types/components/Attachment/VoiceRecording.d.ts.map +1 -1
  1049. package/dist/types/components/Attachment/components/AttachmentUploadProgressIndicator.d.ts +32 -0
  1050. package/dist/types/components/Attachment/components/AttachmentUploadProgressIndicator.d.ts.map +1 -0
  1051. package/dist/types/components/Attachment/components/index.d.ts +1 -0
  1052. package/dist/types/components/Attachment/components/index.d.ts.map +1 -1
  1053. package/dist/types/components/Attachment/hooks/useAttachmentUploadState.d.ts +89 -0
  1054. package/dist/types/components/Attachment/hooks/useAttachmentUploadState.d.ts.map +1 -0
  1055. package/dist/types/components/Attachment/hooks/useLocalVideoDimensions.d.ts +16 -0
  1056. package/dist/types/components/Attachment/hooks/useLocalVideoDimensions.d.ts.map +1 -0
  1057. package/dist/types/components/Attachment/index.d.ts +1 -0
  1058. package/dist/types/components/Attachment/index.d.ts.map +1 -1
  1059. package/dist/types/components/Channel/Channel.d.ts.map +1 -1
  1060. package/dist/types/components/Channel/utils.d.ts +25 -3
  1061. package/dist/types/components/Channel/utils.d.ts.map +1 -1
  1062. package/dist/types/components/Dialog/service/DialogAnchor.d.ts +8 -1
  1063. package/dist/types/components/Dialog/service/DialogAnchor.d.ts.map +1 -1
  1064. package/dist/types/components/Loading/AttachmentUploadedSizeIndicator.d.ts +20 -0
  1065. package/dist/types/components/Loading/AttachmentUploadedSizeIndicator.d.ts.map +1 -0
  1066. package/dist/types/components/Loading/UploadProgressIndicator.d.ts +7 -1
  1067. package/dist/types/components/Loading/UploadProgressIndicator.d.ts.map +1 -1
  1068. package/dist/types/components/Loading/index.d.ts +1 -0
  1069. package/dist/types/components/Loading/index.d.ts.map +1 -1
  1070. package/dist/types/components/Message/MessageStatus.d.ts.map +1 -1
  1071. package/dist/types/components/MessageComposer/AttachmentPreviewList/AudioAttachmentPreview.d.ts.map +1 -1
  1072. package/dist/types/components/MessageComposer/AttachmentPreviewList/FileAttachmentPreview.d.ts.map +1 -1
  1073. package/dist/types/components/MessageComposer/AttachmentPreviewList/MediaAttachmentPreview.d.ts.map +1 -1
  1074. package/dist/types/components/MessageComposer/RemoveAttachmentPreviewButton.d.ts.map +1 -1
  1075. package/dist/types/components/MessageComposer/hooks/useMessageComposerHasSendableData.d.ts.map +1 -1
  1076. package/dist/types/components/MessageComposer/hooks/useSubmitHandler.d.ts.map +1 -1
  1077. package/dist/types/components/MessageComposer/hooks/utils.d.ts.map +1 -1
  1078. package/dist/types/components/TextareaComposer/TextareaComposer.d.ts.map +1 -1
  1079. package/dist/types/components/VideoPlayer/ReactPlayerWrapper.d.ts +1 -1
  1080. package/dist/types/components/VideoPlayer/ReactPlayerWrapper.d.ts.map +1 -1
  1081. package/dist/types/components/VideoPlayer/VideoPlayer.d.ts +7 -1
  1082. package/dist/types/components/VideoPlayer/VideoPlayer.d.ts.map +1 -1
  1083. package/dist/types/context/ComponentContext.d.ts +3 -0
  1084. package/dist/types/context/ComponentContext.d.ts.map +1 -1
  1085. package/dist/types/i18n/Streami18n.d.ts +1 -0
  1086. package/dist/types/i18n/Streami18n.d.ts.map +1 -1
  1087. package/package.json +5 -9
  1088. package/dist/cjs/NotificationList.6abbee1c.js.map +0 -1
  1089. package/dist/cjs/useInertWhenHidden.22151beb.js.map +0 -1
  1090. package/dist/es/NotificationList.db01a56d.mjs +0 -7703
  1091. package/dist/es/NotificationList.db01a56d.mjs.map +0 -1
  1092. package/dist/es/ReactPlayerWrapper.d2ae5941.mjs.map +0 -1
  1093. package/dist/es/audioProcessing.766ca76c.mjs.map +0 -1
  1094. package/dist/es/channel-detail.mjs.map +0 -1
  1095. package/dist/es/emojis.mjs.map +0 -1
  1096. package/dist/es/index.mjs.map +0 -1
  1097. package/dist/es/useChannelHeaderOnlineStatus.a9357343.mjs +0 -771
  1098. package/dist/es/useChannelHeaderOnlineStatus.a9357343.mjs.map +0 -1
  1099. package/dist/es/useInertWhenHidden.3d5fbdba.mjs +0 -5765
  1100. package/dist/es/useInertWhenHidden.3d5fbdba.mjs.map +0 -1
  1101. package/dist/types/components/MessageComposer/AttachmentPreviewList/AttachmentUploadedSizeIndicator.d.ts +0 -14
  1102. package/dist/types/components/MessageComposer/AttachmentPreviewList/AttachmentUploadedSizeIndicator.d.ts.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/context/MessageBounceContext.tsx","../../src/context/MessageListContext.tsx","../../src/context/PollContext.tsx","../../src/context/VirtualizedMessageListContext.tsx","../../src/context/WithComponents.tsx","../../src/components/AIStateIndicator/AIStateIndicator.tsx","../../src/components/Accessibility/AriaLiveAnnouncerProvider.tsx","../../src/components/Accessibility/scheduling/useAnnouncementQueue.ts","../../src/i18n/de.json","../../src/i18n/en.json","../../src/i18n/es.json","../../src/i18n/fr.json","../../src/i18n/hi.json","../../src/i18n/it.json","../../src/i18n/ja.json","../../src/i18n/ko.json","../../src/i18n/nl.json","../../src/i18n/pt.json","../../src/i18n/ru.json","../../src/i18n/tr.json","../../src/i18n/TranslationBuilder/TranslationBuilder.ts","../../src/i18n/TranslationBuilder/notifications/translators.ts","../../src/i18n/TranslationBuilder/notifications/translatorsByNotificationType.ts","../../src/i18n/TranslationBuilder/notifications/NotificationTranslationTopic.ts","../../src/i18n/Streami18n.ts","../../src/components/Loading/LoadingChannels.tsx","../../src/components/Message/hooks/useActionHandler.ts","../../src/components/Message/hooks/useDeleteHandler.ts","../../src/components/Message/hooks/useFlagHandler.ts","../../src/components/Message/hooks/useMentionsHandler.ts","../../src/components/Message/hooks/useMarkUnreadHandler.ts","../../src/components/Message/hooks/useMuteHandler.ts","../../src/components/Message/hooks/useOpenThreadHandler.ts","../../src/components/Message/hooks/usePinHandler.ts","../../src/components/Reactions/reactionOptions.tsx","../../src/components/Message/hooks/useReactionHandler.ts","../../src/components/Message/hooks/useRetryHandler.ts","../../src/components/Message/hooks/useUserHandler.ts","../../src/components/Message/hooks/useUserRole.ts","../../src/components/Message/hooks/useReactionsFetcher.ts","../../src/components/Message/hooks/useMessageTextStreaming.ts","../../src/components/Message/hooks/useMessageReminder.ts","../../src/components/Avatar/AvatarStack.tsx","../../src/components/Dialog/components/Viewer.tsx","../../src/components/MessageBounce/MessageBounceModal.tsx","../../src/components/MessageBounce/MessageBouncePrompt.tsx","../../src/components/Message/MessageBubble.tsx","../../src/components/Message/MessageDeletedBubble.tsx","../../src/components/Message/MessageBlocked.tsx","../../src/components/MessageActions/hooks/useBaseMessageActionSetFilter.ts","../../src/components/Message/MessageAlsoSentInChannelIndicator.tsx","../../src/components/Message/MessageRepliesCountButton.tsx","../../src/components/Message/PinIndicator.tsx","../../src/components/Message/MessageStatus.tsx","../../src/components/Message/renderText/rehypePlugins/emojiMarkdownPlugin.ts","../../src/components/Message/renderText/remarkPlugins/keepLineBreaksPlugin.ts","../../src/components/Message/renderText/remarkPlugins/remarkIgnoreMarkdown.ts","../../src/components/Message/renderText/componentRenderers/Anchor.tsx","../../src/components/Message/renderText/componentRenderers/Emoji.tsx","../../src/components/Message/renderText/componentRenderers/Mention.tsx","../../src/components/UtilityComponents/NullComponent.tsx","../../src/components/UtilityComponents/ErrorBoundary.tsx","../../src/components/Message/renderText/renderText.tsx","../../src/components/Message/MessageText.tsx","../../src/components/Message/MessageEditedIndicator.tsx","../../src/components/Message/MessageTranslationIndicator.tsx","../../src/components/AudioPlayback/components/ProgressBar.tsx","../../src/components/Attachment/Audio.tsx","../../src/components/Attachment/giphyAccessibility.ts","../../src/components/Attachment/AttachmentActions.tsx","../../src/components/Attachment/VoiceRecording.tsx","../../src/components/Attachment/ModalGallery.tsx","../../src/components/Attachment/Image.tsx","../../src/components/SafeAnchor/SafeAnchor.tsx","../../src/components/Attachment/LinkPreview/UnableToRenderCard.tsx","../../src/components/Attachment/LinkPreview/Card.tsx","../../src/components/Attachment/FileAttachment.tsx","../../src/components/Attachment/Giphy.tsx","../../src/components/Attachment/icons.tsx","../../src/components/Attachment/Geolocation.tsx","../../src/components/Attachment/UnsupportedAttachment.tsx","../../src/components/Attachment/VisibilityDisclaimer.tsx","../../src/components/Attachment/VideoAttachment.tsx","../../src/components/Attachment/AttachmentContainer.tsx","../../src/components/Attachment/Attachment.tsx","../../src/components/Location/hooks/useLiveLocationSharingManager.ts","../../src/components/Message/QuotedMessage.tsx","../../src/components/Message/ReminderNotification.tsx","../../src/components/Message/StreamedMessageText.tsx","../../src/components/Poll/PollHeader.tsx","../../src/components/Form/FieldError.tsx","../../src/components/Form/hooks/useFormState.ts","../../src/components/Poll/PollActions/AddCommentPrompt.tsx","../../src/components/Poll/PollActions/EndPollAlert.tsx","../../src/components/Poll/PollActions/PollAction.tsx","../../src/components/Poll/PollActions/SuggestPollOptionPrompt.tsx","../../src/components/Poll/PollVote.tsx","../../src/components/Poll/hooks/useManagePollVotesRealtime.ts","../../src/components/InfiniteScrollPaginator/hooks/useCursorPaginator.ts","../../src/components/Poll/hooks/usePollAnswerPagination.ts","../../src/components/Poll/hooks/usePollOptionVotesPagination.ts","../../src/components/Poll/PollActions/PollAnswerList.tsx","../../src/components/Poll/PollActions/PollResults/PollOptionWithVotesHeader.tsx","../../src/components/Poll/PollActions/PollResults/PollOptionWithVotes.tsx","../../src/components/Poll/PollActions/PollQuestion.tsx","../../src/components/Poll/PollActions/PollResults/PollOptionWithVotesList.tsx","../../src/components/Poll/PollActions/PollResults/PollResults.tsx","../../src/components/Poll/PollActions/PollActions.tsx","../../src/components/Poll/PollOptionSelector.tsx","../../src/components/Poll/PollOptionList.tsx","../../src/components/Poll/PollActions/PollOptionsFullList.tsx","../../src/components/Poll/PollContent.tsx","../../src/components/Poll/Poll.tsx","../../src/components/TypingIndicator/TypingIndicatorDots.tsx","../../src/components/TypingIndicator/hooks/useDebouncedTypingActive.ts","../../src/components/TypingIndicator/utils/getTypingStatusMessage.ts","../../src/components/TypingIndicator/TypingIndicatorHeader.tsx","../../src/components/Thread/ThreadHeader.tsx","../../src/components/Thread/ThreadStart.tsx","../../src/components/DateSeparator/DateSeparator.tsx","../../src/components/Thread/ThreadHead.tsx","../../src/components/Thread/Thread.tsx","../../src/components/Reactions/ReactionSelector.tsx","../../src/components/Reactions/hooks/useFetchReactions.ts","../../src/components/Reactions/MessageReactionsDetail.tsx","../../src/components/Reactions/hooks/useProcessReactions.tsx","../../src/components/Reactions/MessageReactions.tsx","../../src/components/Reactions/utils/utils.ts","../../src/components/Reactions/SpriteImage.tsx","../../src/components/Reactions/ReactionSelectorWithButton.tsx","../../src/components/MessageActions/RemindMeSubmenu.tsx","../../src/components/MessageActions/downloadUtils.ts","../../src/components/MessageActions/DownloadSubmenu.tsx","../../src/components/MessageActions/QuickMessageActionButton.tsx","../../src/components/MessageActions/DeleteMessageAlert.tsx","../../src/components/MessageActions/MessageActions.defaults.tsx","../../src/components/Chat/hooks/useSplitActionSet.ts","../../src/components/MessageActions/MessageActions.tsx","../../src/components/Message/MessageUI.tsx","../../src/components/Message/Message.tsx","../../src/components/MessageList/GiphyPreviewMessage.tsx","../../src/components/MessageList/hooks/MessageList/useEnrichedMessages.ts","../../src/components/MessageList/hooks/MessageList/useFloatingDateSeparatorMessageList.ts","../../src/components/MessageList/hooks/useLastReadData.ts","../../src/components/MessageList/hooks/useLastDeliveredData.ts","../../src/components/MessageList/hooks/MessageList/useMessageListElements.tsx","../../src/components/MessageList/hooks/MessageList/useMessageListScrollManager.ts","../../src/components/MessageList/hooks/MessageList/useScrollLocationLogic.tsx","../../src/components/MessageList/MessageListMainPanel.tsx","../../src/components/MessageList/UnreadMessagesSeparator.tsx","../../src/components/MessageList/hooks/MessageList/useUnreadMessagesNotification.ts","../../src/components/MessageList/hooks/useMarkRead.ts","../../src/components/MessageList/NewMessageNotification.tsx","../../src/components/MessageList/UnreadMessagesNotification.tsx","../../src/components/InfiniteScrollPaginator/InfiniteScroll.tsx","../../src/components/TypingIndicator/TypingIndicator.tsx","../../src/components/MessageList/hooks/VirtualizedMessageList/useFloatingDateSeparator.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useGiphyPreview.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useMessageSetKey.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useNewMessageNotification.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/usePrependMessagesCount.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useScrollToBottomOnNewMessage.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useShouldForceScrollToBottom.ts","../../src/components/MessageList/hooks/VirtualizedMessageList/useUnreadMessagesNotificationVirtualized.ts","../../src/components/MessageList/FloatingDateSeparator.tsx","../../src/components/EventComponent/EventComponent.tsx","../../src/components/MessageList/renderMessages.tsx","../../src/utils/findReverse.ts","../../src/components/MessageList/hooks/useLastOwnMessage.ts","../../src/components/MessageList/hooks/useReducedMotionPreference.ts","../../src/components/MessageList/ScrollToLatestMessageButton.tsx","../../src/components/MessageList/MessageList.tsx","../../src/components/MessageList/VirtualizedMessageListComponents.tsx","../../src/components/MessageList/VirtualizedMessageList.tsx","../../src/utils/getWholeChar.ts","../../src/components/UtilityComponents/hooks/useMutationObserver.ts","../../src/components/Search/hooks/useAnnounceSearchResultCount.ts","../../src/components/Search/hooks/useSearchQueriesInProgress.ts","../../src/a11y/hooks/useListboxKeyboardNavigation.ts","../../src/components/Search/hooks/useSearchResultsKeyboardNavigation.ts","../../src/a11y/hooks/useVirtualizedListboxKeyboardNavigation.ts","../../src/components/ChannelList/hooks/useConnectionRecoveredListener.ts","../../src/components/ChannelList/hooks/usePaginatedChannels.ts","../../src/components/ChannelList/utils.ts","../../src/components/ChannelList/hooks/useChannelListShape.ts","../../src/components/ChannelList/hooks/useChannelListKeyboardNavigation.ts","../../src/components/ChannelList/ChannelListUI.tsx","../../src/components/Search/SearchContext.tsx","../../src/components/Search/SearchBar/SearchBar.tsx","../../src/components/Search/SearchResults/SearchResultItem.tsx","../../src/components/Search/SearchSourceResultsContext.tsx","../../src/components/Search/SearchResults/SearchSourceResultsLoadingIndicator.tsx","../../src/components/Search/SearchResults/SearchSourceResultListFooter.tsx","../../src/components/Search/SearchResults/SearchSourceResultList.tsx","../../src/components/Search/SearchResults/SearchSourceResultsEmpty.tsx","../../src/components/Search/SearchResults/SearchSourceResultsHeader.tsx","../../src/components/Search/SearchResults/SearchSourceResults.tsx","../../src/components/Search/SearchResults/SearchResultsHeader.tsx","../../src/components/Search/SearchResults/SearchResultsPresearch.tsx","../../src/components/Search/SearchResults/SearchResults.tsx","../../src/components/Search/Search.tsx","../../src/components/LoadMore/LoadMoreButton.tsx","../../src/components/LoadMore/LoadMorePaginator.tsx","../../src/components/ChannelList/ChannelListHeader.tsx","../../src/components/ChannelList/ChannelList.tsx","../../src/components/ChannelList/hooks/useChannelMembersState.ts","../../src/components/ChannelListItem/ChannelListItemActionButtons.defaults.tsx","../../src/components/ChannelListItem/ChannelListItemActionButtons.tsx","../../src/components/ChannelListItem/ChannelListItemTimestamp.tsx","../../src/a11y/accessibleLabel.ts","../../src/components/ChannelListItem/hooks/useMessageDeliveryStatus.ts","../../src/components/ChannelListItem/utils.a11y.ts","../../src/components/SummarizedMessagePreview/hooks/useLatestMessagePreview.ts","../../src/components/SummarizedMessagePreview/SummarizedMessagePreview.tsx","../../src/components/ChannelListItem/ChannelListItemUI.tsx","../../src/components/ChannelListItem/ChannelListItem.tsx","../../src/components/Threads/ThreadList/utils.a11y.ts","../../src/components/Threads/ThreadList/ThreadListItemUI.tsx","../../src/components/Threads/ThreadList/ThreadListItem.tsx","../../src/components/Threads/ThreadList/ThreadListEmptyPlaceholder.tsx","../../src/components/Threads/ThreadList/ThreadListUnseenThreadsBanner.tsx","../../src/components/Threads/ThreadList/ThreadListLoadingIndicator.tsx","../../src/components/Threads/ThreadList/ThreadListHeader.tsx","../../src/components/Threads/ThreadList/ThreadList.tsx","../../src/components/Notifications/hooks/useSystemNotifications.ts","../../src/components/Accessibility/NotificationAnnouncer.tsx","../../src/components/Accessibility/hooks/useFocusReturn.ts","../../src/components/Accessibility/hooks/useIncomingMessageAnnouncements.ts","../../src/components/ChannelHeader/ChannelHeader.tsx","../../src/components/SkipNavigation/SkipNavigation.tsx","../../src/components/Chat/hooks/useChat.ts","../../src/components/Chat/hooks/useReportLostConnectionSystemNotification.ts","../../src/components/Chat/hooks/useCreateChatContext.ts","../../src/components/Chat/hooks/useChannelsQueryState.ts","../../src/components/Chat/Chat.tsx","../../src/components/Chat/hooks/useCreateChatClient.ts","../../src/components/Window/Window.tsx"],"sourcesContent":["import type { ReactEventHandler } from 'react';\nimport React, { createContext, useCallback, useContext, useMemo } from 'react';\nimport { useMessageContext } from './MessageContext';\nimport { useChannelActionContext } from './ChannelActionContext';\nimport { isMessageBounced, useMessageComposerController } from '../components';\nimport { savePreEditSnapshot } from '../components/MessageComposer/preEditSnapshot';\nimport type { LocalMessage } from 'stream-chat';\nimport type { PropsWithChildrenOnly } from '../types/types';\n\nexport interface MessageBounceContextValue {\n handleDelete: ReactEventHandler;\n handleEdit: ReactEventHandler;\n handleRetry: ReactEventHandler;\n message: LocalMessage;\n}\n\nconst MessageBounceContext = createContext<MessageBounceContextValue | undefined>(\n undefined,\n);\n\nexport function useMessageBounceContext(componentName?: string) {\n const contextValue = useContext(MessageBounceContext);\n\n if (!contextValue) {\n console.warn(\n `The useMessageBounceContext hook was called outside of the MessageBounceContext provider. The errored call is located in the ${componentName} component.`,\n );\n\n return {} as MessageBounceContextValue;\n }\n\n return contextValue;\n}\n\nexport function MessageBounceProvider({ children }: PropsWithChildrenOnly) {\n const messageComposer = useMessageComposerController();\n const { handleRetry: doHandleRetry, message } = useMessageContext(\n 'MessageBounceProvider',\n );\n\n if (!isMessageBounced(message)) {\n console.warn(\n `The MessageBounceProvider was rendered for a message that is not bounced. Have you missed the \"isMessageBounced\" check?`,\n );\n }\n\n const { removeMessage } = useChannelActionContext('MessageBounceProvider');\n\n const handleDelete: ReactEventHandler = useCallback(() => {\n removeMessage(message);\n }, [message, removeMessage]);\n\n const handleEdit: ReactEventHandler = useCallback(\n (e) => {\n e.preventDefault();\n savePreEditSnapshot(messageComposer);\n messageComposer.initState({ composition: message });\n },\n [message, messageComposer],\n );\n\n const handleRetry = useCallback(() => {\n doHandleRetry(message);\n }, [doHandleRetry, message]);\n\n const value = useMemo(\n () => ({\n handleDelete,\n handleEdit,\n handleRetry,\n message,\n }),\n [handleDelete, handleEdit, handleRetry, message],\n );\n\n return (\n <MessageBounceContext.Provider value={value}>\n {children}\n </MessageBounceContext.Provider>\n );\n}\n","import React, { createContext, useContext } from 'react';\nimport type { PropsWithChildren } from 'react';\nimport type { RenderedMessage } from '../components';\n\nexport type MessageListContextValue = {\n /** Enriched message list, including date separators and intro message (if enabled) */\n processedMessages: RenderedMessage[];\n /** The scroll container within which the messages and typing indicator are rendered */\n listElement: HTMLDivElement | null;\n /** Function that scrolls the `listElement` to the bottom. */\n scrollToBottom: () => void;\n};\n\nexport const MessageListContext = createContext<MessageListContextValue | undefined>(\n undefined,\n);\n\n/**\n * Context provider for components rendered within the `MessageList`\n */\nexport const MessageListContextProvider = ({\n children,\n value,\n}: PropsWithChildren<{\n value: MessageListContextValue;\n}>) => (\n <MessageListContext.Provider value={value as MessageListContextValue}>\n {children}\n </MessageListContext.Provider>\n);\n\nexport const useMessageListContext = (componentName?: string) => {\n const contextValue = useContext(MessageListContext);\n\n if (!contextValue) {\n console.warn(\n `The useMessageListContext hook was called outside of the MessageListContext provider. Make sure this hook is called within the MessageList component. The errored call is located in the ${componentName} component.`,\n );\n\n return {} as MessageListContextValue;\n }\n\n return contextValue as MessageListContextValue;\n};\n","import React, { useContext } from 'react';\nimport type { PropsWithChildren } from 'react';\nimport type { Poll } from 'stream-chat';\n\nexport type PollContextValue = {\n poll: Poll;\n};\n\nexport const PollContext = React.createContext<PollContextValue | undefined>(undefined);\n\nexport const PollProvider = ({\n children,\n poll,\n}: PropsWithChildren<{\n poll: Poll;\n}>) =>\n poll ? (\n <PollContext.Provider value={{ poll } as unknown as PollContextValue}>\n {children}\n </PollContext.Provider>\n ) : null;\n\nexport const usePollContext = () => {\n const contextValue = useContext(PollContext);\n return contextValue as unknown as PollContextValue;\n};\n","import React, { createContext, useContext } from 'react';\nimport type { PropsWithChildren } from 'react';\n\nexport type VirtualizedMessageListContextValue = {\n /** Function that scrolls the list to the bottom. */\n scrollToBottom: () => void;\n};\n\nexport const VirtualizedMessageListContext = createContext<\n VirtualizedMessageListContextValue | undefined\n>(undefined);\n\n/**\n * Context provider for components rendered within the `VirtualizedMessageList`\n */\nexport const VirtualizedMessageListContextProvider = ({\n children,\n value,\n}: PropsWithChildren<{\n value: VirtualizedMessageListContextValue;\n}>) => (\n <VirtualizedMessageListContext.Provider\n value={value as VirtualizedMessageListContextValue}\n >\n {children}\n </VirtualizedMessageListContext.Provider>\n);\n\nexport const useVirtualizedMessageListContext = () =>\n useContext(VirtualizedMessageListContext) as VirtualizedMessageListContextValue;\n","import React, { useContext } from 'react';\nimport type { PropsWithChildren } from 'react';\n\nimport { ComponentContext } from './ComponentContext';\nimport type { ComponentContextValue } from './ComponentContext';\n\nexport function WithComponents({\n children,\n overrides,\n}: PropsWithChildren<{ overrides: Partial<ComponentContextValue> }>) {\n const parentOverrides = useContext(ComponentContext);\n const actualOverrides: ComponentContextValue = {\n ...parentOverrides,\n ...overrides,\n icons: {\n ...parentOverrides?.icons,\n ...overrides?.icons,\n },\n };\n\n return (\n <ComponentContext.Provider value={actualOverrides}>\n {children}\n </ComponentContext.Provider>\n );\n}\n","import React from 'react';\nimport type { Channel } from 'stream-chat';\n\nimport { AIStates, useAIState } from './hooks/useAIState';\n\nimport { useChannelStateContext, useTranslationContext } from '../../context';\n\nexport type AIStateIndicatorProps = {\n channel?: Channel;\n};\n\nexport const AIStateIndicator = ({\n channel: channelFromProps,\n}: AIStateIndicatorProps) => {\n const { t } = useTranslationContext();\n const { channel: channelFromContext } = useChannelStateContext('AIStateIndicator');\n const channel = channelFromProps || channelFromContext;\n const { aiState } = useAIState(channel);\n const allowedStates = {\n [AIStates.Thinking]: t('Thinking...'),\n [AIStates.Generating]: t('Generating...'),\n };\n\n return aiState in allowedStates ? (\n <div className='str-chat__ai-state-indicator-container'>\n <p className='str-chat__ai-state-indicator-text'>{allowedStates[aiState]}</p>\n </div>\n ) : null;\n};\n","import type { PropsWithChildren } from 'react';\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n type AnnouncementsByPriority,\n AriaLiveOutletContext,\n} from './AriaLiveOutletContext';\nimport {\n type AriaLiveAnnounce,\n AriaLiveAnnouncerContext,\n type AriaLivePriority,\n} from './useAriaLiveAnnouncer';\n\n// How long an announcement node stays in the DOM before cleanup. This is NOT how long the\n// message is \"valid\" — with `aria-relevant=\"additions\"` a lingering node is never re-announced;\n// the only cost of a longer value is a few extra (visually hidden) nodes transiently. It must be\n// long enough that a polite message queued BEHIND verbose screen-reader speech (e.g. the typing\n// echo + a focused-field re-announcement) is still present when the reader reaches it — a short\n// window (~1.5s) drops those. 7s comfortably covers that.\nconst LIVE_ANNOUNCEMENT_TTL_MS = 7000;\n\ntype RegisteredOutlet = {\n id: symbol;\n layer: number;\n};\n\n/**\n * Owns the aria-live announcement state and the announce() API for one logical announcer\n * (mount ONE per `Chat`). It renders no DOM region itself — the messages are painted by the\n * single active {@link AriaLiveOutlet} chosen from the registered outlet stack (innermost /\n * highest-layer wins). This is the L1 sink of the unified announcer model; see\n * `specs/a11y-react-web/decisions.md` → \"Unify the aria-live announcer implementations\".\n *\n * All state lives here (per provider instance), never in module scope, so multiple `Chat`\n * instances on one page never share announcements.\n */\nexport const AriaLiveAnnouncerProvider = ({ children }: PropsWithChildren) => {\n const [announcementsByPriority, setAnnouncementsByPriority] =\n useState<AnnouncementsByPriority>({\n assertive: [],\n polite: [],\n });\n const nextAnnouncementIdRef = useRef(0);\n const timeoutByAnnouncementIdRef = useRef<Map<number, ReturnType<typeof setTimeout>>>(\n new Map(),\n );\n // Pending `delayMs` timers (announcements scheduled but not yet emitted). Tracked so they can\n // be cleared on provider unmount; each call also returns a `cancel` that clears its own timer.\n const delayTimersRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());\n // Messages emitted within their `dedupeMs` window (message -> expiry timer). Used to suppress\n // an identical repeat (e.g. a StrictMode-double-invoked effect) within the window.\n const dedupeTimersByMessageRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(\n new Map(),\n );\n // The exact text last rendered into a live region. Screen readers (notably VoiceOver)\n // suppress a live-region update whose text is identical to the previous one, so repeated\n // identical announcements (e.g. shuffling a Giphy, whose description is the constant search\n // term) would be voiced only once. We alternate a trailing zero-width space to force a\n // detectable change — see `announce`.\n const lastRenderedMessageRef = useRef('');\n\n const removeAnnouncement = useCallback((priority: AriaLivePriority, id: number) => {\n setAnnouncementsByPriority((currentAnnouncements) => ({\n ...currentAnnouncements,\n [priority]: currentAnnouncements[priority].filter(\n (announcement) => announcement.id !== id,\n ),\n }));\n\n const timeout = timeoutByAnnouncementIdRef.current.get(id);\n if (!timeout) return;\n\n clearTimeout(timeout);\n timeoutByAnnouncementIdRef.current.delete(id);\n }, []);\n\n const emit = useCallback(\n (message: string, priority: AriaLivePriority) => {\n const announcementId = nextAnnouncementIdRef.current++;\n\n // Append a (silent) zero-width space (U+200B) when the text would repeat the previous\n // render, so consecutive identical announcements still differ and are re-voiced. Because\n // it only appends when equal to the last render, the rendered text alternates between\n // `X` and `X` + U+200B, guaranteeing every update is a change the screen reader speaks.\n const ZERO_WIDTH_SPACE = '\\u200B';\n const renderedMessage =\n message === lastRenderedMessageRef.current\n ? `${message}${ZERO_WIDTH_SPACE}`\n : message;\n lastRenderedMessageRef.current = renderedMessage;\n\n setAnnouncementsByPriority((currentAnnouncements) => ({\n ...currentAnnouncements,\n [priority]: [\n ...currentAnnouncements[priority],\n { id: announcementId, message: renderedMessage },\n ],\n }));\n\n const timeout = setTimeout(() => {\n removeAnnouncement(priority, announcementId);\n }, LIVE_ANNOUNCEMENT_TTL_MS);\n\n timeoutByAnnouncementIdRef.current.set(announcementId, timeout);\n },\n [removeAnnouncement],\n );\n\n const announce = useCallback<AriaLiveAnnounce>(\n (message, options) => {\n const { dedupeMs, delayMs, priority = 'polite' } = options ?? {};\n\n // Emit, applying the dedupe window if requested. The check runs at EMIT time (not call\n // time) so a delayed announcement that is cancelled before it fires never marks the message\n // as seen — only an actually-emitted message opens the window.\n const emitMessage = () => {\n if (dedupeMs) {\n const recent = dedupeTimersByMessageRef.current;\n if (recent.has(message)) return; // identical message within the window — suppress\n recent.set(\n message,\n setTimeout(() => recent.delete(message), dedupeMs),\n );\n }\n emit(message, priority);\n };\n\n if (!delayMs) {\n emitMessage();\n return () => undefined;\n }\n\n const delayTimers = delayTimersRef.current;\n const delayTimer = setTimeout(() => {\n delayTimers.delete(delayTimer);\n emitMessage();\n }, delayMs);\n delayTimers.add(delayTimer);\n\n return () => {\n clearTimeout(delayTimer);\n delayTimers.delete(delayTimer);\n };\n },\n [emit],\n );\n\n useEffect(() => {\n const timeoutById = timeoutByAnnouncementIdRef.current;\n const delayTimers = delayTimersRef.current;\n const dedupeTimers = dedupeTimersByMessageRef.current;\n return () => {\n for (const timeout of timeoutById.values()) {\n clearTimeout(timeout);\n }\n timeoutById.clear();\n for (const timeout of delayTimers) {\n clearTimeout(timeout);\n }\n delayTimers.clear();\n for (const timeout of dedupeTimers.values()) {\n clearTimeout(timeout);\n }\n dedupeTimers.clear();\n };\n }, []);\n\n const [outlets, setOutlets] = useState<RegisteredOutlet[]>([]);\n\n const registerOutlet = useCallback((id: symbol, layer: number) => {\n setOutlets((currentOutlets) => [...currentOutlets, { id, layer }]);\n }, []);\n\n const unregisterOutlet = useCallback((id: symbol) => {\n setOutlets((currentOutlets) => currentOutlets.filter((outlet) => outlet.id !== id));\n }, []);\n\n // Innermost wins: the highest layer, and among equal layers the most recently registered.\n const activeOutlet = useMemo(() => {\n let active: RegisteredOutlet | null = null;\n for (const outlet of outlets) {\n if (!active || outlet.layer >= active.layer) {\n active = outlet;\n }\n }\n return active;\n }, [outlets]);\n const activeOutletId = activeOutlet?.id ?? null;\n\n // Drop pending announcements when the active outlet falls back to a LOWER layer because a higher\n // one unmounted (e.g. a modal dialog closed). The shared announcement state otherwise re-renders\n // into the newly active (main) outlet and the screen reader re-announces it — so messages emitted\n // inside a dialog (e.g. option-reorder pickup/move/drop) would be voiced again after the dialog\n // is gone. We only clear on fall-back: when a HIGHER outlet MOUNTS (a dialog opening), the state\n // must survive so an open-time announcement still renders in the now-active dialog outlet.\n const previousActiveLayerRef = useRef(activeOutlet?.layer ?? -1);\n useEffect(() => {\n const currentLayer = activeOutlet?.layer ?? -1;\n const previousLayer = previousActiveLayerRef.current;\n previousActiveLayerRef.current = currentLayer;\n if (currentLayer >= previousLayer) return;\n\n for (const timeout of timeoutByAnnouncementIdRef.current.values()) {\n clearTimeout(timeout);\n }\n timeoutByAnnouncementIdRef.current.clear();\n lastRenderedMessageRef.current = '';\n setAnnouncementsByPriority({ assertive: [], polite: [] });\n }, [activeOutlet]);\n\n const announcerValue = useMemo(() => ({ announce }), [announce]);\n const outletValue = useMemo(\n () => ({\n activeOutletId,\n announcementsByPriority,\n registerOutlet,\n unregisterOutlet,\n }),\n [activeOutletId, announcementsByPriority, registerOutlet, unregisterOutlet],\n );\n\n return (\n <AriaLiveAnnouncerContext.Provider value={announcerValue}>\n <AriaLiveOutletContext.Provider value={outletValue}>\n {children}\n </AriaLiveOutletContext.Provider>\n </AriaLiveAnnouncerContext.Provider>\n );\n};\n","import { useCallback, useEffect, useRef } from 'react';\n\nimport type { AriaLiveAnnounce, AriaLivePriority } from '../useAriaLiveAnnouncer';\n\nexport type QueuedAnnouncement = {\n message: string;\n priority?: AriaLivePriority;\n};\n\nexport type UseAnnouncementQueueOptions = {\n /** Minimum delay between successive announcements, in ms. Defaults to 150. */\n gapMs?: number;\n};\n\nexport type UseAnnouncementQueueResult = {\n /** Enqueue an announcement. The first drains immediately; the rest are paced by `gapMs`. */\n enqueue: (announcement: QueuedAnnouncement) => void;\n};\n\nconst DEFAULT_GAP_MS = 150;\n\n/**\n * L2 scheduling policy: announce queued messages one at a time, spaced by `gapMs`, through the\n * provided `announce` (from `useAriaLiveAnnouncer`). Replaces per-consumer queue/timer\n * bookkeeping (e.g. the old `NotificationAnnouncer` state machine). The unified announcer already\n * appends a fresh node per call, so no \"clear region first\" trick is needed — the gap simply\n * prevents successive messages from clobbering each other in the screen-reader buffer.\n *\n * React 17/18/19 compatible — `useCallback`/`useRef`/`useEffect` only. Pending timers and the\n * queue are cleared on unmount.\n */\nexport const useAnnouncementQueue = (\n announce: AriaLiveAnnounce,\n { gapMs = DEFAULT_GAP_MS }: UseAnnouncementQueueOptions = {},\n): UseAnnouncementQueueResult => {\n const queueRef = useRef<QueuedAnnouncement[]>([]);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Keep the latest `announce` without forcing `enqueue`/`drain` identity to change.\n const announceRef = useRef(announce);\n announceRef.current = announce;\n\n const drain = useCallback(() => {\n if (timerRef.current) return; // already pacing — the running timer will drain the next item\n\n const next = queueRef.current.shift();\n if (!next) return;\n\n announceRef.current(next.message, { priority: next.priority });\n\n timerRef.current = setTimeout(() => {\n timerRef.current = null;\n drain();\n }, gapMs);\n }, [gapMs]);\n\n const enqueue = useCallback(\n (announcement: QueuedAnnouncement) => {\n queueRef.current.push(announcement);\n drain();\n },\n [drain],\n );\n\n useEffect(\n () => () => {\n if (timerRef.current) clearTimeout(timerRef.current);\n timerRef.current = null;\n queueRef.current = [];\n },\n [],\n );\n\n return { enqueue };\n};\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} und {{moreCount}} mehr\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} und {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} Datei\",\n \"{{ count }} files_other\": \"{{ count }} Dateien\",\n \"{{ count }} members_one\": \"{{ count }} Mitglied\",\n \"{{ count }} members_other\": \"{{ count }} Mitglieder\",\n \"{{ count }} members added_one\": \"{{ count }} Mitglied hinzugefügt\",\n \"{{ count }} members added_other\": \"{{ count }} Mitglieder hinzugefügt\",\n \"{{ count }} people are typing_one\": \"{{ count }} Person tippt\",\n \"{{ count }} people are typing_many\": \"{{ count }} Personen tippen\",\n \"{{ count }} people are typing_other\": \"{{ count }} Personen tippen\",\n \"{{ count }} photos_one\": \"{{ count }} Foto\",\n \"{{ count }} photos_other\": \"{{ count }} Fotos\",\n \"{{ count }} reactions_one\": \"{{ count }} Reaktion\",\n \"{{ count }} reactions_other\": \"{{ count }} Reaktionen\",\n \"{{ count }} videos_one\": \"{{ count }} Video\",\n \"{{ count }} videos_other\": \"{{ count }} Videos\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} und {{ secondUser }}\",\n \"{{ imageCount }} more\": \"{{ imageCount }} mehr\",\n \"{{ member }} will be able to message you again.\": \"{{ member }} kann dir wieder Nachrichten senden.\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }} kann dir keine Nachrichten mehr senden.\",\n \"{{ memberCount }} members\": \"{{ memberCount }} Mitglieder\",\n \"{{ typing }} are typing\": \"{{ typing }} tippen\",\n \"{{ typing }} is typing\": \"{{ typing }} tippt\",\n \"{{ user }} has been muted\": \"{{ user }} wurde stummgeschaltet\",\n \"{{ user }} has been unmuted\": \"Die Stummschaltung von {{ user }} wurde aufgehoben\",\n \"{{ user }} is typing...\": \"{{ user }} tippt...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} und {{ user }} tippen...\",\n \"{{ users }} and more are typing...\": \"{{ users }} und mehr tippen...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} online\",\n \"{{count}} new messages_one\": \"{{count}} neue Nachricht\",\n \"{{count}} new messages_other\": \"{{count}} neue Nachrichten\",\n \"{{count}} unread_one\": \"{{count}} ungelesen\",\n \"{{count}} unread_other\": \"{{count}} ungelesen\",\n \"{{count}} votes_one\": \"{{count}} Stimme\",\n \"{{count}} votes_other\": \"{{count}} Stimmen\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"+{{count}} weitere Option\",\n \"+{{count}} more options_other\": \"+{{count}} weitere Optionen\",\n \"🏙 Attachment...\": \"🏙 Anhang...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} hat erstellt: {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} hat abgestimmt: {{pollOptionText}}\",\n \"📍Shared location\": \"📍Geteilter Standort\",\n \"Actions\": \"Actions\",\n \"Add\": \"Hinzufügen\",\n \"Add {{ count }} members_one\": \"{{ count }} Mitglied hinzufügen\",\n \"Add {{ count }} members_other\": \"{{ count }} Mitglieder hinzufügen\",\n \"Add a comment\": \"Einen Kommentar hinzufügen\",\n \"Add a comment to your poll answer\": \"Füge einen Kommentar zu deiner Umfrageantwort hinzu\",\n \"Add an option\": \"Eine Option hinzufügen\",\n \"Add channel members\": \"Kanalmitglieder hinzufügen\",\n \"Add members\": \"Mitglieder hinzufügen\",\n \"Add reaction\": \"Reaktion hinzufügen\",\n \"Admin\": \"Administrator\",\n \"All results loaded\": \"Alle Ergebnisse geladen\",\n \"Allow access to camera\": \"Zugriff auf Kamera erlauben\",\n \"Allow access to microphone\": \"Zugriff auf Mikrofon erlauben\",\n \"Allow comments\": \"Kommentare erlauben\",\n \"Allow option suggestion\": \"Optionsvorschläge erlauben\",\n \"Allow others to add comments\": \"Anderen das Hinzufügen von Kommentaren erlauben\",\n \"Already a member\": \"Bereits Mitglied\",\n \"Also send as a direct message\": \"Auch als Direktnachricht senden\",\n \"Also send in channel\": \"Auch im Kanal senden\",\n \"Also sent in channel\": \"Auch im Kanal gesendet\",\n \"An error has occurred during recording\": \"Ein Fehler ist während der Aufnahme aufgetreten\",\n \"An error has occurred during the recording processing\": \"Ein Fehler ist während der Aufnahmeverarbeitung aufgetreten\",\n \"Anonymous\": \"Anonym\",\n \"Anonymous poll\": \"Anonyme Umfrage\",\n \"Archive\": \"Archivieren\",\n \"Are you sure you want to delete this message?\": \"Sind Sie sicher, dass Sie diese Nachricht löschen möchten?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_one\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_one\": \"{{ count }} Anhang\",\n \"aria/{{ count }} attachment_other\": \"{{ count }} Anhänge\",\n \"aria/{{ count }} search results_one\": \"{{ count }} Suchergebnis\",\n \"aria/{{ count }} search results_other\": \"{{ count }} Suchergebnisse\",\n \"aria/{{ count }} suggestions_one\": \"{{ count }} Vorschlag\",\n \"aria/{{ count }} suggestions_other\": \"{{ count }} Vorschläge\",\n \"aria/{{ count }} unread message_one\": \"{{ count }} ungelesene Nachricht\",\n \"aria/{{ count }} unread message_other\": \"{{ count }} ungelesene Nachrichten\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} deaktiviert\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} aktiviert\",\n \"aria/Active\": \"Aktiv\",\n \"aria/Animated GIF\": \"Animiertes GIF\",\n \"aria/Animated GIF: {{ title }}\": \"Animiertes GIF: {{ title }}\",\n \"aria/Attachment\": \"Anhang\",\n \"aria/Attachment {{ attachmentType }}\": \"Anhang {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"Anhangaktionen\",\n \"aria/audio\": \"Audio\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Audioposition {{ elapsed }} von {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"Audioposition {{ progress }} Prozent\",\n \"aria/Back to attachments\": \"Zurück zu Anhängen\",\n \"aria/Back to parent menu button\": \"Zurück zum übergeordneten Menü Schaltfläche\",\n \"aria/Block User\": \"Benutzer blockieren\",\n \"aria/Bookmark Message\": \"Nachricht für später speichern\",\n \"aria/Cancel recording\": \"Aufnahme abbrechen\",\n \"aria/Cancel Reply\": \"Antwort abbrechen\",\n \"aria/Channel Actions\": \"Kanalaktionen\",\n \"aria/Channel details\": \"Kanaldetails\",\n \"aria/Channel list\": \"Kanalliste\",\n \"aria/Chat view controls\": \"Chat-Ansicht-Steuerelemente\",\n \"aria/Chat: {{ channelName }}\": \"Chat: {{ channelName }}\",\n \"aria/Clear search\": \"Suche leeren\",\n \"aria/Close callout dialog\": \"Hinweisdialog schließen\",\n \"aria/Close thread\": \"Thread schließen\",\n \"aria/Collapse sidebar\": \"Seitenleiste einklappen\",\n \"aria/Command activated: {{ command }}\": \"Befehl aktiviert: {{ command }}\",\n \"aria/Command Suggestions\": \"Befehlsvorschläge\",\n \"aria/Complete recording\": \"Aufnahme abschließen\",\n \"aria/Copy Message Text\": \"Nachrichtentext kopieren\",\n \"aria/Decrease value\": \"Wert verringern\",\n \"aria/Delete Message\": \"Nachricht löschen\",\n \"aria/Delivered\": \"Zugestellt\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"Zustellstatus: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"Benachrichtigung schließen\",\n \"aria/Download attachment\": \"Anhang herunterladen\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"„{{ option }}“ an Position {{ position }} abgelegt.\",\n \"aria/Edit Message\": \"Nachricht bearbeiten\",\n \"aria/Emoji picker\": \"Emoji-Auswahl\",\n \"aria/Emoji Suggestions\": \"Emoji-Vorschläge\",\n \"aria/Exit search\": \"Suche verlassen\",\n \"aria/Expand sidebar\": \"Seitenleiste einblenden\",\n \"aria/file\": \"Datei\",\n \"aria/File upload\": \"Datei hochladen\",\n \"aria/Flag Message\": \"Nachricht melden\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Giphy-Aktionen\",\n \"aria/Giphy canceled\": \"Giphy abgebrochen\",\n \"aria/Giphy image changed\": \"Giphy-Bild geändert\",\n \"aria/Giphy image changed: {{ title }}\": \"Giphy-Bild geändert: {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Giphy-Vorschau, nur für dich sichtbar. Verwende die Aktionen Senden, Mischen oder Abbrechen.\",\n \"aria/Giphy sent\": \"Giphy gesendet\",\n \"aria/image\": \"Bild\",\n \"aria/Image failed to load\": \"Bild konnte nicht geladen werden\",\n \"aria/Increase value\": \"Wert erhöhen\",\n \"aria/Jump to latest message\": \"Zur neuesten Nachricht springen\",\n \"aria/Jump to quoted message\": \"Zur zitierten Nachricht springen\",\n \"aria/Last activity: {{ time }}\": \"Letzte Aktivität: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"Letzte Nachricht von {{ sender }}: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"Letzte Nachricht: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"Als ungelesen markieren\",\n \"aria/Mark messages as read\": \"Nachrichten als gelesen markieren\",\n \"aria/Mention Suggestions\": \"Erwähnungsvorschläge\",\n \"aria/Message Actions\": \"Nachrichtenaktionen\",\n \"aria/Message from {{ user }},\": \"Nachricht von {{ user }},\",\n \"aria/Message input\": \"Nachrichteneingabe\",\n \"aria/Message with attachments\": \"Nachricht mit Anhängen\",\n \"aria/Message,\": \"Nachricht,\",\n \"aria/Mute User\": \"Benutzer stummschalten\",\n \"aria/Next page\": \"Nächste Seite\",\n \"aria/No search results found\": \"Keine Suchergebnisse gefunden\",\n \"aria/Notifications\": \"Benachrichtigungen\",\n \"aria/Open Attachment Selector\": \"Anhang-Auswahl öffnen\",\n \"aria/Open Channel Actions Menu\": \"Kanalaktionsmenü öffnen\",\n \"aria/Open channel details\": \"Kanaldetails öffnen\",\n \"aria/Open channels view\": \"Kanalansicht öffnen\",\n \"aria/Open image shared by {{ name }}\": \"Von {{ name }} geteiltes Bild öffnen\",\n \"aria/Open Message Actions Menu\": \"Nachrichtenaktionsmenü öffnen\",\n \"aria/Open Reaction Selector\": \"Reaktionsauswahl öffnen\",\n \"aria/Open Thread\": \"Thread öffnen\",\n \"aria/Open threads view\": \"Thread-Ansicht öffnen\",\n \"aria/Open threads view with unread threads_one\": \"Thread-Ansicht öffnen, {{ count }} ungelesener Thread\",\n \"aria/Open threads view with unread threads_other\": \"Thread-Ansicht öffnen, {{ count }} ungelesene Threads\",\n \"aria/Open video shared by {{ name }}\": \"Von {{ name }} geteiltes Video öffnen\",\n \"aria/Opened channel: {{ name }}\": \"Kanal geöffnet: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"Thread in {{ name }} geöffnet\",\n \"aria/Option {{ position }}\": \"Option {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"Optionen können jetzt verschoben und entfernt werden.\",\n \"aria/Pause\": \"Pausieren\",\n \"aria/Pause recording\": \"Aufnahme pausieren\",\n \"aria/Percent complete\": \"{{percent}} Prozent abgeschlossen\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"„{{ option }}“ aufgenommen. Verwenden Sie die Pfeiltasten zum Verschieben. Drücken Sie die Leertaste oder Tab zum Ablegen.\",\n \"aria/Pin Message\": \"Nachricht anheften\",\n \"aria/Play\": \"Abspielen\",\n \"aria/Poll dialog opened\": \"Umfragedialog geöffnet\",\n \"aria/Poll sent\": \"Umfrage gesendet\",\n \"aria/Poll: {{ pollName }}\": \"Umfrage: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Drücken Sie die Eingabetaste, um mit der Eingabe zu beginnen\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"Drücken Sie die Leertaste, um diese Option auszuwählen, verwenden Sie die Pfeiltasten nach oben und unten, um sie zu verschieben, und drücken Sie dann erneut die Leertaste, um die Auswahl aufzuheben.\",\n \"aria/Previous page\": \"Vorherige Seite\",\n \"aria/Quote Message\": \"Nachricht zitieren\",\n \"aria/Reaction list\": \"Reaktionsliste\",\n \"aria/Read\": \"Gelesen\",\n \"aria/Recording paused\": \"Aufnahme pausiert\",\n \"aria/Recording resumed\": \"Aufnahme fortgesetzt\",\n \"aria/Recording started\": \"Aufnahme gestartet\",\n \"aria/Remind Me Message\": \"Erinnern\",\n \"aria/Remove attachment\": \"Anhang entfernen\",\n \"aria/Remove location attachment\": \"Standortanhang entfernen\",\n \"aria/Remove option: {{ option }}\": \"Option entfernen: {{ option }}\",\n \"aria/Remove Reminder\": \"Erinnerung entfernen\",\n \"aria/Remove Save For Later\": \"„Später ansehen“ entfernen\",\n \"aria/Removed option {{ option }}\": \"Option {{ option }} entfernt\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"„{{ option }}“ neu anordnen, Position {{ position }} von {{ total }}\",\n \"aria/Reorder option {{ position }}\": \"Option {{ position }} neu anordnen\",\n \"aria/Resend Message\": \"Nachricht erneut senden\",\n \"aria/Resume recording\": \"Aufnahme fortsetzen\",\n \"aria/Retry upload\": \"Upload erneut versuchen\",\n \"aria/Review bounced message\": \"Zurückgewiesene Nachricht prüfen\",\n \"aria/Search cleared\": \"Suche gelöscht\",\n \"aria/Search results\": \"Suchergebnisse\",\n \"aria/Search results header filter button for: {{ source }}\": \"Filterbutton in der Kopfzeile der Suchergebnisse für: {{ source }}\",\n \"aria/Seek audio position\": \"Audioposition suchen\",\n \"aria/Select Reaction: {{ reactionName }}\": \"Reaktion auswählen: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"Benutzerkanal auswählen: {{ name }}\",\n \"aria/Send\": \"Senden\",\n \"aria/Sent\": \"Gesendet\",\n \"aria/Shared a link\": \"Link geteilt\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"Link geteilt mit Titel: {{ linkTitle }}\",\n \"aria/Shared location\": \"Geteilter Standort\",\n \"aria/Show preview\": \"Vorschau anzeigen\",\n \"aria/Start recording audio\": \"Audioaufnahme starten\",\n \"aria/Stop AI Generation\": \"KI-Generierung stoppen\",\n \"aria/Submenu\": \"Untermenü\",\n \"aria/Suggestions\": \"Vorschläge\",\n \"aria/There are no messages in this chat.\": \"In diesem Chat gibt es keine Nachrichten\",\n \"aria/This option can be reordered and removed.\": \"Diese Option kann verschoben und entfernt werden.\",\n \"aria/Thread list\": \"Thread-Liste\",\n \"aria/Thread: {{ messagePreview }}\": \"Thread: {{ messagePreview }}\",\n \"aria/Unblock User\": \"Benutzer entsperren\",\n \"aria/Unmute User\": \"Stummschaltung aufheben\",\n \"aria/Unpin Message\": \"Anheftung aufheben\",\n \"aria/User selected: {{ user }}\": \"Benutzer ausgewählt: {{ user }}\",\n \"aria/video\": \"Video\",\n \"aria/voice message\": \"Sprachnachricht\",\n \"aria/Voice message sent\": \"Sprachnachricht gesendet\",\n \"aria/Voice recording attached\": \"Sprachaufnahme angehängt\",\n \"Ask a question\": \"Eine Frage stellen\",\n \"Attach\": \"Anhängen\",\n \"Attach files\": \"Dateien anhängen\",\n \"Attachment\": \"Anhang\",\n \"Attachment upload blocked due to {{reason}}\": \"Anhang-Upload blockiert wegen {{reason}}\",\n \"Attachment upload failed due to {{reason}}\": \"Anhang-Upload fehlgeschlagen wegen {{reason}}\",\n \"Back\": \"Zurück\",\n \"ban-command-args\": \"[@Benutzername] [Text]\",\n \"ban-command-description\": \"Einen Benutzer verbannen\",\n \"Block user\": \"Benutzer blockieren\",\n \"Block User\": \"Benutzer blockieren\",\n \"Browse channel members\": \"Kanalmitglieder durchsuchen\",\n \"Browse pinned messages\": \"Angeheftete Nachrichten durchsuchen\",\n \"Cancel\": \"Abbrechen\",\n \"Cannot seek in the recording\": \"In der Aufnahme kann nicht gesucht werden\",\n \"Changes saved\": \"Änderungen gespeichert\",\n \"Channel archived\": \"Kanal archiviert\",\n \"Channel members\": \"Kanalmitglieder\",\n \"Channel Missing\": \"Kanal fehlt\",\n \"Channel muted\": \"Kanal stummgeschaltet\",\n \"Channel pinned\": \"Kanal angeheftet\",\n \"Channel unarchived\": \"Kanal dearchiviert\",\n \"Channel unmuted\": \"Stummschaltung des Kanals aufgehoben\",\n \"Channel unpinned\": \"Kanal nicht mehr angeheftet\",\n \"Channels\": \"Kanäle\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"Chats\",\n \"Choose between 2 to 10 options\": \"Wähle zwischen 2 und 10 Optionen\",\n \"Close\": \"Schließen\",\n \"Close dialog\": \"Dialog schließen\",\n \"Close emoji picker\": \"Emoji-Auswahl schließen\",\n \"Command not available while editing\": \"Befehl beim Bearbeiten nicht verfügbar\",\n \"Command not available while replying\": \"Befehl beim Antworten nicht verfügbar\",\n \"Commands\": \"Befehle\",\n \"Commands matching\": \"Übereinstimmende Befehle\",\n \"Connection failure, reconnecting now...\": \"Verbindungsfehler, Wiederherstellung der Verbindung...\",\n \"Contact info\": \"Kontaktinfo\",\n \"Contact name\": \"Kontaktname\",\n \"Copy Message\": \"Nachricht kopieren\",\n \"Create\": \"Erstellen\",\n \"Create a question, add options, and configure poll settings\": \"Erstelle eine Frage, füge Optionen hinzu und konfiguriere die Umfrageeinstellungen\",\n \"Create poll\": \"Umfrage erstellen\",\n \"Current location\": \"Aktueller Standort\",\n \"Delete\": \"Löschen\",\n \"Delete chat\": \"Chat löschen\",\n \"Delete for me\": \"Für mich löschen\",\n \"Delete message\": \"Nachricht löschen\",\n \"Delivered\": \"Zugestellt\",\n \"Direct message\": \"Direktnachricht\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Möchten Sie diese Umfrage jetzt beenden? Niemand wird mehr in dieser Umfrage abstimmen können.\",\n \"Download {{ fileName }}\": \"{{ fileName }} herunterladen\",\n \"Download All\": \"Alle herunterladen\",\n \"Download Attachment\": \"Anhang herunterladen\",\n \"Download attachment {{ name }}\": \"Anhang {{ name }} herunterladen\",\n \"Download attachment {{ number }}\": \"Anhang {{ number }} herunterladen\",\n \"Drag your files here\": \"Ziehen Sie Ihre Dateien hierher\",\n \"Drag your files here to add to your post\": \"Ziehen Sie Ihre Dateien hierher, um sie Ihrem Beitrag hinzuzufügen\",\n \"Due {{ timeLeft }}\": \"Fällig {{ timeLeft }}\",\n \"Due since {{ dueSince }}\": \"Fällig seit {{ dueSince }}\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"Bearbeiten\",\n \"Edit chat data\": \"Chatdaten bearbeiten\",\n \"Edit contact\": \"Kontakt bearbeiten\",\n \"Edit group\": \"Gruppe bearbeiten\",\n \"Edit Message\": \"Nachricht bearbeiten\",\n \"Edit message request failed\": \"Anfrage zum Bearbeiten der Nachricht fehlgeschlagen\",\n \"Edited\": \"Bearbeitet\",\n \"Emoji matching\": \"Passende Emojis\",\n \"Empty message...\": \"Leere Nachricht...\",\n \"End\": \"Beenden\",\n \"End poll\": \"Umfrage beenden\",\n \"End this poll?\": \"Umfrage beenden?\",\n \"End vote\": \"Abstimmung beenden\",\n \"Enforce unique vote is enabled\": \"Eindeutige Abstimmung ist aktiviert\",\n \"Error\": \"Fehler\",\n \"Error adding flag\": \"Fehler beim Hinzufügen des Flags\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"Fehler beim Blockieren des Benutzers\",\n \"Error connecting to chat, refresh the page to try again.\": \"Verbindungsfehler zum Chat, aktualisieren Sie die Seite, um es erneut zu versuchen.\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"Fehler beim Löschen der Nachricht\",\n \"Error fetching reactions\": \"Fehler beim Laden von Reaktionen\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Fehler beim Markieren der Nachricht als ungelesen. Kann keine älteren ungelesenen Nachrichten markieren als die neuesten 100 Kanalnachrichten.\",\n \"Error muting a user ...\": \"Fehler beim Stummschalten eines Nutzers.\",\n \"Error muting channel\": \"Fehler beim Stummschalten des Kanals\",\n \"Error muting user\": \"Fehler beim Stummschalten des Benutzers\",\n \"Error opening direct message\": \"Fehler beim Öffnen der Direktnachricht\",\n \"Error pinning message\": \"Fehler beim Pinnen der Nachricht\",\n \"Error removing members\": \"Fehler beim Entfernen der Mitglieder\",\n \"Error removing message pin\": \"Fehler beim Entfernen der gepinnten Nachricht\",\n \"Error removing user\": \"Fehler beim Entfernen des Benutzers\",\n \"Error reproducing the recording\": \"Fehler bei der Wiedergabe der Aufnahme\",\n \"Error starting recording\": \"Fehler beim Starten der Aufnahme\",\n \"Error unblocking user\": \"Fehler beim Entsperren des Benutzers\",\n \"Error unmuting a user ...\": \"Fehler beim Aufheben der Stummschaltung eines Nutzers ...\",\n \"Error unmuting channel\": \"Fehler beim Aufheben der Kanal-Stummschaltung\",\n \"Error unmuting user\": \"Fehler beim Aufheben der Benutzer-Stummschaltung\",\n \"Error uploading attachment\": \"Fehler beim Hochladen des Anhangs\",\n \"Error uploading file\": \"Fehler beim Hochladen der Datei\",\n \"Error uploading image\": \"Fehler beim Hochladen des Bildes\",\n \"Error: {{ errorMessage }}\": \"Fehler: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"Befehl beenden {{ command }}\",\n \"Failed to block user\": \"Benutzer konnte nicht blockiert werden\",\n \"Failed to create the poll\": \"Fehler beim Erstellen der Umfrage\",\n \"Failed to create the poll due to {{reason}}\": \"Die Umfrage konnte aufgrund von {{reason}} nicht erstellt werden\",\n \"Failed to delete the message\": \"Nachricht konnte nicht gelöscht werden\",\n \"Failed to end the poll\": \"Umfrage konnte nicht beendet werden\",\n \"Failed to end the poll due to {{reason}}\": \"Umfrage konnte aufgrund von {{reason}} nicht beendet werden\",\n \"Failed to jump to the first unread message\": \"Fehler beim Springen zur ersten ungelesenen Nachricht\",\n \"Failed to leave channel\": \"Kanal konnte nicht verlassen werden\",\n \"Failed to load channels\": \"Kanäle konnten nicht geladen werden\",\n \"Failed to load more channels\": \"Weitere Kanäle konnten nicht geladen werden\",\n \"Failed to mark channel as read\": \"Fehler beim Markieren des Kanals als gelesen\",\n \"Failed to play the recording\": \"Wiedergabe der Aufnahme fehlgeschlagen\",\n \"Failed to retrieve location\": \"Standort konnte nicht abgerufen werden\",\n \"Failed to save changes\": \"Änderungen konnten nicht gespeichert werden\",\n \"Failed to share location\": \"Standort konnte nicht geteilt werden\",\n \"Failed to update channel archive status\": \"Archivierungsstatus des Kanals konnte nicht aktualisiert werden\",\n \"Failed to update channel mute status\": \"Stummschaltungsstatus des Kanals konnte nicht aktualisiert werden\",\n \"Failed to update channel pinned status\": \"Anheftstatus des Kanals konnte nicht aktualisiert werden\",\n \"File\": \"Datei\",\n \"File is required for upload attachment\": \"Datei ist für den Anhang-Upload erforderlich\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Datei ist zu groß: {{ size }}, maximale Upload-Größe beträgt {{ limit }}\",\n \"File too large\": \"Datei ist zu groß\",\n \"fileCount_one\": \"1 datei\",\n \"fileCount_other\": \"{{ count }} dateien\",\n \"Files\": \"Dateien\",\n \"Flag\": \"Melden\",\n \"Generating...\": \"Generieren...\",\n \"giphy-command-args\": \"[Text]\",\n \"giphy-command-description\": \"Poste ein zufälliges Gif in den Kanal\",\n \"Go back\": \"Zurück\",\n \"Group info\": \"Gruppeninfo\",\n \"Group name\": \"Gruppenname\",\n \"Hide who voted\": \"Verbergen, wer abgestimmt hat\",\n \"Image\": \"Bild\",\n \"imageCount_one\": \"Bild\",\n \"imageCount_other\": \"{{ count }} bilder\",\n \"Instant commands\": \"Sofortbefehle\",\n \"language/af\": \"Afrikaans\",\n \"language/am\": \"Amharisch\",\n \"language/ar\": \"Arabisch\",\n \"language/az\": \"Aserbaidschanisch\",\n \"language/bg\": \"Bulgarisch\",\n \"language/bn\": \"Bengalisch\",\n \"language/bs\": \"Bosnisch\",\n \"language/cs\": \"Tschechisch\",\n \"language/da\": \"Dänisch\",\n \"language/de\": \"Deutsch\",\n \"language/el\": \"Griechisch\",\n \"language/en\": \"Englisch\",\n \"language/es\": \"Spanisch\",\n \"language/es-MX\": \"Spanisch (Mexiko)\",\n \"language/et\": \"Estnisch\",\n \"language/fa\": \"Persisch\",\n \"language/fa-AF\": \"Dari\",\n \"language/fi\": \"Finnisch\",\n \"language/fr\": \"Französisch\",\n \"language/fr-CA\": \"Französisch (Kanada)\",\n \"language/ha\": \"Hausa\",\n \"language/he\": \"Hebräisch\",\n \"language/hi\": \"Hindi\",\n \"language/hr\": \"Kroatisch\",\n \"language/ht\": \"Haitianisches Kreolisch\",\n \"language/hu\": \"Ungarisch\",\n \"language/id\": \"Indonesisch\",\n \"language/it\": \"Italienisch\",\n \"language/ja\": \"Japanisch\",\n \"language/ka\": \"Georgisch\",\n \"language/ko\": \"Koreanisch\",\n \"language/lt\": \"Litauisch\",\n \"language/lv\": \"Lettisch\",\n \"language/ms\": \"Malaiisch\",\n \"language/nl\": \"Niederländisch\",\n \"language/no\": \"Norwegisch\",\n \"language/pl\": \"Polnisch\",\n \"language/ps\": \"Paschtu\",\n \"language/pt\": \"Portugiesisch\",\n \"language/ro\": \"Rumänisch\",\n \"language/ru\": \"Russisch\",\n \"language/sk\": \"Slowakisch\",\n \"language/sl\": \"Slowenisch\",\n \"language/so\": \"Somali\",\n \"language/sq\": \"Albanisch\",\n \"language/sr\": \"Serbisch\",\n \"language/sv\": \"Schwedisch\",\n \"language/sw\": \"Swahili\",\n \"language/ta\": \"Tamil\",\n \"language/th\": \"Thailändisch\",\n \"language/tl\": \"Tagalog\",\n \"language/tr\": \"Türkisch\",\n \"language/uk\": \"Ukrainisch\",\n \"language/ur\": \"Urdu\",\n \"language/vi\": \"Vietnamesisch\",\n \"language/zh\": \"Chinesisch (Vereinfacht)\",\n \"language/zh-TW\": \"Chinesisch (Traditionell)\",\n \"Last seen {{ timestamp }}\": \"Zuletzt gesehen {{ timestamp }}\",\n \"Leave Channel\": \"Kanal verlassen\",\n \"Leave chat\": \"Kanal verlassen\",\n \"Left channel\": \"Kanal verlassen\",\n \"Let others add options\": \"Andere Optionen hinzufügen lassen\",\n \"Limit votes per person\": \"Stimmen pro Person begrenzen\",\n \"Link\": \"Link\",\n \"linkCount_one\": \"Link\",\n \"linkCount_other\": \"{{ count }} Links\",\n \"live\": \"live\",\n \"Live for {{duration}}\": \"Live für {{duration}}\",\n \"Live location\": \"Live-Standort\",\n \"Live until {{ timestamp }}\": \"Live bis {{ timestamp }}\",\n \"Load more\": \"Mehr laden\",\n \"Local upload attachment missing local id\": \"Lokaler Upload-Anhang hat keine lokale ID\",\n \"Location\": \"Standort\",\n \"Location sharing ended\": \"Standortfreigabe beendet\",\n \"Location: {{ coordinates }}\": \"Standort: {{ coordinates }}\",\n \"Manage channel\": \"Kanal verwalten\",\n \"Manage members\": \"Mitglieder verwalten\",\n \"Mark as unread\": \"Als ungelesen markieren\",\n \"Maximum number of votes (from 2 to 10)\": \"Maximale Anzahl der Stimmen (von 2 bis 10)\",\n \"Maximum votes per person\": \"Maximale Stimmen pro Person\",\n \"Member detail\": \"Mitgliederdetails\",\n \"mention/Channel\": \"Kanal\",\n \"mention/Channel Description\": \"Alle in diesem Kanal benachrichtigen\",\n \"mention/Here\": \"Hier\",\n \"mention/Here Description\": \"Alle Online-Mitglieder in diesem Kanal benachrichtigen\",\n \"Menu\": \"Menü\",\n \"Message deleted\": \"Nachricht gelöscht\",\n \"Message failed to send\": \"Nachricht konnte nicht gesendet werden\",\n \"Message has been successfully flagged\": \"Nachricht wurde erfolgreich gemeldet\",\n \"Message marked as unread\": \"Nachricht als ungelesen markiert\",\n \"Message pinned\": \"Nachricht angeheftet\",\n \"Message unpinned\": \"Nachricht nicht mehr angeheftet\",\n \"Message was blocked by moderation policies\": \"Nachricht wurde durch moderationsrichtlinien blockiert\",\n \"Messages have been marked unread.\": \"Nachrichten wurden als ungelesen markiert.\",\n \"Missing permissions to upload the attachment\": \"Fehlende Berechtigungen zum Hochladen des Anhangs\",\n \"Moderator\": \"Moderator\",\n \"Multiple votes\": \"Mehrfachstimmen\",\n \"Mute\": \"Stummschalten\",\n \"Mute chat\": \"Chat stummschalten\",\n \"Mute user\": \"Benutzer stummschalten\",\n \"mute-command-args\": \"[@Benutzername]\",\n \"mute-command-description\": \"Stummschalten eines Benutzers\",\n \"network error\": \"Netzwerkfehler\",\n \"New\": \"Neu\",\n \"New message from {{user}}\": \"Neue Nachricht von {{user}}\",\n \"New Messages!\": \"Neue Nachrichten!\",\n \"Next\": \"Weiter\",\n \"Next image\": \"Nächstes Bild\",\n \"No chats here yet…\": \"Noch keine Chats hier...\",\n \"No conversations yet\": \"Noch keine Unterhaltungen\",\n \"No files\": \"Keine Dateien\",\n \"No items exist\": \"Keine Elemente vorhanden\",\n \"No member found\": \"Kein Mitglied gefunden\",\n \"No messages found\": \"Keine Nachrichten gefunden\",\n \"No photos or videos\": \"Keine Fotos oder Videos\",\n \"No pinned messages\": \"Keine angehefteten Nachrichten\",\n \"No results found\": \"Keine Ergebnisse gefunden\",\n \"No user found\": \"Kein Benutzer gefunden\",\n \"Nobody will be able to vote in this poll anymore.\": \"Niemand kann mehr in dieser Umfrage abstimmen.\",\n \"Nothing yet...\": \"Noch nichts...\",\n \"Notify all {{ role }} members\": \"Alle Mitglieder mit Rolle {{ role }} benachrichtigen\",\n \"Offline\": \"Offline\",\n \"Ok\": \"OK\",\n \"Online\": \"Online\",\n \"Only numbers are allowed\": \"Nur Zahlen sind erlaubt\",\n \"Only visible to you\": \"Nur für dich sichtbar\",\n \"Open emoji picker\": \"Emoji-Auswahl öffnen\",\n \"Open gallery at image {{ index }}\": \"Galerie bei Bild {{ index }} öffnen\",\n \"Open image in gallery\": \"Bild in Galerie öffnen\",\n \"Open location in a map\": \"Standort in einer Karte öffnen\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"Menü öffnen\",\n \"Option already exists\": \"Option existiert bereits\",\n \"Option is empty\": \"Option ist leer\",\n \"Options\": \"Optionen\",\n \"Original\": \"Original\",\n \"Owner\": \"Besitzer\",\n \"People matching\": \"Passende Personen\",\n \"Photo\": \"Foto\",\n \"Photos & videos\": \"Fotos & Videos\",\n \"Pin\": \"Anheften\",\n \"Pin a message to see it here\": \"Hefte eine Nachricht an, um sie hier zu sehen\",\n \"Pinned by {{ name }}\": \"Angeheftet von {{ name }}\",\n \"Pinned by You\": \"Von Ihnen angeheftet\",\n \"Pinned message\": \"Angeheftete Nachricht\",\n \"Pinned messages\": \"Angeheftete Nachrichten\",\n \"placeholder/PollComment\": \"Ihr Kommentar\",\n \"placeholder/PollOptionSuggestion\": \"Neue Option eingeben\",\n \"Play video\": \"Video abspielen\",\n \"Playback speed {{ rate }}x\": \"Wiedergabegeschwindigkeit {{ rate }}x\",\n \"Poll\": \"Umfrage\",\n \"Poll comments\": \"Umfragekommentare\",\n \"Poll ended\": \"Umfrage beendet\",\n \"Poll options\": \"Umfrageoptionen\",\n \"Poll results\": \"Umfrageergebnisse\",\n \"Poll sent\": \"Umfrage gesendet\",\n \"Previous\": \"Zurück\",\n \"Previous image\": \"Vorheriges Bild\",\n \"Question\": \"Frage\",\n \"Question {{ optionOrderNumber}}\": \"Frage {{ optionOrderNumber}}\",\n \"Question is required\": \"Frage ist erforderlich\",\n \"Quote Reply\": \"Zitat-Antwort\",\n \"Reached the vote limit. Remove an existing vote first.\": \"Das Abstimmungslimit wurde erreicht. Entfernen Sie zuerst eine bestehende Stimme.\",\n \"Recording format is not supported and cannot be reproduced\": \"Aufnahmeformat wird nicht unterstützt und kann nicht wiedergegeben werden\",\n \"Remind me\": \"Erinnern\",\n \"Remind Me\": \"Erinnern\",\n \"Reminder set\": \"Erinnerung gesetzt\",\n \"Remove\": \"Entfernen\",\n \"Remove {{ count }} members_one\": \"{{ count }} Mitglied entfernen\",\n \"Remove {{ count }} members_other\": \"{{ count }} Mitglieder entfernen\",\n \"Remove {{ member }} from this channel?\": \"{{ member }} aus diesem Kanal entfernen?\",\n \"Remove channel members\": \"Kanalmitglieder entfernen\",\n \"Remove reminder\": \"Erinnerung entfernen\",\n \"Remove save for later\": \"„Später ansehen“ entfernen\",\n \"Remove user\": \"Benutzer entfernen\",\n \"Removed {{ count }} members_one\": \"{{ count }} Mitglied entfernt\",\n \"Removed {{ count }} members_other\": \"{{ count }} Mitglieder entfernt\",\n \"Replied to a thread\": \"In einem Thread geantwortet\",\n \"Reply\": \"Antworten\",\n \"Reply to {{ authorName }}\": \"Antwort an {{ authorName }}\",\n \"Reply to a message to start a thread\": \"Antworte auf eine Nachricht, um einen Thread zu starten\",\n \"Reply to Message\": \"Auf Nachricht antworten\",\n \"replyCount_one\": \"1 Antwort\",\n \"replyCount_other\": \"{{ count }} Antworten\",\n \"Resend\": \"Erneut senden\",\n \"Retry upload\": \"Upload erneut versuchen\",\n \"Review all options available in this poll\": \"Überprüfe alle verfügbaren Optionen in dieser Umfrage\",\n \"Review comments submitted with poll answers\": \"Überprüfe Kommentare, die mit Umfrageantworten eingereicht wurden\",\n \"Review poll results and open an option to see detailed votes\": \"Überprüfe die Umfrageergebnisse und öffne eine Option, um detaillierte Stimmen zu sehen\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Überprüfe diese Nachricht und wähle, ob du sie löschen, bearbeiten oder trotzdem senden möchtest\",\n \"Review who voted for this option\": \"Überprüfe, wer für diese Option gestimmt hat\",\n \"Save\": \"Speichern\",\n \"Save for later\": \"Für später speichern\",\n \"Saved for later\": \"Für später gespeichert\",\n \"Search\": \"Suche\",\n \"Search GIFs\": \"GIFs suchen\",\n \"search-results-header-filter-source-button-label--channels\": \"Kanäle\",\n \"search-results-header-filter-source-button-label--messages\": \"Nachrichten\",\n \"search-results-header-filter-source-button-label--users\": \"Benutzer\",\n \"Searching for {{ searchSourceType }}...\": \"Suche nach {{ searchSourceType }}...\",\n \"Searching...\": \"Suchen...\",\n \"searchResultsCount_one\": \"1 Ergebnis\",\n \"searchResultsCount_other\": \"{{ count }} Ergebnisse\",\n \"Select a thread to continue the conversation\": \"Wähle einen Thread aus, um die Unterhaltung fortzusetzen\",\n \"Select more than one option\": \"Mehr als eine Option auswählen\",\n \"Select one\": \"Eine auswählen\",\n \"Select one or more\": \"Eine oder mehrere auswählen\",\n \"Select up to {{count}}_one\": \"Bis zu {{count}} auswählen\",\n \"Select up to {{count}}_other\": \"Bis zu {{count}} auswählen\",\n \"Select your current location and optionally enable live location sharing\": \"Wähle deinen aktuellen Standort und aktiviere optional das Teilen des Live-Standorts\",\n \"Send\": \"Senden\",\n \"Send a message\": \"Nachricht senden\",\n \"Send a message to start the conversation\": \"Senden Sie eine Nachricht, um die Unterhaltung zu beginnen\",\n \"Send Anyway\": \"Trotzdem senden\",\n \"Send direct message\": \"Direktnachricht senden\",\n \"Send message request failed\": \"Senden der Nachrichtenanfrage fehlgeschlagen\",\n \"Send poll\": \"Umfrage senden\",\n \"Sending...\": \"Senden...\",\n \"Sent\": \"Gesendet\",\n \"Share\": \"Teilen\",\n \"Share a file to see it here\": \"Teile eine Datei, um sie hier zu sehen\",\n \"Share a photo or video to see it here\": \"Teile ein Foto oder Video, um es hier zu sehen\",\n \"Share live location for\": \"Live-Standort teilen für\",\n \"Share Location\": \"Standort teilen\",\n \"Shared live location\": \"Geteilter Live-Standort\",\n \"Shared location\": \"Geteilter Standort\",\n \"Shuffle\": \"Mischen\",\n \"size limit\": \"Größenbeschränkung\",\n \"Slow Mode ON\": \"Langsamer Modus EIN\",\n \"Slow mode, wait {{ seconds }}s...\": \"Langsamer Modus, warte {{ seconds }}s...\",\n \"Some of the files will not be accepted\": \"Einige der Dateien werden nicht akzeptiert\",\n \"Start typing to search\": \"Tippen Sie, um zu suchen\",\n \"Stop sharing\": \"Teilen beenden\",\n \"Submit\": \"Absenden\",\n \"Suggest a new option to add to this poll\": \"Schlage eine neue Option vor, die zu dieser Umfrage hinzugefügt werden soll\",\n \"Suggest an option\": \"Eine Option vorschlagen\",\n \"Tap to remove\": \"Tippen zum Entfernen\",\n \"Tap to remove: {{ reactionName }}\": \"Tippen zum Entfernen: {{ reactionName }}\",\n \"Thinking...\": \"Denken...\",\n \"this content could not be displayed\": \"Dieser Inhalt konnte nicht angezeigt werden\",\n \"This field cannot be empty or contain only spaces\": \"Dieses Feld darf nicht leer sein oder nur Leerzeichen enthalten\",\n \"This message did not meet our content guidelines\": \"Diese Nachricht entsprach nicht unseren Inhaltsrichtlinien\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"Dieser Benutzer kann dir wieder Nachrichten senden.\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"Thread\",\n \"Thread has not been found\": \"Thread wurde nicht gefunden\",\n \"Thread reply\": \"Thread-Antwort\",\n \"Thread Reply\": \"Thread-Antwort\",\n \"ThreadListUnseenThreadsBanner/loading\": \"Laden...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} ungelesener Thread\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} ungelesene Threads\",\n \"Threads\": \"Diskussionen\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Gestern]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Heute]\\\", \\\"nextDay\\\": \\\"[Morgen]\\\", \\\"lastDay\\\": \\\"[Gestern]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Letzte] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"vor {{ count }} Tg.\",\n \"timestamp/relativeToday\": \"Heute\",\n \"timestamp/relativeWeeksAgo\": \"vor {{ count }} Wo.\",\n \"timestamp/relativeYesterday\": \"Gestern\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Heute] [um] HH:mm\\\", \\\"nextDay\\\": \\\"[Morgen] [um] HH:mm\\\", \\\"lastDay\\\": \\\"[Gestern] [um] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [um] HH:mm\\\", \\\"lastWeek\\\": \\\"[letzten] dddd [um] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [um] HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"Um mit der Aufnahme zu beginnen, erlauben Sie den Zugriff auf die Kamera in Ihrem Browser\",\n \"To start recording, allow the microphone access in your browser\": \"Um mit der Aufnahme zu beginnen, erlauben Sie den Zugriff auf das Mikrofon in Ihrem Browser\",\n \"totalVoteCount_one\": \"1 Stimme insgesamt\",\n \"totalVoteCount_other\": \"{{ count }} Stimmen insgesamt\",\n \"Translated\": \"Übersetzt\",\n \"Translated from {{ language }}\": \"Übersetzung aus {{ language }}\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"Geben Sie eine Zahl von 2 bis 10 ein\",\n \"Unarchive\": \"Archivierung aufheben\",\n \"unban-command-args\": \"[@Benutzername]\",\n \"unban-command-description\": \"Einen Benutzer entbannen\",\n \"Unblock\": \"Entsperren\",\n \"Unblock user\": \"Benutzer entsperren\",\n \"Unblock User\": \"Benutzer entsperren\",\n \"unknown error\": \"Unbekannter Fehler\",\n \"Unmute\": \"Stummschaltung aufheben\",\n \"Unmute chat\": \"Chat-Stummschaltung aufheben\",\n \"Unmute user\": \"Benutzer-Stummschaltung aufheben\",\n \"unmute-command-args\": \"[@Benutzername]\",\n \"unmute-command-description\": \"Stummschaltung eines Benutzers aufheben\",\n \"Unpin\": \"Anheftung aufheben\",\n \"Unread messages\": \"Ungelesene Nachrichten\",\n \"Unsupported attachment\": \"Nicht unterstützter Anhang\",\n \"unsupported file type\": \"Nicht unterstützter Dateityp\",\n \"Update\": \"Aktualisieren\",\n \"Update the comment attached to your poll answer\": \"Aktualisiere den Kommentar, der an deine Umfrageantwort angehängt ist\",\n \"Update your comment\": \"Ihren Kommentar aktualisieren\",\n \"Upload blocked\": \"Upload blockiert\",\n \"Upload error\": \"Upload-Fehler\",\n \"Upload failed\": \"Upload fehlgeschlagen\",\n \"Upload Picture\": \"Bild hochladen\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Upload-Typ: \\\"{{ type }}\\\" ist nicht erlaubt\",\n \"User blocked\": \"Benutzer blockiert\",\n \"User muted\": \"Benutzer stummgeschaltet\",\n \"User removed\": \"Benutzer entfernt\",\n \"User unblocked\": \"Blockierung des Benutzers aufgehoben\",\n \"User unmuted\": \"Benutzer-Stummschaltung aufgehoben\",\n \"User uploaded content\": \"Vom Benutzer hochgeladener Inhalt\",\n \"Video\": \"Video\",\n \"videoCount_one\": \"Video\",\n \"videoCount_other\": \"{{ count }} Videos\",\n \"View\": \"Ansehen\",\n \"View {{count}} comments_one\": \"{{count}} Kommentar anzeigen\",\n \"View {{count}} comments_other\": \"{{count}} Kommentare anzeigen\",\n \"View all\": \"Alle anzeigen\",\n \"View member details for {{ member }}\": \"Mitgliederdetails für {{ member }} anzeigen\",\n \"View original\": \"Original anzeigen\",\n \"View results\": \"Ergebnisse anzeigen\",\n \"View translation\": \"Übersetzung anzeigen\",\n \"Voice message\": \"Sprachnachricht\",\n \"Voice message {{ duration }}\": \"Sprachnachricht {{ duration }}\",\n \"Voice message deleted\": \"Sprachnachricht gelöscht\",\n \"voiceMessageCount_one\": \"Sprachnachricht\",\n \"voiceMessageCount_other\": \"{{ count }} sprachnachrichten\",\n \"Vote ended\": \"Abstimmung beendet\",\n \"Votes\": \"Stimmen\",\n \"Wait until all attachments have uploaded\": \"Bitte warten, bis alle Anhänge hochgeladen wurden\",\n \"Waiting for network…\": \"Warte auf Netzwerk…\",\n \"You\": \"Du\",\n \"You've reached the maximum number of files\": \"Die maximale Anzahl an Dateien ist erreicht\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} and {{ moreCount }} more\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }}, and {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} file\",\n \"{{ count }} files_other\": \"{{ count }} files\",\n \"{{ count }} members_one\": \"{{ count }} member\",\n \"{{ count }} members_other\": \"{{ count }} members\",\n \"{{ count }} members added_one\": \"{{ count }} member added\",\n \"{{ count }} members added_other\": \"{{ count }} members added\",\n \"{{ count }} people are typing_one\": \"{{ count }} person is typing\",\n \"{{ count }} people are typing_many\": \"{{ count }} people are typing\",\n \"{{ count }} people are typing_other\": \"{{ count }} people are typing\",\n \"{{ count }} photos_one\": \"{{ count }} photo\",\n \"{{ count }} photos_other\": \"{{ count }} photos\",\n \"{{ count }} reactions_one\": \"{{ count }} reaction\",\n \"{{ count }} reactions_other\": \"{{ count }} reactions\",\n \"{{ count }} videos_one\": \"{{ count }} video\",\n \"{{ count }} videos_other\": \"{{ count }} videos\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} and {{ secondUser }}\",\n \"{{ imageCount }} more\": \"{{ imageCount }} more\",\n \"{{ member }} will be able to message you again.\": \"{{ member }} will be able to message you again.\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }} won't be able to message you anymore.\",\n \"{{ memberCount }} members\": \"{{ memberCount }} members\",\n \"{{ typing }} are typing\": \"{{ typing }} are typing\",\n \"{{ typing }} is typing\": \"{{ typing }} is typing\",\n \"{{ user }} has been muted\": \"{{ user }} has been muted\",\n \"{{ user }} has been unmuted\": \"{{ user }} has been unmuted\",\n \"{{ user }} is typing...\": \"{{ user }} is typing...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} and {{ user }} are typing...\",\n \"{{ users }} and more are typing...\": \"{{ users }} and more are typing...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} online\",\n \"{{count}} new messages_one\": \"{{count}} new message\",\n \"{{count}} new messages_other\": \"{{count}} new messages\",\n \"{{count}} unread_one\": \"{{count}} unread\",\n \"{{count}} unread_other\": \"{{count}} unread\",\n \"{{count}} votes_one\": \"{{count}} vote\",\n \"{{count}} votes_other\": \"{{count}} votes\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"+{{count}} more option\",\n \"+{{count}} more options_other\": \"+{{count}} more options\",\n \"🏙 Attachment...\": \"🏙 Attachment...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} created: {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} voted: {{pollOptionText}}\",\n \"📍Shared location\": \"📍Shared location\",\n \"Actions\": \"Actions\",\n \"Add\": \"Add\",\n \"Add {{ count }} members_one\": \"Add {{ count }} member\",\n \"Add {{ count }} members_other\": \"Add {{ count }} members\",\n \"Add a comment\": \"Add a Comment\",\n \"Add a comment to your poll answer\": \"Add a comment to your poll answer\",\n \"Add an option\": \"Add an Option\",\n \"Add channel members\": \"Add channel members\",\n \"Add members\": \"Add members\",\n \"Add reaction\": \"Add reaction\",\n \"Admin\": \"Admin\",\n \"All results loaded\": \"All results loaded\",\n \"Allow access to camera\": \"Allow access to camera\",\n \"Allow access to microphone\": \"Allow access to microphone\",\n \"Allow comments\": \"Allow comments\",\n \"Allow option suggestion\": \"Allow option suggestion\",\n \"Allow others to add comments\": \"Allow Others to Add Comments\",\n \"Already a member\": \"Already a member\",\n \"Also send as a direct message\": \"Also send as a direct message\",\n \"Also send in channel\": \"Also send in channel\",\n \"Also sent in channel\": \"Also sent in channel\",\n \"An error has occurred during recording\": \"An error has occurred during recording\",\n \"An error has occurred during the recording processing\": \"An error has occurred during the recording processing\",\n \"Anonymous\": \"Anonymous\",\n \"Anonymous poll\": \"Anonymous Poll\",\n \"Archive\": \"Archive\",\n \"Are you sure you want to delete this message?\": \"Are you sure you want to delete this message?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_one\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_one\": \"{{ count }} attachment\",\n \"aria/{{ count }} attachment_other\": \"{{ count }} attachments\",\n \"aria/{{ count }} search results_one\": \"{{ count }} search result\",\n \"aria/{{ count }} search results_other\": \"{{ count }} search results\",\n \"aria/{{ count }} suggestions_one\": \"{{ count }} suggestion\",\n \"aria/{{ count }} suggestions_other\": \"{{ count }} suggestions\",\n \"aria/{{ count }} unread message_one\": \"{{ count }} unread message\",\n \"aria/{{ count }} unread message_other\": \"{{ count }} unread messages\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} disabled\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} enabled\",\n \"aria/Active\": \"Active\",\n \"aria/Animated GIF\": \"Animated GIF\",\n \"aria/Animated GIF: {{ title }}\": \"Animated GIF: {{ title }}\",\n \"aria/Attachment\": \"Attachment\",\n \"aria/Attachment {{ attachmentType }}\": \"Attachment {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"Attachment Actions\",\n \"aria/audio\": \"audio\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Audio position {{ elapsed }} of {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"Audio position {{ progress }} percent\",\n \"aria/Back to attachments\": \"Back to attachments\",\n \"aria/Back to parent menu button\": \"Back to parent menu button\",\n \"aria/Block User\": \"Block User\",\n \"aria/Bookmark Message\": \"Bookmark Message\",\n \"aria/Cancel recording\": \"Cancel recording\",\n \"aria/Cancel Reply\": \"Cancel Reply\",\n \"aria/Channel Actions\": \"Channel Actions\",\n \"aria/Channel details\": \"Channel details\",\n \"aria/Channel list\": \"Channel list\",\n \"aria/Chat view controls\": \"Chat view controls\",\n \"aria/Chat: {{ channelName }}\": \"Chat: {{ channelName }}\",\n \"aria/Clear search\": \"Clear search\",\n \"aria/Close callout dialog\": \"Close callout dialog\",\n \"aria/Close thread\": \"Close thread\",\n \"aria/Collapse sidebar\": \"Collapse sidebar\",\n \"aria/Command activated: {{ command }}\": \"Command activated: {{ command }}\",\n \"aria/Command Suggestions\": \"Command Suggestions\",\n \"aria/Complete recording\": \"Complete recording\",\n \"aria/Copy Message Text\": \"Copy Message Text\",\n \"aria/Decrease value\": \"Decrease value\",\n \"aria/Delete Message\": \"Delete Message\",\n \"aria/Delivered\": \"Delivered\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"Delivery status: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"Dismiss notification\",\n \"aria/Download attachment\": \"Download attachment\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"Dropped \\\"{{ option }}\\\" at position {{ position }}.\",\n \"aria/Edit Message\": \"Edit Message\",\n \"aria/Emoji picker\": \"Emoji picker\",\n \"aria/Emoji Suggestions\": \"Emoji Suggestions\",\n \"aria/Exit search\": \"Exit search\",\n \"aria/Expand sidebar\": \"Expand sidebar\",\n \"aria/file\": \"file\",\n \"aria/File upload\": \"File upload\",\n \"aria/Flag Message\": \"Flag Message\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Giphy actions\",\n \"aria/Giphy canceled\": \"Giphy canceled\",\n \"aria/Giphy image changed\": \"Giphy image changed\",\n \"aria/Giphy image changed: {{ title }}\": \"Giphy image changed: {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\",\n \"aria/Giphy sent\": \"Giphy sent\",\n \"aria/image\": \"image\",\n \"aria/Image failed to load\": \"Image failed to load\",\n \"aria/Increase value\": \"Increase value\",\n \"aria/Jump to latest message\": \"Jump to latest message\",\n \"aria/Jump to quoted message\": \"Jump to quoted message\",\n \"aria/Last activity: {{ time }}\": \"Last activity: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"Last message from {{ sender }}: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"Last message: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"Mark Message Unread\",\n \"aria/Mark messages as read\": \"Mark messages as read\",\n \"aria/Mention Suggestions\": \"Mention Suggestions\",\n \"aria/Message Actions\": \"Message Actions\",\n \"aria/Message from {{ user }},\": \"Message from {{ user }},\",\n \"aria/Message input\": \"Message input\",\n \"aria/Message with attachments\": \"Message with attachments\",\n \"aria/Message,\": \"Message,\",\n \"aria/Mute User\": \"Mute User\",\n \"aria/Next page\": \"Next page\",\n \"aria/No search results found\": \"No search results found\",\n \"aria/Notifications\": \"Notifications\",\n \"aria/Open Attachment Selector\": \"Open Attachment Selector\",\n \"aria/Open Channel Actions Menu\": \"Open Channel Actions Menu\",\n \"aria/Open channel details\": \"Open channel details\",\n \"aria/Open channels view\": \"Open channels view\",\n \"aria/Open image shared by {{ name }}\": \"Open image shared by {{ name }}\",\n \"aria/Open Message Actions Menu\": \"Open Message Actions Menu\",\n \"aria/Open Reaction Selector\": \"Open Reaction Selector\",\n \"aria/Open Thread\": \"Open Thread\",\n \"aria/Open threads view\": \"Open threads view\",\n \"aria/Open threads view with unread threads_one\": \"Open threads view, {{ count }} unread thread\",\n \"aria/Open threads view with unread threads_other\": \"Open threads view, {{ count }} unread threads\",\n \"aria/Open video shared by {{ name }}\": \"Open video shared by {{ name }}\",\n \"aria/Opened channel: {{ name }}\": \"Opened channel: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"Opened thread in {{ name }}\",\n \"aria/Option {{ position }}\": \"Option {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"Options can now be reordered and removed.\",\n \"aria/Pause\": \"Pause\",\n \"aria/Pause recording\": \"Pause recording\",\n \"aria/Percent complete\": \"{{percent}} percent complete\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\",\n \"aria/Pin Message\": \"Pin Message\",\n \"aria/Play\": \"Play\",\n \"aria/Poll dialog opened\": \"Poll dialog opened\",\n \"aria/Poll sent\": \"Poll sent\",\n \"aria/Poll: {{ pollName }}\": \"Poll: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Press Enter to start typing\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\",\n \"aria/Previous page\": \"Previous page\",\n \"aria/Quote Message\": \"Quote Message\",\n \"aria/Reaction list\": \"Reaction list\",\n \"aria/Read\": \"Read\",\n \"aria/Recording paused\": \"Recording paused\",\n \"aria/Recording resumed\": \"Recording resumed\",\n \"aria/Recording started\": \"Recording started\",\n \"aria/Remind Me Message\": \"Remind Me Message\",\n \"aria/Remove attachment\": \"Remove attachment\",\n \"aria/Remove location attachment\": \"Remove location attachment\",\n \"aria/Remove option: {{ option }}\": \"Remove option: {{ option }}\",\n \"aria/Remove Reminder\": \"Remove Reminder\",\n \"aria/Remove Save For Later\": \"Remove Save For Later\",\n \"aria/Removed option {{ option }}\": \"Removed option {{ option }}\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\",\n \"aria/Reorder option {{ position }}\": \"Reorder option {{ position }}\",\n \"aria/Resend Message\": \"Resend Message\",\n \"aria/Resume recording\": \"Resume recording\",\n \"aria/Retry upload\": \"Retry upload\",\n \"aria/Review bounced message\": \"Review bounced message\",\n \"aria/Search cleared\": \"Search cleared\",\n \"aria/Search results\": \"Search results\",\n \"aria/Search results header filter button for: {{ source }}\": \"Search results header filter button for: {{ source }}\",\n \"aria/Seek audio position\": \"Seek audio position\",\n \"aria/Select Reaction: {{ reactionName }}\": \"Select Reaction: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"Select User Channel: {{ name }}\",\n \"aria/Send\": \"Send\",\n \"aria/Sent\": \"Sent\",\n \"aria/Shared a link\": \"Shared a link\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"Shared a link with title: {{ linkTitle }}\",\n \"aria/Shared location\": \"Shared location\",\n \"aria/Show preview\": \"Show preview\",\n \"aria/Start recording audio\": \"Start recording audio\",\n \"aria/Stop AI Generation\": \"Stop AI Generation\",\n \"aria/Submenu\": \"Submenu\",\n \"aria/Suggestions\": \"Suggestions\",\n \"aria/There are no messages in this chat.\": \"There are no messages in this chat.\",\n \"aria/This option can be reordered and removed.\": \"This option can be reordered and removed.\",\n \"aria/Thread list\": \"Thread list\",\n \"aria/Thread: {{ messagePreview }}\": \"Thread: {{ messagePreview }}\",\n \"aria/Unblock User\": \"Unblock User\",\n \"aria/Unmute User\": \"Unmute User\",\n \"aria/Unpin Message\": \"Unpin Message\",\n \"aria/User selected: {{ user }}\": \"User selected: {{ user }}\",\n \"aria/video\": \"video\",\n \"aria/voice message\": \"voice message\",\n \"aria/Voice message sent\": \"Voice message sent\",\n \"aria/Voice recording attached\": \"Voice recording attached\",\n \"Ask a question\": \"Ask a Question\",\n \"Attach\": \"Attach\",\n \"Attach files\": \"Attach files\",\n \"Attachment\": \"Attachment\",\n \"Attachment upload blocked due to {{reason}}\": \"Attachment upload blocked due to {{reason}}\",\n \"Attachment upload failed due to {{reason}}\": \"Attachment upload failed due to {{reason}}\",\n \"Back\": \"Back\",\n \"ban-command-args\": \"[@username] [text]\",\n \"ban-command-description\": \"Ban a user\",\n \"Block user\": \"Block user\",\n \"Block User\": \"Block User\",\n \"Browse channel members\": \"Browse channel members\",\n \"Browse pinned messages\": \"Browse pinned messages\",\n \"Cancel\": \"Cancel\",\n \"Cannot seek in the recording\": \"Cannot seek in the recording\",\n \"Changes saved\": \"Changes saved\",\n \"Channel archived\": \"Channel archived\",\n \"Channel members\": \"Channel members\",\n \"Channel Missing\": \"Channel Missing\",\n \"Channel muted\": \"Channel muted\",\n \"Channel pinned\": \"Channel pinned\",\n \"Channel unarchived\": \"Channel unarchived\",\n \"Channel unmuted\": \"Channel unmuted\",\n \"Channel unpinned\": \"Channel unpinned\",\n \"Channels\": \"Channels\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"Chats\",\n \"Choose between 2 to 10 options\": \"Choose Between 2 to 10 Options\",\n \"Close\": \"Close\",\n \"Close dialog\": \"Close dialog\",\n \"Close emoji picker\": \"Close emoji picker\",\n \"Command not available while editing\": \"Command not available while editing\",\n \"Command not available while replying\": \"Command not available while replying\",\n \"Commands\": \"Commands\",\n \"Commands matching\": \"Commands matching\",\n \"Connection failure, reconnecting now...\": \"Connection failure, reconnecting now...\",\n \"Contact info\": \"Contact info\",\n \"Contact name\": \"Contact name\",\n \"Copy Message\": \"Copy Message\",\n \"Create\": \"Create\",\n \"Create a question, add options, and configure poll settings\": \"Create a question, add options, and configure poll settings\",\n \"Create poll\": \"Create Poll\",\n \"Current location\": \"Current location\",\n \"Delete\": \"Delete\",\n \"Delete chat\": \"Delete chat\",\n \"Delete for me\": \"Delete for me\",\n \"Delete message\": \"Delete message\",\n \"Delivered\": \"Delivered\",\n \"Direct message\": \"Direct message\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\",\n \"Download {{ fileName }}\": \"Download {{ fileName }}\",\n \"Download All\": \"Download All\",\n \"Download Attachment\": \"Download Attachment\",\n \"Download attachment {{ name }}\": \"Download attachment {{ name }}\",\n \"Download attachment {{ number }}\": \"Download attachment {{ number }}\",\n \"Drag your files here\": \"Drag your files here\",\n \"Drag your files here to add to your post\": \"Drag your files here to add to your post\",\n \"Due {{ timeLeft }}\": \"Due {{ timeLeft }}\",\n \"Due since {{ dueSince }}\": \"Due since {{ dueSince }}\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"Edit\",\n \"Edit chat data\": \"Edit chat data\",\n \"Edit contact\": \"Edit contact\",\n \"Edit group\": \"Edit group\",\n \"Edit Message\": \"Edit Message\",\n \"Edit message request failed\": \"Edit message request failed\",\n \"Edited\": \"Edited\",\n \"Emoji matching\": \"Emoji matching\",\n \"Empty message...\": \"Empty message...\",\n \"End\": \"End\",\n \"End poll\": \"End Poll\",\n \"End this poll?\": \"End this Poll?\",\n \"End vote\": \"End Vote\",\n \"Enforce unique vote is enabled\": \"Enforce unique vote is enabled\",\n \"Error\": \"Error\",\n \"Error adding flag\": \"Error adding flag\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"Error blocking user\",\n \"Error connecting to chat, refresh the page to try again.\": \"Error connecting to chat, refresh the page to try again.\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"Error deleting message\",\n \"Error fetching reactions\": \"Error loading reactions\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\",\n \"Error muting a user ...\": \"Error muting a user ...\",\n \"Error muting channel\": \"Error muting channel\",\n \"Error muting user\": \"Error muting user\",\n \"Error opening direct message\": \"Error opening direct message\",\n \"Error pinning message\": \"Error pinning message\",\n \"Error removing members\": \"Error removing members\",\n \"Error removing message pin\": \"Error removing message pin\",\n \"Error removing user\": \"Error removing user\",\n \"Error reproducing the recording\": \"Error reproducing the recording\",\n \"Error starting recording\": \"Error starting recording\",\n \"Error unblocking user\": \"Error unblocking user\",\n \"Error unmuting a user ...\": \"Error unmuting a user ...\",\n \"Error unmuting channel\": \"Error unmuting channel\",\n \"Error unmuting user\": \"Error unmuting user\",\n \"Error uploading attachment\": \"Error uploading attachment\",\n \"Error uploading file\": \"Error uploading file\",\n \"Error uploading image\": \"Error uploading image\",\n \"Error: {{ errorMessage }}\": \"Error: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"Exit command {{ command }}\",\n \"Failed to block user\": \"Failed to block user\",\n \"Failed to create the poll\": \"Failed to create the poll\",\n \"Failed to create the poll due to {{reason}}\": \"Failed to create the poll due to {{reason}}\",\n \"Failed to delete the message\": \"Failed to delete the message\",\n \"Failed to end the poll\": \"Failed to end the poll\",\n \"Failed to end the poll due to {{reason}}\": \"Failed to end the poll due to {{reason}}\",\n \"Failed to jump to the first unread message\": \"Failed to jump to the first unread message\",\n \"Failed to leave channel\": \"Failed to leave channel\",\n \"Failed to load channels\": \"Failed to load channels\",\n \"Failed to load more channels\": \"Failed to load more channels\",\n \"Failed to mark channel as read\": \"Failed to mark channel as read\",\n \"Failed to play the recording\": \"Failed to play the recording\",\n \"Failed to retrieve location\": \"Failed to retrieve location\",\n \"Failed to save changes\": \"Failed to save changes\",\n \"Failed to share location\": \"Failed to share location\",\n \"Failed to update channel archive status\": \"Failed to update channel archive status\",\n \"Failed to update channel mute status\": \"Failed to update channel mute status\",\n \"Failed to update channel pinned status\": \"Failed to update channel pinned status\",\n \"File\": \"File\",\n \"File is required for upload attachment\": \"File is required for upload attachment\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"File is too large: {{ size }}, maximum upload size is {{ limit }}\",\n \"File too large\": \"File too large\",\n \"fileCount_one\": \"File\",\n \"fileCount_other\": \"{{ count }} files\",\n \"Files\": \"Files\",\n \"Flag\": \"Flag\",\n \"Generating...\": \"Generating...\",\n \"giphy-command-args\": \"[text]\",\n \"giphy-command-description\": \"Post a random gif to the channel\",\n \"Go back\": \"Go back\",\n \"Group info\": \"Group info\",\n \"Group name\": \"Group name\",\n \"Hide who voted\": \"Hide Who Voted\",\n \"Image\": \"Image\",\n \"imageCount_one\": \"Image\",\n \"imageCount_other\": \"{{ count }} images\",\n \"Instant commands\": \"Instant commands\",\n \"language/af\": \"Afrikaans\",\n \"language/am\": \"Amharic\",\n \"language/ar\": \"Arabic\",\n \"language/az\": \"Azerbaijani\",\n \"language/bg\": \"Bulgarian\",\n \"language/bn\": \"Bengali\",\n \"language/bs\": \"Bosnian\",\n \"language/cs\": \"Czech\",\n \"language/da\": \"Danish\",\n \"language/de\": \"German\",\n \"language/el\": \"Greek\",\n \"language/en\": \"English\",\n \"language/es\": \"Spanish\",\n \"language/es-MX\": \"Spanish (Mexico)\",\n \"language/et\": \"Estonian\",\n \"language/fa\": \"Persian\",\n \"language/fa-AF\": \"Dari\",\n \"language/fi\": \"Finnish\",\n \"language/fr\": \"French\",\n \"language/fr-CA\": \"French (Canada)\",\n \"language/ha\": \"Hausa\",\n \"language/he\": \"Hebrew\",\n \"language/hi\": \"Hindi\",\n \"language/hr\": \"Croatian\",\n \"language/ht\": \"Haitian Creole\",\n \"language/hu\": \"Hungarian\",\n \"language/id\": \"Indonesian\",\n \"language/it\": \"Italian\",\n \"language/ja\": \"Japanese\",\n \"language/ka\": \"Georgian\",\n \"language/ko\": \"Korean\",\n \"language/lt\": \"Lithuanian\",\n \"language/lv\": \"Latvian\",\n \"language/ms\": \"Malay\",\n \"language/nl\": \"Dutch\",\n \"language/no\": \"Norwegian\",\n \"language/pl\": \"Polish\",\n \"language/ps\": \"Pashto\",\n \"language/pt\": \"Portuguese\",\n \"language/ro\": \"Romanian\",\n \"language/ru\": \"Russian\",\n \"language/sk\": \"Slovak\",\n \"language/sl\": \"Slovenian\",\n \"language/so\": \"Somali\",\n \"language/sq\": \"Albanian\",\n \"language/sr\": \"Serbian\",\n \"language/sv\": \"Swedish\",\n \"language/sw\": \"Swahili\",\n \"language/ta\": \"Tamil\",\n \"language/th\": \"Thai\",\n \"language/tl\": \"Tagalog\",\n \"language/tr\": \"Turkish\",\n \"language/uk\": \"Ukrainian\",\n \"language/ur\": \"Urdu\",\n \"language/vi\": \"Vietnamese\",\n \"language/zh\": \"Chinese (Simplified)\",\n \"language/zh-TW\": \"Chinese (Traditional)\",\n \"Last seen {{ timestamp }}\": \"Last seen {{ timestamp }}\",\n \"Leave Channel\": \"Leave Channel\",\n \"Leave chat\": \"Leave chat\",\n \"Left channel\": \"Left channel\",\n \"Let others add options\": \"Let Others Add Options\",\n \"Limit votes per person\": \"Limit Votes per Person\",\n \"Link\": \"Link\",\n \"linkCount_one\": \"Link\",\n \"linkCount_other\": \"{{ count }} links\",\n \"live\": \"live\",\n \"Live for {{duration}}\": \"Live for {{duration}}\",\n \"Live location\": \"Live location\",\n \"Live until {{ timestamp }}\": \"Live until {{ timestamp }}\",\n \"Load more\": \"Load more\",\n \"Local upload attachment missing local id\": \"Local upload attachment missing local id\",\n \"Location\": \"Location\",\n \"Location sharing ended\": \"Location sharing ended\",\n \"Location: {{ coordinates }}\": \"Location: {{ coordinates }}\",\n \"Manage channel\": \"Manage channel\",\n \"Manage members\": \"Manage members\",\n \"Mark as unread\": \"Mark as unread\",\n \"Maximum number of votes (from 2 to 10)\": \"Maximum number of votes (from 2 to 10)\",\n \"Maximum votes per person\": \"Maximum votes per person\",\n \"Member detail\": \"Member detail\",\n \"mention/Channel\": \"Channel\",\n \"mention/Channel Description\": \"Notify everyone in this channel\",\n \"mention/Here\": \"Here\",\n \"mention/Here Description\": \"Notify every online member in this channel\",\n \"Menu\": \"Menu\",\n \"Message deleted\": \"Message deleted\",\n \"Message failed to send\": \"Message failed to send\",\n \"Message has been successfully flagged\": \"Message has been successfully flagged\",\n \"Message marked as unread\": \"Message marked as unread\",\n \"Message pinned\": \"Message pinned\",\n \"Message unpinned\": \"Message unpinned\",\n \"Message was blocked by moderation policies\": \"Message was blocked by moderation policies\",\n \"Messages have been marked unread.\": \"Messages have been marked unread.\",\n \"Missing permissions to upload the attachment\": \"Missing permissions to upload the attachment\",\n \"Moderator\": \"Moderator\",\n \"Multiple votes\": \"Multiple Votes\",\n \"Mute\": \"Mute\",\n \"Mute chat\": \"Mute chat\",\n \"Mute user\": \"Mute user\",\n \"mute-command-args\": \"[@username]\",\n \"mute-command-description\": \"Mute a user\",\n \"network error\": \"network error\",\n \"New\": \"New\",\n \"New message from {{user}}\": \"New message from {{user}}\",\n \"New Messages!\": \"New Messages!\",\n \"Next\": \"Next\",\n \"Next image\": \"Next image\",\n \"No chats here yet…\": \"No chats here yet…\",\n \"No conversations yet\": \"No conversations yet\",\n \"No files\": \"No files\",\n \"No items exist\": \"No items exist\",\n \"No member found\": \"No member found\",\n \"No messages found\": \"No messages found\",\n \"No photos or videos\": \"No photos or videos\",\n \"No pinned messages\": \"No pinned messages\",\n \"No results found\": \"No results found\",\n \"No user found\": \"No user found\",\n \"Nobody will be able to vote in this poll anymore.\": \"Nobody will be able to vote in this poll anymore.\",\n \"Nothing yet...\": \"Nothing yet...\",\n \"Notify all {{ role }} members\": \"Notify all {{ role }} members\",\n \"Offline\": \"Offline\",\n \"Ok\": \"Ok\",\n \"Online\": \"Online\",\n \"Only numbers are allowed\": \"Only numbers are allowed\",\n \"Only visible to you\": \"Only visible to you\",\n \"Open emoji picker\": \"Open emoji picker\",\n \"Open gallery at image {{ index }}\": \"Open gallery at image {{ index }}\",\n \"Open image in gallery\": \"Open image in gallery\",\n \"Open location in a map\": \"Open location in a map\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"Open menu\",\n \"Option already exists\": \"Option already exists\",\n \"Option is empty\": \"Option is empty\",\n \"Options\": \"Options\",\n \"Original\": \"Original\",\n \"Owner\": \"Owner\",\n \"People matching\": \"People matching\",\n \"Photo\": \"Photo\",\n \"Photos & videos\": \"Photos & videos\",\n \"Pin\": \"Pin\",\n \"Pin a message to see it here\": \"Pin a message to see it here\",\n \"Pinned by {{ name }}\": \"Pinned by {{ name }}\",\n \"Pinned by You\": \"Pinned by You\",\n \"Pinned message\": \"Pinned message\",\n \"Pinned messages\": \"Pinned messages\",\n \"placeholder/PollComment\": \"Your comment\",\n \"placeholder/PollOptionSuggestion\": \"Enter a new option\",\n \"Play video\": \"Play video\",\n \"Playback speed {{ rate }}x\": \"Playback speed {{ rate }}x\",\n \"Poll\": \"Poll\",\n \"Poll comments\": \"Poll Comments\",\n \"Poll ended\": \"Poll Ended\",\n \"Poll options\": \"Poll Options\",\n \"Poll results\": \"Poll Results\",\n \"Poll sent\": \"Poll sent\",\n \"Previous\": \"Previous\",\n \"Previous image\": \"Previous image\",\n \"Question\": \"Question\",\n \"Question {{ optionOrderNumber}}\": \"Question {{ optionOrderNumber}}\",\n \"Question is required\": \"Question is required\",\n \"Quote Reply\": \"Quote Reply\",\n \"Reached the vote limit. Remove an existing vote first.\": \"Reached the vote limit. Remove an existing vote first.\",\n \"Recording format is not supported and cannot be reproduced\": \"Recording format is not supported and cannot be reproduced\",\n \"Remind me\": \"Remind me\",\n \"Remind Me\": \"Remind Me\",\n \"Reminder set\": \"Reminder set\",\n \"Remove\": \"Remove\",\n \"Remove {{ count }} members_one\": \"Remove {{ count }} member\",\n \"Remove {{ count }} members_other\": \"Remove {{ count }} members\",\n \"Remove {{ member }} from this channel?\": \"Remove {{ member }} from this channel?\",\n \"Remove channel members\": \"Remove channel members\",\n \"Remove reminder\": \"Remove reminder\",\n \"Remove save for later\": \"Remove save for later\",\n \"Remove user\": \"Remove user\",\n \"Removed {{ count }} members_one\": \"Removed {{ count }} member\",\n \"Removed {{ count }} members_other\": \"Removed {{ count }} members\",\n \"Replied to a thread\": \"Replied to a thread\",\n \"Reply\": \"Reply\",\n \"Reply to {{ authorName }}\": \"Reply to {{ authorName }}\",\n \"Reply to a message to start a thread\": \"Reply to a message to start a thread\",\n \"Reply to Message\": \"Reply to Message\",\n \"replyCount_one\": \"1 reply\",\n \"replyCount_other\": \"{{ count }} replies\",\n \"Resend\": \"Resend\",\n \"Retry upload\": \"Retry upload\",\n \"Review all options available in this poll\": \"Review all options available in this poll\",\n \"Review comments submitted with poll answers\": \"Review comments submitted with poll answers\",\n \"Review poll results and open an option to see detailed votes\": \"Review poll results and open an option to see detailed votes\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Review this message and choose whether to delete it, edit it, or send it anyway\",\n \"Review who voted for this option\": \"Review who voted for this option\",\n \"Save\": \"Save\",\n \"Save for later\": \"Save for later\",\n \"Saved for later\": \"Saved for later\",\n \"Search\": \"Search\",\n \"Search GIFs\": \"Search GIFs\",\n \"search-results-header-filter-source-button-label--channels\": \"channels\",\n \"search-results-header-filter-source-button-label--messages\": \"messages\",\n \"search-results-header-filter-source-button-label--users\": \"users\",\n \"Searching for {{ searchSourceType }}...\": \"Searching for {{ searchSourceType }}...\",\n \"Searching...\": \"Searching...\",\n \"searchResultsCount_one\": \"1 result\",\n \"searchResultsCount_other\": \"{{ count }} results\",\n \"Select a thread to continue the conversation\": \"Select a thread to continue the conversation\",\n \"Select more than one option\": \"Select More Than One Option\",\n \"Select one\": \"Select one\",\n \"Select one or more\": \"Select one or more\",\n \"Select up to {{count}}_one\": \"Select up to {{count}}\",\n \"Select up to {{count}}_other\": \"Select up to {{count}}\",\n \"Select your current location and optionally enable live location sharing\": \"Select your current location and optionally enable live location sharing\",\n \"Send\": \"Send\",\n \"Send a message\": \"Send a message\",\n \"Send a message to start the conversation\": \"Send a message to start the conversation\",\n \"Send Anyway\": \"Send Anyway\",\n \"Send direct message\": \"Send direct message\",\n \"Send message request failed\": \"Send message request failed\",\n \"Send poll\": \"Send Poll\",\n \"Sending...\": \"Sending...\",\n \"Sent\": \"Sent\",\n \"Share\": \"Share\",\n \"Share a file to see it here\": \"Share a file to see it here\",\n \"Share a photo or video to see it here\": \"Share a photo or video to see it here\",\n \"Share live location for\": \"Share live location for\",\n \"Share Location\": \"Share Location\",\n \"Shared live location\": \"Shared live location\",\n \"Shared location\": \"Shared location\",\n \"Shuffle\": \"Shuffle\",\n \"size limit\": \"size limit\",\n \"Slow Mode ON\": \"Slow Mode ON\",\n \"Slow mode, wait {{ seconds }}s...\": \"Slow mode, wait {{ seconds }}s...\",\n \"Some of the files will not be accepted\": \"Some of the files will not be accepted\",\n \"Start typing to search\": \"Start typing to search\",\n \"Stop sharing\": \"Stop sharing\",\n \"Submit\": \"Submit\",\n \"Suggest a new option to add to this poll\": \"Suggest a new option to add to this poll\",\n \"Suggest an option\": \"Suggest an Option\",\n \"Tap to remove\": \"Tap to remove\",\n \"Tap to remove: {{ reactionName }}\": \"Tap to remove: {{ reactionName }}\",\n \"Thinking...\": \"Thinking...\",\n \"this content could not be displayed\": \"this content could not be displayed\",\n \"This field cannot be empty or contain only spaces\": \"This field cannot be empty or contain only spaces\",\n \"This message did not meet our content guidelines\": \"This message did not meet our content guidelines\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"This user will be able to message you again.\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"Thread\",\n \"Thread has not been found\": \"Thread has not been found\",\n \"Thread reply\": \"Thread reply\",\n \"Thread Reply\": \"Thread Reply\",\n \"ThreadListUnseenThreadsBanner/loading\": \"Loading...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} unread thread\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} unread threads\",\n \"Threads\": \"Threads\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today]\\\", \\\"nextDay\\\": \\\"[Tomorrow]\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Last] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"{{ count }}d ago\",\n \"timestamp/relativeToday\": \"Today\",\n \"timestamp/relativeWeeksAgo\": \"{{ count }}w ago\",\n \"timestamp/relativeYesterday\": \"Yesterday\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Today] [at] HH:mm\\\", \\\"nextDay\\\": \\\"[Tomorrow] [at] HH:mm\\\", \\\"lastDay\\\": \\\"[Yesterday] [at] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [at] HH:mm\\\", \\\"lastWeek\\\": \\\"[Last] dddd [at] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [at] HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"To start recording, allow the camera access in your browser\",\n \"To start recording, allow the microphone access in your browser\": \"To start recording, allow the microphone access in your browser\",\n \"totalVoteCount_one\": \"1 vote total\",\n \"totalVoteCount_other\": \"{{ count }} votes total\",\n \"Translated\": \"Translated\",\n \"Translated from {{ language }}\": \"Translated from {{ language }}\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"Type a number from 2 to 10\",\n \"Unarchive\": \"Unarchive\",\n \"unban-command-args\": \"[@username]\",\n \"unban-command-description\": \"Unban a user\",\n \"Unblock\": \"Unblock\",\n \"Unblock user\": \"Unblock user\",\n \"Unblock User\": \"Unblock User\",\n \"unknown error\": \"unknown error\",\n \"Unmute\": \"Unmute\",\n \"Unmute chat\": \"Unmute chat\",\n \"Unmute user\": \"Unmute user\",\n \"unmute-command-args\": \"[@username]\",\n \"unmute-command-description\": \"Unmute a user\",\n \"Unpin\": \"Unpin\",\n \"Unread messages\": \"Unread messages\",\n \"Unsupported attachment\": \"Unsupported attachment\",\n \"unsupported file type\": \"unsupported file type\",\n \"Update\": \"Update\",\n \"Update the comment attached to your poll answer\": \"Update the comment attached to your poll answer\",\n \"Update your comment\": \"Update Your Comment\",\n \"Upload blocked\": \"Upload blocked\",\n \"Upload error\": \"Upload error\",\n \"Upload failed\": \"Upload failed\",\n \"Upload Picture\": \"Upload Picture\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Upload type: \\\"{{ type }}\\\" is not allowed\",\n \"User blocked\": \"User blocked\",\n \"User muted\": \"User muted\",\n \"User removed\": \"User removed\",\n \"User unblocked\": \"User unblocked\",\n \"User unmuted\": \"User unmuted\",\n \"User uploaded content\": \"User uploaded content\",\n \"Video\": \"Video\",\n \"videoCount_one\": \"Video\",\n \"videoCount_other\": \"{{ count }} videos\",\n \"View\": \"View\",\n \"View {{count}} comments_one\": \"View {{count}} Comment\",\n \"View {{count}} comments_other\": \"View {{count}} Comments\",\n \"View all\": \"View all\",\n \"View member details for {{ member }}\": \"View member details for {{ member }}\",\n \"View original\": \"View original\",\n \"View results\": \"View Results\",\n \"View translation\": \"View translation\",\n \"Voice message\": \"Voice message\",\n \"Voice message {{ duration }}\": \"Voice message {{ duration }}\",\n \"Voice message deleted\": \"Voice message deleted\",\n \"voiceMessageCount_one\": \"Voice message\",\n \"voiceMessageCount_other\": \"{{ count }} voice messages\",\n \"Vote ended\": \"Vote ended\",\n \"Votes\": \"Votes\",\n \"Wait until all attachments have uploaded\": \"Wait until all attachments have uploaded\",\n \"Waiting for network…\": \"Waiting for network…\",\n \"You\": \"You\",\n \"You've reached the maximum number of files\": \"You've reached the maximum number of files\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} y {{ moreCount }} más\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} y {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} archivo\",\n \"{{ count }} files_many\": \"{{ count }} archivos\",\n \"{{ count }} files_other\": \"{{ count }} archivos\",\n \"{{ count }} members_one\": \"{{ count }} miembro\",\n \"{{ count }} members_many\": \"{{ count }} miembros\",\n \"{{ count }} members_other\": \"{{ count }} miembros\",\n \"{{ count }} members added_one\": \"{{ count }} miembro añadido\",\n \"{{ count }} members added_many\": \"{{ count }} miembros añadidos\",\n \"{{ count }} members added_other\": \"{{ count }} miembros añadidos\",\n \"{{ count }} people are typing_one\": \"{{ count }} persona está escribiendo\",\n \"{{ count }} people are typing_many\": \"{{ count }} personas están escribiendo\",\n \"{{ count }} people are typing_other\": \"{{ count }} personas están escribiendo\",\n \"{{ count }} photos_one\": \"{{ count }} foto\",\n \"{{ count }} photos_many\": \"{{ count }} fotos\",\n \"{{ count }} photos_other\": \"{{ count }} fotos\",\n \"{{ count }} reactions_one\": \"{{ count }} reacción\",\n \"{{ count }} reactions_many\": \"{{ count }} reacciones\",\n \"{{ count }} reactions_other\": \"{{ count }} reacciones\",\n \"{{ count }} videos_one\": \"{{ count }} vídeo\",\n \"{{ count }} videos_many\": \"{{ count }} vídeos\",\n \"{{ count }} videos_other\": \"{{ count }} vídeos\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} y {{ secondUser }}\",\n \"{{ imageCount }} more\": \"{{ imageCount }} más\",\n \"{{ member }} will be able to message you again.\": \"{{ member }} podrá enviarte mensajes de nuevo.\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }} ya no podrá enviarte mensajes.\",\n \"{{ memberCount }} members\": \"{{ memberCount }} miembros\",\n \"{{ typing }} are typing\": \"{{ typing }} están escribiendo\",\n \"{{ typing }} is typing\": \"{{ typing }} está escribiendo\",\n \"{{ user }} has been muted\": \"{{ user }} ha sido silenciado\",\n \"{{ user }} has been unmuted\": \"Se ha desactivado el silencio de {{ user }}\",\n \"{{ user }} is typing...\": \"{{ user }} está escribiendo...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} y {{ user }} están escribiendo...\",\n \"{{ users }} and more are typing...\": \"{{ users }} y más están escribiendo...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} en línea\",\n \"{{count}} new messages_one\": \"{{count}} nuevo mensaje\",\n \"{{count}} new messages_many\": \"{{count}} nuevos mensajes\",\n \"{{count}} new messages_other\": \"{{count}} nuevos mensajes\",\n \"{{count}} unread_one\": \"{{count}} no leído\",\n \"{{count}} unread_many\": \"{{count}} no leídos\",\n \"{{count}} unread_other\": \"{{count}} no leídos\",\n \"{{count}} votes_one\": \"1 voto\",\n \"{{count}} votes_many\": \"{{count}} votos\",\n \"{{count}} votes_other\": \"{{count}} votos\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"+{{count}} opción más\",\n \"+{{count}} more options_many\": \"+{{count}} opciones más\",\n \"+{{count}} more options_other\": \"+{{count}} opciones más\",\n \"🏙 Attachment...\": \"🏙 Adjunto...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} creó: {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} votó: {{pollOptionText}}\",\n \"📍Shared location\": \"📍Ubicación compartida\",\n \"Actions\": \"Actions\",\n \"Add\": \"Añadir\",\n \"Add {{ count }} members_one\": \"Añadir {{ count }} miembro\",\n \"Add {{ count }} members_many\": \"Añadir {{ count }} miembros\",\n \"Add {{ count }} members_other\": \"Añadir {{ count }} miembros\",\n \"Add a comment\": \"Agregar un comentario\",\n \"Add a comment to your poll answer\": \"Añade un comentario a tu respuesta de la encuesta\",\n \"Add an option\": \"Agregar una opción\",\n \"Add channel members\": \"Añadir miembros al canal\",\n \"Add members\": \"Añadir miembros\",\n \"Add reaction\": \"Añadir reacción\",\n \"Admin\": \"Administrador\",\n \"All results loaded\": \"Todos los resultados cargados\",\n \"Allow access to camera\": \"Permitir acceso a la cámara\",\n \"Allow access to microphone\": \"Permitir acceso al micrófono\",\n \"Allow comments\": \"Permitir comentarios\",\n \"Allow option suggestion\": \"Permitir sugerencia de opciones\",\n \"Allow others to add comments\": \"Permitir que otros añadan comentarios\",\n \"Already a member\": \"Ya es miembro\",\n \"Also send as a direct message\": \"También enviar como mensaje directo\",\n \"Also send in channel\": \"También enviar en el canal\",\n \"Also sent in channel\": \"También enviado en el canal\",\n \"An error has occurred during recording\": \"Se ha producido un error durante la grabación\",\n \"An error has occurred during the recording processing\": \"Se ha producido un error durante el procesamiento de la grabación\",\n \"Anonymous\": \"Anónimo\",\n \"Anonymous poll\": \"Encuesta anónima\",\n \"Archive\": \"Archivo\",\n \"Are you sure you want to delete this message?\": \"¿Estás seguro de que quieres eliminar este mensaje?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_one\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_many\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_one\": \"{{ count }} adjunto\",\n \"aria/{{ count }} attachment_many\": \"{{ count }} adjuntos\",\n \"aria/{{ count }} attachment_other\": \"{{ count }} adjuntos\",\n \"aria/{{ count }} search results_one\": \"{{ count }} resultado de búsqueda\",\n \"aria/{{ count }} search results_many\": \"{{ count }} resultados de búsqueda\",\n \"aria/{{ count }} search results_other\": \"{{ count }} resultados de búsqueda\",\n \"aria/{{ count }} suggestions_one\": \"{{ count }} sugerencia\",\n \"aria/{{ count }} suggestions_many\": \"{{ count }} sugerencias\",\n \"aria/{{ count }} suggestions_other\": \"{{ count }} sugerencias\",\n \"aria/{{ count }} unread message_one\": \"{{ count }} mensaje sin leer\",\n \"aria/{{ count }} unread message_many\": \"{{ count }} mensajes sin leer\",\n \"aria/{{ count }} unread message_other\": \"{{ count }} mensajes sin leer\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} desactivado\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} activado\",\n \"aria/Active\": \"Activo\",\n \"aria/Animated GIF\": \"GIF animado\",\n \"aria/Animated GIF: {{ title }}\": \"GIF animado: {{ title }}\",\n \"aria/Attachment\": \"Adjunto\",\n \"aria/Attachment {{ attachmentType }}\": \"Adjunto {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"Acciones del adjunto\",\n \"aria/audio\": \"audio\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Posición de audio {{ elapsed }} de {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"Posición de audio {{ progress }} por ciento\",\n \"aria/Back to attachments\": \"Volver a adjuntos\",\n \"aria/Back to parent menu button\": \"Volver al menú superior botón\",\n \"aria/Block User\": \"Bloquear usuario\",\n \"aria/Bookmark Message\": \"Guardar mensaje\",\n \"aria/Cancel recording\": \"Cancelar grabación\",\n \"aria/Cancel Reply\": \"Cancelar respuesta\",\n \"aria/Channel Actions\": \"Acciones del canal\",\n \"aria/Channel details\": \"Detalles del canal\",\n \"aria/Channel list\": \"Lista de canales\",\n \"aria/Chat view controls\": \"Controles de la vista del chat\",\n \"aria/Chat: {{ channelName }}\": \"Chat: {{ channelName }}\",\n \"aria/Clear search\": \"Borrar búsqueda\",\n \"aria/Close callout dialog\": \"Cerrar diálogo de aviso\",\n \"aria/Close thread\": \"Cerrar hilo\",\n \"aria/Collapse sidebar\": \"Contraer barra lateral\",\n \"aria/Command activated: {{ command }}\": \"Comando activado: {{ command }}\",\n \"aria/Command Suggestions\": \"Sugerencias de comandos\",\n \"aria/Complete recording\": \"Completar grabación\",\n \"aria/Copy Message Text\": \"Copiar texto del mensaje\",\n \"aria/Decrease value\": \"Disminuir valor\",\n \"aria/Delete Message\": \"Eliminar mensaje\",\n \"aria/Delivered\": \"Entregado\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"Estado de entrega: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"Descartar notificación\",\n \"aria/Download attachment\": \"Descargar adjunto\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"«{{ option }}» soltada en la posición {{ position }}.\",\n \"aria/Edit Message\": \"Editar mensaje\",\n \"aria/Emoji picker\": \"Selector de emojis\",\n \"aria/Emoji Suggestions\": \"Sugerencias de emojis\",\n \"aria/Exit search\": \"Salir de la búsqueda\",\n \"aria/Expand sidebar\": \"Expandir barra lateral\",\n \"aria/file\": \"archivo\",\n \"aria/File upload\": \"Carga de archivo\",\n \"aria/Flag Message\": \"Marcar mensaje\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Acciones de Giphy\",\n \"aria/Giphy canceled\": \"Giphy cancelado\",\n \"aria/Giphy image changed\": \"Imagen de Giphy cambiada\",\n \"aria/Giphy image changed: {{ title }}\": \"Imagen de Giphy cambiada: {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Vista previa de Giphy, solo visible para ti. Usa las acciones Enviar, Mezclar o Cancelar.\",\n \"aria/Giphy sent\": \"Giphy enviado\",\n \"aria/image\": \"imagen\",\n \"aria/Image failed to load\": \"Error al cargar la imagen\",\n \"aria/Increase value\": \"Aumentar valor\",\n \"aria/Jump to latest message\": \"Ir al mensaje más reciente\",\n \"aria/Jump to quoted message\": \"Ir al mensaje citado\",\n \"aria/Last activity: {{ time }}\": \"Última actividad: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"Último mensaje de {{ sender }}: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"Último mensaje: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"Marcar como no leído\",\n \"aria/Mark messages as read\": \"Marcar mensajes como leídos\",\n \"aria/Mention Suggestions\": \"Sugerencias de menciones\",\n \"aria/Message Actions\": \"Acciones del mensaje\",\n \"aria/Message from {{ user }},\": \"Mensaje de {{ user }},\",\n \"aria/Message input\": \"Entrada de mensaje\",\n \"aria/Message with attachments\": \"Mensaje con adjuntos\",\n \"aria/Message,\": \"Mensaje,\",\n \"aria/Mute User\": \"Silenciar usuario\",\n \"aria/Next page\": \"Página siguiente\",\n \"aria/No search results found\": \"No se encontraron resultados de búsqueda\",\n \"aria/Notifications\": \"Notificaciones\",\n \"aria/Open Attachment Selector\": \"Abrir selector de adjuntos\",\n \"aria/Open Channel Actions Menu\": \"Abrir menú de acciones del canal\",\n \"aria/Open channel details\": \"Abrir detalles del canal\",\n \"aria/Open channels view\": \"Abrir vista de canales\",\n \"aria/Open image shared by {{ name }}\": \"Abrir imagen compartida por {{ name }}\",\n \"aria/Open Message Actions Menu\": \"Abrir menú de acciones de mensaje\",\n \"aria/Open Reaction Selector\": \"Abrir selector de reacciones\",\n \"aria/Open Thread\": \"Abrir hilo\",\n \"aria/Open threads view\": \"Abrir vista de hilos\",\n \"aria/Open threads view with unread threads_one\": \"Abrir vista de hilos, {{ count }} hilo no leído\",\n \"aria/Open threads view with unread threads_many\": \"Abrir vista de hilos, {{ count }} hilos no leídos\",\n \"aria/Open threads view with unread threads_other\": \"Abrir vista de hilos, {{ count }} hilos no leídos\",\n \"aria/Open video shared by {{ name }}\": \"Abrir video compartido por {{ name }}\",\n \"aria/Opened channel: {{ name }}\": \"Canal abierto: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"Hilo abierto en {{ name }}\",\n \"aria/Option {{ position }}\": \"Opción {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"Ahora las opciones se pueden reordenar y eliminar.\",\n \"aria/Pause\": \"Pausar\",\n \"aria/Pause recording\": \"Pausar grabación\",\n \"aria/Percent complete\": \"{{percent}} por ciento completado\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"Has cogido «{{ option }}». Usa las flechas para reordenar. Pulsa Espacio o Tab para soltarla.\",\n \"aria/Pin Message\": \"Fijar mensaje\",\n \"aria/Play\": \"Reproducir\",\n \"aria/Poll dialog opened\": \"Cuadro de diálogo de encuesta abierto\",\n \"aria/Poll sent\": \"Encuesta enviada\",\n \"aria/Poll: {{ pollName }}\": \"Encuesta: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Pulsa Intro para empezar a escribir\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"Pulsa la barra espaciadora para seleccionar esta opción, usa las flechas Arriba y Abajo para moverla y, después, vuelve a pulsar la barra espaciadora para deseleccionarla.\",\n \"aria/Previous page\": \"Página anterior\",\n \"aria/Quote Message\": \"Citar mensaje\",\n \"aria/Reaction list\": \"Lista de reacciones\",\n \"aria/Read\": \"Leído\",\n \"aria/Recording paused\": \"Grabación pausada\",\n \"aria/Recording resumed\": \"Grabación reanudada\",\n \"aria/Recording started\": \"Grabación iniciada\",\n \"aria/Remind Me Message\": \"Recordarme\",\n \"aria/Remove attachment\": \"Eliminar adjunto\",\n \"aria/Remove location attachment\": \"Eliminar adjunto de ubicación\",\n \"aria/Remove option: {{ option }}\": \"Eliminar opción: {{ option }}\",\n \"aria/Remove Reminder\": \"Quitar recordatorio\",\n \"aria/Remove Save For Later\": \"Quitar guardar para después\",\n \"aria/Removed option {{ option }}\": \"Opción {{ option }} eliminada\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"Reordenar «{{ option }}», posición {{ position }} de {{ total }}\",\n \"aria/Reorder option {{ position }}\": \"Reordenar opción {{ position }}\",\n \"aria/Resend Message\": \"Reenviar mensaje\",\n \"aria/Resume recording\": \"Reanudar grabación\",\n \"aria/Retry upload\": \"Reintentar carga\",\n \"aria/Review bounced message\": \"Revisar mensaje rebotado\",\n \"aria/Search cleared\": \"Búsqueda borrada\",\n \"aria/Search results\": \"Resultados de búsqueda\",\n \"aria/Search results header filter button for: {{ source }}\": \"Botón de filtro del encabezado de resultados de búsqueda para: {{ source }}\",\n \"aria/Seek audio position\": \"Buscar posición de audio\",\n \"aria/Select Reaction: {{ reactionName }}\": \"Seleccionar reacción: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"Seleccionar canal de usuario: {{ name }}\",\n \"aria/Send\": \"Enviar\",\n \"aria/Sent\": \"Enviado\",\n \"aria/Shared a link\": \"Enlace compartido\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"Enlace compartido con título: {{ linkTitle }}\",\n \"aria/Shared location\": \"Ubicación compartida\",\n \"aria/Show preview\": \"Mostrar vista previa\",\n \"aria/Start recording audio\": \"Iniciar grabación de audio\",\n \"aria/Stop AI Generation\": \"Detener generación de IA\",\n \"aria/Submenu\": \"Submenú\",\n \"aria/Suggestions\": \"Sugerencias\",\n \"aria/There are no messages in this chat.\": \"No hay mensajes en este chat\",\n \"aria/This option can be reordered and removed.\": \"Esta opción se puede reordenar y eliminar.\",\n \"aria/Thread list\": \"Lista de hilos\",\n \"aria/Thread: {{ messagePreview }}\": \"Hilo: {{ messagePreview }}\",\n \"aria/Unblock User\": \"Desbloquear usuario\",\n \"aria/Unmute User\": \"Activar sonido\",\n \"aria/Unpin Message\": \"Desfijar mensaje\",\n \"aria/User selected: {{ user }}\": \"Usuario seleccionado: {{ user }}\",\n \"aria/video\": \"vídeo\",\n \"aria/voice message\": \"mensaje de voz\",\n \"aria/Voice message sent\": \"Mensaje de voz enviado\",\n \"aria/Voice recording attached\": \"Grabación de voz adjuntada\",\n \"Ask a question\": \"Hacer una pregunta\",\n \"Attach\": \"Adjuntar\",\n \"Attach files\": \"Adjuntar archivos\",\n \"Attachment\": \"Archivo adjunto\",\n \"Attachment upload blocked due to {{reason}}\": \"Carga de adjunto bloqueada debido a {{reason}}\",\n \"Attachment upload failed due to {{reason}}\": \"Carga de adjunto fallida debido a {{reason}}\",\n \"Back\": \"Atrás\",\n \"ban-command-args\": \"[@usuario] [texto]\",\n \"ban-command-description\": \"Prohibir a un usuario\",\n \"Block user\": \"Bloquear usuario\",\n \"Block User\": \"Bloquear usuario\",\n \"Browse channel members\": \"Explorar miembros del canal\",\n \"Browse pinned messages\": \"Explorar mensajes fijados\",\n \"Cancel\": \"Cancelar\",\n \"Cannot seek in the recording\": \"No se puede buscar en la grabación\",\n \"Changes saved\": \"Cambios guardados\",\n \"Channel archived\": \"Canal archivado\",\n \"Channel members\": \"Miembros del canal\",\n \"Channel Missing\": \"Falta canal\",\n \"Channel muted\": \"Canal silenciado\",\n \"Channel pinned\": \"Canal fijado\",\n \"Channel unarchived\": \"Canal desarchivado\",\n \"Channel unmuted\": \"Silencio del canal desactivado\",\n \"Channel unpinned\": \"Canal desanclado\",\n \"Channels\": \"Canales\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"Chats\",\n \"Choose between 2 to 10 options\": \"Elige entre 2 y 10 opciones\",\n \"Close\": \"Cerrar\",\n \"Close dialog\": \"Cerrar diálogo\",\n \"Close emoji picker\": \"Cerrar el selector de emojis\",\n \"Command not available while editing\": \"Comando no disponible durante la edición\",\n \"Command not available while replying\": \"Comando no disponible mientras se responde\",\n \"Commands\": \"Comandos\",\n \"Commands matching\": \"Coincidencia de comandos\",\n \"Connection failure, reconnecting now...\": \"Fallo de conexión, reconectando ahora...\",\n \"Contact info\": \"Información de contacto\",\n \"Contact name\": \"Nombre del contacto\",\n \"Copy Message\": \"Copiar mensaje\",\n \"Create\": \"Crear\",\n \"Create a question, add options, and configure poll settings\": \"Crea una pregunta, añade opciones y configura los ajustes de la encuesta\",\n \"Create poll\": \"Crear encuesta\",\n \"Current location\": \"Ubicación actual\",\n \"Delete\": \"Borrar\",\n \"Delete chat\": \"Eliminar chat\",\n \"Delete for me\": \"Eliminar para mí\",\n \"Delete message\": \"Eliminar mensaje\",\n \"Delivered\": \"Entregado\",\n \"Direct message\": \"Mensaje directo\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"¿Quieres terminar esta encuesta ahora? Nadie podrá votar más en esta encuesta.\",\n \"Download {{ fileName }}\": \"Descargar {{ fileName }}\",\n \"Download All\": \"Descargar todo\",\n \"Download Attachment\": \"Descargar archivo adjunto\",\n \"Download attachment {{ name }}\": \"Descargar adjunto {{ name }}\",\n \"Download attachment {{ number }}\": \"Descargar adjunto {{ number }}\",\n \"Drag your files here\": \"Arrastra tus archivos aquí\",\n \"Drag your files here to add to your post\": \"Arrastra tus archivos aquí para agregarlos a tu publicación\",\n \"Due {{ timeLeft }}\": \"Vence en {{ timeLeft }}\",\n \"Due since {{ dueSince }}\": \"Vencido desde {{ dueSince }}\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"Editar\",\n \"Edit chat data\": \"Editar datos del chat\",\n \"Edit contact\": \"Editar contacto\",\n \"Edit group\": \"Editar grupo\",\n \"Edit Message\": \"Editar mensaje\",\n \"Edit message request failed\": \"Error al editar la solicitud de mensaje\",\n \"Edited\": \"Editado\",\n \"Emoji matching\": \"Coincidencia de emoji\",\n \"Empty message...\": \"Mensaje vacío...\",\n \"End\": \"Final\",\n \"End poll\": \"Terminar encuesta\",\n \"End this poll?\": \"¿Terminar esta encuesta?\",\n \"End vote\": \"Finalizar votación\",\n \"Enforce unique vote is enabled\": \"El voto único está habilitado\",\n \"Error\": \"Error\",\n \"Error adding flag\": \"Error al agregar la bandera\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"Error al bloquear al usuario\",\n \"Error connecting to chat, refresh the page to try again.\": \"Error al conectarse al chat, actualice la página para volver a intentarlo.\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"Error al eliminar el mensaje\",\n \"Error fetching reactions\": \"Error al cargar las reacciones\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Error al marcar el mensaje como no leído. No se pueden marcar mensajes no leídos más antiguos que los últimos 100 mensajes del canal.\",\n \"Error muting a user ...\": \"Error al silenciar el usuario...\",\n \"Error muting channel\": \"Error al silenciar el canal\",\n \"Error muting user\": \"Error al silenciar al usuario\",\n \"Error opening direct message\": \"Error al abrir el mensaje directo\",\n \"Error pinning message\": \"Error al fijar el mensaje\",\n \"Error removing members\": \"Error al eliminar a los miembros\",\n \"Error removing message pin\": \"Error al quitar el pin del mensaje\",\n \"Error removing user\": \"Error al eliminar al usuario\",\n \"Error reproducing the recording\": \"Error al reproducir la grabación\",\n \"Error starting recording\": \"Error al iniciar la grabación\",\n \"Error unblocking user\": \"Error al desbloquear usuario\",\n \"Error unmuting a user ...\": \"Error al desactivar el silencio del usuario...\",\n \"Error unmuting channel\": \"Error al desactivar el silencio del canal\",\n \"Error unmuting user\": \"Error al desactivar el silencio del usuario\",\n \"Error uploading attachment\": \"Error al subir el archivo adjunto\",\n \"Error uploading file\": \"Error al cargar el archivo\",\n \"Error uploading image\": \"Error al subir la imagen\",\n \"Error: {{ errorMessage }}\": \"Error: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"Salir del comando {{ command }}\",\n \"Failed to block user\": \"No se pudo bloquear al usuario\",\n \"Failed to create the poll\": \"Error al crear la encuesta\",\n \"Failed to create the poll due to {{reason}}\": \"No se pudo crear la encuesta debido a {{reason}}\",\n \"Failed to delete the message\": \"No se pudo eliminar el mensaje\",\n \"Failed to end the poll\": \"No se pudo terminar la encuesta\",\n \"Failed to end the poll due to {{reason}}\": \"No se pudo terminar la encuesta debido a {{reason}}\",\n \"Failed to jump to the first unread message\": \"Error al saltar al primer mensaje no leído\",\n \"Failed to leave channel\": \"No se pudo salir del canal\",\n \"Failed to load channels\": \"No se pudieron cargar los canales\",\n \"Failed to load more channels\": \"No se pudieron cargar más canales\",\n \"Failed to mark channel as read\": \"Error al marcar el canal como leído\",\n \"Failed to play the recording\": \"No se pudo reproducir la grabación\",\n \"Failed to retrieve location\": \"No se pudo obtener la ubicación\",\n \"Failed to save changes\": \"No se pudieron guardar los cambios\",\n \"Failed to share location\": \"No se pudo compartir la ubicación\",\n \"Failed to update channel archive status\": \"No se pudo actualizar el estado de archivo del canal\",\n \"Failed to update channel mute status\": \"No se pudo actualizar el estado de silencio del canal\",\n \"Failed to update channel pinned status\": \"No se pudo actualizar el estado de fijación del canal\",\n \"File\": \"Archivo\",\n \"File is required for upload attachment\": \"Se requiere un archivo para subir el adjunto\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"El archivo es demasiado grande: {{ size }}, el tamaño máximo de carga es de {{ limit }}\",\n \"File too large\": \"Archivo demasiado grande\",\n \"fileCount_one\": \"1 archivo\",\n \"fileCount_many\": \"{{ count }} archivos\",\n \"fileCount_other\": \"{{ count }} archivos\",\n \"Files\": \"Archivos\",\n \"Flag\": \"Marcar\",\n \"Generating...\": \"Generando...\",\n \"giphy-command-args\": \"[texto]\",\n \"giphy-command-description\": \"Publicar un gif aleatorio en el canal\",\n \"Go back\": \"Volver\",\n \"Group info\": \"Información del grupo\",\n \"Group name\": \"Nombre del grupo\",\n \"Hide who voted\": \"Ocultar quién votó\",\n \"Image\": \"Imagen\",\n \"imageCount_one\": \"Imagen\",\n \"imageCount_many\": \"{{ count }} imágenes\",\n \"imageCount_other\": \"{{ count }} imágenes\",\n \"Instant commands\": \"Comandos instantáneos\",\n \"language/af\": \"Afrikáans\",\n \"language/am\": \"Amárico\",\n \"language/ar\": \"Árabe\",\n \"language/az\": \"Azerbaiyano\",\n \"language/bg\": \"Búlgaro\",\n \"language/bn\": \"Bengalí\",\n \"language/bs\": \"Bosnio\",\n \"language/cs\": \"Checo\",\n \"language/da\": \"Danés\",\n \"language/de\": \"Alemán\",\n \"language/el\": \"Griego\",\n \"language/en\": \"Inglés\",\n \"language/es\": \"Español\",\n \"language/es-MX\": \"Español (México)\",\n \"language/et\": \"Estonio\",\n \"language/fa\": \"Persa\",\n \"language/fa-AF\": \"Dari\",\n \"language/fi\": \"Finlandés\",\n \"language/fr\": \"Francés\",\n \"language/fr-CA\": \"Francés (Canadá)\",\n \"language/ha\": \"Hausa\",\n \"language/he\": \"Hebreo\",\n \"language/hi\": \"Hindi\",\n \"language/hr\": \"Croata\",\n \"language/ht\": \"Criollo haitiano\",\n \"language/hu\": \"Húngaro\",\n \"language/id\": \"Indonesio\",\n \"language/it\": \"Italiano\",\n \"language/ja\": \"Japonés\",\n \"language/ka\": \"Georgiano\",\n \"language/ko\": \"Coreano\",\n \"language/lt\": \"Lituano\",\n \"language/lv\": \"Letón\",\n \"language/ms\": \"Malayo\",\n \"language/nl\": \"Neerlandés\",\n \"language/no\": \"Noruego\",\n \"language/pl\": \"Polaco\",\n \"language/ps\": \"Pastún\",\n \"language/pt\": \"Portugués\",\n \"language/ro\": \"Rumano\",\n \"language/ru\": \"Ruso\",\n \"language/sk\": \"Eslovaco\",\n \"language/sl\": \"Esloveno\",\n \"language/so\": \"Somalí\",\n \"language/sq\": \"Albanés\",\n \"language/sr\": \"Serbio\",\n \"language/sv\": \"Sueco\",\n \"language/sw\": \"Suajili\",\n \"language/ta\": \"Tamil\",\n \"language/th\": \"Tailandés\",\n \"language/tl\": \"Tagalo\",\n \"language/tr\": \"Turco\",\n \"language/uk\": \"Ucraniano\",\n \"language/ur\": \"Urdu\",\n \"language/vi\": \"Vietnamita\",\n \"language/zh\": \"Chino (simplificado)\",\n \"language/zh-TW\": \"Chino (tradicional)\",\n \"Last seen {{ timestamp }}\": \"Visto por última vez {{ timestamp }}\",\n \"Leave Channel\": \"Abandonar canal\",\n \"Leave chat\": \"Abandonar canal\",\n \"Left channel\": \"Canal abandonado\",\n \"Let others add options\": \"Permitir que otros añadan opciones\",\n \"Limit votes per person\": \"Limitar votos por persona\",\n \"Link\": \"Enlace\",\n \"linkCount_one\": \"Enlace\",\n \"linkCount_many\": \"{{ count }} enlaces\",\n \"linkCount_other\": \"{{ count }} enlaces\",\n \"live\": \"En vivo\",\n \"Live for {{duration}}\": \"En vivo durante {{duration}}\",\n \"Live location\": \"Ubicación en vivo\",\n \"Live until {{ timestamp }}\": \"En vivo hasta {{ timestamp }}\",\n \"Load more\": \"Cargar más\",\n \"Local upload attachment missing local id\": \"El adjunto de subida local no tiene id local\",\n \"Location\": \"Ubicación\",\n \"Location sharing ended\": \"Compartir ubicación terminado\",\n \"Location: {{ coordinates }}\": \"Ubicación: {{ coordinates }}\",\n \"Manage channel\": \"Gestionar canal\",\n \"Manage members\": \"Gestionar miembros\",\n \"Mark as unread\": \"Marcar como no leído\",\n \"Maximum number of votes (from 2 to 10)\": \"Número máximo de votos (de 2 a 10)\",\n \"Maximum votes per person\": \"Máximo de votos por persona\",\n \"Member detail\": \"Detalle del miembro\",\n \"mention/Channel\": \"Canal\",\n \"mention/Channel Description\": \"Notificar a todos en este canal\",\n \"mention/Here\": \"Aqui\",\n \"mention/Here Description\": \"Notificar a todos los miembros en línea de este canal\",\n \"Menu\": \"Menú\",\n \"Message deleted\": \"Mensaje eliminado\",\n \"Message failed to send\": \"No se pudo enviar el mensaje\",\n \"Message has been successfully flagged\": \"El mensaje se marcó correctamente\",\n \"Message marked as unread\": \"Mensaje marcado como no leído\",\n \"Message pinned\": \"Mensaje fijado\",\n \"Message unpinned\": \"Mensaje desanclado\",\n \"Message was blocked by moderation policies\": \"El mensaje fue bloqueado por las políticas de moderación\",\n \"Messages have been marked unread.\": \"Los mensajes han sido marcados como no leídos.\",\n \"Missing permissions to upload the attachment\": \"Faltan permisos para subir el archivo adjunto\",\n \"Moderator\": \"Moderador\",\n \"Multiple votes\": \"Votos múltiples\",\n \"Mute\": \"Silenciar\",\n \"Mute chat\": \"Silenciar chat\",\n \"Mute user\": \"Silenciar usuario\",\n \"mute-command-args\": \"[@usuario]\",\n \"mute-command-description\": \"Silenciar a un usuario\",\n \"network error\": \"error de red\",\n \"New\": \"Nuevo\",\n \"New message from {{user}}\": \"Nuevo mensaje de {{user}}\",\n \"New Messages!\": \"¡Nuevos mensajes!\",\n \"Next\": \"Siguiente\",\n \"Next image\": \"Siguiente imagen\",\n \"No chats here yet…\": \"Aún no hay mensajes aquí...\",\n \"No conversations yet\": \"Aún no hay conversaciones\",\n \"No files\": \"No hay archivos\",\n \"No items exist\": \"No existen elementos\",\n \"No member found\": \"No se encontró ningún miembro\",\n \"No messages found\": \"No se encontraron mensajes\",\n \"No photos or videos\": \"No hay fotos ni videos\",\n \"No pinned messages\": \"No hay mensajes fijados\",\n \"No results found\": \"No se han encontrado resultados\",\n \"No user found\": \"No se encontró ningún usuario\",\n \"Nobody will be able to vote in this poll anymore.\": \"Nadie podrá votar en esta encuesta.\",\n \"Nothing yet...\": \"Nada aún...\",\n \"Notify all {{ role }} members\": \"Notificar a todos los miembros con rol {{ role }}\",\n \"Offline\": \"Desconectado\",\n \"Ok\": \"Aceptar\",\n \"Online\": \"En línea\",\n \"Only numbers are allowed\": \"Solo se permiten números\",\n \"Only visible to you\": \"Solo visible para ti\",\n \"Open emoji picker\": \"Abrir el selector de emojis\",\n \"Open gallery at image {{ index }}\": \"Abrir galería en la imagen {{ index }}\",\n \"Open image in gallery\": \"Abrir imagen en la galería\",\n \"Open location in a map\": \"Abrir ubicación en un mapa\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"Abrir menú\",\n \"Option already exists\": \"La opción ya existe\",\n \"Option is empty\": \"La opción está vacía\",\n \"Options\": \"Opciones\",\n \"Original\": \"Original\",\n \"Owner\": \"Propietario\",\n \"People matching\": \"Personas que coinciden\",\n \"Photo\": \"Foto\",\n \"Photos & videos\": \"Fotos y videos\",\n \"Pin\": \"Fijar\",\n \"Pin a message to see it here\": \"Fija un mensaje para verlo aquí\",\n \"Pinned by {{ name }}\": \"Fijado por {{ name }}\",\n \"Pinned by You\": \"Anclado por ti\",\n \"Pinned message\": \"Mensaje fijado\",\n \"Pinned messages\": \"Mensajes fijados\",\n \"placeholder/PollComment\": \"Tu comentario\",\n \"placeholder/PollOptionSuggestion\": \"Introduce una nueva opción\",\n \"Play video\": \"Reproducir video\",\n \"Playback speed {{ rate }}x\": \"Velocidad de reproducción {{ rate }}x\",\n \"Poll\": \"Encuesta\",\n \"Poll comments\": \"Comentarios de la encuesta\",\n \"Poll ended\": \"Encuesta finalizada\",\n \"Poll options\": \"Opciones de la encuesta\",\n \"Poll results\": \"Resultados de la encuesta\",\n \"Poll sent\": \"Encuesta enviada\",\n \"Previous\": \"Anterior\",\n \"Previous image\": \"Imagen anterior\",\n \"Question\": \"Pregunta\",\n \"Question {{ optionOrderNumber}}\": \"Pregunta {{ optionOrderNumber}}\",\n \"Question is required\": \"La pregunta es obligatoria\",\n \"Quote Reply\": \"Responder con cita\",\n \"Reached the vote limit. Remove an existing vote first.\": \"Se ha alcanzado el límite de votos. Elimina un voto existente primero.\",\n \"Recording format is not supported and cannot be reproduced\": \"El formato de grabación no es compatible y no se puede reproducir\",\n \"Remind me\": \"Recordarme\",\n \"Remind Me\": \"Recordarme\",\n \"Reminder set\": \"Recordatorio establecido\",\n \"Remove\": \"Eliminar\",\n \"Remove {{ count }} members_one\": \"Eliminar {{ count }} miembro\",\n \"Remove {{ count }} members_many\": \"Eliminar {{ count }} miembros\",\n \"Remove {{ count }} members_other\": \"Eliminar {{ count }} miembros\",\n \"Remove {{ member }} from this channel?\": \"¿Eliminar a {{ member }} de este canal?\",\n \"Remove channel members\": \"Eliminar miembros del canal\",\n \"Remove reminder\": \"Eliminar recordatorio\",\n \"Remove save for later\": \"Quitar guardar para después\",\n \"Remove user\": \"Eliminar usuario\",\n \"Removed {{ count }} members_one\": \"Se eliminó {{ count }} miembro\",\n \"Removed {{ count }} members_many\": \"Se eliminaron {{ count }} miembros\",\n \"Removed {{ count }} members_other\": \"Se eliminaron {{ count }} miembros\",\n \"Replied to a thread\": \"Respondió en un hilo\",\n \"Reply\": \"Responder\",\n \"Reply to {{ authorName }}\": \"Responder a {{ authorName }}\",\n \"Reply to a message to start a thread\": \"Responde a un mensaje para iniciar un hilo\",\n \"Reply to Message\": \"Responder al mensaje\",\n \"replyCount_one\": \"1 respuesta\",\n \"replyCount_many\": \"{{ count }} respuestas\",\n \"replyCount_other\": \"{{ count }} respuestas\",\n \"Resend\": \"Reenviar\",\n \"Retry upload\": \"Reintentar la carga\",\n \"Review all options available in this poll\": \"Revisa todas las opciones disponibles en esta encuesta\",\n \"Review comments submitted with poll answers\": \"Revisa los comentarios enviados con las respuestas de la encuesta\",\n \"Review poll results and open an option to see detailed votes\": \"Revisa los resultados de la encuesta y abre una opción para ver votos detallados\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Revisa este mensaje y elige si eliminarlo, editarlo o enviarlo de todos modos\",\n \"Review who voted for this option\": \"Revisa quién votó por esta opción\",\n \"Save\": \"Guardar\",\n \"Save for later\": \"Guardar para más tarde\",\n \"Saved for later\": \"Guardado para más tarde\",\n \"Search\": \"Buscar\",\n \"Search GIFs\": \"Buscar GIFs\",\n \"search-results-header-filter-source-button-label--channels\": \"canales\",\n \"search-results-header-filter-source-button-label--messages\": \"mensajes\",\n \"search-results-header-filter-source-button-label--users\": \"usuarios\",\n \"Searching for {{ searchSourceType }}...\": \"Buscando {{ searchSourceType }}...\",\n \"Searching...\": \"Buscando...\",\n \"searchResultsCount_one\": \"1 resultado\",\n \"searchResultsCount_many\": \"{{ count }} resultados\",\n \"searchResultsCount_other\": \"{{ count }} resultados\",\n \"Select a thread to continue the conversation\": \"Selecciona un hilo para continuar la conversación\",\n \"Select more than one option\": \"Seleccionar más de una opción\",\n \"Select one\": \"Seleccionar uno\",\n \"Select one or more\": \"Seleccionar uno o más\",\n \"Select up to {{count}}_one\": \"Selecciona hasta {{count}}\",\n \"Select up to {{count}}_many\": \"Selecciona hasta {{count}}\",\n \"Select up to {{count}}_other\": \"Selecciona hasta {{count}}\",\n \"Select your current location and optionally enable live location sharing\": \"Selecciona tu ubicación actual y, opcionalmente, habilita el uso compartido de ubicación en vivo\",\n \"Send\": \"Enviar\",\n \"Send a message\": \"Envía un mensaje\",\n \"Send a message to start the conversation\": \"Envía un mensaje para iniciar la conversación\",\n \"Send Anyway\": \"Enviar de todos modos\",\n \"Send direct message\": \"Enviar mensaje directo\",\n \"Send message request failed\": \"Error al enviar la solicitud de mensaje\",\n \"Send poll\": \"Enviar encuesta\",\n \"Sending...\": \"Enviando...\",\n \"Sent\": \"Enviado\",\n \"Share\": \"Compartir\",\n \"Share a file to see it here\": \"Comparte un archivo para verlo aquí\",\n \"Share a photo or video to see it here\": \"Comparte una foto o un video para verlo aquí\",\n \"Share live location for\": \"Compartir ubicación en vivo durante\",\n \"Share Location\": \"Compartir ubicación\",\n \"Shared live location\": \"Ubicación en vivo compartida\",\n \"Shared location\": \"Ubicación compartida\",\n \"Shuffle\": \"Mezclar\",\n \"size limit\": \"límite de tamaño\",\n \"Slow Mode ON\": \"Modo lento activado\",\n \"Slow mode, wait {{ seconds }}s...\": \"Modo lento, espera {{ seconds }} s...\",\n \"Some of the files will not be accepted\": \"Algunos archivos no serán aceptados\",\n \"Start typing to search\": \"Empieza a escribir para buscar\",\n \"Stop sharing\": \"Dejar de compartir\",\n \"Submit\": \"Enviar\",\n \"Suggest a new option to add to this poll\": \"Sugiere una nueva opción para añadir a esta encuesta\",\n \"Suggest an option\": \"Sugerir una opción\",\n \"Tap to remove\": \"Toca para quitar\",\n \"Tap to remove: {{ reactionName }}\": \"Toca para quitar: {{ reactionName }}\",\n \"Thinking...\": \"Pensando...\",\n \"this content could not be displayed\": \"Este contenido no se pudo mostrar\",\n \"This field cannot be empty or contain only spaces\": \"Este campo no puede estar vacío o contener solo espacios\",\n \"This message did not meet our content guidelines\": \"Este mensaje no cumple con nuestras directrices de contenido\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"Este usuario podrá enviarte mensajes de nuevo.\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"Hilo\",\n \"Thread has not been found\": \"No se ha encontrado el hilo\",\n \"Thread reply\": \"Respuesta en hilo\",\n \"Thread Reply\": \"Respuesta en hilo\",\n \"ThreadListUnseenThreadsBanner/loading\": \"Cargando...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} hilo no leído\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_many\": \"{{ count }} hilos no leídos\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} hilos no leídos\",\n \"Threads\": \"Hilos\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Ayer]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Hoy]\\\", \\\"nextDay\\\": \\\"[Mañana]\\\", \\\"lastDay\\\": \\\"[Ayer]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Último] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"hace {{ count }} d\",\n \"timestamp/relativeToday\": \"Hoy\",\n \"timestamp/relativeWeeksAgo\": \"hace {{ count }} sem\",\n \"timestamp/relativeYesterday\": \"Ayer\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Hoy] [a las] HH:mm\\\", \\\"nextDay\\\": \\\"[Mañana] [a las] HH:mm\\\", \\\"lastDay\\\": \\\"[Ayer] [a las] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [a las] HH:mm\\\", \\\"lastWeek\\\": \\\"[Último] dddd [a las] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [a las] HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"Para comenzar a grabar, permita el acceso a la cámara en su navegador\",\n \"To start recording, allow the microphone access in your browser\": \"Para comenzar a grabar, permita el acceso al micrófono en su navegador\",\n \"totalVoteCount_one\": \"1 voto en total\",\n \"totalVoteCount_many\": \"{{ count }} votos en total\",\n \"totalVoteCount_other\": \"{{ count }} votos en total\",\n \"Translated\": \"Traducido\",\n \"Translated from {{ language }}\": \"Traducido de {{ language }}\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"Escribe un número del 2 al 10\",\n \"Unarchive\": \"Desarchivar\",\n \"unban-command-args\": \"[@usuario]\",\n \"unban-command-description\": \"Quitar la prohibición a un usuario\",\n \"Unblock\": \"Desbloquear\",\n \"Unblock user\": \"Desbloquear usuario\",\n \"Unblock User\": \"Desbloquear usuario\",\n \"unknown error\": \"error desconocido\",\n \"Unmute\": \"Activar sonido\",\n \"Unmute chat\": \"Desactivar silencio del chat\",\n \"Unmute user\": \"Desactivar silencio del usuario\",\n \"unmute-command-args\": \"[@usuario]\",\n \"unmute-command-description\": \"Desactivar el silencio de un usuario\",\n \"Unpin\": \"Desfijar\",\n \"Unread messages\": \"Mensajes no leídos\",\n \"Unsupported attachment\": \"Adjunto no compatible\",\n \"unsupported file type\": \"tipo de archivo no compatible\",\n \"Update\": \"Actualizar\",\n \"Update the comment attached to your poll answer\": \"Actualiza el comentario adjunto a tu respuesta de la encuesta\",\n \"Update your comment\": \"Actualizar tu comentario\",\n \"Upload blocked\": \"Carga bloqueada\",\n \"Upload error\": \"Error de carga\",\n \"Upload failed\": \"Carga fallida\",\n \"Upload Picture\": \"Subir imagen\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Tipo de carga: \\\"{{ type }}\\\" no está permitido\",\n \"User blocked\": \"Usuario bloqueado\",\n \"User muted\": \"Usuario silenciado\",\n \"User removed\": \"Usuario eliminado\",\n \"User unblocked\": \"Usuario desbloqueado\",\n \"User unmuted\": \"Usuario con silencio desactivado\",\n \"User uploaded content\": \"Contenido subido por el usuario\",\n \"Video\": \"Vídeo\",\n \"videoCount_one\": \"Video\",\n \"videoCount_many\": \"{{ count }} videos\",\n \"videoCount_other\": \"{{ count }} videos\",\n \"View\": \"Ver\",\n \"View {{count}} comments_one\": \"Ver {{count}} comentario\",\n \"View {{count}} comments_many\": \"Ver {{count}} comentarios\",\n \"View {{count}} comments_other\": \"Ver {{count}} comentarios\",\n \"View all\": \"Ver todo\",\n \"View member details for {{ member }}\": \"Ver detalles del miembro {{ member }}\",\n \"View original\": \"Ver original\",\n \"View results\": \"Ver resultados\",\n \"View translation\": \"Ver traducción\",\n \"Voice message\": \"Mensaje de voz\",\n \"Voice message {{ duration }}\": \"Mensaje de voz {{ duration }}\",\n \"Voice message deleted\": \"Mensaje de voz eliminado\",\n \"voiceMessageCount_one\": \"Mensaje de voz\",\n \"voiceMessageCount_many\": \"{{ count }} mensajes de voz\",\n \"voiceMessageCount_other\": \"{{ count }} mensajes de voz\",\n \"Vote ended\": \"Votación finalizada\",\n \"Votes\": \"Votos\",\n \"Wait until all attachments have uploaded\": \"Espere hasta que se hayan cargado todos los archivos adjuntos\",\n \"Waiting for network…\": \"Esperando red…\",\n \"You\": \"Tú\",\n \"You've reached the maximum number of files\": \"Has alcanzado el número máximo de archivos\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} et {{ moreCount }} autres\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} et {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} fichier\",\n \"{{ count }} files_many\": \"{{ count }} fichiers\",\n \"{{ count }} files_other\": \"{{ count }} fichiers\",\n \"{{ count }} members_one\": \"{{ count }} membre\",\n \"{{ count }} members_many\": \"{{ count }} membres\",\n \"{{ count }} members_other\": \"{{ count }} membres\",\n \"{{ count }} members added_one\": \"{{ count }} membre ajouté\",\n \"{{ count }} members added_many\": \"{{ count }} membres ajoutés\",\n \"{{ count }} members added_other\": \"{{ count }} membres ajoutés\",\n \"{{ count }} people are typing_one\": \"{{ count }} personne écrit\",\n \"{{ count }} people are typing_many\": \"{{ count }} personnes écrivent\",\n \"{{ count }} people are typing_other\": \"{{ count }} personnes écrivent\",\n \"{{ count }} photos_one\": \"{{ count }} photo\",\n \"{{ count }} photos_many\": \"{{ count }} photos\",\n \"{{ count }} photos_other\": \"{{ count }} photos\",\n \"{{ count }} reactions_one\": \"{{ count }} réaction\",\n \"{{ count }} reactions_many\": \"{{ count }} réactions\",\n \"{{ count }} reactions_other\": \"{{ count }} réactions\",\n \"{{ count }} videos_one\": \"{{ count }} vidéo\",\n \"{{ count }} videos_many\": \"{{ count }} vidéos\",\n \"{{ count }} videos_other\": \"{{ count }} vidéos\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} et {{ secondUser }}\",\n \"{{ imageCount }} more\": \"{{ imageCount }} supplémentaires\",\n \"{{ member }} will be able to message you again.\": \"{{ member }} pourra à nouveau vous envoyer des messages.\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }} ne pourra plus vous envoyer de messages.\",\n \"{{ memberCount }} members\": \"{{ memberCount }} membres\",\n \"{{ typing }} are typing\": \"{{ typing }} écrivent\",\n \"{{ typing }} is typing\": \"{{ typing }} écrit\",\n \"{{ user }} has been muted\": \"{{ user }} a été mis en sourdine\",\n \"{{ user }} has been unmuted\": \"{{ user }} n'est plus en sourdine\",\n \"{{ user }} is typing...\": \"{{ user }} est en train d'écrire...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} et {{ user }} sont en train d'écrire...\",\n \"{{ users }} and more are typing...\": \"{{ users }} et plus sont en train d'écrire...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} en ligne\",\n \"{{count}} new messages_one\": \"{{count}} nouveau message\",\n \"{{count}} new messages_many\": \"{{count}} nouveaux messages\",\n \"{{count}} new messages_other\": \"{{count}} nouveaux messages\",\n \"{{count}} unread_one\": \"{{count}} non lu\",\n \"{{count}} unread_many\": \"{{count}} non lus\",\n \"{{count}} unread_other\": \"{{count}} non lus\",\n \"{{count}} votes_one\": \"{{count}} vote\",\n \"{{count}} votes_many\": \"{{count}} votes\",\n \"{{count}} votes_other\": \"{{count}} votes\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"+{{count}} option de plus\",\n \"+{{count}} more options_many\": \"+{{count}} options de plus\",\n \"+{{count}} more options_other\": \"+{{count}} options de plus\",\n \"🏙 Attachment...\": \"🏙 Pièce jointe...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} a créé : {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} a voté : {{pollOptionText}}\",\n \"📍Shared location\": \"📍Emplacement partagé\",\n \"Actions\": \"Actions\",\n \"Add\": \"Ajouter\",\n \"Add {{ count }} members_one\": \"Ajouter {{ count }} membre\",\n \"Add {{ count }} members_many\": \"Ajouter {{ count }} membres\",\n \"Add {{ count }} members_other\": \"Ajouter {{ count }} membres\",\n \"Add a comment\": \"Ajouter un commentaire\",\n \"Add a comment to your poll answer\": \"Ajoutez un commentaire à votre réponse au sondage\",\n \"Add an option\": \"Ajouter une option\",\n \"Add channel members\": \"Ajouter des membres au canal\",\n \"Add members\": \"Ajouter des membres\",\n \"Add reaction\": \"Ajouter une réaction\",\n \"Admin\": \"Admin\",\n \"All results loaded\": \"Tous les résultats sont chargés\",\n \"Allow access to camera\": \"Autoriser l'accès à la caméra\",\n \"Allow access to microphone\": \"Autoriser l'accès au microphone\",\n \"Allow comments\": \"Autoriser les commentaires\",\n \"Allow option suggestion\": \"Autoriser la suggestion d'options\",\n \"Allow others to add comments\": \"Permettre à d'autres d'ajouter des commentaires\",\n \"Already a member\": \"Déjà membre\",\n \"Also send as a direct message\": \"Également envoyer en message direct\",\n \"Also send in channel\": \"Également envoyer dans le canal\",\n \"Also sent in channel\": \"Également envoyé dans le canal\",\n \"An error has occurred during recording\": \"Une erreur s'est produite pendant l'enregistrement\",\n \"An error has occurred during the recording processing\": \"Une erreur s'est produite pendant le traitement de l'enregistrement\",\n \"Anonymous\": \"Anonyme\",\n \"Anonymous poll\": \"Sondage anonyme\",\n \"Archive\": \"Archiver\",\n \"Are you sure you want to delete this message?\": \"Êtes-vous sûr de vouloir supprimer ce message ?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_one\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_many\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_one\": \"{{ count }} pièce jointe\",\n \"aria/{{ count }} attachment_many\": \"{{ count }} pièces jointes\",\n \"aria/{{ count }} attachment_other\": \"{{ count }} pièces jointes\",\n \"aria/{{ count }} search results_one\": \"{{ count }} résultat de recherche\",\n \"aria/{{ count }} search results_many\": \"{{ count }} résultats de recherche\",\n \"aria/{{ count }} search results_other\": \"{{ count }} résultats de recherche\",\n \"aria/{{ count }} suggestions_one\": \"{{ count }} suggestion\",\n \"aria/{{ count }} suggestions_many\": \"{{ count }} suggestions\",\n \"aria/{{ count }} suggestions_other\": \"{{ count }} suggestions\",\n \"aria/{{ count }} unread message_one\": \"{{ count }} message non lu\",\n \"aria/{{ count }} unread message_many\": \"{{ count }} messages non lus\",\n \"aria/{{ count }} unread message_other\": \"{{ count }} messages non lus\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} désactivé\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} activé\",\n \"aria/Active\": \"Actif\",\n \"aria/Animated GIF\": \"GIF animé\",\n \"aria/Animated GIF: {{ title }}\": \"GIF animé : {{ title }}\",\n \"aria/Attachment\": \"Pièce jointe\",\n \"aria/Attachment {{ attachmentType }}\": \"Pièce jointe {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"Actions de la pièce jointe\",\n \"aria/audio\": \"audio\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Position audio {{ elapsed }} sur {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"Position audio {{ progress }} pour cent\",\n \"aria/Back to attachments\": \"Retour aux pièces jointes\",\n \"aria/Back to parent menu button\": \"Retour au menu parent bouton\",\n \"aria/Block User\": \"Bloquer l'utilisateur\",\n \"aria/Bookmark Message\": \"Enregistrer le message\",\n \"aria/Cancel recording\": \"Annuler l'enregistrement\",\n \"aria/Cancel Reply\": \"Annuler la réponse\",\n \"aria/Channel Actions\": \"Actions du canal\",\n \"aria/Channel details\": \"Détails du canal\",\n \"aria/Channel list\": \"Liste des canaux\",\n \"aria/Chat view controls\": \"Commandes de la vue du chat\",\n \"aria/Chat: {{ channelName }}\": \"Chat : {{ channelName }}\",\n \"aria/Clear search\": \"Effacer la recherche\",\n \"aria/Close callout dialog\": \"Fermer la boîte de dialogue d'information\",\n \"aria/Close thread\": \"Fermer le fil\",\n \"aria/Collapse sidebar\": \"Réduire la barre latérale\",\n \"aria/Command activated: {{ command }}\": \"Commande activée : {{ command }}\",\n \"aria/Command Suggestions\": \"Suggestions de commandes\",\n \"aria/Complete recording\": \"Terminer l'enregistrement\",\n \"aria/Copy Message Text\": \"Copier le texte du message\",\n \"aria/Decrease value\": \"Diminuer la valeur\",\n \"aria/Delete Message\": \"Supprimer le message\",\n \"aria/Delivered\": \"Remis\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"Statut de remise : {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"Ignorer la notification\",\n \"aria/Download attachment\": \"Télécharger la pièce jointe\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"« {{ option }} » déposé à la position {{ position }}.\",\n \"aria/Edit Message\": \"Éditer un message\",\n \"aria/Emoji picker\": \"Sélecteur d'émojis\",\n \"aria/Emoji Suggestions\": \"Suggestions d'émojis\",\n \"aria/Exit search\": \"Quitter la recherche\",\n \"aria/Expand sidebar\": \"Développer la barre latérale\",\n \"aria/file\": \"fichier\",\n \"aria/File upload\": \"Téléchargement de fichier\",\n \"aria/Flag Message\": \"Signaler le message\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Actions Giphy\",\n \"aria/Giphy canceled\": \"Giphy annulé\",\n \"aria/Giphy image changed\": \"Image Giphy modifiée\",\n \"aria/Giphy image changed: {{ title }}\": \"Image Giphy modifiée : {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Aperçu Giphy, visible uniquement par vous. Utilisez les actions Envoyer, Mélanger ou Annuler.\",\n \"aria/Giphy sent\": \"Giphy envoyé\",\n \"aria/image\": \"image\",\n \"aria/Image failed to load\": \"Échec du chargement de l'image\",\n \"aria/Increase value\": \"Augmenter la valeur\",\n \"aria/Jump to latest message\": \"Aller au dernier message\",\n \"aria/Jump to quoted message\": \"Aller au message cité\",\n \"aria/Last activity: {{ time }}\": \"Dernière activité : {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"Dernier message de {{ sender }} : {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"Dernier message : {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"Marquer comme non lu\",\n \"aria/Mark messages as read\": \"Marquer les messages comme lus\",\n \"aria/Mention Suggestions\": \"Suggestions de mentions\",\n \"aria/Message Actions\": \"Actions du message\",\n \"aria/Message from {{ user }},\": \"Message de {{ user }},\",\n \"aria/Message input\": \"Saisie du message\",\n \"aria/Message with attachments\": \"Message avec des pièces jointes\",\n \"aria/Message,\": \"Message,\",\n \"aria/Mute User\": \"Mettre en sourdine\",\n \"aria/Next page\": \"Page suivante\",\n \"aria/No search results found\": \"Aucun résultat de recherche\",\n \"aria/Notifications\": \"Notifications\",\n \"aria/Open Attachment Selector\": \"Ouvrir le sélecteur de pièces jointes\",\n \"aria/Open Channel Actions Menu\": \"Ouvrir le menu des actions du canal\",\n \"aria/Open channel details\": \"Ouvrir les détails du canal\",\n \"aria/Open channels view\": \"Ouvrir la vue des canaux\",\n \"aria/Open image shared by {{ name }}\": \"Ouvrir l'image partagée par {{ name }}\",\n \"aria/Open Message Actions Menu\": \"Ouvrir le menu des actions du message\",\n \"aria/Open Reaction Selector\": \"Ouvrir le sélecteur de réactions\",\n \"aria/Open Thread\": \"Ouvrir le fil\",\n \"aria/Open threads view\": \"Ouvrir la vue des fils\",\n \"aria/Open threads view with unread threads_one\": \"Ouvrir la vue des fils, {{ count }} fil non lu\",\n \"aria/Open threads view with unread threads_many\": \"Ouvrir la vue des fils, {{ count }} fils non lus\",\n \"aria/Open threads view with unread threads_other\": \"Ouvrir la vue des fils, {{ count }} fils non lus\",\n \"aria/Open video shared by {{ name }}\": \"Ouvrir la vidéo partagée par {{ name }}\",\n \"aria/Opened channel: {{ name }}\": \"Canal ouvert : {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"Fil ouvert dans {{ name }}\",\n \"aria/Option {{ position }}\": \"Option {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"Les options peuvent désormais être réorganisées et supprimées.\",\n \"aria/Pause\": \"Pause\",\n \"aria/Pause recording\": \"Mettre en pause l'enregistrement\",\n \"aria/Percent complete\": \"{{percent}} pour cent terminé\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"« {{ option }} » saisi. Utilisez les flèches pour réorganiser. Appuyez sur Espace ou Tab pour déposer.\",\n \"aria/Pin Message\": \"Épingler le message\",\n \"aria/Play\": \"Lecture\",\n \"aria/Poll dialog opened\": \"Boîte de dialogue du sondage ouverte\",\n \"aria/Poll sent\": \"Sondage envoyé\",\n \"aria/Poll: {{ pollName }}\": \"Sondage : {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Appuyez sur Entrée pour commencer à saisir\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"Appuyez sur la barre d'espace pour sélectionner cette option, utilisez les flèches Haut et Bas pour la déplacer, puis appuyez à nouveau sur la barre d'espace pour la désélectionner.\",\n \"aria/Previous page\": \"Page précédente\",\n \"aria/Quote Message\": \"Citer le message\",\n \"aria/Reaction list\": \"Liste des réactions\",\n \"aria/Read\": \"Lu\",\n \"aria/Recording paused\": \"Enregistrement en pause\",\n \"aria/Recording resumed\": \"Enregistrement repris\",\n \"aria/Recording started\": \"Enregistrement démarré\",\n \"aria/Remind Me Message\": \"Me rappeler\",\n \"aria/Remove attachment\": \"Supprimer la pièce jointe\",\n \"aria/Remove location attachment\": \"Supprimer la pièce jointe d'emplacement\",\n \"aria/Remove option: {{ option }}\": \"Supprimer l'option : {{ option }}\",\n \"aria/Remove Reminder\": \"Supprimer le rappel\",\n \"aria/Remove Save For Later\": \"Supprimer « Enregistrer pour plus tard »\",\n \"aria/Removed option {{ option }}\": \"Option {{ option }} supprimée\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"Réorganiser « {{ option }} », position {{ position }} sur {{ total }}\",\n \"aria/Reorder option {{ position }}\": \"Réorganiser l'option {{ position }}\",\n \"aria/Resend Message\": \"Renvoyer le message\",\n \"aria/Resume recording\": \"Reprendre l'enregistrement\",\n \"aria/Retry upload\": \"Réessayer le téléchargement\",\n \"aria/Review bounced message\": \"Examiner le message rejeté\",\n \"aria/Search cleared\": \"Recherche effacée\",\n \"aria/Search results\": \"Résultats de recherche\",\n \"aria/Search results header filter button for: {{ source }}\": \"Bouton de filtre d'en-tête des résultats de recherche pour : {{ source }}\",\n \"aria/Seek audio position\": \"Rechercher la position audio\",\n \"aria/Select Reaction: {{ reactionName }}\": \"Sélectionner la réaction : {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"Sélectionner le canal utilisateur : {{ name }}\",\n \"aria/Send\": \"Envoyer\",\n \"aria/Sent\": \"Envoyé\",\n \"aria/Shared a link\": \"Lien partagé\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"Lien partagé avec le titre : {{ linkTitle }}\",\n \"aria/Shared location\": \"Position partagée\",\n \"aria/Show preview\": \"Afficher l'aperçu\",\n \"aria/Start recording audio\": \"Commencer l'enregistrement audio\",\n \"aria/Stop AI Generation\": \"Arrêter la génération d'IA\",\n \"aria/Submenu\": \"Sous-menu\",\n \"aria/Suggestions\": \"Suggestions\",\n \"aria/There are no messages in this chat.\": \"Aucun message dans cette discussion\",\n \"aria/This option can be reordered and removed.\": \"Cette option peut être réorganisée et supprimée.\",\n \"aria/Thread list\": \"Liste des fils\",\n \"aria/Thread: {{ messagePreview }}\": \"Fil : {{ messagePreview }}\",\n \"aria/Unblock User\": \"Débloquer l'utilisateur\",\n \"aria/Unmute User\": \"Désactiver muet\",\n \"aria/Unpin Message\": \"Détacher le message\",\n \"aria/User selected: {{ user }}\": \"Utilisateur sélectionné : {{ user }}\",\n \"aria/video\": \"vidéo\",\n \"aria/voice message\": \"message vocal\",\n \"aria/Voice message sent\": \"Message vocal envoyé\",\n \"aria/Voice recording attached\": \"Enregistrement vocal joint\",\n \"Ask a question\": \"Poser une question\",\n \"Attach\": \"Joindre\",\n \"Attach files\": \"Joindre des fichiers\",\n \"Attachment\": \"Pièce jointe\",\n \"Attachment upload blocked due to {{reason}}\": \"Téléchargement de pièce jointe bloqué en raison de {{reason}}\",\n \"Attachment upload failed due to {{reason}}\": \"Échec du téléchargement de la pièce jointe en raison de {{reason}}\",\n \"Back\": \"Retour\",\n \"ban-command-args\": \"[@nomdutilisateur] [texte]\",\n \"ban-command-description\": \"Bannir un utilisateur\",\n \"Block user\": \"Bloquer l'utilisateur\",\n \"Block User\": \"Bloquer l'utilisateur\",\n \"Browse channel members\": \"Parcourir les membres du canal\",\n \"Browse pinned messages\": \"Parcourir les messages épinglés\",\n \"Cancel\": \"Annuler\",\n \"Cannot seek in the recording\": \"Impossible de rechercher dans l'enregistrement\",\n \"Changes saved\": \"Modifications enregistrées\",\n \"Channel archived\": \"Canal archivé\",\n \"Channel members\": \"Membres du canal\",\n \"Channel Missing\": \"Canal Manquant\",\n \"Channel muted\": \"Canal mis en sourdine\",\n \"Channel pinned\": \"Canal épinglé\",\n \"Channel unarchived\": \"Canal désarchivé\",\n \"Channel unmuted\": \"Sourdine du canal désactivée\",\n \"Channel unpinned\": \"Canal désépinglé\",\n \"Channels\": \"Canaux\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"Discussions\",\n \"Choose between 2 to 10 options\": \"Choisir entre 2 et 10 options\",\n \"Close\": \"Fermer\",\n \"Close dialog\": \"Fermer la boîte de dialogue\",\n \"Close emoji picker\": \"Fermer le sélecteur d'émojis\",\n \"Command not available while editing\": \"Commande non disponible pendant la modification\",\n \"Command not available while replying\": \"Commande non disponible pendant la réponse\",\n \"Commands\": \"Commandes\",\n \"Commands matching\": \"Correspondance des commandes\",\n \"Connection failure, reconnecting now...\": \"Échec de la connexion, reconnexion en cours...\",\n \"Contact info\": \"Informations du contact\",\n \"Contact name\": \"Nom du contact\",\n \"Copy Message\": \"Copier le message\",\n \"Create\": \"Créer\",\n \"Create a question, add options, and configure poll settings\": \"Créez une question, ajoutez des options et configurez les paramètres du sondage\",\n \"Create poll\": \"Créer un sondage\",\n \"Current location\": \"Emplacement actuel\",\n \"Delete\": \"Supprimer\",\n \"Delete chat\": \"Supprimer le chat\",\n \"Delete for me\": \"Supprimer pour moi\",\n \"Delete message\": \"Supprimer le message\",\n \"Delivered\": \"Publié\",\n \"Direct message\": \"Message direct\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Voulez-vous terminer ce sondage maintenant ? Personne ne pourra plus voter dans ce sondage.\",\n \"Download {{ fileName }}\": \"Télécharger {{ fileName }}\",\n \"Download All\": \"Tout télécharger\",\n \"Download Attachment\": \"Télécharger la pièce jointe\",\n \"Download attachment {{ name }}\": \"Télécharger la pièce jointe {{ name }}\",\n \"Download attachment {{ number }}\": \"Télécharger la pièce jointe {{ number }}\",\n \"Drag your files here\": \"Glissez vos fichiers ici\",\n \"Drag your files here to add to your post\": \"Glissez vos fichiers ici pour les ajouter à votre publication\",\n \"Due {{ timeLeft }}\": \"Échéance dans {{ timeLeft }}\",\n \"Due since {{ dueSince }}\": \"Échéance depuis {{ dueSince }}\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"Modifier\",\n \"Edit chat data\": \"Modifier les données du chat\",\n \"Edit contact\": \"Modifier le contact\",\n \"Edit group\": \"Modifier le groupe\",\n \"Edit Message\": \"Éditer un message\",\n \"Edit message request failed\": \"Échec de la demande de modification du message\",\n \"Edited\": \"Modifié\",\n \"Emoji matching\": \"Correspondance d'émojis\",\n \"Empty message...\": \"Message vide...\",\n \"End\": \"Fin\",\n \"End poll\": \"Terminer le sondage\",\n \"End this poll?\": \"Terminer ce sondage ?\",\n \"End vote\": \"Fin du vote\",\n \"Enforce unique vote is enabled\": \"Le vote unique est activé\",\n \"Error\": \"Erreur\",\n \"Error adding flag\": \"Erreur lors de l'ajout du signalement\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"Erreur lors du blocage de l'utilisateur\",\n \"Error connecting to chat, refresh the page to try again.\": \"Erreur de connexion au chat, rafraîchissez la page pour réessayer.\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"Erreur lors de la suppression du message\",\n \"Error fetching reactions\": \"Erreur lors du chargement des réactions\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Erreur lors de la marque du message comme non lu. Impossible de marquer des messages non lus plus anciens que les 100 derniers messages du canal.\",\n \"Error muting a user ...\": \"Erreur lors de la mise en sourdine d'un utilisateur...\",\n \"Error muting channel\": \"Erreur lors de la mise en sourdine du canal\",\n \"Error muting user\": \"Erreur lors de la mise en sourdine de l'utilisateur\",\n \"Error opening direct message\": \"Erreur lors de l'ouverture du message direct\",\n \"Error pinning message\": \"Erreur lors de l'épinglage du message\",\n \"Error removing members\": \"Erreur lors du retrait des membres\",\n \"Error removing message pin\": \"Erreur lors du retrait de l'épinglage du message\",\n \"Error removing user\": \"Erreur lors du retrait de l'utilisateur\",\n \"Error reproducing the recording\": \"Erreur lors de la reproduction de l'enregistrement\",\n \"Error starting recording\": \"Erreur lors du démarrage de l'enregistrement\",\n \"Error unblocking user\": \"Erreur lors du déblocage de l'utilisateur\",\n \"Error unmuting a user ...\": \"Erreur lors du démarrage de la sourdine d'un utilisateur ...\",\n \"Error unmuting channel\": \"Erreur lors de la désactivation de la sourdine du canal\",\n \"Error unmuting user\": \"Erreur lors de la désactivation de la sourdine de l'utilisateur\",\n \"Error uploading attachment\": \"Erreur lors du téléchargement de la pièce jointe\",\n \"Error uploading file\": \"Erreur lors du téléchargement du fichier\",\n \"Error uploading image\": \"Erreur lors de l'envoi de l'image\",\n \"Error: {{ errorMessage }}\": \"Erreur : {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"Quitter la commande {{ command }}\",\n \"Failed to block user\": \"Impossible de bloquer l'utilisateur\",\n \"Failed to create the poll\": \"Échec de la création du sondage\",\n \"Failed to create the poll due to {{reason}}\": \"Échec de la création du sondage en raison de {{reason}}\",\n \"Failed to delete the message\": \"Échec de la suppression du message\",\n \"Failed to end the poll\": \"Impossible de terminer le sondage\",\n \"Failed to end the poll due to {{reason}}\": \"Impossible de terminer le sondage en raison de {{reason}}\",\n \"Failed to jump to the first unread message\": \"Échec du saut vers le premier message non lu\",\n \"Failed to leave channel\": \"Impossible de quitter le canal\",\n \"Failed to load channels\": \"Impossible de charger les canaux\",\n \"Failed to load more channels\": \"Impossible de charger davantage de canaux\",\n \"Failed to mark channel as read\": \"Échec du marquage du canal comme lu\",\n \"Failed to play the recording\": \"Impossible de lire l'enregistrement\",\n \"Failed to retrieve location\": \"Impossible de récupérer l'emplacement\",\n \"Failed to save changes\": \"Échec de l'enregistrement des modifications\",\n \"Failed to share location\": \"Impossible de partager l'emplacement\",\n \"Failed to update channel archive status\": \"Impossible de mettre à jour l'état d'archivage du canal\",\n \"Failed to update channel mute status\": \"Impossible de mettre à jour l'état de la mise en sourdine du canal\",\n \"Failed to update channel pinned status\": \"Impossible de mettre à jour l'état d'épinglage du canal\",\n \"File\": \"Fichier\",\n \"File is required for upload attachment\": \"Un fichier est requis pour joindre une pièce\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Le fichier est trop volumineux : {{ size }}, la taille maximale de téléchargement est de {{ limit }}\",\n \"File too large\": \"Fichier trop volumineux\",\n \"fileCount_one\": \"1 fichier\",\n \"fileCount_many\": \"{{ count }} fichiers\",\n \"fileCount_other\": \"{{ count }} fichiers\",\n \"Files\": \"Fichiers\",\n \"Flag\": \"Signaler\",\n \"Generating...\": \"Génération...\",\n \"giphy-command-args\": \"[texte]\",\n \"giphy-command-description\": \"Poster un GIF aléatoire dans le canal\",\n \"Go back\": \"Retour\",\n \"Group info\": \"Informations du groupe\",\n \"Group name\": \"Nom du groupe\",\n \"Hide who voted\": \"Masquer qui a voté\",\n \"Image\": \"Image\",\n \"imageCount_one\": \"Photo\",\n \"imageCount_many\": \"{{ count }} photos\",\n \"imageCount_other\": \"{{ count }} photos\",\n \"Instant commands\": \"Commandes instantanées\",\n \"language/af\": \"Afrikaans\",\n \"language/am\": \"Amharique\",\n \"language/ar\": \"Arabe\",\n \"language/az\": \"Azéri\",\n \"language/bg\": \"Bulgare\",\n \"language/bn\": \"Bengali\",\n \"language/bs\": \"Bosnien\",\n \"language/cs\": \"Tchèque\",\n \"language/da\": \"Danois\",\n \"language/de\": \"Allemand\",\n \"language/el\": \"Grec\",\n \"language/en\": \"Anglais\",\n \"language/es\": \"Espagnol\",\n \"language/es-MX\": \"Espagnol (Mexique)\",\n \"language/et\": \"Estonien\",\n \"language/fa\": \"Persan\",\n \"language/fa-AF\": \"Dari\",\n \"language/fi\": \"Finnois\",\n \"language/fr\": \"Français\",\n \"language/fr-CA\": \"Français (Canada)\",\n \"language/ha\": \"Haoussa\",\n \"language/he\": \"Hébreu\",\n \"language/hi\": \"Hindi\",\n \"language/hr\": \"Croate\",\n \"language/ht\": \"Créole haïtien\",\n \"language/hu\": \"Hongrois\",\n \"language/id\": \"Indonésien\",\n \"language/it\": \"Italien\",\n \"language/ja\": \"Japonais\",\n \"language/ka\": \"Géorgien\",\n \"language/ko\": \"Coréen\",\n \"language/lt\": \"Lituanien\",\n \"language/lv\": \"Letton\",\n \"language/ms\": \"Malais\",\n \"language/nl\": \"Néerlandais\",\n \"language/no\": \"Norvégien\",\n \"language/pl\": \"Polonais\",\n \"language/ps\": \"Pachto\",\n \"language/pt\": \"Portugais\",\n \"language/ro\": \"Roumain\",\n \"language/ru\": \"Russe\",\n \"language/sk\": \"Slovaque\",\n \"language/sl\": \"Slovène\",\n \"language/so\": \"Somali\",\n \"language/sq\": \"Albanais\",\n \"language/sr\": \"Serbe\",\n \"language/sv\": \"Suédois\",\n \"language/sw\": \"Swahili\",\n \"language/ta\": \"Tamoul\",\n \"language/th\": \"Thaï\",\n \"language/tl\": \"Tagalog\",\n \"language/tr\": \"Turc\",\n \"language/uk\": \"Ukrainien\",\n \"language/ur\": \"Ourdou\",\n \"language/vi\": \"Vietnamien\",\n \"language/zh\": \"Chinois (simplifié)\",\n \"language/zh-TW\": \"Chinois (traditionnel)\",\n \"Last seen {{ timestamp }}\": \"Vu pour la dernière fois {{ timestamp }}\",\n \"Leave Channel\": \"Quitter le canal\",\n \"Leave chat\": \"Quitter le canal\",\n \"Left channel\": \"Canal quitté\",\n \"Let others add options\": \"Permettre à d'autres d'ajouter des options\",\n \"Limit votes per person\": \"Limiter les votes par personne\",\n \"Link\": \"Lien\",\n \"linkCount_one\": \"Lien\",\n \"linkCount_many\": \"{{ count }} liens\",\n \"linkCount_other\": \"{{ count }} liens\",\n \"live\": \"en direct\",\n \"Live for {{duration}}\": \"En direct pendant {{duration}}\",\n \"Live location\": \"Emplacement en direct\",\n \"Live until {{ timestamp }}\": \"En direct jusqu'à {{ timestamp }}\",\n \"Load more\": \"Charger plus\",\n \"Local upload attachment missing local id\": \"Pièce jointe locale sans identifiant local\",\n \"Location\": \"Emplacement\",\n \"Location sharing ended\": \"Partage d'emplacement terminé\",\n \"Location: {{ coordinates }}\": \"Emplacement : {{ coordinates }}\",\n \"Manage channel\": \"Gérer le canal\",\n \"Manage members\": \"Gérer les membres\",\n \"Mark as unread\": \"Marquer comme non lu\",\n \"Maximum number of votes (from 2 to 10)\": \"Nombre maximum de votes (de 2 à 10)\",\n \"Maximum votes per person\": \"Nombre maximal de votes par personne\",\n \"Member detail\": \"Détails du membre\",\n \"mention/Channel\": \"Canal\",\n \"mention/Channel Description\": \"Notifier tout le monde dans ce canal\",\n \"mention/Here\": \"Ici\",\n \"mention/Here Description\": \"Notifier tous les membres en ligne dans ce canal\",\n \"Menu\": \"Menu\",\n \"Message deleted\": \"Message supprimé\",\n \"Message failed to send\": \"Échec de l'envoi du message\",\n \"Message has been successfully flagged\": \"Le message a été signalé avec succès\",\n \"Message marked as unread\": \"Message marqué comme non lu\",\n \"Message pinned\": \"Message épinglé\",\n \"Message unpinned\": \"Message désépinglé\",\n \"Message was blocked by moderation policies\": \"Le message a été bloqué par les politiques de modération\",\n \"Messages have been marked unread.\": \"Les messages ont été marqués comme non lus.\",\n \"Missing permissions to upload the attachment\": \"Autorisations manquantes pour télécharger la pièce jointe\",\n \"Moderator\": \"Modérateur\",\n \"Multiple votes\": \"Votes multiples\",\n \"Mute\": \"Muet\",\n \"Mute chat\": \"Mettre le chat en sourdine\",\n \"Mute user\": \"Mettre l'utilisateur en sourdine\",\n \"mute-command-args\": \"[@nomdutilisateur]\",\n \"mute-command-description\": \"Muter un utilisateur\",\n \"network error\": \"erreur réseau\",\n \"New\": \"Nouveau\",\n \"New message from {{user}}\": \"Nouveau message de {{user}}\",\n \"New Messages!\": \"Nouveaux Messages!\",\n \"Next\": \"Suivant\",\n \"Next image\": \"Image suivante\",\n \"No chats here yet…\": \"Pas encore de messages ici...\",\n \"No conversations yet\": \"Aucune conversation pour le moment\",\n \"No files\": \"Aucun fichier\",\n \"No items exist\": \"Aucun élément\",\n \"No member found\": \"Aucun membre trouvé\",\n \"No messages found\": \"Aucun message trouvé\",\n \"No photos or videos\": \"Aucune photo ni vidéo\",\n \"No pinned messages\": \"Aucun message épinglé\",\n \"No results found\": \"Aucun résultat trouvé\",\n \"No user found\": \"Aucun utilisateur trouvé\",\n \"Nobody will be able to vote in this poll anymore.\": \"Personne ne pourra plus voter dans ce sondage.\",\n \"Nothing yet...\": \"Rien pour l'instant...\",\n \"Notify all {{ role }} members\": \"Notifier tous les membres ayant le rôle {{ role }}\",\n \"Offline\": \"Hors ligne\",\n \"Ok\": \"D'accord\",\n \"Online\": \"En ligne\",\n \"Only numbers are allowed\": \"Seuls les chiffres sont autorisés\",\n \"Only visible to you\": \"Visible uniquement pour vous\",\n \"Open emoji picker\": \"Ouvrir le sélecteur d'émojis\",\n \"Open gallery at image {{ index }}\": \"Ouvrir la galerie à l'image {{ index }}\",\n \"Open image in gallery\": \"Ouvrir l'image dans la galerie\",\n \"Open location in a map\": \"Ouvrir l'emplacement dans une carte\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"Ouvrir le menu\",\n \"Option already exists\": \"L'option existe déjà\",\n \"Option is empty\": \"L'option est vide\",\n \"Options\": \"Options\",\n \"Original\": \"Original\",\n \"Owner\": \"Propriétaire\",\n \"People matching\": \"Correspondance de personnes\",\n \"Photo\": \"Photo\",\n \"Photos & videos\": \"Photos et vidéos\",\n \"Pin\": \"Épingler\",\n \"Pin a message to see it here\": \"Épinglez un message pour le voir ici\",\n \"Pinned by {{ name }}\": \"Épinglé par {{ name }}\",\n \"Pinned by You\": \"Épinglé par vous\",\n \"Pinned message\": \"Message épinglé\",\n \"Pinned messages\": \"Messages épinglés\",\n \"placeholder/PollComment\": \"Votre commentaire\",\n \"placeholder/PollOptionSuggestion\": \"Saisir une nouvelle option\",\n \"Play video\": \"Lire la vidéo\",\n \"Playback speed {{ rate }}x\": \"Vitesse de lecture {{ rate }}x\",\n \"Poll\": \"Sondage\",\n \"Poll comments\": \"Commentaires du sondage\",\n \"Poll ended\": \"Sondage terminé\",\n \"Poll options\": \"Options du sondage\",\n \"Poll results\": \"Résultats du sondage\",\n \"Poll sent\": \"Sondage envoyé\",\n \"Previous\": \"Précédent\",\n \"Previous image\": \"Image précédente\",\n \"Question\": \"Question\",\n \"Question {{ optionOrderNumber}}\": \"Question {{ optionOrderNumber}}\",\n \"Question is required\": \"La question est obligatoire\",\n \"Quote Reply\": \"Répondre par citation\",\n \"Reached the vote limit. Remove an existing vote first.\": \"La limite de votes a été atteinte. Supprimez d'abord un vote existant.\",\n \"Recording format is not supported and cannot be reproduced\": \"Le format d'enregistrement n'est pas pris en charge et ne peut pas être reproduit\",\n \"Remind me\": \"Me rappeler\",\n \"Remind Me\": \"Me rappeler\",\n \"Reminder set\": \"Rappel défini\",\n \"Remove\": \"Retirer\",\n \"Remove {{ count }} members_one\": \"Retirer {{ count }} membre\",\n \"Remove {{ count }} members_many\": \"Retirer {{ count }} membres\",\n \"Remove {{ count }} members_other\": \"Retirer {{ count }} membres\",\n \"Remove {{ member }} from this channel?\": \"Retirer {{ member }} de ce canal ?\",\n \"Remove channel members\": \"Retirer les membres du canal\",\n \"Remove reminder\": \"Supprimer le rappel\",\n \"Remove save for later\": \"Supprimer « Enregistrer pour plus tard »\",\n \"Remove user\": \"Retirer l'utilisateur\",\n \"Removed {{ count }} members_one\": \"{{ count }} membre retiré\",\n \"Removed {{ count }} members_many\": \"{{ count }} membres retirés\",\n \"Removed {{ count }} members_other\": \"{{ count }} membres retirés\",\n \"Replied to a thread\": \"A répondu à un fil\",\n \"Reply\": \"Répondre\",\n \"Reply to {{ authorName }}\": \"Répondre à {{ authorName }}\",\n \"Reply to a message to start a thread\": \"Répondez à un message pour démarrer un fil\",\n \"Reply to Message\": \"Répondre au message\",\n \"replyCount_one\": \"1 réponse\",\n \"replyCount_many\": \"{{ count }} réponses\",\n \"replyCount_other\": \"{{ count }} réponses\",\n \"Resend\": \"Renvoyer\",\n \"Retry upload\": \"Réessayer le téléchargement\",\n \"Review all options available in this poll\": \"Consultez toutes les options disponibles dans ce sondage\",\n \"Review comments submitted with poll answers\": \"Consultez les commentaires envoyés avec les réponses au sondage\",\n \"Review poll results and open an option to see detailed votes\": \"Consultez les résultats du sondage et ouvrez une option pour voir les votes détaillés\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Consultez ce message et choisissez de le supprimer, le modifier ou l'envoyer quand même\",\n \"Review who voted for this option\": \"Consultez qui a voté pour cette option\",\n \"Save\": \"Enregistrer\",\n \"Save for later\": \"Enregistrer pour plus tard\",\n \"Saved for later\": \"Enregistré pour plus tard\",\n \"Search\": \"Rechercher\",\n \"Search GIFs\": \"Rechercher des GIFs\",\n \"search-results-header-filter-source-button-label--channels\": \"canaux\",\n \"search-results-header-filter-source-button-label--messages\": \"messages\",\n \"search-results-header-filter-source-button-label--users\": \"utilisateurs\",\n \"Searching for {{ searchSourceType }}...\": \"Recherche de {{ searchSourceType }}...\",\n \"Searching...\": \"Recherche en cours...\",\n \"searchResultsCount_one\": \"1 résultat\",\n \"searchResultsCount_many\": \"{{ count }} résultats\",\n \"searchResultsCount_other\": \"{{ count }} résultats\",\n \"Select a thread to continue the conversation\": \"Sélectionnez un fil pour continuer la conversation\",\n \"Select more than one option\": \"Sélectionner plus d'une option\",\n \"Select one\": \"Sélectionner un\",\n \"Select one or more\": \"Sélectionner un ou plusieurs\",\n \"Select up to {{count}}_one\": \"Sélectionner jusqu'à {{count}}\",\n \"Select up to {{count}}_many\": \"Sélectionner jusqu'à {{count}}\",\n \"Select up to {{count}}_other\": \"Sélectionner jusqu'à {{count}}\",\n \"Select your current location and optionally enable live location sharing\": \"Sélectionnez votre position actuelle et activez éventuellement le partage de position en direct\",\n \"Send\": \"Envoyer\",\n \"Send a message\": \"Envoyez un message\",\n \"Send a message to start the conversation\": \"Envoyez un message pour commencer la conversation\",\n \"Send Anyway\": \"Envoyer quand même\",\n \"Send direct message\": \"Envoyer un message direct\",\n \"Send message request failed\": \"Échec de la demande d'envoi de message\",\n \"Send poll\": \"Envoyer le sondage\",\n \"Sending...\": \"Envoi en cours...\",\n \"Sent\": \"Envoyé\",\n \"Share\": \"Partager\",\n \"Share a file to see it here\": \"Partagez un fichier pour le voir ici\",\n \"Share a photo or video to see it here\": \"Partagez une photo ou une vidéo pour la voir ici\",\n \"Share live location for\": \"Partager l'emplacement en direct pendant\",\n \"Share Location\": \"Partager l'emplacement\",\n \"Shared live location\": \"Emplacement en direct partagé\",\n \"Shared location\": \"Position partagée\",\n \"Shuffle\": \"Mélanger\",\n \"size limit\": \"limite de taille\",\n \"Slow Mode ON\": \"Mode lent activé\",\n \"Slow mode, wait {{ seconds }}s...\": \"Mode lent, attendez {{ seconds }} s...\",\n \"Some of the files will not be accepted\": \"Certains fichiers ne seront pas acceptés\",\n \"Start typing to search\": \"Commencez à taper pour rechercher\",\n \"Stop sharing\": \"Arrêter de partager\",\n \"Submit\": \"Envoyer\",\n \"Suggest a new option to add to this poll\": \"Suggérez une nouvelle option à ajouter à ce sondage\",\n \"Suggest an option\": \"Suggérer une option\",\n \"Tap to remove\": \"Appuyez pour retirer\",\n \"Tap to remove: {{ reactionName }}\": \"Appuyez pour retirer: {{ reactionName }}\",\n \"Thinking...\": \"Réflexion...\",\n \"this content could not be displayed\": \"ce contenu n'a pas pu être affiché\",\n \"This field cannot be empty or contain only spaces\": \"Ce champ ne peut pas être vide ou contenir uniquement des espaces\",\n \"This message did not meet our content guidelines\": \"Ce message ne respecte pas nos directives de contenu\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"Cet utilisateur pourra à nouveau vous envoyer des messages.\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"Fil de discussion\",\n \"Thread has not been found\": \"Le fil de discussion n'a pas été trouvé\",\n \"Thread reply\": \"Réponse dans le fil\",\n \"Thread Reply\": \"Réponse dans le fil\",\n \"ThreadListUnseenThreadsBanner/loading\": \"Chargement...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} fil non lu\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_many\": \"{{ count }} fils non lus\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} fils non lus\",\n \"Threads\": \"Fils\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Hier]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Aujourd'hui]\\\", \\\"nextDay\\\": \\\"[Demain]\\\", \\\"lastDay\\\": \\\"[Hier]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Dernier] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"il y a {{ count }} j\",\n \"timestamp/relativeToday\": \"Aujourd'hui\",\n \"timestamp/relativeWeeksAgo\": \"il y a {{ count }} sem\",\n \"timestamp/relativeYesterday\": \"Hier\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Aujourd'hui] [à] HH:mm\\\", \\\"nextDay\\\": \\\"[Demain] [à] HH:mm\\\", \\\"lastDay\\\": \\\"[Hier] [à] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [à] HH:mm\\\", \\\"lastWeek\\\": \\\"dddd [dernier à] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [à] HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"Pour commencer l'enregistrement, autorisez l'accès à la caméra dans votre navigateur\",\n \"To start recording, allow the microphone access in your browser\": \"Pour commencer l'enregistrement, autorisez l'accès au microphone dans votre navigateur\",\n \"totalVoteCount_one\": \"1 vote au total\",\n \"totalVoteCount_many\": \"{{ count }} votes au total\",\n \"totalVoteCount_other\": \"{{ count }} votes au total\",\n \"Translated\": \"Traduit\",\n \"Translated from {{ language }}\": \"Traduit du {{ language }}\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"Tapez un nombre de 2 à 10\",\n \"Unarchive\": \"Désarchiver\",\n \"unban-command-args\": \"[@nomdutilisateur]\",\n \"unban-command-description\": \"Débannir un utilisateur\",\n \"Unblock\": \"Débloquer\",\n \"Unblock user\": \"Débloquer l'utilisateur\",\n \"Unblock User\": \"Débloquer l'utilisateur\",\n \"unknown error\": \"erreur inconnue\",\n \"Unmute\": \"Désactiver muet\",\n \"Unmute chat\": \"Désactiver la sourdine du chat\",\n \"Unmute user\": \"Désactiver la sourdine de l'utilisateur\",\n \"unmute-command-args\": \"[@nomdutilisateur]\",\n \"unmute-command-description\": \"Démuter un utilisateur\",\n \"Unpin\": \"Détacher\",\n \"Unread messages\": \"Messages non lus\",\n \"Unsupported attachment\": \"Pièce jointe non prise en charge\",\n \"unsupported file type\": \"type de fichier non pris en charge\",\n \"Update\": \"Mettre à jour\",\n \"Update the comment attached to your poll answer\": \"Mettez à jour le commentaire joint à votre réponse au sondage\",\n \"Update your comment\": \"Mettre à jour votre commentaire\",\n \"Upload blocked\": \"Téléversement bloqué\",\n \"Upload error\": \"Erreur de téléversement\",\n \"Upload failed\": \"Échec du téléversement\",\n \"Upload Picture\": \"Importer une image\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Le type de fichier : \\\"{{ type }}\\\" n'est pas autorisé\",\n \"User blocked\": \"Utilisateur bloqué\",\n \"User muted\": \"Utilisateur mis en sourdine\",\n \"User removed\": \"Utilisateur retiré\",\n \"User unblocked\": \"Utilisateur débloqué\",\n \"User unmuted\": \"Sourdine de l'utilisateur désactivée\",\n \"User uploaded content\": \"Contenu téléchargé par l'utilisateur\",\n \"Video\": \"Vidéo\",\n \"videoCount_one\": \"Vidéo\",\n \"videoCount_many\": \"{{ count }} vidéos\",\n \"videoCount_other\": \"{{ count }} vidéos\",\n \"View\": \"Voir\",\n \"View {{count}} comments_one\": \"Voir {{count}} commentaire\",\n \"View {{count}} comments_many\": \"Voir {{count}} commentaires\",\n \"View {{count}} comments_other\": \"Voir {{count}} commentaires\",\n \"View all\": \"Tout voir\",\n \"View member details for {{ member }}\": \"Voir les détails du membre {{ member }}\",\n \"View original\": \"Voir l'original\",\n \"View results\": \"Voir les résultats\",\n \"View translation\": \"Voir la traduction\",\n \"Voice message\": \"Message vocal\",\n \"Voice message {{ duration }}\": \"Message vocal {{ duration }}\",\n \"Voice message deleted\": \"Message vocal supprimé\",\n \"voiceMessageCount_one\": \"Mémo vocal\",\n \"voiceMessageCount_many\": \"{{ count }} mémos vocaux\",\n \"voiceMessageCount_other\": \"{{ count }} mémos vocaux\",\n \"Vote ended\": \"Vote terminé\",\n \"Votes\": \"Votes\",\n \"Wait until all attachments have uploaded\": \"Attendez que toutes les pièces jointes soient téléchargées\",\n \"Waiting for network…\": \"En attente du réseau…\",\n \"You\": \"Vous\",\n \"You've reached the maximum number of files\": \"Vous avez atteint le nombre maximal de fichiers\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} और {{ moreCount }} और\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} और {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} फ़ाइल\",\n \"{{ count }} files_other\": \"{{ count }} फ़ाइलें\",\n \"{{ count }} members_one\": \"{{ count }} सदस्य\",\n \"{{ count }} members_other\": \"{{ count }} सदस्य\",\n \"{{ count }} members added_one\": \"{{ count }} सदस्य जोड़ा गया\",\n \"{{ count }} members added_other\": \"{{ count }} सदस्य जोड़े गए\",\n \"{{ count }} people are typing_one\": \"{{ count }} व्यक्ति टाइप कर रहा है\",\n \"{{ count }} people are typing_many\": \"{{ count }} लोग टाइप कर रहे हैं\",\n \"{{ count }} people are typing_other\": \"{{ count }} लोग टाइप कर रहे हैं\",\n \"{{ count }} photos_one\": \"{{ count }} फ़ोटो\",\n \"{{ count }} photos_other\": \"{{ count }} फ़ोटो\",\n \"{{ count }} reactions_one\": \"{{ count }} प्रतिक्रिया\",\n \"{{ count }} reactions_other\": \"{{ count }} प्रतिक्रियाएं\",\n \"{{ count }} videos_one\": \"{{ count }} वीडियो\",\n \"{{ count }} videos_other\": \"{{ count }} वीडियो\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} और {{ secondUser }}\",\n \"{{ imageCount }} more\": \"{{ imageCount }} और\",\n \"{{ member }} will be able to message you again.\": \"{{ member }} आपको फिर से संदेश भेज सकेगा।\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }} अब आपको संदेश नहीं भेज सकेगा।\",\n \"{{ memberCount }} members\": \"{{ memberCount }} मेंबर्स\",\n \"{{ typing }} are typing\": \"{{ typing }} टाइप कर रहे हैं\",\n \"{{ typing }} is typing\": \"{{ typing }} टाइप कर रहा है\",\n \"{{ user }} has been muted\": \"{{ user }} को म्यूट कर दिया गया है\",\n \"{{ user }} has been unmuted\": \"{{ user }} को अनम्यूट कर दिया गया है\",\n \"{{ user }} is typing...\": \"{{ user }} टाइप कर रहा है...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} और {{ user }} टाइप कर रहे हैं...\",\n \"{{ users }} and more are typing...\": \"{{ users }} और अधिक टाइप कर रहे हैं...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} ऑनलाइन\",\n \"{{count}} new messages_one\": \"{{count}} नया संदेश\",\n \"{{count}} new messages_other\": \"{{count}} नए संदेश\",\n \"{{count}} unread_one\": \"{{count}} अपठित\",\n \"{{count}} unread_other\": \"{{count}} अपठित\",\n \"{{count}} votes_one\": \"{{count}} वोट\",\n \"{{count}} votes_other\": \"{{count}} वोट\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"+{{count}} और विकल्प\",\n \"+{{count}} more options_other\": \"+{{count}} और विकल्प\",\n \"🏙 Attachment...\": \"🏙 अटैचमेंट\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} ने बनाया: {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} ने वोट दिया: {{pollOptionText}}\",\n \"📍Shared location\": \"📍साझा किया गया स्थान\",\n \"Actions\": \"Actions\",\n \"Add\": \"जोड़ें\",\n \"Add {{ count }} members_one\": \"{{ count }} सदस्य जोड़ें\",\n \"Add {{ count }} members_other\": \"{{ count }} सदस्य जोड़ें\",\n \"Add a comment\": \"एक टिप्पणी जोड़ें\",\n \"Add a comment to your poll answer\": \"अपने पोल उत्तर में एक टिप्पणी जोड़ें\",\n \"Add an option\": \"एक विकल्प जोड़ें\",\n \"Add channel members\": \"चैनल सदस्य जोड़ें\",\n \"Add members\": \"सदस्य जोड़ें\",\n \"Add reaction\": \"प्रतिक्रिया जोड़ें\",\n \"Admin\": \"एडमिन\",\n \"All results loaded\": \"सभी परिणाम लोड हो गए\",\n \"Allow access to camera\": \"कैमरा तक पहुँच दें\",\n \"Allow access to microphone\": \"माइक्रोफ़ोन तक पहुँच दें\",\n \"Allow comments\": \"टिप्पणियाँ की अनुमति दें\",\n \"Allow option suggestion\": \"विकल्प सुझाव की अनुमति दें\",\n \"Allow others to add comments\": \"दूसरों को टिप्पणी जोड़ने दें\",\n \"Already a member\": \"पहले से सदस्य\",\n \"Also send as a direct message\": \"सीधे संदेश के रूप में भी भेजें\",\n \"Also send in channel\": \"चैनल में भी भेजें\",\n \"Also sent in channel\": \"चैनल में भी भेजा गया\",\n \"An error has occurred during recording\": \"रेकॉर्डिंग के दौरान एक त्रुटि आ गई है\",\n \"An error has occurred during the recording processing\": \"रेकॉर्डिंग प्रोसेसिंग के दौरान एक त्रुटि आ गई है\",\n \"Anonymous\": \"गुमनाम\",\n \"Anonymous poll\": \"गुमनाम मतदान\",\n \"Archive\": \"आर्काइव\",\n \"Are you sure you want to delete this message?\": \"क्या आप वाकई इस संदेश को हटाना चाहते हैं?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_one\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_one\": \"{{ count }} अटैचमेंट\",\n \"aria/{{ count }} attachment_other\": \"{{ count }} अटैचमेंट\",\n \"aria/{{ count }} search results_one\": \"{{ count }} खोज परिणाम\",\n \"aria/{{ count }} search results_other\": \"{{ count }} खोज परिणाम\",\n \"aria/{{ count }} suggestions_one\": \"{{ count }} सुझाव\",\n \"aria/{{ count }} suggestions_other\": \"{{ count }} सुझाव\",\n \"aria/{{ count }} unread message_one\": \"{{ count }} अपठित संदेश\",\n \"aria/{{ count }} unread message_other\": \"{{ count }} अपठित संदेश\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} अक्षम किया गया\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} सक्षम किया गया\",\n \"aria/Active\": \"सक्रिय\",\n \"aria/Animated GIF\": \"एनिमेटेड GIF\",\n \"aria/Animated GIF: {{ title }}\": \"एनिमेटेड GIF: {{ title }}\",\n \"aria/Attachment\": \"अटैचमेंट\",\n \"aria/Attachment {{ attachmentType }}\": \"अटैचमेंट {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"अटैचमेंट क्रियाएँ\",\n \"aria/audio\": \"ऑडियो\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"ऑडियो स्थिति {{ elapsed }} / {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"ऑडियो स्थिति {{ progress }} प्रतिशत\",\n \"aria/Back to attachments\": \"अनुलग्नकों पर वापस जाएं\",\n \"aria/Back to parent menu button\": \"मूल मेनू पर वापस जाएँ बटन\",\n \"aria/Block User\": \"उपयोगकर्ता को ब्लॉक करें\",\n \"aria/Bookmark Message\": \"संदेश बुकमार्क करें\",\n \"aria/Cancel recording\": \"रिकॉर्डिंग रद्द करें\",\n \"aria/Cancel Reply\": \"उत्तर रद्द करें\",\n \"aria/Channel Actions\": \"चैनल क्रियाएँ\",\n \"aria/Channel details\": \"चैनल विवरण\",\n \"aria/Channel list\": \"चैनल सूची\",\n \"aria/Chat view controls\": \"चैट व्यू नियंत्रण\",\n \"aria/Chat: {{ channelName }}\": \"चैट: {{ channelName }}\",\n \"aria/Clear search\": \"खोज साफ़ करें\",\n \"aria/Close callout dialog\": \"कॉलआउट संवाद बंद करें\",\n \"aria/Close thread\": \"थ्रेड बंद करें\",\n \"aria/Collapse sidebar\": \"साइडबार संक्षिप्त करें\",\n \"aria/Command activated: {{ command }}\": \"कमांड सक्रिय किया गया: {{ command }}\",\n \"aria/Command Suggestions\": \"कमांड सुझाव\",\n \"aria/Complete recording\": \"रिकॉर्डिंग पूर्ण करें\",\n \"aria/Copy Message Text\": \"संदेश की टेक्स्ट कॉपी करें\",\n \"aria/Decrease value\": \"मान घटाएं\",\n \"aria/Delete Message\": \"संदेश डिलीट करें\",\n \"aria/Delivered\": \"डिलीवर हो गया\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"डिलीवरी स्थिति: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"सूचना बंद करें\",\n \"aria/Download attachment\": \"अनुलग्नक डाउनलोड करें\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"\\\"{{ option }}\\\" को स्थिति {{ position }} पर छोड़ा गया।\",\n \"aria/Edit Message\": \"मैसेज में बदलाव करे\",\n \"aria/Emoji picker\": \"इमोजी चुनने वाला\",\n \"aria/Emoji Suggestions\": \"इमोजी सुझाव\",\n \"aria/Exit search\": \"खोज से बाहर निकलें\",\n \"aria/Expand sidebar\": \"साइडबार विस्तारित करें\",\n \"aria/file\": \"फ़ाइल\",\n \"aria/File upload\": \"फ़ाइल अपलोड\",\n \"aria/Flag Message\": \"संदेश फ्लैग करें\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Giphy क्रियाएं\",\n \"aria/Giphy canceled\": \"Giphy रद्द किया गया\",\n \"aria/Giphy image changed\": \"Giphy छवि बदल गई\",\n \"aria/Giphy image changed: {{ title }}\": \"Giphy छवि बदल गई: {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Giphy पूर्वावलोकन, केवल आपको दिखाई देता है। भेजें, शफल करें या रद्द करें क्रियाओं का उपयोग करें।\",\n \"aria/Giphy sent\": \"Giphy भेजा गया\",\n \"aria/image\": \"छवि\",\n \"aria/Image failed to load\": \"छवि लोड होने में विफल\",\n \"aria/Increase value\": \"मान बढ़ाएं\",\n \"aria/Jump to latest message\": \"नवीनतम संदेश पर जाएं\",\n \"aria/Jump to quoted message\": \"उद्धृत संदेश पर जाएं\",\n \"aria/Last activity: {{ time }}\": \"अंतिम गतिविधि: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"{{ sender }} का आखिरी संदेश: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"आखिरी संदेश: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"अपठित चिह्नित करें\",\n \"aria/Mark messages as read\": \"संदेशों को पढ़ा हुआ चिह्नित करें\",\n \"aria/Mention Suggestions\": \"उल्लेख सुझाव\",\n \"aria/Message Actions\": \"संदेश कार्रवाइयाँ\",\n \"aria/Message from {{ user }},\": \"{{ user }} का संदेश,\",\n \"aria/Message input\": \"संदेश इनपुट\",\n \"aria/Message with attachments\": \"अटैचमेंट के साथ संदेश\",\n \"aria/Message,\": \"संदेश,\",\n \"aria/Mute User\": \"उपयोगकर्ता म्यूट करें\",\n \"aria/Next page\": \"अगला पृष्ठ\",\n \"aria/No search results found\": \"कोई खोज परिणाम नहीं मिला\",\n \"aria/Notifications\": \"सूचनाएं\",\n \"aria/Open Attachment Selector\": \"अटैचमेंट चयनकर्ता खोलें\",\n \"aria/Open Channel Actions Menu\": \"चैनल क्रियाएँ मेनू खोलें\",\n \"aria/Open channel details\": \"चैनल विवरण खोलें\",\n \"aria/Open channels view\": \"चैनल व्यू खोलें\",\n \"aria/Open image shared by {{ name }}\": \"{{ name }} द्वारा साझा की गई छवि खोलें\",\n \"aria/Open Message Actions Menu\": \"संदेश क्रिया मेन्यू खोलें\",\n \"aria/Open Reaction Selector\": \"प्रतिक्रिया चयनकर्ता खोलें\",\n \"aria/Open Thread\": \"थ्रेड खोलें\",\n \"aria/Open threads view\": \"थ्रेड व्यू खोलें\",\n \"aria/Open threads view with unread threads_one\": \"थ्रेड व्यू खोलें, {{ count }} अपठित थ्रेड\",\n \"aria/Open threads view with unread threads_other\": \"थ्रेड व्यू खोलें, {{ count }} अपठित थ्रेड\",\n \"aria/Open video shared by {{ name }}\": \"{{ name }} द्वारा साझा किया गया वीडियो खोलें\",\n \"aria/Opened channel: {{ name }}\": \"चैनल खोला गया: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"{{ name }} में थ्रेड खोला गया\",\n \"aria/Option {{ position }}\": \"विकल्प {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"अब विकल्पों को पुनः क्रमित और हटाया जा सकता है।\",\n \"aria/Pause\": \"रोकें\",\n \"aria/Pause recording\": \"रिकॉर्डिंग रोकें\",\n \"aria/Percent complete\": \"{{percent}} प्रतिशत पूर्ण\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"\\\"{{ option }}\\\" को उठाया गया। पुनर्व्यवस्थित करने के लिए तीर कुंजियों का उपयोग करें। छोड़ने के लिए स्पेस या टैब दबाएं।\",\n \"aria/Pin Message\": \"संदेश पिन करें\",\n \"aria/Play\": \"चलाएँ\",\n \"aria/Poll dialog opened\": \"पोल संवाद खुला\",\n \"aria/Poll sent\": \"पोल भेजा गया\",\n \"aria/Poll: {{ pollName }}\": \"पोल: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"टाइप करना शुरू करने के लिए Enter दबाएँ\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"इस विकल्प को चुनने के लिए स्पेस दबाएं, इसे स्थानांतरित करने के लिए ऊपर और नीचे तीर कुंजियों का उपयोग करें, फिर चयन हटाने के लिए फिर से स्पेस दबाएं।\",\n \"aria/Previous page\": \"पिछला पृष्ठ\",\n \"aria/Quote Message\": \"संदेश उद्धरण\",\n \"aria/Reaction list\": \"प्रतिक्रिया सूची\",\n \"aria/Read\": \"पढ़ा गया\",\n \"aria/Recording paused\": \"रिकॉर्डिंग रोकी गई\",\n \"aria/Recording resumed\": \"रिकॉर्डिंग फिर से शुरू हुई\",\n \"aria/Recording started\": \"रिकॉर्डिंग शुरू हुई\",\n \"aria/Remind Me Message\": \"मुझे याद दिलाएं\",\n \"aria/Remove attachment\": \"संलग्नक हटाएं\",\n \"aria/Remove location attachment\": \"स्थान संलग्नक हटाएं\",\n \"aria/Remove option: {{ option }}\": \"विकल्प हटाएं: {{ option }}\",\n \"aria/Remove Reminder\": \"अनुस्मारक हटाएं\",\n \"aria/Remove Save For Later\": \"बाद में देखें हटाएं\",\n \"aria/Removed option {{ option }}\": \"विकल्प {{ option }} हटाया गया\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"\\\"{{ option }}\\\" को पुनर्व्यवस्थित करें, {{ total }} में से स्थिति {{ position }}\",\n \"aria/Reorder option {{ position }}\": \"विकल्प {{ position }} को पुनर्व्यवस्थित करें\",\n \"aria/Resend Message\": \"संदेश फिर से भेजें\",\n \"aria/Resume recording\": \"रिकॉर्डिंग फिर शुरू करें\",\n \"aria/Retry upload\": \"अपलोड पुनः प्रयास करें\",\n \"aria/Review bounced message\": \"वापस लौटा संदेश समीक्षा करें\",\n \"aria/Search cleared\": \"खोज साफ़ की गई\",\n \"aria/Search results\": \"खोज परिणाम\",\n \"aria/Search results header filter button for: {{ source }}\": \"{{ source }} के लिए खोज परिणाम शीर्षक फ़िल्टर बटन\",\n \"aria/Seek audio position\": \"ऑडियो स्थिति खोजें\",\n \"aria/Select Reaction: {{ reactionName }}\": \"प्रतिक्रिया चुनें: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"उपयोगकर्ता चैनल चुनें: {{ name }}\",\n \"aria/Send\": \"भेजें\",\n \"aria/Sent\": \"भेजा गया\",\n \"aria/Shared a link\": \"लिंक साझा किया गया\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"शीर्षक के साथ लिंक साझा किया गया: {{ linkTitle }}\",\n \"aria/Shared location\": \"साझा किया गया स्थान\",\n \"aria/Show preview\": \"पूर्वावलोकन दिखाएं\",\n \"aria/Start recording audio\": \"ऑडियो रिकॉर्डिंग शुरू करें\",\n \"aria/Stop AI Generation\": \"एआई जनरेशन रोकें\",\n \"aria/Submenu\": \"उप-मेन्यू\",\n \"aria/Suggestions\": \"सुझाव\",\n \"aria/There are no messages in this chat.\": \"इस चैट में कोई संदेश नहीं है\",\n \"aria/This option can be reordered and removed.\": \"इस विकल्प को पुनः क्रमित और हटाया जा सकता है।\",\n \"aria/Thread list\": \"थ्रेड सूची\",\n \"aria/Thread: {{ messagePreview }}\": \"थ्रेड: {{ messagePreview }}\",\n \"aria/Unblock User\": \"उपयोगकर्ता अनब्लॉक करें\",\n \"aria/Unmute User\": \"उपयोगकर्ता अनम्यूट करें\",\n \"aria/Unpin Message\": \"संदेश अनपिन करें\",\n \"aria/User selected: {{ user }}\": \"उपयोगकर्ता चयनित: {{ user }}\",\n \"aria/video\": \"वीडियो\",\n \"aria/voice message\": \"वॉइस मैसेज\",\n \"aria/Voice message sent\": \"वॉइस संदेश भेजा गया\",\n \"aria/Voice recording attached\": \"वॉइस रिकॉर्डिंग संलग्न की गई\",\n \"Ask a question\": \"एक प्रश्न पूछें\",\n \"Attach\": \"संलग्न करें\",\n \"Attach files\": \"फाइल्स अटैच करे\",\n \"Attachment\": \"अनुलग्नक\",\n \"Attachment upload blocked due to {{reason}}\": \"{{reason}} के कारण अटैचमेंट अपलोड ब्लॉक किया गया\",\n \"Attachment upload failed due to {{reason}}\": \"{{reason}} के कारण अटैचमेंट अपलोड विफल रहा\",\n \"Back\": \"वापस\",\n \"ban-command-args\": \"[@उपयोगकर्तनाम] [पाठ]\",\n \"ban-command-description\": \"एक उपयोगकर्ता को प्रतिषेधित करें\",\n \"Block user\": \"उपयोगकर्ता को ब्लॉक करें\",\n \"Block User\": \"उपयोगकर्ता को ब्लॉक करें\",\n \"Browse channel members\": \"चैनल सदस्य देखें\",\n \"Browse pinned messages\": \"पिन किए गए संदेश देखें\",\n \"Cancel\": \"रद्द करें\",\n \"Cannot seek in the recording\": \"रेकॉर्डिंग में खोज नहीं की जा सकती\",\n \"Changes saved\": \"बदलाव सहेजे गए\",\n \"Channel archived\": \"चैनल संग्रहीत किया गया\",\n \"Channel members\": \"चैनल सदस्य\",\n \"Channel Missing\": \"चैनल उपलब्ध नहीं है\",\n \"Channel muted\": \"चैनल म्यूट किया गया\",\n \"Channel pinned\": \"चैनल पिन किया गया\",\n \"Channel unarchived\": \"चैनल असंग्रहीत किया गया\",\n \"Channel unmuted\": \"चैनल अनम्यूट किया गया\",\n \"Channel unpinned\": \"चैनल अनपिन किया गया\",\n \"Channels\": \"चैनल\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"चैट\",\n \"Choose between 2 to 10 options\": \"2 से 10 विकल्प चुनें\",\n \"Close\": \"बंद करे\",\n \"Close dialog\": \"डायलॉग बंद करें\",\n \"Close emoji picker\": \"इमोजी पिकर बंद करें\",\n \"Command not available while editing\": \"संपादन के दौरान कमांड उपलब्ध नहीं है\",\n \"Command not available while replying\": \"उत्तर देते समय कमांड उपलब्ध नहीं है\",\n \"Commands\": \"कमांड\",\n \"Commands matching\": \"मेल खाती है\",\n \"Connection failure, reconnecting now...\": \"कनेक्शन विफल रहा, अब पुनः कनेक्ट हो रहा है ...\",\n \"Contact info\": \"संपर्क जानकारी\",\n \"Contact name\": \"संपर्क का नाम\",\n \"Copy Message\": \"संदेश कॉपी करें\",\n \"Create\": \"बनाएँ\",\n \"Create a question, add options, and configure poll settings\": \"एक प्रश्न बनाएं, विकल्प जोड़ें और पोल सेटिंग्स कॉन्फ़िगर करें\",\n \"Create poll\": \"मतदान बनाएँ\",\n \"Current location\": \"वर्तमान स्थान\",\n \"Delete\": \"डिलीट\",\n \"Delete chat\": \"चैट हटाएं\",\n \"Delete for me\": \"मेरे लिए डिलीट करें\",\n \"Delete message\": \"संदेश हटाएं\",\n \"Delivered\": \"पहुंच गया\",\n \"Direct message\": \"प्रत्यक्ष संदेश\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"क्या आप अभी इस पोल को समाप्त करना चाहते हैं? इस पोल में अब कोई भी वोट नहीं कर पाएगा।\",\n \"Download {{ fileName }}\": \"{{ fileName }} डाउनलोड करें\",\n \"Download All\": \"सब डाउनलोड करें\",\n \"Download Attachment\": \"अटैचमेंट डाउनलोड करें\",\n \"Download attachment {{ name }}\": \"अनुलग्नक {{ name }} डाउनलोड करें\",\n \"Download attachment {{ number }}\": \"अनुलग्नक {{ number }} डाउनलोड करें\",\n \"Drag your files here\": \"अपनी फ़ाइलें यहाँ खींचें\",\n \"Drag your files here to add to your post\": \"अपनी फ़ाइलें यहाँ खींचें और अपने पोस्ट में जोड़ने के लिए\",\n \"Due {{ timeLeft }}\": \"{{ timeLeft }} में देय\",\n \"Due since {{ dueSince }}\": \"{{ dueSince }} से देय\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"संपादित करें\",\n \"Edit chat data\": \"चैट डेटा संपादित करें\",\n \"Edit contact\": \"संपर्क संपादित करें\",\n \"Edit group\": \"समूह संपादित करें\",\n \"Edit Message\": \"मैसेज में बदलाव करे\",\n \"Edit message request failed\": \"संदेश संपादित करने का अनुरोध विफल रहा\",\n \"Edited\": \"संपादित\",\n \"Emoji matching\": \"इमोजी मिलान\",\n \"Empty message...\": \"खाली संदेश ...\",\n \"End\": \"समाप्त\",\n \"End poll\": \"पोल समाप्त करें\",\n \"End this poll?\": \"इस पोल को समाप्त करें?\",\n \"End vote\": \"मत समाप्त करें\",\n \"Enforce unique vote is enabled\": \"अनोखा वोट सक्षम है\",\n \"Error\": \"त्रुटि\",\n \"Error adding flag\": \"ध्वज जोड़ने में त्रुटि\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"उपयोगकर्ता को ब्लॉक करने में त्रुटि\",\n \"Error connecting to chat, refresh the page to try again.\": \"चैट से कनेक्ट करने में त्रुटि, पेज को रिफ्रेश करें\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"संदेश हटाने में त्रुटि\",\n \"Error fetching reactions\": \"प्रतिक्रियाएँ लोड करने में त्रुटि\",\n \"Error marking message unread\": \"संदेश को अपठित चिह्नित करने में त्रुटि\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"संदेश को अपठित मार्क करने में त्रुटि। सबसे नए 100 चैनल संदेश से पहले के सभी अपठित संदेशों को अपठित मार्क नहीं किया जा सकता है।\",\n \"Error muting a user ...\": \"यूजर को म्यूट करने का प्रयास फेल हुआ\",\n \"Error muting channel\": \"चैनल म्यूट करने में त्रुटि\",\n \"Error muting user\": \"उपयोगकर्ता को म्यूट करने में त्रुटि\",\n \"Error opening direct message\": \"सीधा संदेश खोलने में त्रुटि\",\n \"Error pinning message\": \"संदेश को पिन करने में त्रुटि\",\n \"Error removing members\": \"सदस्यों को हटाने में त्रुटि\",\n \"Error removing message pin\": \"संदेश पिन निकालने में त्रुटि\",\n \"Error removing user\": \"उपयोगकर्ता हटाने में त्रुटि\",\n \"Error reproducing the recording\": \"रिकॉर्डिंग पुन: उत्पन्न करने में त्रुटि\",\n \"Error starting recording\": \"रेकॉर्डिंग शुरू करने में त्रुटि\",\n \"Error unblocking user\": \"उपयोगकर्ता को अनब्लॉक करने में त्रुटि\",\n \"Error unmuting a user ...\": \"यूजर को अनम्यूट करने का प्रयास फेल हुआ\",\n \"Error unmuting channel\": \"चैनल को अनम्यूट करने में त्रुटि\",\n \"Error unmuting user\": \"उपयोगकर्ता को अनम्यूट करने में त्रुटि\",\n \"Error uploading attachment\": \"अटैचमेंट अपलोड करते समय त्रुटि\",\n \"Error uploading file\": \"फ़ाइल अपलोड करने में त्रुटि\",\n \"Error uploading image\": \"छवि अपलोड करने में त्रुटि\",\n \"Error: {{ errorMessage }}\": \"फेल: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"कमांड से बाहर निकलें {{ command }}\",\n \"Failed to block user\": \"उपयोगकर्ता को ब्लॉक करने में विफल\",\n \"Failed to create the poll\": \"मतदान बनाने में विफल\",\n \"Failed to create the poll due to {{reason}}\": \"मतदान {{reason}} के कारण नहीं बन सका\",\n \"Failed to delete the message\": \"संदेश हटाने में विफल\",\n \"Failed to end the poll\": \"पोल समाप्त करने में विफल\",\n \"Failed to end the poll due to {{reason}}\": \"{{reason}} के कारण पोल समाप्त करने में विफल\",\n \"Failed to jump to the first unread message\": \"पहले अपठित संदेश पर जाने में विफल\",\n \"Failed to leave channel\": \"चैनल छोड़ने में विफल\",\n \"Failed to load channels\": \"चैनल लोड करने में विफल\",\n \"Failed to load more channels\": \"और चैनल लोड करने में विफल\",\n \"Failed to mark channel as read\": \"चैनल को पढ़ा हुआ चिह्नित करने में विफल।\",\n \"Failed to play the recording\": \"रेकॉर्डिंग प्ले करने में विफल\",\n \"Failed to retrieve location\": \"स्थान प्राप्त करने में विफल\",\n \"Failed to save changes\": \"बदलाव सहेजने में विफल\",\n \"Failed to share location\": \"स्थान साझा करने में विफल\",\n \"Failed to update channel archive status\": \"चैनल के आर्काइव स्थिति को अपडेट करने में विफल\",\n \"Failed to update channel mute status\": \"चैनल की म्यूट स्थिति को अपडेट करने में विफल\",\n \"Failed to update channel pinned status\": \"चैनल की पिन स्थिति को अपडेट करने में विफल\",\n \"File\": \"फ़ाइल\",\n \"File is required for upload attachment\": \"अटैचमेंट अपलोड के लिए फ़ाइल आवश्यक है\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"फ़ाइल बहुत बड़ी है: {{ size }}, अधिकतम अपलोड साइज़ {{ limit }} है\",\n \"File too large\": \"फ़ाइल बहुत बड़ी है\",\n \"fileCount_one\": \"1 फ़ाइल\",\n \"fileCount_other\": \"{{ count }} फ़ाइलें\",\n \"Files\": \"फ़ाइलें\",\n \"Flag\": \"फ्लैग करे\",\n \"Generating...\": \"बना रहा है...\",\n \"giphy-command-args\": \"[पाठ]\",\n \"giphy-command-description\": \"चैनल पर एक क्रॉफिल जीआइएफ पोस्ट करें\",\n \"Go back\": \"वापस जाएं\",\n \"Group info\": \"समूह जानकारी\",\n \"Group name\": \"समूह का नाम\",\n \"Hide who voted\": \"किसने वोट दिया छिपाएं\",\n \"Image\": \"छवि\",\n \"imageCount_one\": \"1 छवि\",\n \"imageCount_other\": \"{{ count }} छवियाँ\",\n \"Instant commands\": \"तत्काल कमांड\",\n \"language/af\": \"अफ्रीकी\",\n \"language/am\": \"अम्हारिक\",\n \"language/ar\": \"अरबी\",\n \"language/az\": \"अज़रबैजानी\",\n \"language/bg\": \"बुल्गारियाई\",\n \"language/bn\": \"बंगाली\",\n \"language/bs\": \"बोस्नियाई\",\n \"language/cs\": \"चेक\",\n \"language/da\": \"डेनिश\",\n \"language/de\": \"जर्मन\",\n \"language/el\": \"यूनानी\",\n \"language/en\": \"अंग्रेज़ी\",\n \"language/es\": \"स्पेनिश\",\n \"language/es-MX\": \"स्पेनिश (मेक्सिको)\",\n \"language/et\": \"एस्तोनियाई\",\n \"language/fa\": \"फ़ारसी\",\n \"language/fa-AF\": \"दरी\",\n \"language/fi\": \"फ़िनिश\",\n \"language/fr\": \"फ़्रेंच\",\n \"language/fr-CA\": \"फ़्रेंच (कनाडा)\",\n \"language/ha\": \"हौसा\",\n \"language/he\": \"हिब्रू\",\n \"language/hi\": \"हिंदी\",\n \"language/hr\": \"क्रोएशियाई\",\n \"language/ht\": \"हैतियाई क्रियोल\",\n \"language/hu\": \"हंगेरी\",\n \"language/id\": \"इंडोनेशियाई\",\n \"language/it\": \"इतालवी\",\n \"language/ja\": \"जापानी\",\n \"language/ka\": \"जॉर्जियाई\",\n \"language/ko\": \"कोरियाई\",\n \"language/lt\": \"लिथुआनियाई\",\n \"language/lv\": \"लातवियाई\",\n \"language/ms\": \"मलय\",\n \"language/nl\": \"डच\",\n \"language/no\": \"नॉर्वेजियाई\",\n \"language/pl\": \"पोलिश\",\n \"language/ps\": \"पश्तो\",\n \"language/pt\": \"पुर्तगाली\",\n \"language/ro\": \"रोमानियाई\",\n \"language/ru\": \"रूसी\",\n \"language/sk\": \"स्लोवाक\",\n \"language/sl\": \"स्लोवेनियाई\",\n \"language/so\": \"सोमाली\",\n \"language/sq\": \"अल्बानियाई\",\n \"language/sr\": \"सर्बियाई\",\n \"language/sv\": \"स्वीडिश\",\n \"language/sw\": \"स्वाहिली\",\n \"language/ta\": \"तमिल\",\n \"language/th\": \"थाई\",\n \"language/tl\": \"तागालोग\",\n \"language/tr\": \"तुर्की\",\n \"language/uk\": \"यूक्रेनियाई\",\n \"language/ur\": \"उर्दू\",\n \"language/vi\": \"वियतनामी\",\n \"language/zh\": \"चीनी (सरलीकृत)\",\n \"language/zh-TW\": \"चीनी (पारंपरिक)\",\n \"Last seen {{ timestamp }}\": \"अंतिम बार {{ timestamp }} देखा गया\",\n \"Leave Channel\": \"चैनल छोड़ें\",\n \"Leave chat\": \"चैनल छोड़ें\",\n \"Left channel\": \"चैनल छोड़ दिया गया\",\n \"Let others add options\": \"दूसरों को विकल्प जोड़ने दें\",\n \"Limit votes per person\": \"प्रति व्यक्ति वोट सीमित करें\",\n \"Link\": \"लिंक\",\n \"linkCount_one\": \"1 लिंक\",\n \"linkCount_other\": \"{{ count }} लिंक\",\n \"live\": \"लाइव\",\n \"Live for {{duration}}\": \"{{duration}} के लिए लाइव\",\n \"Live location\": \"लाइव स्थान\",\n \"Live until {{ timestamp }}\": \"{{ timestamp }} तक लाइव\",\n \"Load more\": \"और लोड करें\",\n \"Local upload attachment missing local id\": \"लोकल अपलोड अटैचमेंट में लोकल आईडी नहीं है\",\n \"Location\": \"स्थान\",\n \"Location sharing ended\": \"स्थान साझा करना समाप्त\",\n \"Location: {{ coordinates }}\": \"स्थान: {{ coordinates }}\",\n \"Manage channel\": \"चैनल प्रबंधित करें\",\n \"Manage members\": \"सदस्य प्रबंधित करें\",\n \"Mark as unread\": \"अपठित चिह्नित करें\",\n \"Maximum number of votes (from 2 to 10)\": \"अधिकतम वोटों की संख्या (2 से 10)\",\n \"Maximum votes per person\": \"प्रति व्यक्ति अधिकतम वोट\",\n \"Member detail\": \"सदस्य विवरण\",\n \"mention/Channel\": \"चैनल\",\n \"mention/Channel Description\": \"इस चैनल में सभी को सूचित करें\",\n \"mention/Here\": \"यहां\",\n \"mention/Here Description\": \"इस चैनल के सभी ऑनलाइन सदस्यों को सूचित करें\",\n \"Menu\": \"मेन्यू\",\n \"Message deleted\": \"मैसेज हटा दिया गया\",\n \"Message failed to send\": \"संदेश भेजने में विफल\",\n \"Message has been successfully flagged\": \"मैसेज को फ्लैग कर दिया गया है\",\n \"Message marked as unread\": \"संदेश को अपठित के रूप में चिह्नित किया गया\",\n \"Message pinned\": \"संदेश पिन किया गया\",\n \"Message unpinned\": \"संदेश अनपिन किया गया\",\n \"Message was blocked by moderation policies\": \"संदेश को मॉडरेशन नीतियों द्वारा ब्लॉक कर दिया गया है\",\n \"Messages have been marked unread.\": \"संदेशों को अपठित चिह्नित किया गया है।\",\n \"Missing permissions to upload the attachment\": \"अटैचमेंट अपलोड करने के लिए अनुमतियां गायब\",\n \"Moderator\": \"मॉडरेटर\",\n \"Multiple votes\": \"कई वोट\",\n \"Mute\": \"म्यूट करे\",\n \"Mute chat\": \"चैट म्यूट करें\",\n \"Mute user\": \"उपयोगकर्ता को म्यूट करें\",\n \"mute-command-args\": \"[@उपयोगकर्तनाम]\",\n \"mute-command-description\": \"एक उपयोगकर्ता को म्यूट करें\",\n \"network error\": \"नेटवर्क त्रुटि\",\n \"New\": \"नए\",\n \"New message from {{user}}\": \"{{user}} से नया संदेश\",\n \"New Messages!\": \"नए मैसेज!\",\n \"Next\": \"अगला\",\n \"Next image\": \"अगली छवि\",\n \"No chats here yet…\": \"यहां अभी तक कोई चैट नहीं...\",\n \"No conversations yet\": \"अभी तक कोई बातचीत नहीं है\",\n \"No files\": \"कोई फ़ाइल नहीं\",\n \"No items exist\": \"कोई आइटम मौजूद नहीं है\",\n \"No member found\": \"कोई सदस्य नहीं मिला\",\n \"No messages found\": \"कोई संदेश नहीं मिला\",\n \"No photos or videos\": \"कोई फ़ोटो या वीडियो नहीं\",\n \"No pinned messages\": \"कोई पिन किया गया संदेश नहीं\",\n \"No results found\": \"कोई परिणाम नहीं मिला\",\n \"No user found\": \"कोई उपयोगकर्ता नहीं मिला\",\n \"Nobody will be able to vote in this poll anymore.\": \"अब कोई भी इस मतदान में मतदान नहीं कर सकेगा।\",\n \"Nothing yet...\": \"कोई मैसेज नहीं है\",\n \"Notify all {{ role }} members\": \"{{ role }} भूमिका वाले सभी सदस्यों को सूचित करें\",\n \"Offline\": \"ऑफलाइन\",\n \"Ok\": \"ठीक है\",\n \"Online\": \"ऑनलाइन\",\n \"Only numbers are allowed\": \"केवल संख्याएँ अनुमत हैं\",\n \"Only visible to you\": \"केवल आपको दिखाई देता है\",\n \"Open emoji picker\": \"इमोजी पिकर खोलिये\",\n \"Open gallery at image {{ index }}\": \"गैलरी को छवि {{ index }} पर खोलें\",\n \"Open image in gallery\": \"छवि को गैलरी में खोलें\",\n \"Open location in a map\": \"मानचित्र में स्थान खोलें\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"मेन्यू खोलें\",\n \"Option already exists\": \"विकल्प पहले से मौजूद है\",\n \"Option is empty\": \"विकल्प खाली है\",\n \"Options\": \"विकल्प\",\n \"Original\": \"मूल\",\n \"Owner\": \"मालिक\",\n \"People matching\": \"मेल खाते लोग\",\n \"Photo\": \"फ़ोटो\",\n \"Photos & videos\": \"फ़ोटो और वीडियो\",\n \"Pin\": \"पिन\",\n \"Pin a message to see it here\": \"इसे यहाँ देखने के लिए संदेश पिन करें\",\n \"Pinned by {{ name }}\": \"{{ name }} द्वारा पिन किया गया\",\n \"Pinned by You\": \"आपके द्वारा पिन किया गया\",\n \"Pinned message\": \"पिन किया गया संदेश\",\n \"Pinned messages\": \"पिन किए गए संदेश\",\n \"placeholder/PollComment\": \"आपकी टिप्पणी\",\n \"placeholder/PollOptionSuggestion\": \"नया विकल्प दर्ज करें\",\n \"Play video\": \"वीडियो चलाएं\",\n \"Playback speed {{ rate }}x\": \"प्लेबैक गति {{ rate }}x\",\n \"Poll\": \"मतदान\",\n \"Poll comments\": \"मतदान टिप्पणियाँ\",\n \"Poll ended\": \"पोल समाप्त\",\n \"Poll options\": \"मतदान विकल्प\",\n \"Poll results\": \"मतदान परिणाम\",\n \"Poll sent\": \"पोल भेजा गया\",\n \"Previous\": \"पिछला\",\n \"Previous image\": \"पिछली छवि\",\n \"Question\": \"प्रश्न\",\n \"Question {{ optionOrderNumber}}\": \"प्रश्न {{ optionOrderNumber}}\",\n \"Question is required\": \"प्रश्न आवश्यक है\",\n \"Quote Reply\": \"उद्धरण जवाब\",\n \"Reached the vote limit. Remove an existing vote first.\": \"मतदान सीमा तक पहुंच गया। पहले एक मौजूदा वोट हटाएं।\",\n \"Recording format is not supported and cannot be reproduced\": \"रेकॉर्डिंग फ़ॉर्मेट समर्थित नहीं है और पुनः उत्पन्न नहीं किया जा सकता\",\n \"Remind me\": \"मुझे याद दिलाएं\",\n \"Remind Me\": \"मुझे याद दिलाएं\",\n \"Reminder set\": \"अनुस्मारक सेट किया गया\",\n \"Remove\": \"हटाएं\",\n \"Remove {{ count }} members_one\": \"{{ count }} सदस्य हटाएं\",\n \"Remove {{ count }} members_other\": \"{{ count }} सदस्य हटाएं\",\n \"Remove {{ member }} from this channel?\": \"इस चैनल से {{ member }} को हटाएं?\",\n \"Remove channel members\": \"चैनल सदस्य हटाएं\",\n \"Remove reminder\": \"रिमाइंडर हटाएं\",\n \"Remove save for later\": \"बाद में देखें हटाएं\",\n \"Remove user\": \"उपयोगकर्ता हटाएं\",\n \"Removed {{ count }} members_one\": \"{{ count }} सदस्य हटाया गया\",\n \"Removed {{ count }} members_other\": \"{{ count }} सदस्य हटाए गए\",\n \"Replied to a thread\": \"थ्रेड में जवाब दिया\",\n \"Reply\": \"जवाब दे दो\",\n \"Reply to {{ authorName }}\": \"{{ authorName }} को जवाब दें\",\n \"Reply to a message to start a thread\": \"थ्रेड शुरू करने के लिए किसी संदेश का जवाब दें\",\n \"Reply to Message\": \"संदेश का जवाब दें\",\n \"replyCount_one\": \"1 रिप्लाई\",\n \"replyCount_other\": \"{{ count }} रिप्लाई\",\n \"Resend\": \"फिर से भेजें\",\n \"Retry upload\": \"अपलोड फिर से करें\",\n \"Review all options available in this poll\": \"इस पोल में उपलब्ध सभी विकल्पों की समीक्षा करें\",\n \"Review comments submitted with poll answers\": \"पोल उत्तरों के साथ भेजी गई टिप्पणियों की समीक्षा करें\",\n \"Review poll results and open an option to see detailed votes\": \"पोल परिणामों की समीक्षा करें और विस्तृत वोट देखने के लिए एक विकल्प खोलें\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"इस संदेश की समीक्षा करें और चुनें कि इसे हटाना है, संपादित करना है या फिर भी भेजना है\",\n \"Review who voted for this option\": \"समीक्षा करें कि इस विकल्प के लिए किसने वोट किया\",\n \"Save\": \"सहेजें\",\n \"Save for later\": \"बाद के लिए सहेजें\",\n \"Saved for later\": \"बाद के लिए सहेजा गया\",\n \"Search\": \"खोज\",\n \"Search GIFs\": \"GIF खोजें\",\n \"search-results-header-filter-source-button-label--channels\": \"चैनल्स\",\n \"search-results-header-filter-source-button-label--messages\": \"संदेश\",\n \"search-results-header-filter-source-button-label--users\": \"उपयोगकर्ता\",\n \"Searching for {{ searchSourceType }}...\": \"{{ searchSourceType }} खोज रहे हैं...\",\n \"Searching...\": \"खोज कर...\",\n \"searchResultsCount_one\": \"1 परिणाम\",\n \"searchResultsCount_other\": \"{{ count }} परिणाम\",\n \"Select a thread to continue the conversation\": \"बातचीत जारी रखने के लिए एक थ्रेड चुनें\",\n \"Select more than one option\": \"एक से अधिक विकल्प चुनें\",\n \"Select one\": \"एक चुनें\",\n \"Select one or more\": \"एक या अधिक चुनें\",\n \"Select up to {{count}}_one\": \"अधिकतम {{count}} तक चुनें\",\n \"Select up to {{count}}_other\": \"अधिकतम {{count}} तक चुनें\",\n \"Select your current location and optionally enable live location sharing\": \"अपना वर्तमान स्थान चुनें और वैकल्पिक रूप से लाइव लोकेशन शेयरिंग सक्षम करें\",\n \"Send\": \"भेजे\",\n \"Send a message\": \"संदेश भेजें\",\n \"Send a message to start the conversation\": \"बातचीत शुरू करने के लिए संदेश भेजें\",\n \"Send Anyway\": \"वैसे भी भेजें\",\n \"Send direct message\": \"सीधा संदेश भेजें\",\n \"Send message request failed\": \"संदेश भेजने का अनुरोध विफल रहा\",\n \"Send poll\": \"पोल भेजें\",\n \"Sending...\": \"भेजा जा रहा है\",\n \"Sent\": \"भेजा गया\",\n \"Share\": \"साझा करें\",\n \"Share a file to see it here\": \"इसे यहाँ देखने के लिए एक फ़ाइल साझा करें\",\n \"Share a photo or video to see it here\": \"इसे यहाँ देखने के लिए एक फ़ोटो या वीडियो साझा करें\",\n \"Share live location for\": \"लाइव स्थान साझा करें\",\n \"Share Location\": \"स्थान साझा करें\",\n \"Shared live location\": \"साझा किया गया लाइव स्थान\",\n \"Shared location\": \"साझा स्थान\",\n \"Shuffle\": \"मिश्रित करें\",\n \"size limit\": \"आकार सीमा\",\n \"Slow Mode ON\": \"स्लो मोड ऑन\",\n \"Slow mode, wait {{ seconds }}s...\": \"स्लो मोड, {{ seconds }} सेकंड प्रतीक्षा करें...\",\n \"Some of the files will not be accepted\": \"कुछ फ़ाइलें स्वीकार नहीं की जाएंगी\",\n \"Start typing to search\": \"खोजने के लिए टाइप करना शुरू करें\",\n \"Stop sharing\": \"साझा करना बंद करें\",\n \"Submit\": \"जमा करें\",\n \"Suggest a new option to add to this poll\": \"इस पोल में जोड़ने के लिए एक नया विकल्प सुझाएं\",\n \"Suggest an option\": \"एक विकल्प सुझाव दें\",\n \"Tap to remove\": \"हटाने के लिए टैप करें\",\n \"Tap to remove: {{ reactionName }}\": \"हटाने के लिए टैप करें: {{ reactionName }}\",\n \"Thinking...\": \"सोच रहा है...\",\n \"this content could not be displayed\": \"यह कॉन्टेंट लोड नहीं हो पाया\",\n \"This field cannot be empty or contain only spaces\": \"यह फ़ील्ड खाली नहीं हो सकता या केवल रिक्त स्थान नहीं रख सकता\",\n \"This message did not meet our content guidelines\": \"यह संदेश हमारे सामग्री दिशानिर्देशों के अनुरूप नहीं था\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"यह उपयोगकर्ता आपको फिर से संदेश भेज सकेगा।\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"रिप्लाई थ्रेड\",\n \"Thread has not been found\": \"थ्रेड नहीं मिला\",\n \"Thread reply\": \"थ्रेड में उत्तर\",\n \"Thread Reply\": \"थ्रेड में उत्तर\",\n \"ThreadListUnseenThreadsBanner/loading\": \"लोड हो रहा है...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} अपठित थ्रेड\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} अपठित थ्रेड\",\n \"Threads\": \"थ्रेड्स\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[बीता कल]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[आज]\\\", \\\"nextDay\\\": \\\"[कल]\\\", \\\"lastDay\\\": \\\"[बीता कल]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[पिछला] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"{{ count }} दिन पहले\",\n \"timestamp/relativeToday\": \"आज\",\n \"timestamp/relativeWeeksAgo\": \"{{ count }} सप्ताह पहले\",\n \"timestamp/relativeYesterday\": \"बीता कल\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[आज] HH:mm\\\", \\\"nextDay\\\": \\\"[कल] HH:mm\\\", \\\"lastDay\\\": \\\"[बीता कल] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd HH:mm\\\", \\\"lastWeek\\\": \\\"[पिछले] dddd, HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"रिकॉर्डिंग शुरू करने के लिए, अपने ब्राउज़र में कैमरा तक पहुँच दें\",\n \"To start recording, allow the microphone access in your browser\": \"रिकॉर्डिंग शुरू करने के लिए, अपने ब्राउज़र में माइक्रोफ़ोन तक पहुँच दें\",\n \"totalVoteCount_one\": \"कुल 1 वोट\",\n \"totalVoteCount_other\": \"कुल {{ count }} वोट\",\n \"Translated\": \"अनुवादित\",\n \"Translated from {{ language }}\": \"{{ language }} से अनुवादित\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"2 से 10 तक का एक नंबर टाइप करें\",\n \"Unarchive\": \"अनआर्काइव\",\n \"unban-command-args\": \"[@उपयोगकर्तनाम]\",\n \"unban-command-description\": \"एक उपयोगकर्ता को प्रतिषेध से मुक्त करें\",\n \"Unblock\": \"अनब्लॉक करें\",\n \"Unblock user\": \"उपयोगकर्ता अनब्लॉक करें\",\n \"Unblock User\": \"उपयोगकर्ता अनब्लॉक करें\",\n \"unknown error\": \"अज्ञात त्रुटि\",\n \"Unmute\": \"अनम्यूट\",\n \"Unmute chat\": \"चैट अनम्यूट करें\",\n \"Unmute user\": \"उपयोगकर्ता को अनम्यूट करें\",\n \"unmute-command-args\": \"[@उपयोगकर्तनाम]\",\n \"unmute-command-description\": \"एक उपयोगकर्ता को अनम्यूट करें\",\n \"Unpin\": \"अनपिन\",\n \"Unread messages\": \"अपठित संदेश\",\n \"Unsupported attachment\": \"असमर्थित अटैचमेंट\",\n \"unsupported file type\": \"असमर्थित फ़ाइल प्रकार\",\n \"Update\": \"अपडेट करें\",\n \"Update the comment attached to your poll answer\": \"अपने पोल उत्तर से जुड़ी टिप्पणी अपडेट करें\",\n \"Update your comment\": \"अपने टिप्पणी को अपडेट करें\",\n \"Upload blocked\": \"अपलोड अवरुद्ध\",\n \"Upload error\": \"अपलोड त्रुटि\",\n \"Upload failed\": \"अपलोड विफल\",\n \"Upload Picture\": \"चित्र अपलोड करें\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"अपलोड प्रकार: \\\"{{ type }}\\\" की अनुमति नहीं है\",\n \"User blocked\": \"उपयोगकर्ता अवरुद्ध किया गया\",\n \"User muted\": \"उपयोगकर्ता म्यूट किया गया\",\n \"User removed\": \"उपयोगकर्ता हटा दिया गया\",\n \"User unblocked\": \"उपयोगकर्ता अनब्लॉक किया गया\",\n \"User unmuted\": \"उपयोगकर्ता अनम्यूट किया गया\",\n \"User uploaded content\": \"उपयोगकर्ता अपलोड की गई सामग्री\",\n \"Video\": \"वीडियो\",\n \"videoCount_one\": \"1 वीडियो\",\n \"videoCount_other\": \"{{ count }} वीडियो\",\n \"View\": \"देखें\",\n \"View {{count}} comments_one\": \"देखें {{count}} टिप्पणी\",\n \"View {{count}} comments_other\": \"देखें {{count}} टिप्पणियाँ\",\n \"View all\": \"सभी देखें\",\n \"View member details for {{ member }}\": \"{{ member }} के सदस्य विवरण देखें\",\n \"View original\": \"मूल देखें\",\n \"View results\": \"परिणाम देखें\",\n \"View translation\": \"अनुवाद देखें\",\n \"Voice message\": \"आवाज संदेश\",\n \"Voice message {{ duration }}\": \"वॉइस संदेश {{ duration }}\",\n \"Voice message deleted\": \"वॉइस संदेश हटा दिया गया\",\n \"voiceMessageCount_one\": \"1 ध्वनि संदेश\",\n \"voiceMessageCount_other\": \"{{ count }} ध्वनि संदेश\",\n \"Vote ended\": \"मतदान समाप्त\",\n \"Votes\": \"वोट\",\n \"Wait until all attachments have uploaded\": \"सभी अटैचमेंट अपलोड होने तक प्रतीक्षा करें\",\n \"Waiting for network…\": \"नेटवर्क की प्रतीक्षा…\",\n \"You\": \"आप\",\n \"You've reached the maximum number of files\": \"आप अधिकतम फ़ाइलों तक पहुँच गए हैं\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} e altri {{ moreCount }}\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} e {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} file\",\n \"{{ count }} files_many\": \"{{ count }} file\",\n \"{{ count }} files_other\": \"{{ count }} file\",\n \"{{ count }} members_one\": \"{{ count }} membro\",\n \"{{ count }} members_many\": \"{{ count }} membri\",\n \"{{ count }} members_other\": \"{{ count }} membri\",\n \"{{ count }} members added_one\": \"{{ count }} membro aggiunto\",\n \"{{ count }} members added_many\": \"{{ count }} membri aggiunti\",\n \"{{ count }} members added_other\": \"{{ count }} membri aggiunti\",\n \"{{ count }} people are typing_one\": \"{{ count }} persona sta scrivendo\",\n \"{{ count }} people are typing_many\": \"{{ count }} persone stanno scrivendo\",\n \"{{ count }} people are typing_other\": \"{{ count }} persone stanno scrivendo\",\n \"{{ count }} photos_one\": \"{{ count }} foto\",\n \"{{ count }} photos_many\": \"{{ count }} foto\",\n \"{{ count }} photos_other\": \"{{ count }} foto\",\n \"{{ count }} reactions_one\": \"{{ count }} reazione\",\n \"{{ count }} reactions_many\": \"{{ count }} reazioni\",\n \"{{ count }} reactions_other\": \"{{ count }} reazioni\",\n \"{{ count }} videos_one\": \"{{ count }} video\",\n \"{{ count }} videos_many\": \"{{ count }} video\",\n \"{{ count }} videos_other\": \"{{ count }} video\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} e {{ secondUser }}\",\n \"{{ imageCount }} more\": \"+ {{ imageCount }}\",\n \"{{ member }} will be able to message you again.\": \"{{ member }} potrà inviarti di nuovo messaggi.\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }} non potrà più inviarti messaggi.\",\n \"{{ memberCount }} members\": \"{{ memberCount }} membri\",\n \"{{ typing }} are typing\": \"{{ typing }} stanno scrivendo\",\n \"{{ typing }} is typing\": \"{{ typing }} sta scrivendo\",\n \"{{ user }} has been muted\": \"{{ user }} è stato silenziato\",\n \"{{ user }} has been unmuted\": \"Notifiche riattivate per {{ user }}\",\n \"{{ user }} is typing...\": \"{{ user }} sta digitando...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} e {{ user }} stanno digitando...\",\n \"{{ users }} and more are typing...\": \"{{ users }} e altri stanno digitando...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} online\",\n \"{{count}} new messages_one\": \"{{count}} nuovo messaggio\",\n \"{{count}} new messages_many\": \"{{count}} nuovi messaggi\",\n \"{{count}} new messages_other\": \"{{count}} nuovi messaggi\",\n \"{{count}} unread_one\": \"{{count}} non letto\",\n \"{{count}} unread_many\": \"{{count}} non letti\",\n \"{{count}} unread_other\": \"{{count}} non letti\",\n \"{{count}} votes_one\": \"{{count}} voto\",\n \"{{count}} votes_many\": \"{{count}} voti\",\n \"{{count}} votes_other\": \"{{count}} voti\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"+{{count}} altra opzione\",\n \"+{{count}} more options_many\": \"+{{count}} altre opzioni\",\n \"+{{count}} more options_other\": \"+{{count}} altre opzioni\",\n \"🏙 Attachment...\": \"🏙 Allegato...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} ha creato: {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} ha votato: {{pollOptionText}}\",\n \"📍Shared location\": \"📍Posizione condivisa\",\n \"Actions\": \"Actions\",\n \"Add\": \"Aggiungi\",\n \"Add {{ count }} members_one\": \"Aggiungi {{ count }} membro\",\n \"Add {{ count }} members_many\": \"Aggiungi {{ count }} membri\",\n \"Add {{ count }} members_other\": \"Aggiungi {{ count }} membri\",\n \"Add a comment\": \"Aggiungi un commento\",\n \"Add a comment to your poll answer\": \"Aggiungi un commento alla tua risposta al sondaggio\",\n \"Add an option\": \"Aggiungi un'opzione\",\n \"Add channel members\": \"Aggiungi membri al canale\",\n \"Add members\": \"Aggiungi membri\",\n \"Add reaction\": \"Aggiungi reazione\",\n \"Admin\": \"Admin\",\n \"All results loaded\": \"Tutti i risultati caricati\",\n \"Allow access to camera\": \"Consenti l'accesso alla fotocamera\",\n \"Allow access to microphone\": \"Consenti l'accesso al microfono\",\n \"Allow comments\": \"Consenti i commenti\",\n \"Allow option suggestion\": \"Consenti il suggerimento di opzioni\",\n \"Allow others to add comments\": \"Consenti ad altri di aggiungere commenti\",\n \"Already a member\": \"Già membro\",\n \"Also send as a direct message\": \"Invia anche come messaggio diretto\",\n \"Also send in channel\": \"Invia anche nel canale\",\n \"Also sent in channel\": \"Inviato anche nel canale\",\n \"An error has occurred during recording\": \"Si è verificato un errore durante la registrazione\",\n \"An error has occurred during the recording processing\": \"Si è verificato un errore durante l'elaborazione della registrazione\",\n \"Anonymous\": \"Anonimo\",\n \"Anonymous poll\": \"Sondaggio anonimo\",\n \"Archive\": \"Archivia\",\n \"Are you sure you want to delete this message?\": \"Sei sicuro di voler eliminare questo messaggio?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_one\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_many\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_one\": \"{{ count }} allegato\",\n \"aria/{{ count }} attachment_many\": \"{{ count }} allegati\",\n \"aria/{{ count }} attachment_other\": \"{{ count }} allegati\",\n \"aria/{{ count }} search results_one\": \"{{ count }} risultato di ricerca\",\n \"aria/{{ count }} search results_many\": \"{{ count }} risultati di ricerca\",\n \"aria/{{ count }} search results_other\": \"{{ count }} risultati di ricerca\",\n \"aria/{{ count }} suggestions_one\": \"{{ count }} suggerimento\",\n \"aria/{{ count }} suggestions_many\": \"{{ count }} suggerimenti\",\n \"aria/{{ count }} suggestions_other\": \"{{ count }} suggerimenti\",\n \"aria/{{ count }} unread message_one\": \"{{ count }} messaggio non letto\",\n \"aria/{{ count }} unread message_many\": \"{{ count }} messaggi non letti\",\n \"aria/{{ count }} unread message_other\": \"{{ count }} messaggi non letti\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} disattivato\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} attivato\",\n \"aria/Active\": \"Attivo\",\n \"aria/Animated GIF\": \"GIF animata\",\n \"aria/Animated GIF: {{ title }}\": \"GIF animata: {{ title }}\",\n \"aria/Attachment\": \"Allegato\",\n \"aria/Attachment {{ attachmentType }}\": \"Allegato {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"Azioni allegato\",\n \"aria/audio\": \"audio\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Posizione audio {{ elapsed }} di {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"Posizione audio {{ progress }} percento\",\n \"aria/Back to attachments\": \"Torna agli allegati\",\n \"aria/Back to parent menu button\": \"Torna al menu principale pulsante\",\n \"aria/Block User\": \"Blocca utente\",\n \"aria/Bookmark Message\": \"Salva messaggio\",\n \"aria/Cancel recording\": \"Annulla registrazione\",\n \"aria/Cancel Reply\": \"Annulla risposta\",\n \"aria/Channel Actions\": \"Azioni canale\",\n \"aria/Channel details\": \"Dettagli canale\",\n \"aria/Channel list\": \"Elenco dei canali\",\n \"aria/Chat view controls\": \"Controlli visualizzazione chat\",\n \"aria/Chat: {{ channelName }}\": \"Chat: {{ channelName }}\",\n \"aria/Clear search\": \"Cancella ricerca\",\n \"aria/Close callout dialog\": \"Chiudi finestra informativa\",\n \"aria/Close thread\": \"Chiudi discussione\",\n \"aria/Collapse sidebar\": \"Comprimi barra laterale\",\n \"aria/Command activated: {{ command }}\": \"Comando attivato: {{ command }}\",\n \"aria/Command Suggestions\": \"Suggerimenti comandi\",\n \"aria/Complete recording\": \"Completa registrazione\",\n \"aria/Copy Message Text\": \"Copia testo messaggio\",\n \"aria/Decrease value\": \"Diminuisci valore\",\n \"aria/Delete Message\": \"Elimina messaggio\",\n \"aria/Delivered\": \"Consegnato\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"Stato di consegna: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"Chiudi notifica\",\n \"aria/Download attachment\": \"Scarica l'allegato\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"«{{ option }}» rilasciato in posizione {{ position }}.\",\n \"aria/Edit Message\": \"Modifica messaggio\",\n \"aria/Emoji picker\": \"Selettore di emoji\",\n \"aria/Emoji Suggestions\": \"Suggerimenti emoji\",\n \"aria/Exit search\": \"Esci dalla ricerca\",\n \"aria/Expand sidebar\": \"Espandi barra laterale\",\n \"aria/file\": \"file\",\n \"aria/File upload\": \"Caricamento di file\",\n \"aria/Flag Message\": \"Segnala messaggio\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Azioni Giphy\",\n \"aria/Giphy canceled\": \"Giphy annullato\",\n \"aria/Giphy image changed\": \"Immagine Giphy cambiata\",\n \"aria/Giphy image changed: {{ title }}\": \"Immagine Giphy cambiata: {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Anteprima Giphy, visibile solo a te. Usa le azioni Invia, Mescola o Annulla.\",\n \"aria/Giphy sent\": \"Giphy inviato\",\n \"aria/image\": \"immagine\",\n \"aria/Image failed to load\": \"Caricamento immagine non riuscito\",\n \"aria/Increase value\": \"Aumenta valore\",\n \"aria/Jump to latest message\": \"Vai all'ultimo messaggio\",\n \"aria/Jump to quoted message\": \"Vai al messaggio citato\",\n \"aria/Last activity: {{ time }}\": \"Ultima attività: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"Ultimo messaggio da {{ sender }}: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"Ultimo messaggio: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"Contrassegna come non letto\",\n \"aria/Mark messages as read\": \"Segna i messaggi come letti\",\n \"aria/Mention Suggestions\": \"Suggerimenti di menzione\",\n \"aria/Message Actions\": \"Azioni del messaggio\",\n \"aria/Message from {{ user }},\": \"Messaggio di {{ user }},\",\n \"aria/Message input\": \"Campo messaggio\",\n \"aria/Message with attachments\": \"Messaggio con allegati\",\n \"aria/Message,\": \"Messaggio,\",\n \"aria/Mute User\": \"Mute utente\",\n \"aria/Next page\": \"Pagina successiva\",\n \"aria/No search results found\": \"Nessun risultato di ricerca trovato\",\n \"aria/Notifications\": \"Notifiche\",\n \"aria/Open Attachment Selector\": \"Apri selettore allegati\",\n \"aria/Open Channel Actions Menu\": \"Apri menu azioni canale\",\n \"aria/Open channel details\": \"Apri dettagli canale\",\n \"aria/Open channels view\": \"Apri visualizzazione canali\",\n \"aria/Open image shared by {{ name }}\": \"Apri l'immagine condivisa da {{ name }}\",\n \"aria/Open Message Actions Menu\": \"Apri il menu delle azioni di messaggio\",\n \"aria/Open Reaction Selector\": \"Apri il selettore di reazione\",\n \"aria/Open Thread\": \"Apri discussione\",\n \"aria/Open threads view\": \"Apri visualizzazione discussioni\",\n \"aria/Open threads view with unread threads_one\": \"Apri visualizzazione discussioni, {{ count }} discussione non letta\",\n \"aria/Open threads view with unread threads_many\": \"Apri visualizzazione discussioni, {{ count }} discussioni non lette\",\n \"aria/Open threads view with unread threads_other\": \"Apri visualizzazione discussioni, {{ count }} discussioni non lette\",\n \"aria/Open video shared by {{ name }}\": \"Apri il video condiviso da {{ name }}\",\n \"aria/Opened channel: {{ name }}\": \"Canale aperto: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"Thread aperto in {{ name }}\",\n \"aria/Option {{ position }}\": \"Opzione {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"Ora le opzioni possono essere riordinate e rimosse.\",\n \"aria/Pause\": \"Pausa\",\n \"aria/Pause recording\": \"Metti in pausa registrazione\",\n \"aria/Percent complete\": \"{{percent}} percento completato\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"Hai preso «{{ option }}». Usa le frecce per riordinare. Premi Spazio o Tab per rilasciare.\",\n \"aria/Pin Message\": \"Appunta messaggio\",\n \"aria/Play\": \"Riproduci\",\n \"aria/Poll dialog opened\": \"Finestra di dialogo del sondaggio aperta\",\n \"aria/Poll sent\": \"Sondaggio inviato\",\n \"aria/Poll: {{ pollName }}\": \"Sondaggio: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Premi Invio per iniziare a digitare\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"Premi la barra spaziatrice per selezionare questa opzione, usa i tasti freccia Su e Giù per spostarla, quindi premi di nuovo la barra spaziatrice per deselezionarla.\",\n \"aria/Previous page\": \"Pagina precedente\",\n \"aria/Quote Message\": \"Citazione messaggio\",\n \"aria/Reaction list\": \"Elenco delle reazioni\",\n \"aria/Read\": \"Letto\",\n \"aria/Recording paused\": \"Registrazione in pausa\",\n \"aria/Recording resumed\": \"Registrazione ripresa\",\n \"aria/Recording started\": \"Registrazione avviata\",\n \"aria/Remind Me Message\": \"Ricordami\",\n \"aria/Remove attachment\": \"Rimuovi allegato\",\n \"aria/Remove location attachment\": \"Rimuovi allegato posizione\",\n \"aria/Remove option: {{ option }}\": \"Rimuovi opzione: {{ option }}\",\n \"aria/Remove Reminder\": \"Rimuovi promemoria\",\n \"aria/Remove Save For Later\": \"Rimuovi Salva per dopo\",\n \"aria/Removed option {{ option }}\": \"Opzione {{ option }} rimossa\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"Riordina «{{ option }}», posizione {{ position }} di {{ total }}\",\n \"aria/Reorder option {{ position }}\": \"Riordina opzione {{ position }}\",\n \"aria/Resend Message\": \"Invia di nuovo messaggio\",\n \"aria/Resume recording\": \"Riprendi registrazione\",\n \"aria/Retry upload\": \"Riprova caricamento\",\n \"aria/Review bounced message\": \"Rivedi il messaggio respinto\",\n \"aria/Search cleared\": \"Ricerca cancellata\",\n \"aria/Search results\": \"Risultati della ricerca\",\n \"aria/Search results header filter button for: {{ source }}\": \"Pulsante filtro intestazione risultati di ricerca per: {{ source }}\",\n \"aria/Seek audio position\": \"Cerca posizione audio\",\n \"aria/Select Reaction: {{ reactionName }}\": \"Seleziona reazione: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"Seleziona canale utente: {{ name }}\",\n \"aria/Send\": \"Invia\",\n \"aria/Sent\": \"Inviato\",\n \"aria/Shared a link\": \"Link condiviso\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"Link condiviso con titolo: {{ linkTitle }}\",\n \"aria/Shared location\": \"Posizione condivisa\",\n \"aria/Show preview\": \"Mostra anteprima\",\n \"aria/Start recording audio\": \"Avvia registrazione audio\",\n \"aria/Stop AI Generation\": \"Interrompi generazione IA\",\n \"aria/Submenu\": \"Sottomenu\",\n \"aria/Suggestions\": \"Suggerimenti\",\n \"aria/There are no messages in this chat.\": \"Non ci sono messaggi in questa chat\",\n \"aria/This option can be reordered and removed.\": \"Questa opzione può essere riordinata e rimossa.\",\n \"aria/Thread list\": \"Elenco thread\",\n \"aria/Thread: {{ messagePreview }}\": \"Discussione: {{ messagePreview }}\",\n \"aria/Unblock User\": \"Sblocca utente\",\n \"aria/Unmute User\": \"Riattiva il notifiche\",\n \"aria/Unpin Message\": \"Rimuovi messaggio appuntato\",\n \"aria/User selected: {{ user }}\": \"Utente selezionato: {{ user }}\",\n \"aria/video\": \"video\",\n \"aria/voice message\": \"messaggio vocale\",\n \"aria/Voice message sent\": \"Messaggio vocale inviato\",\n \"aria/Voice recording attached\": \"Registrazione vocale allegata\",\n \"Ask a question\": \"Fai una domanda\",\n \"Attach\": \"Allega\",\n \"Attach files\": \"Allega file\",\n \"Attachment\": \"Allegato\",\n \"Attachment upload blocked due to {{reason}}\": \"Caricamento allegato bloccato a causa di {{reason}}\",\n \"Attachment upload failed due to {{reason}}\": \"Caricamento allegato fallito a causa di {{reason}}\",\n \"Back\": \"Indietro\",\n \"ban-command-args\": \"[@nomeutente] [testo]\",\n \"ban-command-description\": \"Vietare un utente\",\n \"Block user\": \"Blocca utente\",\n \"Block User\": \"Blocca utente\",\n \"Browse channel members\": \"Sfoglia membri del canale\",\n \"Browse pinned messages\": \"Sfoglia messaggi fissati\",\n \"Cancel\": \"Annulla\",\n \"Cannot seek in the recording\": \"Impossibile cercare nella registrazione\",\n \"Changes saved\": \"Modifiche salvate\",\n \"Channel archived\": \"Canale archiviato\",\n \"Channel members\": \"Membri del canale\",\n \"Channel Missing\": \"Il canale non esiste\",\n \"Channel muted\": \"Canale silenziato\",\n \"Channel pinned\": \"Canale fissato\",\n \"Channel unarchived\": \"Archiviazione del canale annullata\",\n \"Channel unmuted\": \"Canale non più silenziato\",\n \"Channel unpinned\": \"Canale rimosso dai fissati\",\n \"Channels\": \"Canali\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"Chat\",\n \"Choose between 2 to 10 options\": \"Scegli tra 2 e 10 opzioni\",\n \"Close\": \"Chiudi\",\n \"Close dialog\": \"Chiudi finestra di dialogo\",\n \"Close emoji picker\": \"Chiudi il selettore di emoji\",\n \"Command not available while editing\": \"Comando non disponibile durante la modifica\",\n \"Command not available while replying\": \"Comando non disponibile durante la risposta\",\n \"Commands\": \"Comandi\",\n \"Commands matching\": \"Comandi corrispondenti\",\n \"Connection failure, reconnecting now...\": \"Errore di connessione, riconnessione in corso...\",\n \"Contact info\": \"Informazioni contatto\",\n \"Contact name\": \"Nome del contatto\",\n \"Copy Message\": \"Copia messaggio\",\n \"Create\": \"Crea\",\n \"Create a question, add options, and configure poll settings\": \"Crea una domanda, aggiungi opzioni e configura le impostazioni del sondaggio\",\n \"Create poll\": \"Crea sondaggio\",\n \"Current location\": \"Posizione attuale\",\n \"Delete\": \"Elimina\",\n \"Delete chat\": \"Elimina chat\",\n \"Delete for me\": \"Elimina per me\",\n \"Delete message\": \"Elimina messaggio\",\n \"Delivered\": \"Consegnato\",\n \"Direct message\": \"Messaggio diretto\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Vuoi terminare questo sondaggio ora? Nessuno potrà più votare in questo sondaggio.\",\n \"Download {{ fileName }}\": \"Scarica {{ fileName }}\",\n \"Download All\": \"Scarica tutto\",\n \"Download Attachment\": \"Scarica allegato\",\n \"Download attachment {{ name }}\": \"Scarica l'allegato {{ name }}\",\n \"Download attachment {{ number }}\": \"Scarica l'allegato {{ number }}\",\n \"Drag your files here\": \"Trascina i tuoi file qui\",\n \"Drag your files here to add to your post\": \"Trascina i tuoi file qui per aggiungerli al tuo post\",\n \"Due {{ timeLeft }}\": \"Scadenza tra {{ timeLeft }}\",\n \"Due since {{ dueSince }}\": \"Scaduto dal {{ dueSince }}\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"Modifica\",\n \"Edit chat data\": \"Modifica dati chat\",\n \"Edit contact\": \"Modifica contatto\",\n \"Edit group\": \"Modifica gruppo\",\n \"Edit Message\": \"Modifica messaggio\",\n \"Edit message request failed\": \"Richiesta di modifica del messaggio non riuscita\",\n \"Edited\": \"Modificato\",\n \"Emoji matching\": \"Abbinamento emoji\",\n \"Empty message...\": \"Messaggio vuoto...\",\n \"End\": \"Fine\",\n \"End poll\": \"Termina sondaggio\",\n \"End this poll?\": \"Terminare questo sondaggio?\",\n \"End vote\": \"Termina il voto\",\n \"Enforce unique vote is enabled\": \"Il voto unico è abilitato\",\n \"Error\": \"Errore\",\n \"Error adding flag\": \"Errore durante l'aggiunta del flag\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"Errore durante il blocco dell'utente\",\n \"Error connecting to chat, refresh the page to try again.\": \"Errore di connessione alla chat, aggiorna la pagina per riprovare.\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"Errore durante l'eliminazione del messaggio\",\n \"Error fetching reactions\": \"Errore nel caricamento delle reazioni\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Errore durante la marcatura del messaggio come non letto. Impossibile marcare messaggi non letti più vecchi dei più recenti 100 messaggi del canale.\",\n \"Error muting a user ...\": \"Errore nel silenziare un utente ...\",\n \"Error muting channel\": \"Errore durante la disattivazione delle notifiche del canale\",\n \"Error muting user\": \"Errore durante la disattivazione delle notifiche dell'utente\",\n \"Error opening direct message\": \"Errore nell'apertura del messaggio diretto\",\n \"Error pinning message\": \"Errore durante il blocco del messaggio\",\n \"Error removing members\": \"Errore nella rimozione dei membri\",\n \"Error removing message pin\": \"Errore durante la rimozione del PIN del messaggio\",\n \"Error removing user\": \"Errore nella rimozione dell'utente\",\n \"Error reproducing the recording\": \"Errore durante la riproduzione della registrazione\",\n \"Error starting recording\": \"Errore durante l'avvio della registrazione\",\n \"Error unblocking user\": \"Errore durante lo sblocco dell'utente\",\n \"Error unmuting a user ...\": \"Errore nel riattivare un utente ...\",\n \"Error unmuting channel\": \"Errore durante la riattivazione del canale\",\n \"Error unmuting user\": \"Errore durante la riattivazione dell'utente\",\n \"Error uploading attachment\": \"Errore durante il caricamento dell'allegato\",\n \"Error uploading file\": \"Errore durante il caricamento del file\",\n \"Error uploading image\": \"Errore durante il caricamento dell'immagine\",\n \"Error: {{ errorMessage }}\": \"Errore: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"Esci dal comando {{ command }}\",\n \"Failed to block user\": \"Impossibile bloccare l'utente\",\n \"Failed to create the poll\": \"Impossibile creare il sondaggio\",\n \"Failed to create the poll due to {{reason}}\": \"Impossibile creare il sondaggio a causa di {{reason}}\",\n \"Failed to delete the message\": \"Impossibile eliminare il messaggio\",\n \"Failed to end the poll\": \"Impossibile terminare il sondaggio\",\n \"Failed to end the poll due to {{reason}}\": \"Impossibile terminare il sondaggio a causa di {{reason}}\",\n \"Failed to jump to the first unread message\": \"Impossibile passare al primo messaggio non letto\",\n \"Failed to leave channel\": \"Impossibile lasciare il canale\",\n \"Failed to load channels\": \"Impossibile caricare i canali\",\n \"Failed to load more channels\": \"Impossibile caricare altri canali\",\n \"Failed to mark channel as read\": \"Impossibile contrassegnare il canale come letto\",\n \"Failed to play the recording\": \"Impossibile riprodurre la registrazione\",\n \"Failed to retrieve location\": \"Impossibile recuperare la posizione\",\n \"Failed to save changes\": \"Impossibile salvare le modifiche\",\n \"Failed to share location\": \"Impossibile condividere la posizione\",\n \"Failed to update channel archive status\": \"Impossibile aggiornare lo stato di archiviazione del canale\",\n \"Failed to update channel mute status\": \"Impossibile aggiornare lo stato di silenziamento del canale\",\n \"Failed to update channel pinned status\": \"Impossibile aggiornare lo stato di blocco del canale\",\n \"File\": \"File\",\n \"File is required for upload attachment\": \"È richiesto un file per caricare l'allegato\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Il file è troppo grande: {{ size }}, la dimensione massima di caricamento è {{ limit }}\",\n \"File too large\": \"File troppo grande\",\n \"fileCount_one\": \"1 file\",\n \"fileCount_many\": \"{{ count }} file\",\n \"fileCount_other\": \"{{ count }} file\",\n \"Files\": \"File\",\n \"Flag\": \"Segnala\",\n \"Generating...\": \"Generando...\",\n \"giphy-command-args\": \"[testo]\",\n \"giphy-command-description\": \"Pubblica un gif casuale sul canale\",\n \"Go back\": \"Indietro\",\n \"Group info\": \"Informazioni gruppo\",\n \"Group name\": \"Nome del gruppo\",\n \"Hide who voted\": \"Nascondi chi ha votato\",\n \"Image\": \"Immagine\",\n \"imageCount_one\": \"Immagine\",\n \"imageCount_many\": \"{{ count }} immagini\",\n \"imageCount_other\": \"{{ count }} immagini\",\n \"Instant commands\": \"Comandi istantanei\",\n \"language/af\": \"Afrikaans\",\n \"language/am\": \"Amarico\",\n \"language/ar\": \"Arabo\",\n \"language/az\": \"Azero\",\n \"language/bg\": \"Bulgaro\",\n \"language/bn\": \"Bengalese\",\n \"language/bs\": \"Bosniaco\",\n \"language/cs\": \"Ceco\",\n \"language/da\": \"Danese\",\n \"language/de\": \"Tedesco\",\n \"language/el\": \"Greco\",\n \"language/en\": \"Inglese\",\n \"language/es\": \"Spagnolo\",\n \"language/es-MX\": \"Spagnolo (Messico)\",\n \"language/et\": \"Estone\",\n \"language/fa\": \"Persiano\",\n \"language/fa-AF\": \"Dari\",\n \"language/fi\": \"Finlandese\",\n \"language/fr\": \"Francese\",\n \"language/fr-CA\": \"Francese (Canada)\",\n \"language/ha\": \"Hausa\",\n \"language/he\": \"Ebraico\",\n \"language/hi\": \"Hindi\",\n \"language/hr\": \"Croato\",\n \"language/ht\": \"Creolo haitiano\",\n \"language/hu\": \"Ungherese\",\n \"language/id\": \"Indonesiano\",\n \"language/it\": \"Italiano\",\n \"language/ja\": \"Giapponese\",\n \"language/ka\": \"Georgiano\",\n \"language/ko\": \"Coreano\",\n \"language/lt\": \"Lituano\",\n \"language/lv\": \"Lettone\",\n \"language/ms\": \"Malese\",\n \"language/nl\": \"Olandese\",\n \"language/no\": \"Norvegese\",\n \"language/pl\": \"Polacco\",\n \"language/ps\": \"Pashto\",\n \"language/pt\": \"Portoghese\",\n \"language/ro\": \"Rumeno\",\n \"language/ru\": \"Russo\",\n \"language/sk\": \"Slovacco\",\n \"language/sl\": \"Sloveno\",\n \"language/so\": \"Somalo\",\n \"language/sq\": \"Albanese\",\n \"language/sr\": \"Serbo\",\n \"language/sv\": \"Svedese\",\n \"language/sw\": \"Swahili\",\n \"language/ta\": \"Tamil\",\n \"language/th\": \"Thai\",\n \"language/tl\": \"Tagalog\",\n \"language/tr\": \"Turco\",\n \"language/uk\": \"Ucraino\",\n \"language/ur\": \"Urdu\",\n \"language/vi\": \"Vietnamita\",\n \"language/zh\": \"Cinese (semplificato)\",\n \"language/zh-TW\": \"Cinese (tradizionale)\",\n \"Last seen {{ timestamp }}\": \"Ultimo accesso {{ timestamp }}\",\n \"Leave Channel\": \"Lascia il canale\",\n \"Leave chat\": \"Lascia il canale\",\n \"Left channel\": \"Canale lasciato\",\n \"Let others add options\": \"Lascia che altri aggiungano opzioni\",\n \"Limit votes per person\": \"Limita i voti per persona\",\n \"Link\": \"Collegamento\",\n \"linkCount_one\": \"Link\",\n \"linkCount_many\": \"{{ count }} link\",\n \"linkCount_other\": \"{{ count }} link\",\n \"live\": \"live\",\n \"Live for {{duration}}\": \"Live per {{duration}}\",\n \"Live location\": \"Posizione live\",\n \"Live until {{ timestamp }}\": \"Live fino a {{ timestamp }}\",\n \"Load more\": \"Carica di più\",\n \"Local upload attachment missing local id\": \"Allegato di caricamento locale senza id locale\",\n \"Location\": \"Posizione\",\n \"Location sharing ended\": \"Condivisione posizione terminata\",\n \"Location: {{ coordinates }}\": \"Posizione: {{ coordinates }}\",\n \"Manage channel\": \"Gestisci canale\",\n \"Manage members\": \"Gestisci membri\",\n \"Mark as unread\": \"Contrassegna come non letto\",\n \"Maximum number of votes (from 2 to 10)\": \"Numero massimo di voti (da 2 a 10)\",\n \"Maximum votes per person\": \"Voti massimi per persona\",\n \"Member detail\": \"Dettagli membro\",\n \"mention/Channel\": \"Canale\",\n \"mention/Channel Description\": \"Notifica tutti in questo canale\",\n \"mention/Here\": \"Qui\",\n \"mention/Here Description\": \"Notifica tutti i membri online in questo canale\",\n \"Menu\": \"Menù\",\n \"Message deleted\": \"Messaggio cancellato\",\n \"Message failed to send\": \"Invio del messaggio non riuscito\",\n \"Message has been successfully flagged\": \"Il messaggio è stato segnalato con successo\",\n \"Message marked as unread\": \"Messaggio contrassegnato come non letto\",\n \"Message pinned\": \"Messaggio bloccato\",\n \"Message unpinned\": \"Messaggio rimosso dai fissati\",\n \"Message was blocked by moderation policies\": \"Il messaggio è stato bloccato dalle politiche di moderazione\",\n \"Messages have been marked unread.\": \"I messaggi sono stati contrassegnati come non letti.\",\n \"Missing permissions to upload the attachment\": \"Autorizzazioni mancanti per caricare l'allegato\",\n \"Moderator\": \"Moderatore\",\n \"Multiple votes\": \"Voti multipli\",\n \"Mute\": \"Silenzia\",\n \"Mute chat\": \"Disattiva notifiche chat\",\n \"Mute user\": \"Disattiva notifiche utente\",\n \"mute-command-args\": \"[@nomeutente]\",\n \"mute-command-description\": \"Silenzia un utente\",\n \"network error\": \"errore di rete\",\n \"New\": \"Nuovo\",\n \"New message from {{user}}\": \"Nuovo messaggio da {{user}}\",\n \"New Messages!\": \"Nuovi messaggi!\",\n \"Next\": \"Avanti\",\n \"Next image\": \"Immagine successiva\",\n \"No chats here yet…\": \"Non ci sono ancora messaggi qui...\",\n \"No conversations yet\": \"Ancora nessuna conversazione\",\n \"No files\": \"Nessun file\",\n \"No items exist\": \"Nessun elemento presente\",\n \"No member found\": \"Nessun membro trovato\",\n \"No messages found\": \"Nessun messaggio trovato\",\n \"No photos or videos\": \"Nessuna foto o video\",\n \"No pinned messages\": \"Nessun messaggio fissato\",\n \"No results found\": \"Nessun risultato trovato\",\n \"No user found\": \"Nessun utente trovato\",\n \"Nobody will be able to vote in this poll anymore.\": \"Nessuno potrà più votare in questo sondaggio.\",\n \"Nothing yet...\": \"Ancora niente...\",\n \"Notify all {{ role }} members\": \"Notifica tutti i membri con ruolo {{ role }}\",\n \"Offline\": \"Offline\",\n \"Ok\": \"OK\",\n \"Online\": \"Online\",\n \"Only numbers are allowed\": \"Sono consentiti solo numeri\",\n \"Only visible to you\": \"Visibile solo per te\",\n \"Open emoji picker\": \"Apri il selettore di emoji\",\n \"Open gallery at image {{ index }}\": \"Apri la galleria all'immagine {{ index }}\",\n \"Open image in gallery\": \"Apri immagine nella galleria\",\n \"Open location in a map\": \"Apri posizione in una mappa\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"Apri menu\",\n \"Option already exists\": \"L'opzione esiste già\",\n \"Option is empty\": \"L'opzione è vuota\",\n \"Options\": \"Opzioni\",\n \"Original\": \"Originale\",\n \"Owner\": \"Proprietario\",\n \"People matching\": \"Persone che corrispondono\",\n \"Photo\": \"Foto\",\n \"Photos & videos\": \"Foto e video\",\n \"Pin\": \"Appunta\",\n \"Pin a message to see it here\": \"Appunta un messaggio per vederlo qui\",\n \"Pinned by {{ name }}\": \"Appuntato da {{ name }}\",\n \"Pinned by You\": \"Fissato da te\",\n \"Pinned message\": \"Messaggio fissato\",\n \"Pinned messages\": \"Messaggi fissati\",\n \"placeholder/PollComment\": \"Il tuo commento\",\n \"placeholder/PollOptionSuggestion\": \"Inserisci una nuova opzione\",\n \"Play video\": \"Riproduci video\",\n \"Playback speed {{ rate }}x\": \"Velocità di riproduzione {{ rate }}x\",\n \"Poll\": \"Sondaggio\",\n \"Poll comments\": \"Commenti del sondaggio\",\n \"Poll ended\": \"Sondaggio terminato\",\n \"Poll options\": \"Opzioni del sondaggio\",\n \"Poll results\": \"Risultati del sondaggio\",\n \"Poll sent\": \"Sondaggio inviato\",\n \"Previous\": \"Indietro\",\n \"Previous image\": \"Immagine precedente\",\n \"Question\": \"Domanda\",\n \"Question {{ optionOrderNumber}}\": \"Domanda {{ optionOrderNumber}}\",\n \"Question is required\": \"La domanda è obbligatoria\",\n \"Quote Reply\": \"Rispondi con citazione\",\n \"Reached the vote limit. Remove an existing vote first.\": \"Raggiunto il limite di voti. Rimuovi prima un voto esistente.\",\n \"Recording format is not supported and cannot be reproduced\": \"Il formato di registrazione non è supportato e non può essere riprodotto\",\n \"Remind me\": \"Promemoria\",\n \"Remind Me\": \"Ricordami\",\n \"Reminder set\": \"Promemoria impostato\",\n \"Remove\": \"Rimuovi\",\n \"Remove {{ count }} members_one\": \"Rimuovi {{ count }} membro\",\n \"Remove {{ count }} members_many\": \"Rimuovi {{ count }} membri\",\n \"Remove {{ count }} members_other\": \"Rimuovi {{ count }} membri\",\n \"Remove {{ member }} from this channel?\": \"Rimuovere {{ member }} da questo canale?\",\n \"Remove channel members\": \"Rimuovi membri del canale\",\n \"Remove reminder\": \"Rimuovi promemoria\",\n \"Remove save for later\": \"Rimuovi Salva per dopo\",\n \"Remove user\": \"Rimuovi utente\",\n \"Removed {{ count }} members_one\": \"Rimosso {{ count }} membro\",\n \"Removed {{ count }} members_many\": \"Rimossi {{ count }} membri\",\n \"Removed {{ count }} members_other\": \"Rimossi {{ count }} membri\",\n \"Replied to a thread\": \"Ha risposto in un thread\",\n \"Reply\": \"Rispondi\",\n \"Reply to {{ authorName }}\": \"Rispondi a {{ authorName }}\",\n \"Reply to a message to start a thread\": \"Rispondi a un messaggio per avviare un thread\",\n \"Reply to Message\": \"Rispondi al messaggio\",\n \"replyCount_one\": \"Una risposta\",\n \"replyCount_many\": \"{{ count }} risposte\",\n \"replyCount_other\": \"{{ count }} risposte\",\n \"Resend\": \"Invia di nuovo\",\n \"Retry upload\": \"Riprova caricamento\",\n \"Review all options available in this poll\": \"Rivedi tutte le opzioni disponibili in questo sondaggio\",\n \"Review comments submitted with poll answers\": \"Rivedi i commenti inviati con le risposte al sondaggio\",\n \"Review poll results and open an option to see detailed votes\": \"Rivedi i risultati del sondaggio e apri un'opzione per vedere i voti dettagliati\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Rivedi questo messaggio e scegli se eliminarlo, modificarlo o inviarlo comunque\",\n \"Review who voted for this option\": \"Rivedi chi ha votato per questa opzione\",\n \"Save\": \"Salva\",\n \"Save for later\": \"Salva per dopo\",\n \"Saved for later\": \"Salvato per dopo\",\n \"Search\": \"Cerca\",\n \"Search GIFs\": \"Cerca GIF\",\n \"search-results-header-filter-source-button-label--channels\": \"canali\",\n \"search-results-header-filter-source-button-label--messages\": \"messaggi\",\n \"search-results-header-filter-source-button-label--users\": \"utenti\",\n \"Searching for {{ searchSourceType }}...\": \"Ricerca di {{ searchSourceType }}...\",\n \"Searching...\": \"Ricerca in corso...\",\n \"searchResultsCount_one\": \"1 risultato\",\n \"searchResultsCount_many\": \"{{ count }} risultati\",\n \"searchResultsCount_other\": \"{{ count }} risultati\",\n \"Select a thread to continue the conversation\": \"Seleziona un thread per continuare la conversazione\",\n \"Select more than one option\": \"Seleziona più di un'opzione\",\n \"Select one\": \"Seleziona uno\",\n \"Select one or more\": \"Seleziona uno o più\",\n \"Select up to {{count}}_one\": \"Seleziona fino a {{count}}\",\n \"Select up to {{count}}_many\": \"Seleziona fino a {{count}}\",\n \"Select up to {{count}}_other\": \"Seleziona fino a {{count}}\",\n \"Select your current location and optionally enable live location sharing\": \"Seleziona la tua posizione attuale e abilita facoltativamente la condivisione della posizione in tempo reale\",\n \"Send\": \"Invia\",\n \"Send a message\": \"Invia un messaggio\",\n \"Send a message to start the conversation\": \"Invia un messaggio per iniziare la conversazione\",\n \"Send Anyway\": \"Invia comunque\",\n \"Send direct message\": \"Invia messaggio diretto\",\n \"Send message request failed\": \"Richiesta di invio messaggio non riuscita\",\n \"Send poll\": \"Invia sondaggio\",\n \"Sending...\": \"Invio in corso...\",\n \"Sent\": \"Inviato\",\n \"Share\": \"Condividi\",\n \"Share a file to see it here\": \"Condividi un file per vederlo qui\",\n \"Share a photo or video to see it here\": \"Condividi una foto o un video per vederlo qui\",\n \"Share live location for\": \"Condividi posizione live per\",\n \"Share Location\": \"Condividi posizione\",\n \"Shared live location\": \"Posizione live condivisa\",\n \"Shared location\": \"Posizione condivisa\",\n \"Shuffle\": \"Mescolare\",\n \"size limit\": \"limite di dimensione\",\n \"Slow Mode ON\": \"Modalità lenta attivata\",\n \"Slow mode, wait {{ seconds }}s...\": \"Modalità lenta, attendi {{ seconds }} s...\",\n \"Some of the files will not be accepted\": \"Alcuni dei file non saranno accettati\",\n \"Start typing to search\": \"Inizia a digitare per cercare\",\n \"Stop sharing\": \"Ferma condivisione\",\n \"Submit\": \"Invia\",\n \"Suggest a new option to add to this poll\": \"Suggerisci una nuova opzione da aggiungere a questo sondaggio\",\n \"Suggest an option\": \"Suggerisci un'opzione\",\n \"Tap to remove\": \"Tocca per rimuovere\",\n \"Tap to remove: {{ reactionName }}\": \"Tocca per rimuovere: {{ reactionName }}\",\n \"Thinking...\": \"Pensando...\",\n \"this content could not be displayed\": \"questo contenuto non può essere mostrato\",\n \"This field cannot be empty or contain only spaces\": \"Questo campo non può essere vuoto o contenere solo spazi\",\n \"This message did not meet our content guidelines\": \"Questo messaggio non soddisfa le nostre linee guida sui contenuti\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"Questo utente potrà inviarti di nuovo messaggi.\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"Discussione\",\n \"Thread has not been found\": \"Discussione non trovata\",\n \"Thread reply\": \"Risposta nella discussione\",\n \"Thread Reply\": \"Risposta nella discussione\",\n \"ThreadListUnseenThreadsBanner/loading\": \"Caricamento...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} thread non letto\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_many\": \"{{ count }} thread non letti\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} thread non letti\",\n \"Threads\": \"Thread\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Ieri]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Oggi]\\\", \\\"nextDay\\\": \\\"[Domani]\\\", \\\"lastDay\\\": \\\"[Ieri]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Scorsa] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"{{ count }} g fa\",\n \"timestamp/relativeToday\": \"Oggi\",\n \"timestamp/relativeWeeksAgo\": \"{{ count }} sett fa\",\n \"timestamp/relativeYesterday\": \"Ieri\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Oggi] [alle] HH:mm\\\", \\\"nextDay\\\": \\\"[Domani] [alle] HH:mm\\\", \\\"lastDay\\\": \\\"[Ieri] [alle] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [alle] HH:mm\\\", \\\"lastWeek\\\": \\\"[lo scorso] dddd [alle] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [alle] HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"Per iniziare a registrare, consenti l'accesso alla fotocamera nel tuo browser\",\n \"To start recording, allow the microphone access in your browser\": \"Per iniziare a registrare, consenti l'accesso al microfono nel tuo browser\",\n \"totalVoteCount_one\": \"1 voto in totale\",\n \"totalVoteCount_many\": \"{{ count }} voti in totale\",\n \"totalVoteCount_other\": \"{{ count }} voti in totale\",\n \"Translated\": \"Tradotto\",\n \"Translated from {{ language }}\": \"Tradotto da {{ language }}\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"Digita un numero da 2 a 10\",\n \"Unarchive\": \"Ripristina\",\n \"unban-command-args\": \"[@nomeutente]\",\n \"unban-command-description\": \"Togliere il divieto a un utente\",\n \"Unblock\": \"Sblocca\",\n \"Unblock user\": \"Sblocca utente\",\n \"Unblock User\": \"Sblocca utente\",\n \"unknown error\": \"errore sconosciuto\",\n \"Unmute\": \"Riattiva il notifiche\",\n \"Unmute chat\": \"Riattiva chat\",\n \"Unmute user\": \"Riattiva utente\",\n \"unmute-command-args\": \"[@nomeutente]\",\n \"unmute-command-description\": \"Togliere il silenzio a un utente\",\n \"Unpin\": \"Sblocca\",\n \"Unread messages\": \"Messaggi non letti\",\n \"Unsupported attachment\": \"Allegato non supportato\",\n \"unsupported file type\": \"tipo di file non supportato\",\n \"Update\": \"Aggiorna\",\n \"Update the comment attached to your poll answer\": \"Aggiorna il commento allegato alla tua risposta al sondaggio\",\n \"Update your comment\": \"Aggiorna il tuo commento\",\n \"Upload blocked\": \"Caricamento bloccato\",\n \"Upload error\": \"Errore di caricamento\",\n \"Upload failed\": \"Caricamento non riuscito\",\n \"Upload Picture\": \"Carica immagine\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Tipo di caricamento: \\\"{{ type }}\\\" non è consentito\",\n \"User blocked\": \"Utente bloccato\",\n \"User muted\": \"Utente silenziato\",\n \"User removed\": \"Utente rimosso\",\n \"User unblocked\": \"Utente sbloccato\",\n \"User unmuted\": \"Utente riattivato\",\n \"User uploaded content\": \"Contenuto caricato dall'utente\",\n \"Video\": \"Video\",\n \"videoCount_one\": \"Video\",\n \"videoCount_many\": \"{{ count }} video\",\n \"videoCount_other\": \"{{ count }} video\",\n \"View\": \"Visualizza\",\n \"View {{count}} comments_one\": \"Visualizza {{count}} commento\",\n \"View {{count}} comments_many\": \"Visualizza {{count}} commenti\",\n \"View {{count}} comments_other\": \"Visualizza {{count}} commenti\",\n \"View all\": \"Visualizza tutto\",\n \"View member details for {{ member }}\": \"Visualizza dettagli membro per {{ member }}\",\n \"View original\": \"Visualizza originale\",\n \"View results\": \"Vedi risultati\",\n \"View translation\": \"Visualizza traduzione\",\n \"Voice message\": \"Messaggio vocale\",\n \"Voice message {{ duration }}\": \"Messaggio vocale {{ duration }}\",\n \"Voice message deleted\": \"Messaggio vocale eliminato\",\n \"voiceMessageCount_one\": \"Messaggio vocale\",\n \"voiceMessageCount_many\": \"{{ count }} messaggi vocali\",\n \"voiceMessageCount_other\": \"{{ count }} messaggi vocali\",\n \"Vote ended\": \"Voto terminato\",\n \"Votes\": \"Voti\",\n \"Wait until all attachments have uploaded\": \"Attendi il caricamento di tutti gli allegati\",\n \"Waiting for network…\": \"In attesa della rete…\",\n \"You\": \"Tu\",\n \"You've reached the maximum number of files\": \"Hai raggiunto il numero massimo di file\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} と {{ moreCount }} 他人\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} と {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} ファイル\",\n \"{{ count }} files_other\": \"{{ count }} ファイル\",\n \"{{ count }} members_other\": \"{{ count }}人のメンバー\",\n \"{{ count }} members added_other\": \"{{ count }}人のメンバーを追加しました\",\n \"{{ count }} people are typing_one\": \"{{ count }}人が入力中です\",\n \"{{ count }} people are typing_many\": \"{{ count }}人が入力中です\",\n \"{{ count }} people are typing_other\": \"{{ count }}人が入力中です\",\n \"{{ count }} photos_one\": \"{{ count }} 写真\",\n \"{{ count }} photos_other\": \"{{ count }} 写真\",\n \"{{ count }} reactions_other\": \"{{ count }}件のリアクション\",\n \"{{ count }} videos_one\": \"{{ count }} 動画\",\n \"{{ count }} videos_other\": \"{{ count }} 動画\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} と {{ secondUser }}\",\n \"{{ imageCount }} more\": \"{{ imageCount }} イメージ\",\n \"{{ member }} will be able to message you again.\": \"{{ member }}は再びメッセージを送信できるようになります。\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }}はメッセージを送信できなくなります。\",\n \"{{ memberCount }} members\": \"{{ memberCount }} メンバー\",\n \"{{ typing }} are typing\": \"{{ typing }}が入力中です\",\n \"{{ typing }} is typing\": \"{{ typing }}が入力中です\",\n \"{{ user }} has been muted\": \"{{ user }} 無音されています\",\n \"{{ user }} has been unmuted\": \"{{ user }} 無音されていません\",\n \"{{ user }} is typing...\": \"{{ user }} が入力中...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} と {{ user }} が入力中...\",\n \"{{ users }} and more are typing...\": \"{{ users }} とその他が入力中...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} オンライン\",\n \"{{count}} new messages_one\": \"{{count}}件の新しいメッセージ\",\n \"{{count}} new messages_other\": \"{{count}}件の新しいメッセージ\",\n \"{{count}} unread_one\": \"{{count}} 未読\",\n \"{{count}} unread_other\": \"{{count}} 未読\",\n \"{{count}} votes_one\": \"{{count}} 票\",\n \"{{count}} votes_other\": \"{{count}} 票\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"あと{{count}}件のオプション\",\n \"+{{count}} more options_other\": \"あと{{count}}件のオプション\",\n \"🏙 Attachment...\": \"🏙 アタッチメント...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} が作成: {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} が投票: {{pollOptionText}}\",\n \"📍Shared location\": \"📍共有された位置情報\",\n \"Actions\": \"Actions\",\n \"Add\": \"追加\",\n \"Add {{ count }} members_other\": \"{{ count }}人のメンバーを追加\",\n \"Add a comment\": \"コメントを追加\",\n \"Add a comment to your poll answer\": \"投票回答にコメントを追加\",\n \"Add an option\": \"オプションを追加\",\n \"Add channel members\": \"チャンネルメンバーを追加\",\n \"Add members\": \"メンバーを追加\",\n \"Add reaction\": \"リアクションを追加\",\n \"Admin\": \"管理者\",\n \"All results loaded\": \"すべての結果が読み込まれました\",\n \"Allow access to camera\": \"カメラへのアクセスを許可する\",\n \"Allow access to microphone\": \"マイクロフォンへのアクセスを許可する\",\n \"Allow comments\": \"コメントを許可\",\n \"Allow option suggestion\": \"オプションの提案を許可\",\n \"Allow others to add comments\": \"他の人にコメントを追加することを許可する\",\n \"Already a member\": \"すでにメンバーです\",\n \"Also send as a direct message\": \"ダイレクトメッセージとしても送信\",\n \"Also send in channel\": \"チャンネルにも送信\",\n \"Also sent in channel\": \"チャンネルにも送信済み\",\n \"An error has occurred during recording\": \"録音中にエラーが発生しました\",\n \"An error has occurred during the recording processing\": \"録音処理中にエラーが発生しました\",\n \"Anonymous\": \"匿名\",\n \"Anonymous poll\": \"匿名投票\",\n \"Archive\": \"アーカイブ\",\n \"Are you sure you want to delete this message?\": \"このメッセージを削除してもよろしいですか?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_other\": \"添付ファイル {{ count }} 件\",\n \"aria/{{ count }} search results_other\": \"{{ count }} 件の検索結果\",\n \"aria/{{ count }} suggestions_other\": \"候補 {{ count }} 件\",\n \"aria/{{ count }} unread message_other\": \"未読メッセージ {{ count }} 件\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} をオフにしました\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} をオンにしました\",\n \"aria/Active\": \"アクティブ\",\n \"aria/Animated GIF\": \"アニメーションGIF\",\n \"aria/Animated GIF: {{ title }}\": \"アニメーションGIF:{{ title }}\",\n \"aria/Attachment\": \"添付ファイル\",\n \"aria/Attachment {{ attachmentType }}\": \"添付ファイル {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"添付ファイルの操作\",\n \"aria/audio\": \"オーディオ\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"音声位置 {{ elapsed }} / {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"音声位置 {{ progress }} パーセント\",\n \"aria/Back to attachments\": \"添付ファイルに戻る\",\n \"aria/Back to parent menu button\": \"親メニューに戻るボタン\",\n \"aria/Block User\": \"ユーザーをブロック\",\n \"aria/Bookmark Message\": \"メッセージをブックマーク\",\n \"aria/Cancel recording\": \"録音をキャンセル\",\n \"aria/Cancel Reply\": \"返信をキャンセル\",\n \"aria/Channel Actions\": \"チャンネル操作\",\n \"aria/Channel details\": \"チャンネル詳細\",\n \"aria/Channel list\": \"チャンネル一覧\",\n \"aria/Chat view controls\": \"チャットビューのコントロール\",\n \"aria/Chat: {{ channelName }}\": \"チャット: {{ channelName }}\",\n \"aria/Clear search\": \"検索をクリア\",\n \"aria/Close callout dialog\": \"吹き出しダイアログを閉じる\",\n \"aria/Close thread\": \"スレッドを閉じる\",\n \"aria/Collapse sidebar\": \"サイドバーを折りたたむ\",\n \"aria/Command activated: {{ command }}\": \"コマンドを有効化しました: {{ command }}\",\n \"aria/Command Suggestions\": \"コマンド候補\",\n \"aria/Complete recording\": \"録音を完了\",\n \"aria/Copy Message Text\": \"メッセージテキストをコピー\",\n \"aria/Decrease value\": \"値を減らす\",\n \"aria/Delete Message\": \"メッセージを削除\",\n \"aria/Delivered\": \"配信済み\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"配信状況: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"通知を閉じる\",\n \"aria/Download attachment\": \"添付ファイルをダウンロード\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"「{{ option }}」を位置 {{ position }} に配置しました。\",\n \"aria/Edit Message\": \"メッセージを編集\",\n \"aria/Emoji picker\": \"絵文字ピッカー\",\n \"aria/Emoji Suggestions\": \"絵文字候補\",\n \"aria/Exit search\": \"検索を終了\",\n \"aria/Expand sidebar\": \"サイドバーを展開\",\n \"aria/file\": \"ファイル\",\n \"aria/File upload\": \"ファイルアップロード\",\n \"aria/Flag Message\": \"メッセージをフラグ\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Giphyの操作\",\n \"aria/Giphy canceled\": \"Giphyをキャンセルしました\",\n \"aria/Giphy image changed\": \"Giphy画像が変更されました\",\n \"aria/Giphy image changed: {{ title }}\": \"Giphy画像が変更されました:{{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Giphyのプレビューです。あなたにのみ表示されます。送信、シャッフル、またはキャンセルの操作を使用してください。\",\n \"aria/Giphy sent\": \"Giphyを送信しました\",\n \"aria/image\": \"画像\",\n \"aria/Image failed to load\": \"画像の読み込みに失敗しました\",\n \"aria/Increase value\": \"値を増やす\",\n \"aria/Jump to latest message\": \"最新のメッセージに移動\",\n \"aria/Jump to quoted message\": \"引用されたメッセージに移動\",\n \"aria/Last activity: {{ time }}\": \"最終アクティビティ: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"{{ sender }} からの最新メッセージ: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"最新メッセージ: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"未読としてマーク\",\n \"aria/Mark messages as read\": \"メッセージを既読にする\",\n \"aria/Mention Suggestions\": \"メンション候補\",\n \"aria/Message Actions\": \"メッセージ操作\",\n \"aria/Message from {{ user }},\": \"{{ user }}さんからのメッセージ,\",\n \"aria/Message input\": \"メッセージ入力\",\n \"aria/Message with attachments\": \"添付ファイル付きのメッセージ\",\n \"aria/Message,\": \"メッセージ,\",\n \"aria/Mute User\": \"ユーザーをミュート\",\n \"aria/Next page\": \"次のページ\",\n \"aria/No search results found\": \"検索結果が見つかりませんでした\",\n \"aria/Notifications\": \"通知\",\n \"aria/Open Attachment Selector\": \"添付ファイル選択を開く\",\n \"aria/Open Channel Actions Menu\": \"チャンネルアクションメニューを開く\",\n \"aria/Open channel details\": \"チャンネル詳細を開く\",\n \"aria/Open channels view\": \"チャンネルビューを開く\",\n \"aria/Open image shared by {{ name }}\": \"{{ name }}が共有した画像を開く\",\n \"aria/Open Message Actions Menu\": \"メッセージアクションメニューを開く\",\n \"aria/Open Reaction Selector\": \"リアクションセレクターを開く\",\n \"aria/Open Thread\": \"スレッドを開く\",\n \"aria/Open threads view\": \"スレッドビューを開く\",\n \"aria/Open threads view with unread threads_one\": \"スレッドビューを開く、未読スレッド{{ count }}件\",\n \"aria/Open threads view with unread threads_other\": \"スレッドビューを開く、未読スレッド{{ count }}件\",\n \"aria/Open video shared by {{ name }}\": \"{{ name }}が共有した動画を開く\",\n \"aria/Opened channel: {{ name }}\": \"チャンネルを開きました: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"{{ name }} でスレッドを開きました\",\n \"aria/Option {{ position }}\": \"オプション {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"選択肢の並べ替えと削除ができるようになりました。\",\n \"aria/Pause\": \"一時停止\",\n \"aria/Pause recording\": \"録音を一時停止\",\n \"aria/Percent complete\": \"{{percent}}パーセント完了\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"「{{ option }}」を持ち上げました。矢印キーで並べ替え、スペースまたはタブで配置してください。\",\n \"aria/Pin Message\": \"メッセージをピン\",\n \"aria/Play\": \"再生\",\n \"aria/Poll dialog opened\": \"投票ダイアログを開きました\",\n \"aria/Poll sent\": \"投票を送信しました\",\n \"aria/Poll: {{ pollName }}\": \"投票: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Enter キーを押して入力を開始します\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"このオプションを選択するにはスペースキーを押し、移動するには上下矢印キーを使用し、選択を解除するにはもう一度スペースキーを押してください。\",\n \"aria/Previous page\": \"前のページ\",\n \"aria/Quote Message\": \"メッセージを引用\",\n \"aria/Reaction list\": \"リアクション一覧\",\n \"aria/Read\": \"既読\",\n \"aria/Recording paused\": \"録音を一時停止しました\",\n \"aria/Recording resumed\": \"録音を再開しました\",\n \"aria/Recording started\": \"録音を開始しました\",\n \"aria/Remind Me Message\": \"リマインダー\",\n \"aria/Remove attachment\": \"添付ファイルを削除\",\n \"aria/Remove location attachment\": \"位置情報の添付ファイルを削除\",\n \"aria/Remove option: {{ option }}\": \"オプションを削除: {{ option }}\",\n \"aria/Remove Reminder\": \"リマインダーを削除\",\n \"aria/Remove Save For Later\": \"「後で見る」を削除\",\n \"aria/Removed option {{ option }}\": \"選択肢「{{ option }}」を削除しました\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"「{{ option }}」を並べ替え、{{ total }} 中 {{ position }} 番目\",\n \"aria/Reorder option {{ position }}\": \"オプション {{ position }} を並べ替える\",\n \"aria/Resend Message\": \"メッセージを再送信\",\n \"aria/Resume recording\": \"録音を再開\",\n \"aria/Retry upload\": \"アップロードを再試行\",\n \"aria/Review bounced message\": \"バウンスされたメッセージを確認\",\n \"aria/Search cleared\": \"検索をクリアしました\",\n \"aria/Search results\": \"検索結果\",\n \"aria/Search results header filter button for: {{ source }}\": \"{{ source }} の検索結果ヘッダーのフィルターボタン\",\n \"aria/Seek audio position\": \"音声位置をシーク\",\n \"aria/Select Reaction: {{ reactionName }}\": \"リアクションを選択: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"ユーザーチャンネルを選択: {{ name }}\",\n \"aria/Send\": \"送信\",\n \"aria/Sent\": \"送信済み\",\n \"aria/Shared a link\": \"リンクを共有しました\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"タイトル付きのリンクを共有しました: {{ linkTitle }}\",\n \"aria/Shared location\": \"共有された位置情報\",\n \"aria/Show preview\": \"プレビューを表示\",\n \"aria/Start recording audio\": \"音声録音を開始\",\n \"aria/Stop AI Generation\": \"AI生成を停止\",\n \"aria/Submenu\": \"サブメニュー\",\n \"aria/Suggestions\": \"候補\",\n \"aria/There are no messages in this chat.\": \"このチャットにはメッセージがありません\",\n \"aria/This option can be reordered and removed.\": \"この選択肢は並べ替えと削除ができます。\",\n \"aria/Thread list\": \"スレッド一覧\",\n \"aria/Thread: {{ messagePreview }}\": \"スレッド: {{ messagePreview }}\",\n \"aria/Unblock User\": \"ユーザーのブロックを解除\",\n \"aria/Unmute User\": \"無音を解除する\",\n \"aria/Unpin Message\": \"ピンを解除\",\n \"aria/User selected: {{ user }}\": \"選択したユーザー:{{ user }}\",\n \"aria/video\": \"動画\",\n \"aria/voice message\": \"ボイスメッセージ\",\n \"aria/Voice message sent\": \"ボイスメッセージを送信しました\",\n \"aria/Voice recording attached\": \"ボイス録音を添付しました\",\n \"Ask a question\": \"質問する\",\n \"Attach\": \"添付\",\n \"Attach files\": \"ファイルを添付する\",\n \"Attachment\": \"添付ファイル\",\n \"Attachment upload blocked due to {{reason}}\": \"{{reason}}のため添付ファイルのアップロードがブロックされました\",\n \"Attachment upload failed due to {{reason}}\": \"{{reason}}のため添付ファイルのアップロードに失敗しました\",\n \"Back\": \"戻る\",\n \"ban-command-args\": \"[@ユーザ名] [テキスト]\",\n \"ban-command-description\": \"ユーザーを禁止する\",\n \"Block user\": \"ユーザーをブロック\",\n \"Block User\": \"ユーザーをブロック\",\n \"Browse channel members\": \"チャンネルメンバーを表示\",\n \"Browse pinned messages\": \"ピン留めメッセージを表示\",\n \"Cancel\": \"キャンセル\",\n \"Cannot seek in the recording\": \"録音中にシークできません\",\n \"Changes saved\": \"変更を保存しました\",\n \"Channel archived\": \"チャンネルをアーカイブしました\",\n \"Channel members\": \"チャンネルメンバー\",\n \"Channel Missing\": \"チャネルがありません\",\n \"Channel muted\": \"チャンネルをミュートしました\",\n \"Channel pinned\": \"チャンネルをピン留めしました\",\n \"Channel unarchived\": \"チャンネルのアーカイブを解除しました\",\n \"Channel unmuted\": \"チャンネルのミュートを解除しました\",\n \"Channel unpinned\": \"チャンネルのピン留めを解除しました\",\n \"Channels\": \"チャンネル\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"チャット\",\n \"Choose between 2 to 10 options\": \"2〜10の選択肢から選ぶ\",\n \"Close\": \"閉める\",\n \"Close dialog\": \"ダイアログを閉じる\",\n \"Close emoji picker\": \"絵文字ピッカーを閉める\",\n \"Command not available while editing\": \"編集中はコマンドを使用できません\",\n \"Command not available while replying\": \"返信中はコマンドを使用できません\",\n \"Commands\": \"コマンド\",\n \"Commands matching\": \"一致するコマンド\",\n \"Connection failure, reconnecting now...\": \"接続が失敗しました。再接続中...\",\n \"Contact info\": \"連絡先情報\",\n \"Contact name\": \"連絡先名\",\n \"Copy Message\": \"メッセージをコピー\",\n \"Create\": \"作成\",\n \"Create a question, add options, and configure poll settings\": \"質問を作成し、選択肢を追加して投票設定を構成\",\n \"Create poll\": \"投票を作成\",\n \"Current location\": \"現在の位置\",\n \"Delete\": \"消去\",\n \"Delete chat\": \"チャットを削除\",\n \"Delete for me\": \"自分用に削除\",\n \"Delete message\": \"メッセージを削除\",\n \"Delivered\": \"配信しました\",\n \"Direct message\": \"ダイレクトメッセージ\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"このアンケートを今終了しますか?終了すると、誰も投票できなくなります。\",\n \"Download {{ fileName }}\": \"{{ fileName }} をダウンロード\",\n \"Download All\": \"すべてダウンロード\",\n \"Download Attachment\": \"添付ファイルをダウンロード\",\n \"Download attachment {{ name }}\": \"添付ファイル {{ name }} をダウンロード\",\n \"Download attachment {{ number }}\": \"添付ファイル {{ number }} をダウンロード\",\n \"Drag your files here\": \"ここにファイルをドラッグ\",\n \"Drag your files here to add to your post\": \"投稿に追加するためにここにファイルをドラッグ\",\n \"Due {{ timeLeft }}\": \"{{ timeLeft }}に期限切れ\",\n \"Due since {{ dueSince }}\": \"{{ dueSince }}から期限切れ\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"編集\",\n \"Edit chat data\": \"チャットデータを編集\",\n \"Edit contact\": \"連絡先を編集\",\n \"Edit group\": \"グループを編集\",\n \"Edit Message\": \"メッセージを編集\",\n \"Edit message request failed\": \"メッセージの編集要求が失敗しました\",\n \"Edited\": \"編集済み\",\n \"Emoji matching\": \"絵文字マッチング\",\n \"Empty message...\": \"空のメッセージ...\",\n \"End\": \"終了\",\n \"End poll\": \"アンケートを終了\",\n \"End this poll?\": \"このアンケートを終了しますか?\",\n \"End vote\": \"投票を終了\",\n \"Enforce unique vote is enabled\": \"一意の投票が有効になっています\",\n \"Error\": \"エラー\",\n \"Error adding flag\": \"フラグを追加のエラーが発生しました\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"ユーザーのブロック中にエラーが発生しました\",\n \"Error connecting to chat, refresh the page to try again.\": \"チャットへの接続ができませんでした。ページを更新してください。\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"メッセージを削除するエラーが発生しました\",\n \"Error fetching reactions\": \"反応の読み込みエラー\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"メッセージを未読にする際にエラーが発生しました。最新の100件のチャンネルメッセージより古い未読メッセージはマークできません。\",\n \"Error muting a user ...\": \"ユーザーを無音するエラーが発生しました...\",\n \"Error muting channel\": \"チャンネルのミュート中にエラーが発生しました\",\n \"Error muting user\": \"ユーザーのミュート中にエラーが発生しました\",\n \"Error opening direct message\": \"ダイレクトメッセージを開く際にエラーが発生しました\",\n \"Error pinning message\": \"メッセージをピンのエラーが発生しました\",\n \"Error removing members\": \"メンバーの削除中にエラーが発生しました\",\n \"Error removing message pin\": \"メッセージのピンを削除のエラーが発生しました\",\n \"Error removing user\": \"ユーザーの削除中にエラーが発生しました\",\n \"Error reproducing the recording\": \"録音の再生中にエラーが発生しました\",\n \"Error starting recording\": \"録音の開始時にエラーが発生しました\",\n \"Error unblocking user\": \"ユーザーのブロック解除中にエラーが発生しました\",\n \"Error unmuting a user ...\": \"ユーザーの無音解除のエラーが発生しました...\",\n \"Error unmuting channel\": \"チャンネルのミュート解除中にエラーが発生しました\",\n \"Error unmuting user\": \"ユーザーのミュート解除中にエラーが発生しました\",\n \"Error uploading attachment\": \"添付ファイルのアップロード中にエラーが発生しました\",\n \"Error uploading file\": \"ファイルをアップロードのエラーが発生しました\",\n \"Error uploading image\": \"画像をアップロードのエラーが発生しました\",\n \"Error: {{ errorMessage }}\": \"エラー: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"コマンドを終了 {{ command }}\",\n \"Failed to block user\": \"ユーザーのブロックに失敗しました\",\n \"Failed to create the poll\": \"投票の作成に失敗しました\",\n \"Failed to create the poll due to {{reason}}\": \"{{reason}} のため投票の作成に失敗しました\",\n \"Failed to delete the message\": \"メッセージの削除に失敗しました\",\n \"Failed to end the poll\": \"アンケートの終了に失敗しました\",\n \"Failed to end the poll due to {{reason}}\": \"{{reason}}のためアンケートの終了に失敗しました\",\n \"Failed to jump to the first unread message\": \"最初の未読メッセージにジャンプできませんでした\",\n \"Failed to leave channel\": \"チャンネルの退出に失敗しました\",\n \"Failed to load channels\": \"チャンネルの読み込みに失敗しました\",\n \"Failed to load more channels\": \"さらにチャンネルを読み込めませんでした\",\n \"Failed to mark channel as read\": \"チャンネルを既読にすることができませんでした\",\n \"Failed to play the recording\": \"録音の再生に失敗しました\",\n \"Failed to retrieve location\": \"位置情報の取得に失敗しました\",\n \"Failed to save changes\": \"変更を保存できませんでした\",\n \"Failed to share location\": \"位置情報の共有に失敗しました\",\n \"Failed to update channel archive status\": \"チャンネルのアーカイブ状態の更新に失敗しました\",\n \"Failed to update channel mute status\": \"チャンネルのミュート状態の更新に失敗しました\",\n \"Failed to update channel pinned status\": \"チャンネルのピン状態の更新に失敗しました\",\n \"File\": \"ファイル\",\n \"File is required for upload attachment\": \"添付ファイルのアップロードにはファイルが必要です\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"ファイルが大きすぎます:{{ size }}、最大アップロードサイズは{{ limit }}です\",\n \"File too large\": \"ファイルが大きすぎます\",\n \"fileCount_other\": \"{{ count }}件のファイル\",\n \"Files\": \"ファイル\",\n \"Flag\": \"フラグ\",\n \"Generating...\": \"生成中...\",\n \"giphy-command-args\": \"[テキスト]\",\n \"giphy-command-description\": \"チャンネルにランダムなGIFを投稿する\",\n \"Go back\": \"戻る\",\n \"Group info\": \"グループ情報\",\n \"Group name\": \"グループ名\",\n \"Hide who voted\": \"誰が投票したかを非表示にする\",\n \"Image\": \"画像\",\n \"imageCount_other\": \"{{ count }}件の画像\",\n \"Instant commands\": \"インスタントコマンド\",\n \"language/af\": \"アフリカース語\",\n \"language/am\": \"アムハラ語\",\n \"language/ar\": \"アラビア語\",\n \"language/az\": \"アゼルバイジャン語\",\n \"language/bg\": \"ブルガリア語\",\n \"language/bn\": \"ベンガル語\",\n \"language/bs\": \"ボスニア語\",\n \"language/cs\": \"チェコ語\",\n \"language/da\": \"デンマーク語\",\n \"language/de\": \"ドイツ語\",\n \"language/el\": \"ギリシャ語\",\n \"language/en\": \"英語\",\n \"language/es\": \"スペイン語\",\n \"language/es-MX\": \"スペイン語(メキシコ)\",\n \"language/et\": \"エストニア語\",\n \"language/fa\": \"ペルシア語\",\n \"language/fa-AF\": \"ダリー語\",\n \"language/fi\": \"フィンランド語\",\n \"language/fr\": \"フランス語\",\n \"language/fr-CA\": \"フランス語(カナダ)\",\n \"language/ha\": \"ハウサ語\",\n \"language/he\": \"ヘブライ語\",\n \"language/hi\": \"ヒンディー語\",\n \"language/hr\": \"クロアチア語\",\n \"language/ht\": \"ハイチ・クレオール語\",\n \"language/hu\": \"ハンガリー語\",\n \"language/id\": \"インドネシア語\",\n \"language/it\": \"イタリア語\",\n \"language/ja\": \"日本語\",\n \"language/ka\": \"グルジア語\",\n \"language/ko\": \"韓国語\",\n \"language/lt\": \"リトアニア語\",\n \"language/lv\": \"ラトビア語\",\n \"language/ms\": \"マレー語\",\n \"language/nl\": \"オランダ語\",\n \"language/no\": \"ノルウェー語\",\n \"language/pl\": \"ポーランド語\",\n \"language/ps\": \"パシュトー語\",\n \"language/pt\": \"ポルトガル語\",\n \"language/ro\": \"ルーマニア語\",\n \"language/ru\": \"ロシア語\",\n \"language/sk\": \"スロバキア語\",\n \"language/sl\": \"スロベニア語\",\n \"language/so\": \"ソマリ語\",\n \"language/sq\": \"アルバニア語\",\n \"language/sr\": \"セルビア語\",\n \"language/sv\": \"スウェーデン語\",\n \"language/sw\": \"スワヒリ語\",\n \"language/ta\": \"タミル語\",\n \"language/th\": \"タイ語\",\n \"language/tl\": \"タガログ語\",\n \"language/tr\": \"トルコ語\",\n \"language/uk\": \"ウクライナ語\",\n \"language/ur\": \"ウルドゥー語\",\n \"language/vi\": \"ベトナム語\",\n \"language/zh\": \"中国語(簡体字)\",\n \"language/zh-TW\": \"中国語(繁体字)\",\n \"Last seen {{ timestamp }}\": \"最終表示 {{ timestamp }}\",\n \"Leave Channel\": \"チャンネルを退出\",\n \"Leave chat\": \"チャンネルを退出\",\n \"Left channel\": \"チャンネルを退出しました\",\n \"Let others add options\": \"他の人が選択肢を追加できるようにする\",\n \"Limit votes per person\": \"1人あたりの投票数を制限する\",\n \"Link\": \"リンク\",\n \"linkCount_other\": \"{{ count }}件のリンク\",\n \"live\": \"ライブ\",\n \"Live for {{duration}}\": \"{{duration}}間ライブ\",\n \"Live location\": \"ライブ位置情報\",\n \"Live until {{ timestamp }}\": \"{{ timestamp }}までライブ\",\n \"Load more\": \"もっと読み込む\",\n \"Local upload attachment missing local id\": \"ローカルアップロード添付にローカルIDがありません\",\n \"Location\": \"位置情報\",\n \"Location sharing ended\": \"位置情報の共有が終了しました\",\n \"Location: {{ coordinates }}\": \"位置: {{ coordinates }}\",\n \"Manage channel\": \"チャンネルを管理\",\n \"Manage members\": \"メンバーを管理\",\n \"Mark as unread\": \"未読としてマーク\",\n \"Maximum number of votes (from 2 to 10)\": \"最大投票数(2から10まで)\",\n \"Maximum votes per person\": \"1人あたりの最大投票数\",\n \"Member detail\": \"メンバー詳細\",\n \"mention/Channel\": \"チャンネル\",\n \"mention/Channel Description\": \"このチャンネルの全員に通知\",\n \"mention/Here\": \"ここ\",\n \"mention/Here Description\": \"このチャンネルのオンライン中の全メンバーに通知\",\n \"Menu\": \"メニュー\",\n \"Message deleted\": \"メッセージが削除されました\",\n \"Message failed to send\": \"メッセージの送信に失敗しました\",\n \"Message has been successfully flagged\": \"メッセージに正常にフラグが付けられました\",\n \"Message marked as unread\": \"メッセージを未読にしました\",\n \"Message pinned\": \"メッセージにピンが付けられました\",\n \"Message unpinned\": \"メッセージのピン留めを解除しました\",\n \"Message was blocked by moderation policies\": \"メッセージはモデレーションポリシーによってブロックされました\",\n \"Messages have been marked unread.\": \"メッセージは未読としてマークされました。\",\n \"Missing permissions to upload the attachment\": \"添付ファイルをアップロードするための許可がありません\",\n \"Moderator\": \"モデレーター\",\n \"Multiple votes\": \"複数投票\",\n \"Mute\": \"無音\",\n \"Mute chat\": \"チャットをミュート\",\n \"Mute user\": \"ユーザーをミュート\",\n \"mute-command-args\": \"[@ユーザ名]\",\n \"mute-command-description\": \"ユーザーをミュートする\",\n \"network error\": \"ネットワークエラー\",\n \"New\": \"新しい\",\n \"New message from {{user}}\": \"{{user}}からの新しいメッセージ\",\n \"New Messages!\": \"新しいメッセージ!\",\n \"Next\": \"次へ\",\n \"Next image\": \"次の画像\",\n \"No chats here yet…\": \"ここにはまだチャットはありません…\",\n \"No conversations yet\": \"まだ会話はありません\",\n \"No files\": \"ファイルはありません\",\n \"No items exist\": \"項目がありません\",\n \"No member found\": \"メンバーが見つかりません\",\n \"No messages found\": \"メッセージが見つかりません\",\n \"No photos or videos\": \"写真や動画はありません\",\n \"No pinned messages\": \"ピン留めメッセージはありません\",\n \"No results found\": \"結果が見つかりません\",\n \"No user found\": \"ユーザーが見つかりません\",\n \"Nobody will be able to vote in this poll anymore.\": \"この投票では、誰も投票できなくなります。\",\n \"Nothing yet...\": \"まだ何もありません...\",\n \"Notify all {{ role }} members\": \"{{ role }} メンバー全員に通知\",\n \"Offline\": \"オフライン\",\n \"Ok\": \"OK\",\n \"Online\": \"オンライン\",\n \"Only numbers are allowed\": \"数字のみ許可されています\",\n \"Only visible to you\": \"あなただけに表示\",\n \"Open emoji picker\": \"絵文字ピッカーを開く\",\n \"Open gallery at image {{ index }}\": \"画像 {{ index }} でギャラリーを開く\",\n \"Open image in gallery\": \"画像をギャラリーで開く\",\n \"Open location in a map\": \"地図で位置情報を開く\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"メニューを開く\",\n \"Option already exists\": \"オプションは既に存在します\",\n \"Option is empty\": \"オプションが空です\",\n \"Options\": \"オプション\",\n \"Original\": \"原文\",\n \"Owner\": \"オーナー\",\n \"People matching\": \"一致する人\",\n \"Photo\": \"写真\",\n \"Photos & videos\": \"写真と動画\",\n \"Pin\": \"ピン\",\n \"Pin a message to see it here\": \"ここに表示するにはメッセージをピン留めしてください\",\n \"Pinned by {{ name }}\": \"{{ name }}がピンしました\",\n \"Pinned by You\": \"あなたがピン留めしました\",\n \"Pinned message\": \"ピン留めメッセージ\",\n \"Pinned messages\": \"ピン留めメッセージ\",\n \"placeholder/PollComment\": \"コメント\",\n \"placeholder/PollOptionSuggestion\": \"新しい選択肢を入力\",\n \"Play video\": \"動画を再生\",\n \"Playback speed {{ rate }}x\": \"再生速度 {{ rate }}x\",\n \"Poll\": \"投票\",\n \"Poll comments\": \"投票コメント\",\n \"Poll ended\": \"アンケート終了\",\n \"Poll options\": \"投票オプション\",\n \"Poll results\": \"投票結果\",\n \"Poll sent\": \"アンケートを送信しました\",\n \"Previous\": \"前へ\",\n \"Previous image\": \"前の画像\",\n \"Question\": \"質問\",\n \"Question {{ optionOrderNumber}}\": \"質問 {{ optionOrderNumber}}\",\n \"Question is required\": \"質問は必須です\",\n \"Quote Reply\": \"引用返信\",\n \"Reached the vote limit. Remove an existing vote first.\": \"投票制限に達しました。既存の投票を先に削除してください。\",\n \"Recording format is not supported and cannot be reproduced\": \"録音形式はサポートされておらず、再生できません\",\n \"Remind me\": \"リマインド\",\n \"Remind Me\": \"リマインダー\",\n \"Reminder set\": \"リマインダーを設定しました\",\n \"Remove\": \"削除\",\n \"Remove {{ count }} members_other\": \"{{ count }}人のメンバーを削除\",\n \"Remove {{ member }} from this channel?\": \"{{ member }}をこのチャンネルから削除しますか?\",\n \"Remove channel members\": \"チャンネルメンバーを削除\",\n \"Remove reminder\": \"リマインダーを削除\",\n \"Remove save for later\": \"「後で見る」を削除\",\n \"Remove user\": \"ユーザーを削除\",\n \"Removed {{ count }} members_other\": \"{{ count }}人のメンバーを削除しました\",\n \"Replied to a thread\": \"スレッドに返信しました\",\n \"Reply\": \"返事\",\n \"Reply to {{ authorName }}\": \"{{ authorName }} に返信\",\n \"Reply to a message to start a thread\": \"メッセージに返信してスレッドを開始してください\",\n \"Reply to Message\": \"メッセージに返信\",\n \"replyCount_one\": \"1件の返信\",\n \"replyCount_other\": \"{{ count }} 返信\",\n \"Resend\": \"再送信\",\n \"Retry upload\": \"アップロードを再試行\",\n \"Review all options available in this poll\": \"この投票で利用可能なすべての選択肢を確認\",\n \"Review comments submitted with poll answers\": \"投票回答とともに送信されたコメントを確認\",\n \"Review poll results and open an option to see detailed votes\": \"投票結果を確認し、選択肢を開いて詳細な投票を表示\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"このメッセージを確認し、削除・編集・そのまま送信するかを選択\",\n \"Review who voted for this option\": \"この選択肢に投票した人を確認\",\n \"Save\": \"保存\",\n \"Save for later\": \"後で保存\",\n \"Saved for later\": \"後で保存済み\",\n \"Search\": \"探す\",\n \"Search GIFs\": \"GIFを検索\",\n \"search-results-header-filter-source-button-label--channels\": \"チャンネル\",\n \"search-results-header-filter-source-button-label--messages\": \"メッセージ\",\n \"search-results-header-filter-source-button-label--users\": \"ユーザー\",\n \"Searching for {{ searchSourceType }}...\": \"{{ searchSourceType }}を検索中...\",\n \"Searching...\": \"検索中...\",\n \"searchResultsCount_one\": \"1件の結果\",\n \"searchResultsCount_other\": \"{{ count }}件の結果\",\n \"Select a thread to continue the conversation\": \"会話を続けるにはスレッドを選択してください\",\n \"Select more than one option\": \"複数の選択肢を選ぶ\",\n \"Select one\": \"1つ選択\",\n \"Select one or more\": \"1つ以上選択\",\n \"Select up to {{count}}_one\": \"最大{{count}}まで選択\",\n \"Select up to {{count}}_other\": \"最大{{count}}まで選択\",\n \"Select your current location and optionally enable live location sharing\": \"現在地を選択し、必要に応じてライブ位置情報共有を有効化\",\n \"Send\": \"送信\",\n \"Send a message\": \"メッセージを送る\",\n \"Send a message to start the conversation\": \"メッセージを送って会話を始めましょう\",\n \"Send Anyway\": \"とにかく送信する\",\n \"Send direct message\": \"ダイレクトメッセージを送信\",\n \"Send message request failed\": \"メッセージ送信リクエストが失敗しました\",\n \"Send poll\": \"アンケートを送信\",\n \"Sending...\": \"送信中...\",\n \"Sent\": \"送信済み\",\n \"Share\": \"共有\",\n \"Share a file to see it here\": \"ファイルを共有するとここに表示されます\",\n \"Share a photo or video to see it here\": \"写真や動画を共有するとここに表示されます\",\n \"Share live location for\": \"ライブ位置情報を共有\",\n \"Share Location\": \"位置情報を共有\",\n \"Shared live location\": \"共有されたライブ位置情報\",\n \"Shared location\": \"共有された位置情報\",\n \"Shuffle\": \"シャッフル\",\n \"size limit\": \"サイズ制限\",\n \"Slow Mode ON\": \"スローモードオン\",\n \"Slow mode, wait {{ seconds }}s...\": \"スローモード、{{ seconds }}秒お待ちください...\",\n \"Some of the files will not be accepted\": \"一部のファイルは受け付けられません\",\n \"Start typing to search\": \"検索するには入力を開始してください\",\n \"Stop sharing\": \"共有を停止\",\n \"Submit\": \"送信\",\n \"Suggest a new option to add to this poll\": \"この投票に追加する新しい選択肢を提案\",\n \"Suggest an option\": \"オプションを提案\",\n \"Tap to remove\": \"タップして削除\",\n \"Tap to remove: {{ reactionName }}\": \"タップして削除: {{ reactionName }}\",\n \"Thinking...\": \"考え中...\",\n \"this content could not be displayed\": \"このコンテンツは表示できませんでした\",\n \"This field cannot be empty or contain only spaces\": \"このフィールドは空にすることはできません。また、空白文字のみを含むこともできません\",\n \"This message did not meet our content guidelines\": \"このメッセージはコンテンツガイドラインに適合していません\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"このユーザーは再びあなたにメッセージを送信できるようになります。\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"スレッド\",\n \"Thread has not been found\": \"スレッドが見つかりませんでした\",\n \"Thread reply\": \"スレッドの返信\",\n \"Thread Reply\": \"スレッドの返信\",\n \"ThreadListUnseenThreadsBanner/loading\": \"読み込み中...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }}件の未読スレッド\",\n \"Threads\": \"スレッド\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[昨日]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[今日]\\\", \\\"nextDay\\\": \\\"[明日]\\\", \\\"lastDay\\\": \\\"[昨日]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[先週の] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"{{ count }}日前\",\n \"timestamp/relativeToday\": \"今日\",\n \"timestamp/relativeWeeksAgo\": \"{{ count }}週間前\",\n \"timestamp/relativeYesterday\": \"昨日\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[今日] HH:mm\\\", \\\"nextDay\\\": \\\"[明日] HH:mm\\\", \\\"lastDay\\\": \\\"[昨日] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd HH:mm\\\", \\\"lastWeek\\\": \\\"dddd HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"録音を開始するには、ブラウザーでカメラへのアクセスを許可してください\",\n \"To start recording, allow the microphone access in your browser\": \"録音を開始するには、ブラウザーでマイクロフォンへのアクセスを許可してください\",\n \"totalVoteCount_other\": \"合計{{ count }}票\",\n \"Translated\": \"翻訳済み\",\n \"Translated from {{ language }}\": \"{{ language }}から翻訳\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"2から10までの数字を入力してください\",\n \"Unarchive\": \"アーカイブ解除\",\n \"unban-command-args\": \"[@ユーザ名]\",\n \"unban-command-description\": \"ユーザーの禁止を解除する\",\n \"Unblock\": \"ブロック解除\",\n \"Unblock user\": \"ユーザーのブロックを解除\",\n \"Unblock User\": \"ユーザーのブロックを解除\",\n \"unknown error\": \"不明なエラー\",\n \"Unmute\": \"無音を解除する\",\n \"Unmute chat\": \"チャットのミュートを解除\",\n \"Unmute user\": \"ユーザーのミュートを解除\",\n \"unmute-command-args\": \"[@ユーザ名]\",\n \"unmute-command-description\": \"ユーザーのミュートを解除する\",\n \"Unpin\": \"ピンを解除する\",\n \"Unread messages\": \"未読メッセージ\",\n \"Unsupported attachment\": \"サポートされていない添付ファイル\",\n \"unsupported file type\": \"サポートされていないファイル形式\",\n \"Update\": \"更新\",\n \"Update the comment attached to your poll answer\": \"投票回答に添付されたコメントを更新\",\n \"Update your comment\": \"コメントを更新\",\n \"Upload blocked\": \"アップロードがブロックされました\",\n \"Upload error\": \"アップロードエラー\",\n \"Upload failed\": \"アップロードに失敗しました\",\n \"Upload Picture\": \"画像をアップロード\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"アップロードタイプ:\\\"{{ type }}\\\"は許可されていません\",\n \"User blocked\": \"ユーザーをブロックしました\",\n \"User muted\": \"ユーザーをミュートしました\",\n \"User removed\": \"ユーザーを削除しました\",\n \"User unblocked\": \"ユーザーのブロックを解除しました\",\n \"User unmuted\": \"ユーザーのミュートを解除しました\",\n \"User uploaded content\": \"ユーザーがアップロードしたコンテンツ\",\n \"Video\": \"動画\",\n \"videoCount_other\": \"{{ count }}件の動画\",\n \"View\": \"表示\",\n \"View {{count}} comments_one\": \"{{count}} コメントを表示\",\n \"View {{count}} comments_other\": \"{{count}} コメントを表示\",\n \"View all\": \"すべて表示\",\n \"View member details for {{ member }}\": \"{{ member }}のメンバー詳細を表示\",\n \"View original\": \"原文を表示\",\n \"View results\": \"結果を表示\",\n \"View translation\": \"翻訳を表示\",\n \"Voice message\": \"ボイスメッセージ\",\n \"Voice message {{ duration }}\": \"ボイスメッセージ {{ duration }}\",\n \"Voice message deleted\": \"ボイスメッセージが削除されました\",\n \"voiceMessageCount_other\": \"{{ count }}件のボイスメッセージ\",\n \"Vote ended\": \"投票が終了しました\",\n \"Votes\": \"投票\",\n \"Wait until all attachments have uploaded\": \"すべての添付ファイルがアップロードされるまでお待ちください\",\n \"Waiting for network…\": \"ネットワークを待機中…\",\n \"You\": \"あなた\",\n \"You've reached the maximum number of files\": \"ファイルの最大数に達しました\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} 그리고 {{ moreCount }}명 더\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} 그리고 {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }}개 파일\",\n \"{{ count }} files_other\": \"{{ count }}개 파일\",\n \"{{ count }} members_other\": \"{{ count }}명 멤버\",\n \"{{ count }} members added_other\": \"{{ count }}명 멤버가 추가됨\",\n \"{{ count }} people are typing_one\": \"{{ count }}명이 입력 중입니다\",\n \"{{ count }} people are typing_many\": \"{{ count }}명이 입력 중입니다\",\n \"{{ count }} people are typing_other\": \"{{ count }}명이 입력 중입니다\",\n \"{{ count }} photos_one\": \"{{ count }}개 사진\",\n \"{{ count }} photos_other\": \"{{ count }}개 사진\",\n \"{{ count }} reactions_other\": \"{{ count }}개 반응\",\n \"{{ count }} videos_one\": \"{{ count }}개 동영상\",\n \"{{ count }} videos_other\": \"{{ count }}개 동영상\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} 그리고 {{ secondUser }}\",\n \"{{ imageCount }} more\": \"{{ imageCount }}개 더\",\n \"{{ member }} will be able to message you again.\": \"{{ member }}님이 다시 메시지를 보낼 수 있습니다.\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }}님은 더 이상 메시지를 보낼 수 없습니다.\",\n \"{{ memberCount }} members\": \"{{ memberCount }}명\",\n \"{{ typing }} are typing\": \"{{ typing }} 입력 중입니다\",\n \"{{ typing }} is typing\": \"{{ typing }} 입력 중입니다\",\n \"{{ user }} has been muted\": \"{{ user }} 음소거되었습니다\",\n \"{{ user }} has been unmuted\": \"{{ user }} 음소거가 해제되었습니다\",\n \"{{ user }} is typing...\": \"{{ user }}이(가) 입력 중입니다...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }}와(과) {{ user }}이(가) 입력 중입니다...\",\n \"{{ users }} and more are typing...\": \"{{ users }}와(과) 더 많은 사람들이 입력 중입니다...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} 온라인\",\n \"{{count}} new messages_one\": \"{{count}}개의 새 메시지\",\n \"{{count}} new messages_other\": \"{{count}}개의 새 메시지\",\n \"{{count}} unread_one\": \"{{count}} 읽지 않음\",\n \"{{count}} unread_other\": \"{{count}} 읽지 않음\",\n \"{{count}} votes_one\": \"{{count}} 투표\",\n \"{{count}} votes_other\": \"{{count}} 투표\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"옵션 {{count}}개 더\",\n \"+{{count}} more options_other\": \"옵션 {{count}}개 더\",\n \"🏙 Attachment...\": \"🏙 부착...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}}이(가) 생성함: {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}}이(가) 투표함: {{pollOptionText}}\",\n \"📍Shared location\": \"📍공유된 위치\",\n \"Actions\": \"Actions\",\n \"Add\": \"추가\",\n \"Add {{ count }} members_other\": \"{{ count }}명 멤버 추가\",\n \"Add a comment\": \"댓글 추가\",\n \"Add a comment to your poll answer\": \"투표 답변에 댓글 추가\",\n \"Add an option\": \"옵션 추가\",\n \"Add channel members\": \"채널 멤버 추가\",\n \"Add members\": \"멤버 추가\",\n \"Add reaction\": \"반응 추가\",\n \"Admin\": \"관리자\",\n \"All results loaded\": \"모든 결과가 로드되었습니다\",\n \"Allow access to camera\": \"카메라에 대한 액세스 허용\",\n \"Allow access to microphone\": \"마이크로폰에 대한 액세스 허용\",\n \"Allow comments\": \"댓글 허용\",\n \"Allow option suggestion\": \"옵션 제안 허용\",\n \"Allow others to add comments\": \"다른 사람이 댓글을 추가할 수 있도록 허용\",\n \"Already a member\": \"이미 멤버입니다\",\n \"Also send as a direct message\": \"다이렉트 메시지로도 보내기\",\n \"Also send in channel\": \"채널에도 보내기\",\n \"Also sent in channel\": \"채널에도 전송됨\",\n \"An error has occurred during recording\": \"녹음 중 오류가 발생했습니다\",\n \"An error has occurred during the recording processing\": \"녹음 처리 중 오류가 발생했습니다\",\n \"Anonymous\": \"익명\",\n \"Anonymous poll\": \"익명 투표\",\n \"Archive\": \"아카이브\",\n \"Are you sure you want to delete this message?\": \"이 메시지를 삭제하시겠습니까?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_other\": \"첨부 파일 {{ count }}개\",\n \"aria/{{ count }} search results_other\": \"검색 결과 {{ count }}개\",\n \"aria/{{ count }} suggestions_other\": \"제안 {{ count }}개\",\n \"aria/{{ count }} unread message_other\": \"읽지 않은 메시지 {{ count }}개\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} 해제\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} 사용\",\n \"aria/Active\": \"활성\",\n \"aria/Animated GIF\": \"움직이는 GIF\",\n \"aria/Animated GIF: {{ title }}\": \"움직이는 GIF: {{ title }}\",\n \"aria/Attachment\": \"첨부 파일\",\n \"aria/Attachment {{ attachmentType }}\": \"첨부 파일 {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"첨부 파일 작업\",\n \"aria/audio\": \"오디오\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"오디오 위치 {{ elapsed }} / {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"오디오 위치 {{ progress }}퍼센트\",\n \"aria/Back to attachments\": \"첨부 파일로 돌아가기\",\n \"aria/Back to parent menu button\": \"상위 메뉴로 돌아가기 버튼\",\n \"aria/Block User\": \"사용자 차단\",\n \"aria/Bookmark Message\": \"메시지 북마크\",\n \"aria/Cancel recording\": \"녹음 취소\",\n \"aria/Cancel Reply\": \"답장 취소\",\n \"aria/Channel Actions\": \"채널 작업\",\n \"aria/Channel details\": \"채널 세부 정보\",\n \"aria/Channel list\": \"채널 목록\",\n \"aria/Chat view controls\": \"채팅 보기 컨트롤\",\n \"aria/Chat: {{ channelName }}\": \"채팅: {{ channelName }}\",\n \"aria/Clear search\": \"검색 지우기\",\n \"aria/Close callout dialog\": \"콜아웃 대화 상자 닫기\",\n \"aria/Close thread\": \"스레드 닫기\",\n \"aria/Collapse sidebar\": \"사이드바 접기\",\n \"aria/Command activated: {{ command }}\": \"명령 활성화됨: {{ command }}\",\n \"aria/Command Suggestions\": \"명령어 제안\",\n \"aria/Complete recording\": \"녹음 완료\",\n \"aria/Copy Message Text\": \"메시지 텍스트 복사\",\n \"aria/Decrease value\": \"값 감소\",\n \"aria/Delete Message\": \"메시지 삭제\",\n \"aria/Delivered\": \"전달됨\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"전송 상태: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"알림 닫기\",\n \"aria/Download attachment\": \"첨부 파일 다운로드\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"\\\"{{ option }}\\\"을(를) {{ position }}번 위치에 놓았습니다.\",\n \"aria/Edit Message\": \"메시지 수정\",\n \"aria/Emoji picker\": \"이모지 선택기\",\n \"aria/Emoji Suggestions\": \"이모지 제안\",\n \"aria/Exit search\": \"검색 종료\",\n \"aria/Expand sidebar\": \"사이드바 확장\",\n \"aria/file\": \"파일\",\n \"aria/File upload\": \"파일 업로드\",\n \"aria/Flag Message\": \"메시지 신고\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Giphy 작업\",\n \"aria/Giphy canceled\": \"Giphy를 취소했습니다\",\n \"aria/Giphy image changed\": \"Giphy 이미지가 변경되었습니다\",\n \"aria/Giphy image changed: {{ title }}\": \"Giphy 이미지가 변경되었습니다: {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Giphy 미리 보기이며 나에게만 표시됩니다. 보내기, 셔플 또는 취소 작업을 사용하세요.\",\n \"aria/Giphy sent\": \"Giphy를 보냈습니다\",\n \"aria/image\": \"이미지\",\n \"aria/Image failed to load\": \"이미지를 불러오지 못했습니다\",\n \"aria/Increase value\": \"값 증가\",\n \"aria/Jump to latest message\": \"최신 메시지로 이동\",\n \"aria/Jump to quoted message\": \"인용된 메시지로 이동\",\n \"aria/Last activity: {{ time }}\": \"마지막 활동: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"{{ sender }}님의 마지막 메시지: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"마지막 메시지: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"읽지 않음으로 표시\",\n \"aria/Mark messages as read\": \"메시지를 읽음으로 표시\",\n \"aria/Mention Suggestions\": \"멘션 제안\",\n \"aria/Message Actions\": \"메시지 작업\",\n \"aria/Message from {{ user }},\": \"{{ user }}의 메시지,\",\n \"aria/Message input\": \"메시지 입력\",\n \"aria/Message with attachments\": \"첨부 파일이 있는 메시지\",\n \"aria/Message,\": \"메시지,\",\n \"aria/Mute User\": \"사용자 음소거\",\n \"aria/Next page\": \"다음 페이지\",\n \"aria/No search results found\": \"검색 결과가 없습니다\",\n \"aria/Notifications\": \"알림\",\n \"aria/Open Attachment Selector\": \"첨부 파일 선택기 열기\",\n \"aria/Open Channel Actions Menu\": \"채널 작업 메뉴 열기\",\n \"aria/Open channel details\": \"채널 세부 정보 열기\",\n \"aria/Open channels view\": \"채널 보기 열기\",\n \"aria/Open image shared by {{ name }}\": \"{{ name }}님이 공유한 이미지 열기\",\n \"aria/Open Message Actions Menu\": \"메시지 액션 메뉴 열기\",\n \"aria/Open Reaction Selector\": \"반응 선택기 열기\",\n \"aria/Open Thread\": \"스레드 열기\",\n \"aria/Open threads view\": \"스레드 보기 열기\",\n \"aria/Open threads view with unread threads_one\": \"스레드 보기 열기, 읽지 않은 스레드 {{ count }}개\",\n \"aria/Open threads view with unread threads_other\": \"스레드 보기 열기, 읽지 않은 스레드 {{ count }}개\",\n \"aria/Open video shared by {{ name }}\": \"{{ name }}님이 공유한 동영상 열기\",\n \"aria/Opened channel: {{ name }}\": \"채널 열림: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"{{ name }}에서 스레드 열림\",\n \"aria/Option {{ position }}\": \"옵션 {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"이제 옵션의 순서를 변경하고 제거할 수 있습니다.\",\n \"aria/Pause\": \"일시정지\",\n \"aria/Pause recording\": \"녹음 일시정지\",\n \"aria/Percent complete\": \"{{percent}}퍼센트 완료\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"\\\"{{ option }}\\\"을(를) 집었습니다. 화살표 키로 순서를 변경하고, 스페이스 또는 탭 키로 놓으세요.\",\n \"aria/Pin Message\": \"메시지 고정\",\n \"aria/Play\": \"재생\",\n \"aria/Poll dialog opened\": \"투표 대화 상자 열림\",\n \"aria/Poll sent\": \"투표를 보냈습니다\",\n \"aria/Poll: {{ pollName }}\": \"투표: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Enter 키를 눌러 입력을 시작하세요\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"이 옵션을 선택하려면 스페이스 키를 누르고, 이동하려면 위쪽 및 아래쪽 화살표 키를 사용한 다음, 선택을 해제하려면 스페이스 키를 다시 누르세요.\",\n \"aria/Previous page\": \"이전 페이지\",\n \"aria/Quote Message\": \"메시지 인용\",\n \"aria/Reaction list\": \"반응 목록\",\n \"aria/Read\": \"읽음\",\n \"aria/Recording paused\": \"녹음 일시정지됨\",\n \"aria/Recording resumed\": \"녹음 재개됨\",\n \"aria/Recording started\": \"녹음 시작됨\",\n \"aria/Remind Me Message\": \"알림 설정\",\n \"aria/Remove attachment\": \"첨부 파일 제거\",\n \"aria/Remove location attachment\": \"위치 첨부 파일 제거\",\n \"aria/Remove option: {{ option }}\": \"옵션 제거: {{ option }}\",\n \"aria/Remove Reminder\": \"알림 제거\",\n \"aria/Remove Save For Later\": \"나중에 보기 제거\",\n \"aria/Removed option {{ option }}\": \"옵션 {{ option }}이(가) 제거되었습니다\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"\\\"{{ option }}\\\" 순서 변경, {{ total }}개 중 {{ position }}번째\",\n \"aria/Reorder option {{ position }}\": \"옵션 {{ position }} 순서 변경\",\n \"aria/Resend Message\": \"메시지 다시 보내기\",\n \"aria/Resume recording\": \"녹음 재개\",\n \"aria/Retry upload\": \"업로드 다시 시도\",\n \"aria/Review bounced message\": \"반송된 메시지 검토\",\n \"aria/Search cleared\": \"검색을 지웠습니다\",\n \"aria/Search results\": \"검색 결과\",\n \"aria/Search results header filter button for: {{ source }}\": \"{{ source }}에 대한 검색 결과 헤더 필터 버튼\",\n \"aria/Seek audio position\": \"오디오 위치 탐색\",\n \"aria/Select Reaction: {{ reactionName }}\": \"반응 선택: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"사용자 채널 선택: {{ name }}\",\n \"aria/Send\": \"보내기\",\n \"aria/Sent\": \"보냄\",\n \"aria/Shared a link\": \"링크를 공유했습니다\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"제목과 함께 링크를 공유했습니다: {{ linkTitle }}\",\n \"aria/Shared location\": \"공유된 위치\",\n \"aria/Show preview\": \"미리보기 표시\",\n \"aria/Start recording audio\": \"오디오 녹음 시작\",\n \"aria/Stop AI Generation\": \"AI 생성 중지\",\n \"aria/Submenu\": \"하위 메뉴\",\n \"aria/Suggestions\": \"제안\",\n \"aria/There are no messages in this chat.\": \"이 채팅에 메시지가 없습니다\",\n \"aria/This option can be reordered and removed.\": \"이 옵션은 순서를 변경하고 제거할 수 있습니다.\",\n \"aria/Thread list\": \"스레드 목록\",\n \"aria/Thread: {{ messagePreview }}\": \"스레드: {{ messagePreview }}\",\n \"aria/Unblock User\": \"사용자 차단 해제\",\n \"aria/Unmute User\": \"음소거 해제\",\n \"aria/Unpin Message\": \"핀 해제\",\n \"aria/User selected: {{ user }}\": \"선택한 사용자: {{ user }}\",\n \"aria/video\": \"동영상\",\n \"aria/voice message\": \"음성 메시지\",\n \"aria/Voice message sent\": \"음성 메시지 전송됨\",\n \"aria/Voice recording attached\": \"음성 녹음 첨부됨\",\n \"Ask a question\": \"질문하기\",\n \"Attach\": \"첨부\",\n \"Attach files\": \"파일 첨부\",\n \"Attachment\": \"첨부 파일\",\n \"Attachment upload blocked due to {{reason}}\": \"{{reason}}로 인해 첨부 파일 업로드가 차단되었습니다\",\n \"Attachment upload failed due to {{reason}}\": \"{{reason}}로 인해 첨부 파일 업로드가 실패했습니다\",\n \"Back\": \"뒤로\",\n \"ban-command-args\": \"[@사용자이름] [텍스트]\",\n \"ban-command-description\": \"사용자를 차단\",\n \"Block user\": \"사용자 차단\",\n \"Block User\": \"사용자 차단\",\n \"Browse channel members\": \"채널 멤버 보기\",\n \"Browse pinned messages\": \"고정된 메시지 보기\",\n \"Cancel\": \"취소\",\n \"Cannot seek in the recording\": \"녹음에서 찾을 수 없습니다\",\n \"Changes saved\": \"변경 사항이 저장되었습니다\",\n \"Channel archived\": \"채널이 보관됨\",\n \"Channel members\": \"채널 멤버\",\n \"Channel Missing\": \"채널 누락\",\n \"Channel muted\": \"채널이 음소거됨\",\n \"Channel pinned\": \"채널이 고정됨\",\n \"Channel unarchived\": \"채널 보관이 해제됨\",\n \"Channel unmuted\": \"채널 음소거가 해제됨\",\n \"Channel unpinned\": \"채널 고정이 해제됨\",\n \"Channels\": \"채널\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"채팅\",\n \"Choose between 2 to 10 options\": \"2~10개의 선택지 중에서 선택\",\n \"Close\": \"닫기\",\n \"Close dialog\": \"대화 상자 닫기\",\n \"Close emoji picker\": \"이모티콘 선택기 닫기\",\n \"Command not available while editing\": \"편집 중에는 명령을 사용할 수 없습니다\",\n \"Command not available while replying\": \"답장 중에는 명령을 사용할 수 없습니다\",\n \"Commands\": \"명령어\",\n \"Commands matching\": \"일치하는 명령\",\n \"Connection failure, reconnecting now...\": \"연결 실패, 지금 다시 연결 중...\",\n \"Contact info\": \"연락처 정보\",\n \"Contact name\": \"연락처 이름\",\n \"Copy Message\": \"메시지 복사\",\n \"Create\": \"생성\",\n \"Create a question, add options, and configure poll settings\": \"질문을 만들고 옵션을 추가한 뒤 투표 설정 구성\",\n \"Create poll\": \"투표 생성\",\n \"Current location\": \"현재 위치\",\n \"Delete\": \"삭제\",\n \"Delete chat\": \"채팅 삭제\",\n \"Delete for me\": \"나만 삭제\",\n \"Delete message\": \"메시지 삭제\",\n \"Delivered\": \"배달됨\",\n \"Direct message\": \"다이렉트 메시지\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"지금 이 투표를 종료하시겠습니까? 종료 후에는 더 이상 투표할 수 없습니다.\",\n \"Download {{ fileName }}\": \"{{ fileName }} 다운로드\",\n \"Download All\": \"모두 다운로드\",\n \"Download Attachment\": \"첨부 파일 다운로드\",\n \"Download attachment {{ name }}\": \"첨부 파일 {{ name }} 다운로드\",\n \"Download attachment {{ number }}\": \"첨부 파일 {{ number }} 다운로드\",\n \"Drag your files here\": \"여기로 파일을 끌어다 놓으세요\",\n \"Drag your files here to add to your post\": \"게시물에 추가하려면 파일을 여기로 끌어다 놓으세요\",\n \"Due {{ timeLeft }}\": \"{{ timeLeft }}에 기한\",\n \"Due since {{ dueSince }}\": \"{{ dueSince }}부터 기한\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"수정\",\n \"Edit chat data\": \"채팅 데이터 수정\",\n \"Edit contact\": \"연락처 편집\",\n \"Edit group\": \"그룹 편집\",\n \"Edit Message\": \"메시지 수정\",\n \"Edit message request failed\": \"메시지 수정 요청 실패\",\n \"Edited\": \"편집됨\",\n \"Emoji matching\": \"이모티콘 매칭\",\n \"Empty message...\": \"빈 메시지...\",\n \"End\": \"종료\",\n \"End poll\": \"투표 종료\",\n \"End this poll?\": \"이 투표를 종료하시겠습니까?\",\n \"End vote\": \"투표 종료\",\n \"Enforce unique vote is enabled\": \"고유 투표가 활성화되었습니다\",\n \"Error\": \"오류\",\n \"Error adding flag\": \"플래그를 추가하는 동안 오류가 발생했습니다.\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"사용자 차단 중 오류 발생\",\n \"Error connecting to chat, refresh the page to try again.\": \"채팅에 연결하는 동안 오류가 발생했습니다. 페이지를 새로고침하여 다시 시도하세요.\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"메시지를 삭제하는 중에 오류가 발생했습니다.\",\n \"Error fetching reactions\": \"반응 로딩 오류.\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"메시지를 읽지 않음으로 표시하는 중 오류가 발생했습니다. 가장 최근 100개의 채널 메시지보다 오래된 읽지 않은 메시지는 표시할 수 없습니다.\",\n \"Error muting a user ...\": \"사용자를 음소거하는 중에 오류가 발생했습니다...\",\n \"Error muting channel\": \"채널 음소거 중 오류 발생\",\n \"Error muting user\": \"사용자 음소거 중 오류 발생\",\n \"Error opening direct message\": \"다이렉트 메시지를 여는 중 오류가 발생했습니다\",\n \"Error pinning message\": \"메시지를 핀하는 중에 오류가 발생했습니다.\",\n \"Error removing members\": \"멤버를 제거하는 중 오류가 발생했습니다\",\n \"Error removing message pin\": \"메시지 핀을 제거하는 중에 오류가 발생했습니다.\",\n \"Error removing user\": \"사용자를 제거하는 중 오류가 발생했습니다\",\n \"Error reproducing the recording\": \"녹음 재생 중 오류 발생\",\n \"Error starting recording\": \"녹음 시작 중 오류가 발생했습니다\",\n \"Error unblocking user\": \"사용자 차단 해제 중 오류가 발생했습니다\",\n \"Error unmuting a user ...\": \"사용자 음소거 해제 중 오류 발생...\",\n \"Error unmuting channel\": \"채널 음소거 해제 중 오류 발생\",\n \"Error unmuting user\": \"사용자 음소거 해제 중 오류 발생\",\n \"Error uploading attachment\": \"첨부 파일 업로드 중 오류가 발생했습니다\",\n \"Error uploading file\": \"파일 업로드 오류\",\n \"Error uploading image\": \"이미지를 업로드하는 동안 오류가 발생했습니다.\",\n \"Error: {{ errorMessage }}\": \"오류: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"명령 종료 {{ command }}\",\n \"Failed to block user\": \"사용자 차단에 실패했습니다\",\n \"Failed to create the poll\": \"투표 생성 실패\",\n \"Failed to create the poll due to {{reason}}\": \"{{reason}} 때문에 투표를 생성하지 못했습니다\",\n \"Failed to delete the message\": \"메시지 삭제에 실패했습니다\",\n \"Failed to end the poll\": \"투표 종료에 실패했습니다\",\n \"Failed to end the poll due to {{reason}}\": \"{{reason}}(으)로 인해 투표 종료에 실패했습니다\",\n \"Failed to jump to the first unread message\": \"첫 번째 읽지 않은 메시지로 이동하지 못했습니다\",\n \"Failed to leave channel\": \"채널 나가기에 실패했습니다\",\n \"Failed to load channels\": \"채널을 불러오지 못했습니다\",\n \"Failed to load more channels\": \"채널을 더 불러오지 못했습니다\",\n \"Failed to mark channel as read\": \"채널을 읽음으로 표시하는 데 실패했습니다\",\n \"Failed to play the recording\": \"녹음을 재생하지 못했습니다\",\n \"Failed to retrieve location\": \"위치를 가져오지 못했습니다\",\n \"Failed to save changes\": \"변경 사항을 저장하지 못했습니다\",\n \"Failed to share location\": \"위치를 공유하지 못했습니다\",\n \"Failed to update channel archive status\": \"채널 아카이브 상태 업데이트에 실패했습니다\",\n \"Failed to update channel mute status\": \"채널 음소거 상태 업데이트에 실패했습니다\",\n \"Failed to update channel pinned status\": \"채널 고정 상태 업데이트에 실패했습니다\",\n \"File\": \"파일\",\n \"File is required for upload attachment\": \"첨부 파일 업로드에 파일이 필요합니다\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"파일이 너무 큽니다: {{ size }}, 최대 업로드 크기는 {{ limit }}입니다\",\n \"File too large\": \"파일이 너무 큽니다\",\n \"fileCount_other\": \"파일 {{ count }}개\",\n \"Files\": \"파일\",\n \"Flag\": \"플래그\",\n \"Generating...\": \"생성 중...\",\n \"giphy-command-args\": \"[텍스트]\",\n \"giphy-command-description\": \"채널에 무작위 GIF 게시\",\n \"Go back\": \"뒤로 가기\",\n \"Group info\": \"그룹 정보\",\n \"Group name\": \"그룹 이름\",\n \"Hide who voted\": \"누가 투표했는지 숨기기\",\n \"Image\": \"이미지\",\n \"imageCount_other\": \"이미지 {{ count }}개\",\n \"Instant commands\": \"즉시 명령어\",\n \"language/af\": \"아프리칸스어\",\n \"language/am\": \"암하라어\",\n \"language/ar\": \"아랍어\",\n \"language/az\": \"아제르바이잔어\",\n \"language/bg\": \"불가리아어\",\n \"language/bn\": \"벵골어\",\n \"language/bs\": \"보스니아어\",\n \"language/cs\": \"체코어\",\n \"language/da\": \"덴마크어\",\n \"language/de\": \"독일어\",\n \"language/el\": \"그리스어\",\n \"language/en\": \"영어\",\n \"language/es\": \"스페인어\",\n \"language/es-MX\": \"스페인어(멕시코)\",\n \"language/et\": \"에스토니아어\",\n \"language/fa\": \"페르시아어\",\n \"language/fa-AF\": \"다리어\",\n \"language/fi\": \"핀란드어\",\n \"language/fr\": \"프랑스어\",\n \"language/fr-CA\": \"프랑스어(캐나다)\",\n \"language/ha\": \"하우사어\",\n \"language/he\": \"히브리어\",\n \"language/hi\": \"힌디어\",\n \"language/hr\": \"크로아티아어\",\n \"language/ht\": \"아이티 크리올어\",\n \"language/hu\": \"헝가리어\",\n \"language/id\": \"인도네시아어\",\n \"language/it\": \"이탈리아어\",\n \"language/ja\": \"일본어\",\n \"language/ka\": \"조지아어\",\n \"language/ko\": \"한국어\",\n \"language/lt\": \"리투아니아어\",\n \"language/lv\": \"라트비아어\",\n \"language/ms\": \"말레이어\",\n \"language/nl\": \"네덜란드어\",\n \"language/no\": \"노르웨이어\",\n \"language/pl\": \"폴란드어\",\n \"language/ps\": \"파슈토어\",\n \"language/pt\": \"포르투갈어\",\n \"language/ro\": \"루마니아어\",\n \"language/ru\": \"러시아어\",\n \"language/sk\": \"슬로바키아어\",\n \"language/sl\": \"슬로베니아어\",\n \"language/so\": \"소말리아어\",\n \"language/sq\": \"알바니아어\",\n \"language/sr\": \"세르비아어\",\n \"language/sv\": \"스웨덴어\",\n \"language/sw\": \"스와힐리어\",\n \"language/ta\": \"타밀어\",\n \"language/th\": \"태국어\",\n \"language/tl\": \"타갈로그어\",\n \"language/tr\": \"터키어\",\n \"language/uk\": \"우크라이나어\",\n \"language/ur\": \"우르두어\",\n \"language/vi\": \"베트남어\",\n \"language/zh\": \"중국어(간체)\",\n \"language/zh-TW\": \"중국어(번체)\",\n \"Last seen {{ timestamp }}\": \"마지막 접속 {{ timestamp }}\",\n \"Leave Channel\": \"채널 나가기\",\n \"Leave chat\": \"채널 나가기\",\n \"Left channel\": \"채널을 나갔습니다\",\n \"Let others add options\": \"다른 사람이 선택지를 추가할 수 있도록 허용\",\n \"Limit votes per person\": \"1인당 투표 수 제한\",\n \"Link\": \"링크\",\n \"linkCount_other\": \"링크 {{ count }}개\",\n \"live\": \"라이브\",\n \"Live for {{duration}}\": \"{{duration}} 동안 라이브\",\n \"Live location\": \"라이브 위치\",\n \"Live until {{ timestamp }}\": \"{{ timestamp }}까지 라이브\",\n \"Load more\": \"더 불러오기\",\n \"Local upload attachment missing local id\": \"로컬 업로드 첨부에 로컬 ID가 없습니다\",\n \"Location\": \"위치\",\n \"Location sharing ended\": \"위치 공유가 종료되었습니다\",\n \"Location: {{ coordinates }}\": \"위치: {{ coordinates }}\",\n \"Manage channel\": \"채널 관리\",\n \"Manage members\": \"멤버 관리\",\n \"Mark as unread\": \"읽지 않음으로 표시\",\n \"Maximum number of votes (from 2 to 10)\": \"최대 투표 수 (2에서 10까지)\",\n \"Maximum votes per person\": \"1인당 최대 투표 수\",\n \"Member detail\": \"멤버 상세 정보\",\n \"mention/Channel\": \"채널\",\n \"mention/Channel Description\": \"이 채널의 모두에게 알림\",\n \"mention/Here\": \"여기\",\n \"mention/Here Description\": \"이 채널의 모든 온라인 멤버에게 알림\",\n \"Menu\": \"메뉴\",\n \"Message deleted\": \"메시지가 삭제되었습니다.\",\n \"Message failed to send\": \"메시지 전송 실패\",\n \"Message has been successfully flagged\": \"메시지에 플래그가 지정되었습니다.\",\n \"Message marked as unread\": \"메시지를 읽지 않음으로 표시했습니다\",\n \"Message pinned\": \"메시지 핀했습니다\",\n \"Message unpinned\": \"메시지 고정이 해제됨\",\n \"Message was blocked by moderation policies\": \"메시지가 관리 정책에 의해 차단되었습니다.\",\n \"Messages have been marked unread.\": \"메시지가 읽지 않음으로 표시되었습니다.\",\n \"Missing permissions to upload the attachment\": \"첨부 파일을 업로드하려면 권한이 필요합니다\",\n \"Moderator\": \"운영자\",\n \"Multiple votes\": \"복수 투표\",\n \"Mute\": \"무음\",\n \"Mute chat\": \"채팅 음소거\",\n \"Mute user\": \"사용자 음소거\",\n \"mute-command-args\": \"[@사용자이름]\",\n \"mute-command-description\": \"사용자 음소거\",\n \"network error\": \"네트워크 오류\",\n \"New\": \"새로운\",\n \"New message from {{user}}\": \"{{user}}의 새 메시지\",\n \"New Messages!\": \"새 메시지!\",\n \"Next\": \"다음\",\n \"Next image\": \"다음 이미지\",\n \"No chats here yet…\": \"아직 채팅이 없습니다...\",\n \"No conversations yet\": \"아직 대화가 없습니다.\",\n \"No files\": \"파일이 없습니다\",\n \"No items exist\": \"항목이 없습니다.\",\n \"No member found\": \"멤버를 찾을 수 없습니다\",\n \"No messages found\": \"메시지를 찾을 수 없습니다\",\n \"No photos or videos\": \"사진 또는 동영상이 없습니다\",\n \"No pinned messages\": \"고정된 메시지가 없습니다\",\n \"No results found\": \"검색 결과가 없습니다\",\n \"No user found\": \"사용자를 찾을 수 없습니다\",\n \"Nobody will be able to vote in this poll anymore.\": \"이 투표에 더 이상 아무도 투표할 수 없습니다.\",\n \"Nothing yet...\": \"아직 아무것도...\",\n \"Notify all {{ role }} members\": \"{{ role }} 역할의 모든 멤버에게 알림\",\n \"Offline\": \"오프라인\",\n \"Ok\": \"확인\",\n \"Online\": \"온라인\",\n \"Only numbers are allowed\": \"숫자만 입력 가능합니다\",\n \"Only visible to you\": \"당신에게만 표시됨\",\n \"Open emoji picker\": \"이모지 선택기 열기\",\n \"Open gallery at image {{ index }}\": \"이미지 {{ index }}에서 갤러리 열기\",\n \"Open image in gallery\": \"갤러리에서 이미지 열기\",\n \"Open location in a map\": \"지도에서 위치 열기\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"메뉴 열기\",\n \"Option already exists\": \"옵션이 이미 존재합니다\",\n \"Option is empty\": \"옵션이 비어 있습니다\",\n \"Options\": \"옵션\",\n \"Original\": \"원문\",\n \"Owner\": \"소유자\",\n \"People matching\": \"일치하는 사람\",\n \"Photo\": \"사진\",\n \"Photos & videos\": \"사진 및 동영상\",\n \"Pin\": \"핀\",\n \"Pin a message to see it here\": \"여기에서 보려면 메시지를 고정하세요\",\n \"Pinned by {{ name }}\": \"{{ name }}님이 핀함\",\n \"Pinned by You\": \"내가 고정함\",\n \"Pinned message\": \"고정된 메시지\",\n \"Pinned messages\": \"고정된 메시지\",\n \"placeholder/PollComment\": \"댓글\",\n \"placeholder/PollOptionSuggestion\": \"새 옵션 입력\",\n \"Play video\": \"동영상 재생\",\n \"Playback speed {{ rate }}x\": \"재생 속도 {{ rate }}x\",\n \"Poll\": \"투표\",\n \"Poll comments\": \"투표 댓글\",\n \"Poll ended\": \"투표 종료됨\",\n \"Poll options\": \"투표 옵션\",\n \"Poll results\": \"투표 결과\",\n \"Poll sent\": \"투표 전송됨\",\n \"Previous\": \"이전\",\n \"Previous image\": \"이전 이미지\",\n \"Question\": \"질문\",\n \"Question {{ optionOrderNumber}}\": \"질문 {{ optionOrderNumber}}\",\n \"Question is required\": \"질문이 필요합니다\",\n \"Quote Reply\": \"인용 답장\",\n \"Reached the vote limit. Remove an existing vote first.\": \"투표 한도에 도달했습니다. 기존 투표를 먼저 제거하세요.\",\n \"Recording format is not supported and cannot be reproduced\": \"녹음 형식이 지원되지 않으므로 재생할 수 없습니다\",\n \"Remind me\": \"알림\",\n \"Remind Me\": \"알림 설정\",\n \"Reminder set\": \"알림 설정됨\",\n \"Remove\": \"제거\",\n \"Remove {{ count }} members_other\": \"{{ count }}명의 멤버 제거\",\n \"Remove {{ member }} from this channel?\": \"이 채널에서 {{ member }}님을 제거하시겠습니까?\",\n \"Remove channel members\": \"채널 멤버 제거\",\n \"Remove reminder\": \"알림 제거\",\n \"Remove save for later\": \"나중에 보기 제거\",\n \"Remove user\": \"사용자 제거\",\n \"Removed {{ count }} members_other\": \"{{ count }}명의 멤버를 제거했습니다\",\n \"Replied to a thread\": \"스레드에 답글을 남겼습니다\",\n \"Reply\": \"답장\",\n \"Reply to {{ authorName }}\": \"{{ authorName }}님에게 답장\",\n \"Reply to a message to start a thread\": \"스레드를 시작하려면 메시지에 답장하세요\",\n \"Reply to Message\": \"메시지에 답장\",\n \"replyCount_one\": \"답장 1개\",\n \"replyCount_other\": \"{{ count }} 답장\",\n \"Resend\": \"다시 보내기\",\n \"Retry upload\": \"업로드 다시 시도\",\n \"Review all options available in this poll\": \"이 투표에서 사용 가능한 모든 옵션 검토\",\n \"Review comments submitted with poll answers\": \"투표 답변과 함께 제출된 댓글 검토\",\n \"Review poll results and open an option to see detailed votes\": \"투표 결과를 검토하고 옵션을 열어 상세 득표 보기\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"이 메시지를 검토하고 삭제, 수정 또는 그대로 전송할지 선택\",\n \"Review who voted for this option\": \"이 옵션에 투표한 사람 검토\",\n \"Save\": \"저장\",\n \"Save for later\": \"나중에 저장\",\n \"Saved for later\": \"나중에 저장됨\",\n \"Search\": \"찾다\",\n \"Search GIFs\": \"GIF 검색\",\n \"search-results-header-filter-source-button-label--channels\": \"채널\",\n \"search-results-header-filter-source-button-label--messages\": \"메시지\",\n \"search-results-header-filter-source-button-label--users\": \"사용자\",\n \"Searching for {{ searchSourceType }}...\": \"{{ searchSourceType }} 검색 중...\",\n \"Searching...\": \"수색...\",\n \"searchResultsCount_one\": \"1개의 결과\",\n \"searchResultsCount_other\": \"{{ count }}개 결과\",\n \"Select a thread to continue the conversation\": \"대화를 계속하려면 스레드를 선택하세요\",\n \"Select more than one option\": \"하나 이상의 선택지 선택\",\n \"Select one\": \"하나 선택\",\n \"Select one or more\": \"하나 이상 선택\",\n \"Select up to {{count}}_one\": \"{{count}}개까지 선택\",\n \"Select up to {{count}}_other\": \"{{count}}개까지 선택\",\n \"Select your current location and optionally enable live location sharing\": \"현재 위치를 선택하고 필요 시 실시간 위치 공유를 활성화\",\n \"Send\": \"보내다\",\n \"Send a message\": \"메시지 보내기\",\n \"Send a message to start the conversation\": \"대화를 시작하려면 메시지를 보내세요\",\n \"Send Anyway\": \"어쨌든 보내기\",\n \"Send direct message\": \"다이렉트 메시지 보내기\",\n \"Send message request failed\": \"메시지 보내기 요청 실패\",\n \"Send poll\": \"투표 보내기\",\n \"Sending...\": \"배상중...\",\n \"Sent\": \"전송됨\",\n \"Share\": \"공유\",\n \"Share a file to see it here\": \"파일을 공유하면 여기에 표시됩니다\",\n \"Share a photo or video to see it here\": \"사진이나 동영상을 공유하면 여기에 표시됩니다\",\n \"Share live location for\": \"라이브 위치 공유\",\n \"Share Location\": \"위치 공유\",\n \"Shared live location\": \"공유된 라이브 위치\",\n \"Shared location\": \"공유된 위치\",\n \"Shuffle\": \"셔플\",\n \"size limit\": \"크기 제한\",\n \"Slow Mode ON\": \"슬로우 모드 켜짐\",\n \"Slow mode, wait {{ seconds }}s...\": \"슬로우 모드, {{ seconds }}초 기다려 주세요...\",\n \"Some of the files will not be accepted\": \"일부 파일은 허용되지 않을 수 있습니다\",\n \"Start typing to search\": \"검색하려면 입력을 시작하세요\",\n \"Stop sharing\": \"공유 중지\",\n \"Submit\": \"제출\",\n \"Suggest a new option to add to this poll\": \"이 투표에 추가할 새 옵션 제안\",\n \"Suggest an option\": \"옵션 제안\",\n \"Tap to remove\": \"제거하려면 탭하세요\",\n \"Tap to remove: {{ reactionName }}\": \"제거하려면 탭하세요: {{ reactionName }}\",\n \"Thinking...\": \"생각 중...\",\n \"this content could not be displayed\": \"이 콘텐츠를 표시할 수 없습니다\",\n \"This field cannot be empty or contain only spaces\": \"이 필드는 비워둘 수 없으며 공백만 포함할 수도 없습니다\",\n \"This message did not meet our content guidelines\": \"이 메시지는 콘텐츠 가이드라인을 충족하지 않습니다.\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"이 사용자가 다시 메시지를 보낼 수 있습니다.\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"스레드\",\n \"Thread has not been found\": \"스레드를 찾을 수 없습니다\",\n \"Thread reply\": \"스레드 답장\",\n \"Thread Reply\": \"스레드 답장\",\n \"ThreadListUnseenThreadsBanner/loading\": \"로딩 중...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"읽지 않은 스레드 {{ count }}개\",\n \"Threads\": \"스레드\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[어제]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[오늘]\\\", \\\"nextDay\\\": \\\"[내일]\\\", \\\"lastDay\\\": \\\"[어제]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[지난] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"{{ count }}일 전\",\n \"timestamp/relativeToday\": \"오늘\",\n \"timestamp/relativeWeeksAgo\": \"{{ count }}주 전\",\n \"timestamp/relativeYesterday\": \"어제\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[오늘] HH:mm\\\", \\\"nextDay\\\": \\\"[내일] HH:mm\\\", \\\"lastDay\\\": \\\"[어제] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd HH:mm\\\", \\\"lastWeek\\\": \\\"[지난] dddd HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"브라우저에서 카메라 액세스를 허용하여 녹음을 시작합니다\",\n \"To start recording, allow the microphone access in your browser\": \"브라우저에서 마이크로폰 액세스를 허용하여 녹음을 시작합니다\",\n \"totalVoteCount_other\": \"총 {{ count }}표\",\n \"Translated\": \"번역됨\",\n \"Translated from {{ language }}\": \"{{ language }}(으)로 번역됨\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"2에서 10 사이의 숫자를 입력하세요\",\n \"Unarchive\": \"아카이브 해제\",\n \"unban-command-args\": \"[@사용자이름]\",\n \"unban-command-description\": \"사용자 차단 해제\",\n \"Unblock\": \"차단 해제\",\n \"Unblock user\": \"사용자 차단 해제\",\n \"Unblock User\": \"사용자 차단 해제\",\n \"unknown error\": \"알 수 없는 오류\",\n \"Unmute\": \"음소거 해제\",\n \"Unmute chat\": \"채팅 음소거 해제\",\n \"Unmute user\": \"사용자 음소거 해제\",\n \"unmute-command-args\": \"[@사용자이름]\",\n \"unmute-command-description\": \"사용자 음소거 해제\",\n \"Unpin\": \"핀 해제\",\n \"Unread messages\": \"읽지 않은 메시지\",\n \"Unsupported attachment\": \"지원되지 않는 첨부 파일\",\n \"unsupported file type\": \"지원되지 않는 파일 형식\",\n \"Update\": \"업데이트\",\n \"Update the comment attached to your poll answer\": \"투표 답변에 첨부된 댓글 업데이트\",\n \"Update your comment\": \"댓글 업데이트\",\n \"Upload blocked\": \"업로드가 차단되었습니다\",\n \"Upload error\": \"업로드 오류\",\n \"Upload failed\": \"업로드에 실패했습니다\",\n \"Upload Picture\": \"사진 업로드\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"업로드 유형: \\\"{{ type }}\\\"은(는) 허용되지 않습니다.\",\n \"User blocked\": \"사용자가 차단됨\",\n \"User muted\": \"사용자가 음소거되었습니다\",\n \"User removed\": \"사용자가 제거되었습니다\",\n \"User unblocked\": \"사용자 차단이 해제됨\",\n \"User unmuted\": \"사용자 음소거가 해제되었습니다\",\n \"User uploaded content\": \"사용자 업로드 콘텐츠\",\n \"Video\": \"동영상\",\n \"videoCount_other\": \"동영상 {{ count }}개\",\n \"View\": \"보기\",\n \"View {{count}} comments_one\": \"{{count}}개의 댓글 보기\",\n \"View {{count}} comments_other\": \"{{count}}개의 댓글 보기\",\n \"View all\": \"전체 보기\",\n \"View member details for {{ member }}\": \"{{ member }} 멤버 상세 정보 보기\",\n \"View original\": \"원문 보기\",\n \"View results\": \"결과 보기\",\n \"View translation\": \"번역 보기\",\n \"Voice message\": \"음성 메시지\",\n \"Voice message {{ duration }}\": \"음성 메시지 {{ duration }}\",\n \"Voice message deleted\": \"음성 메시지가 삭제됨\",\n \"voiceMessageCount_other\": \"음성 메시지 {{ count }}개\",\n \"Vote ended\": \"투표 종료\",\n \"Votes\": \"투표\",\n \"Wait until all attachments have uploaded\": \"모든 첨부 파일이 업로드될 때까지 기다립니다.\",\n \"Waiting for network…\": \"네트워크 대기 중…\",\n \"You\": \"당신\",\n \"You've reached the maximum number of files\": \"최대 파일 수에 도달했습니다.\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} en {{ moreCount }} meer\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} en {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} bestand\",\n \"{{ count }} files_other\": \"{{ count }} bestanden\",\n \"{{ count }} members_one\": \"{{ count }} lid\",\n \"{{ count }} members_other\": \"{{ count }} leden\",\n \"{{ count }} members added_one\": \"{{ count }} lid toegevoegd\",\n \"{{ count }} members added_other\": \"{{ count }} leden toegevoegd\",\n \"{{ count }} people are typing_one\": \"{{ count }} persoon typt\",\n \"{{ count }} people are typing_many\": \"{{ count }} personen typen\",\n \"{{ count }} people are typing_other\": \"{{ count }} personen typen\",\n \"{{ count }} photos_one\": \"{{ count }} foto\",\n \"{{ count }} photos_other\": \"{{ count }} foto's\",\n \"{{ count }} reactions_one\": \"{{ count }} reactie\",\n \"{{ count }} reactions_other\": \"{{ count }} reacties\",\n \"{{ count }} videos_one\": \"{{ count }} video\",\n \"{{ count }} videos_other\": \"{{ count }} video's\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} en {{ secondUser }}\",\n \"{{ imageCount }} more\": \"+{{ imageCount }}\",\n \"{{ member }} will be able to message you again.\": \"{{ member }} kan je weer berichten sturen.\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }} kan je geen berichten meer sturen.\",\n \"{{ memberCount }} members\": \"{{ memberCount }} deelnemers\",\n \"{{ typing }} are typing\": \"{{ typing }} typen\",\n \"{{ typing }} is typing\": \"{{ typing }} typt\",\n \"{{ user }} has been muted\": \"{{ user }} is gedempt\",\n \"{{ user }} has been unmuted\": \"{{ user }} is niet meer gedempt\",\n \"{{ user }} is typing...\": \"{{ user }} is aan het typen...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} en {{ user }} zijn aan het typen...\",\n \"{{ users }} and more are typing...\": \"{{ users }} en meer zijn aan het typen...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} online\",\n \"{{count}} new messages_one\": \"{{count}} nieuw bericht\",\n \"{{count}} new messages_other\": \"{{count}} nieuwe berichten\",\n \"{{count}} unread_one\": \"{{count}} ongelezen\",\n \"{{count}} unread_other\": \"{{count}} ongelezen\",\n \"{{count}} votes_one\": \"{{count}} stem\",\n \"{{count}} votes_other\": \"{{count}} stemmen\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"+{{count}} meer optie\",\n \"+{{count}} more options_other\": \"+{{count}} meer opties\",\n \"🏙 Attachment...\": \"🏙 Bijlage...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} heeft gemaakt: {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} heeft gestemd: {{pollOptionText}}\",\n \"📍Shared location\": \"📍Gedeelde locatie\",\n \"Actions\": \"Actions\",\n \"Add\": \"Toevoegen\",\n \"Add {{ count }} members_one\": \"{{ count }} lid toevoegen\",\n \"Add {{ count }} members_other\": \"{{ count }} leden toevoegen\",\n \"Add a comment\": \"Voeg een opmerking toe\",\n \"Add a comment to your poll answer\": \"Voeg een reactie toe aan je pollantwoord\",\n \"Add an option\": \"Voeg een optie toe\",\n \"Add channel members\": \"Kanaalleden toevoegen\",\n \"Add members\": \"Leden toevoegen\",\n \"Add reaction\": \"Reactie toevoegen\",\n \"Admin\": \"Beheerder\",\n \"All results loaded\": \"Alle resultaten geladen\",\n \"Allow access to camera\": \"Toegang tot camera toestaan\",\n \"Allow access to microphone\": \"Toegang tot microfoon toestaan\",\n \"Allow comments\": \"Sta opmerkingen toe\",\n \"Allow option suggestion\": \"Sta optie-suggesties toe\",\n \"Allow others to add comments\": \"Sta anderen toe om opmerkingen toe te voegen\",\n \"Already a member\": \"Al lid\",\n \"Also send as a direct message\": \"Ook als direct bericht versturen\",\n \"Also send in channel\": \"Ook in kanaal versturen\",\n \"Also sent in channel\": \"Ook in kanaal verzonden\",\n \"An error has occurred during recording\": \"Er is een fout opgetreden tijdens het opnemen\",\n \"An error has occurred during the recording processing\": \"Er is een fout opgetreden tijdens de verwerking van de opname\",\n \"Anonymous\": \"Anoniem\",\n \"Anonymous poll\": \"Anonieme peiling\",\n \"Archive\": \"Archief\",\n \"Are you sure you want to delete this message?\": \"Weet je zeker dat je dit bericht wilt verwijderen?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_one\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_one\": \"{{ count }} bijlage\",\n \"aria/{{ count }} attachment_other\": \"{{ count }} bijlagen\",\n \"aria/{{ count }} search results_one\": \"{{ count }} zoekresultaat\",\n \"aria/{{ count }} search results_other\": \"{{ count }} zoekresultaten\",\n \"aria/{{ count }} suggestions_one\": \"{{ count }} suggestie\",\n \"aria/{{ count }} suggestions_other\": \"{{ count }} suggesties\",\n \"aria/{{ count }} unread message_one\": \"{{ count }} ongelezen bericht\",\n \"aria/{{ count }} unread message_other\": \"{{ count }} ongelezen berichten\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} uitgeschakeld\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} ingeschakeld\",\n \"aria/Active\": \"Actief\",\n \"aria/Animated GIF\": \"Geanimeerde GIF\",\n \"aria/Animated GIF: {{ title }}\": \"Geanimeerde GIF: {{ title }}\",\n \"aria/Attachment\": \"Bijlage\",\n \"aria/Attachment {{ attachmentType }}\": \"Bijlage {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"Bijlageacties\",\n \"aria/audio\": \"audio\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Audiopositie {{ elapsed }} van {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"Audiopositie {{ progress }} procent\",\n \"aria/Back to attachments\": \"Terug naar bijlagen\",\n \"aria/Back to parent menu button\": \"Terug naar bovenliggend menu knop\",\n \"aria/Block User\": \"Gebruiker blokkeren\",\n \"aria/Bookmark Message\": \"Bericht bookmarken\",\n \"aria/Cancel recording\": \"Opname annuleren\",\n \"aria/Cancel Reply\": \"Antwoord annuleren\",\n \"aria/Channel Actions\": \"Kanaalacties\",\n \"aria/Channel details\": \"Kanaaldetails\",\n \"aria/Channel list\": \"Kanaallijst\",\n \"aria/Chat view controls\": \"Bedieningselementen chatweergave\",\n \"aria/Chat: {{ channelName }}\": \"Chat: {{ channelName }}\",\n \"aria/Clear search\": \"Zoekopdracht wissen\",\n \"aria/Close callout dialog\": \"Calloutdialoog sluiten\",\n \"aria/Close thread\": \"Draad sluiten\",\n \"aria/Collapse sidebar\": \"Zijbalk samenklappen\",\n \"aria/Command activated: {{ command }}\": \"Opdracht geactiveerd: {{ command }}\",\n \"aria/Command Suggestions\": \"Opdrachtsuggesties\",\n \"aria/Complete recording\": \"Opname voltooien\",\n \"aria/Copy Message Text\": \"Berichttekst kopiëren\",\n \"aria/Decrease value\": \"Waarde verlagen\",\n \"aria/Delete Message\": \"Bericht verwijderen\",\n \"aria/Delivered\": \"Bezorgd\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"Bezorgstatus: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"Melding sluiten\",\n \"aria/Download attachment\": \"Bijlage downloaden\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"'{{ option }}' losgelaten op positie {{ position }}.\",\n \"aria/Edit Message\": \"Bericht bewerken\",\n \"aria/Emoji picker\": \"Emoji kiezer\",\n \"aria/Emoji Suggestions\": \"Emoji-suggesties\",\n \"aria/Exit search\": \"Zoeken afsluiten\",\n \"aria/Expand sidebar\": \"Zijbalken uitvouwen\",\n \"aria/file\": \"bestand\",\n \"aria/File upload\": \"Bestand uploaden\",\n \"aria/Flag Message\": \"Bericht markeren\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Giphy-acties\",\n \"aria/Giphy canceled\": \"Giphy geannuleerd\",\n \"aria/Giphy image changed\": \"Giphy-afbeelding gewijzigd\",\n \"aria/Giphy image changed: {{ title }}\": \"Giphy-afbeelding gewijzigd: {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Giphy-voorbeeld, alleen zichtbaar voor jou. Gebruik de acties Verzenden, Shuffelen of Annuleren.\",\n \"aria/Giphy sent\": \"Giphy verzonden\",\n \"aria/image\": \"afbeelding\",\n \"aria/Image failed to load\": \"Afbeelding laden mislukt\",\n \"aria/Increase value\": \"Waarde verhogen\",\n \"aria/Jump to latest message\": \"Ga naar laatste bericht\",\n \"aria/Jump to quoted message\": \"Ga naar geciteerd bericht\",\n \"aria/Last activity: {{ time }}\": \"Laatste activiteit: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"Laatste bericht van {{ sender }}: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"Laatste bericht: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"Markeren als ongelezen\",\n \"aria/Mark messages as read\": \"Markeer berichten als gelezen\",\n \"aria/Mention Suggestions\": \"Vermeldingssuggesties\",\n \"aria/Message Actions\": \"Berichtacties\",\n \"aria/Message from {{ user }},\": \"Bericht van {{ user }},\",\n \"aria/Message input\": \"Berichtinvoer\",\n \"aria/Message with attachments\": \"Bericht met bijlagen\",\n \"aria/Message,\": \"Bericht,\",\n \"aria/Mute User\": \"Gebruiker dempen\",\n \"aria/Next page\": \"Volgende pagina\",\n \"aria/No search results found\": \"Geen zoekresultaten gevonden\",\n \"aria/Notifications\": \"Meldingen\",\n \"aria/Open Attachment Selector\": \"Open bijlage selector\",\n \"aria/Open Channel Actions Menu\": \"Kanaalactiemenu openen\",\n \"aria/Open channel details\": \"Kanaaldetails openen\",\n \"aria/Open channels view\": \"Kanaalweergave openen\",\n \"aria/Open image shared by {{ name }}\": \"Door {{ name }} gedeelde afbeelding openen\",\n \"aria/Open Message Actions Menu\": \"Menu voor berichtacties openen\",\n \"aria/Open Reaction Selector\": \"Reactiekiezer openen\",\n \"aria/Open Thread\": \"Draad openen\",\n \"aria/Open threads view\": \"Threadweergave openen\",\n \"aria/Open threads view with unread threads_one\": \"Threadweergave openen, {{ count }} ongelezen thread\",\n \"aria/Open threads view with unread threads_other\": \"Threadweergave openen, {{ count }} ongelezen threads\",\n \"aria/Open video shared by {{ name }}\": \"Door {{ name }} gedeelde video openen\",\n \"aria/Opened channel: {{ name }}\": \"Kanaal geopend: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"Thread geopend in {{ name }}\",\n \"aria/Option {{ position }}\": \"Optie {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"Opties kunnen nu worden herschikt en verwijderd.\",\n \"aria/Pause\": \"Pauzeren\",\n \"aria/Pause recording\": \"Opname pauzeren\",\n \"aria/Percent complete\": \"{{percent}} procent voltooid\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"'{{ option }}' opgepakt. Gebruik de pijltoetsen om opnieuw te ordenen. Druk op spatie of tab om los te laten.\",\n \"aria/Pin Message\": \"Bericht vastmaken\",\n \"aria/Play\": \"Afspelen\",\n \"aria/Poll dialog opened\": \"Peilingdialoogvenster geopend\",\n \"aria/Poll sent\": \"Peiling verzonden\",\n \"aria/Poll: {{ pollName }}\": \"Peiling: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Druk op Enter om te beginnen met typen\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"Druk op de spatiebalk om deze optie te selecteren, gebruik de pijltoetsen omhoog en omlaag om deze te verplaatsen en druk daarna opnieuw op de spatiebalk om de selectie op te heffen.\",\n \"aria/Previous page\": \"Vorige pagina\",\n \"aria/Quote Message\": \"Bericht citeren\",\n \"aria/Reaction list\": \"Reactielijst\",\n \"aria/Read\": \"Gelezen\",\n \"aria/Recording paused\": \"Opname gepauzeerd\",\n \"aria/Recording resumed\": \"Opname hervat\",\n \"aria/Recording started\": \"Opname gestart\",\n \"aria/Remind Me Message\": \"Herinner mij\",\n \"aria/Remove attachment\": \"Bijlage verwijderen\",\n \"aria/Remove location attachment\": \"Locatie bijlage verwijderen\",\n \"aria/Remove option: {{ option }}\": \"Optie verwijderen: {{ option }}\",\n \"aria/Remove Reminder\": \"Herinnering verwijderen\",\n \"aria/Remove Save For Later\": \"Verwijder 'Bewaren voor later'\",\n \"aria/Removed option {{ option }}\": \"Optie {{ option }} verwijderd\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"'{{ option }}' opnieuw ordenen, positie {{ position }} van {{ total }}\",\n \"aria/Reorder option {{ position }}\": \"Optie {{ position }} opnieuw ordenen\",\n \"aria/Resend Message\": \"Bericht opnieuw verzenden\",\n \"aria/Resume recording\": \"Opname hervatten\",\n \"aria/Retry upload\": \"Upload opnieuw proberen\",\n \"aria/Review bounced message\": \"Controleer teruggestuurd bericht\",\n \"aria/Search cleared\": \"Zoekopdracht gewist\",\n \"aria/Search results\": \"Zoekresultaten\",\n \"aria/Search results header filter button for: {{ source }}\": \"Filterknop koptekst zoekresultaten voor: {{ source }}\",\n \"aria/Seek audio position\": \"Audiopositie zoeken\",\n \"aria/Select Reaction: {{ reactionName }}\": \"Reactie selecteren: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"Gebruikerskanaal selecteren: {{ name }}\",\n \"aria/Send\": \"Verzenden\",\n \"aria/Sent\": \"Verzonden\",\n \"aria/Shared a link\": \"Link gedeeld\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"Link gedeeld met titel: {{ linkTitle }}\",\n \"aria/Shared location\": \"Gedeelde locatie\",\n \"aria/Show preview\": \"Voorbeeld tonen\",\n \"aria/Start recording audio\": \"Audio-opname starten\",\n \"aria/Stop AI Generation\": \"AI-generatie stoppen\",\n \"aria/Submenu\": \"Submenu\",\n \"aria/Suggestions\": \"Suggesties\",\n \"aria/There are no messages in this chat.\": \"Er zijn geen berichten in deze chat\",\n \"aria/This option can be reordered and removed.\": \"Deze optie kan worden herschikt en verwijderd.\",\n \"aria/Thread list\": \"Threadlijst\",\n \"aria/Thread: {{ messagePreview }}\": \"Thread: {{ messagePreview }}\",\n \"aria/Unblock User\": \"Gebruiker deblokkeren\",\n \"aria/Unmute User\": \"Dempen opheffen\",\n \"aria/Unpin Message\": \"Losmaken\",\n \"aria/User selected: {{ user }}\": \"Gebruiker geselecteerd: {{ user }}\",\n \"aria/video\": \"video\",\n \"aria/voice message\": \"spraakbericht\",\n \"aria/Voice message sent\": \"Spraakbericht verzonden\",\n \"aria/Voice recording attached\": \"Spraakopname bijgevoegd\",\n \"Ask a question\": \"Stel een vraag\",\n \"Attach\": \"Bijvoegen\",\n \"Attach files\": \"Bijlage toevoegen\",\n \"Attachment\": \"Bijlage\",\n \"Attachment upload blocked due to {{reason}}\": \"Bijlage upload geblokkeerd vanwege {{reason}}\",\n \"Attachment upload failed due to {{reason}}\": \"Bijlage upload mislukt vanwege {{reason}}\",\n \"Back\": \"Terug\",\n \"ban-command-args\": \"[@gebruikersnaam] [tekst]\",\n \"ban-command-description\": \"Een gebruiker verbannen\",\n \"Block user\": \"Gebruiker blokkeren\",\n \"Block User\": \"Gebruiker blokkeren\",\n \"Browse channel members\": \"Kanaalleden bekijken\",\n \"Browse pinned messages\": \"Vastgemaakte berichten bekijken\",\n \"Cancel\": \"Annuleer\",\n \"Cannot seek in the recording\": \"Kan niet zoeken in de opname\",\n \"Changes saved\": \"Wijzigingen opgeslagen\",\n \"Channel archived\": \"Kanaal gearchiveerd\",\n \"Channel members\": \"Kanaalleden\",\n \"Channel Missing\": \"Kanaal niet gevonden\",\n \"Channel muted\": \"Kanaal gedempt\",\n \"Channel pinned\": \"Kanaal vastgezet\",\n \"Channel unarchived\": \"Kanaal uit archief gehaald\",\n \"Channel unmuted\": \"Dempen van kanaal opgeheven\",\n \"Channel unpinned\": \"Kanaal losgemaakt\",\n \"Channels\": \"Kanalen\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"Chats\",\n \"Choose between 2 to 10 options\": \"Kies tussen 2 en 10 opties\",\n \"Close\": \"Sluit\",\n \"Close dialog\": \"Dialoog sluiten\",\n \"Close emoji picker\": \"Sluit de emoji-kiezer\",\n \"Command not available while editing\": \"Opdracht niet beschikbaar tijdens bewerken\",\n \"Command not available while replying\": \"Opdracht niet beschikbaar tijdens beantwoorden\",\n \"Commands\": \"Commando's\",\n \"Commands matching\": \"Bijpassende opdrachten\",\n \"Connection failure, reconnecting now...\": \"Verbindingsfout, opnieuw verbinden...\",\n \"Contact info\": \"Contactgegevens\",\n \"Contact name\": \"Contactnaam\",\n \"Copy Message\": \"Bericht kopiëren\",\n \"Create\": \"Maak\",\n \"Create a question, add options, and configure poll settings\": \"Maak een vraag, voeg opties toe en stel de pollinstellingen in\",\n \"Create poll\": \"Maak peiling\",\n \"Current location\": \"Huidige locatie\",\n \"Delete\": \"Verwijder\",\n \"Delete chat\": \"Chat verwijderen\",\n \"Delete for me\": \"Voor mij verwijderen\",\n \"Delete message\": \"Bericht verwijderen\",\n \"Delivered\": \"Afgeleverd\",\n \"Direct message\": \"Direct bericht\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Wil je deze peiling nu beëindigen? Niemand kan daarna meer op deze peiling stemmen.\",\n \"Download {{ fileName }}\": \"{{ fileName }} downloaden\",\n \"Download All\": \"Alles downloaden\",\n \"Download Attachment\": \"Bijlage downloaden\",\n \"Download attachment {{ name }}\": \"Bijlage {{ name }} downloaden\",\n \"Download attachment {{ number }}\": \"Bijlage {{ number }} downloaden\",\n \"Drag your files here\": \"Sleep je bestanden hier naartoe\",\n \"Drag your files here to add to your post\": \"Sleep je bestanden hier naartoe om aan je bericht toe te voegen\",\n \"Due {{ timeLeft }}\": \"Vervallen in {{ timeLeft }}\",\n \"Due since {{ dueSince }}\": \"Vervallen sinds {{ dueSince }}\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"Bewerken\",\n \"Edit chat data\": \"Chatgegevens bewerken\",\n \"Edit contact\": \"Contact bewerken\",\n \"Edit group\": \"Groep bewerken\",\n \"Edit Message\": \"Bericht bewerken\",\n \"Edit message request failed\": \"Verzoek om bericht bewerken mislukt\",\n \"Edited\": \"Bewerkt\",\n \"Emoji matching\": \"Emoji-overeenkomsten\",\n \"Empty message...\": \"Leeg bericht...\",\n \"End\": \"Einde\",\n \"End poll\": \"Peiling beëindigen\",\n \"End this poll?\": \"Peiling beëindigen?\",\n \"End vote\": \"Einde stem\",\n \"Enforce unique vote is enabled\": \"Unieke stem is ingeschakeld\",\n \"Error\": \"Fout\",\n \"Error adding flag\": \"Fout bij toevoegen van vlag\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"Fout bij blokkeren van gebruiker\",\n \"Error connecting to chat, refresh the page to try again.\": \"Fout bij het verbinden, ververs de pagina om nogmaals te proberen\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"Fout bij verwijderen van bericht\",\n \"Error fetching reactions\": \"Fout bij het laden van reacties\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Fout bij markeren van bericht als ongelezen. Kan geen oudere ongelezen berichten markeren dan de nieuwste 100 kanaalberichten.\",\n \"Error muting a user ...\": \"Fout bij het muten van de gebruiker\",\n \"Error muting channel\": \"Fout bij dempen van kanaal\",\n \"Error muting user\": \"Fout bij dempen van gebruiker\",\n \"Error opening direct message\": \"Fout bij het openen van het directe bericht\",\n \"Error pinning message\": \"Fout bij vastzetten van bericht\",\n \"Error removing members\": \"Fout bij het verwijderen van de leden\",\n \"Error removing message pin\": \"Fout bij verwijderen van berichtpin\",\n \"Error removing user\": \"Fout bij het verwijderen van de gebruiker\",\n \"Error reproducing the recording\": \"Fout bij het afspelen van de opname\",\n \"Error starting recording\": \"Fout bij het starten van de opname\",\n \"Error unblocking user\": \"Fout bij deblokkeren van gebruiker\",\n \"Error unmuting a user ...\": \"Fout bij het unmuten van de gebruiker\",\n \"Error unmuting channel\": \"Fout bij opheffen van kanaaldemping\",\n \"Error unmuting user\": \"Fout bij opheffen van gebruikersdemping\",\n \"Error uploading attachment\": \"Fout bij het uploaden van de bijlage\",\n \"Error uploading file\": \"Fout bij uploaden bestand\",\n \"Error uploading image\": \"Fout bij uploaden afbeelding\",\n \"Error: {{ errorMessage }}\": \"Fout: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"Opdracht verlaten {{ command }}\",\n \"Failed to block user\": \"Gebruiker blokkeren mislukt\",\n \"Failed to create the poll\": \"Fout bij het maken van de peiling\",\n \"Failed to create the poll due to {{reason}}\": \"Peiling kon niet worden aangemaakt vanwege {{reason}}\",\n \"Failed to delete the message\": \"Bericht verwijderen mislukt\",\n \"Failed to end the poll\": \"Peiling kon niet worden beëindigd\",\n \"Failed to end the poll due to {{reason}}\": \"Peiling kon niet worden beëindigd vanwege {{reason}}\",\n \"Failed to jump to the first unread message\": \"Niet gelukt om naar het eerste ongelezen bericht te springen\",\n \"Failed to leave channel\": \"Kanaal verlaten mislukt\",\n \"Failed to load channels\": \"Kanalen konden niet worden geladen\",\n \"Failed to load more channels\": \"Meer kanalen konden niet worden geladen\",\n \"Failed to mark channel as read\": \"Kanaal kon niet als gelezen worden gemarkeerd\",\n \"Failed to play the recording\": \"Kan de opname niet afspelen\",\n \"Failed to retrieve location\": \"Locatie kon niet worden opgehaald\",\n \"Failed to save changes\": \"Wijzigingen opslaan mislukt\",\n \"Failed to share location\": \"Locatie kon niet worden gedeeld\",\n \"Failed to update channel archive status\": \"Archiefstatus van kanaal kon niet worden bijgewerkt\",\n \"Failed to update channel mute status\": \"Muteerstatus van kanaal kon niet worden bijgewerkt\",\n \"Failed to update channel pinned status\": \"Vastgezette status van kanaal kon niet worden bijgewerkt\",\n \"File\": \"Bestand\",\n \"File is required for upload attachment\": \"Bestand is vereist voor het uploaden van een bijlage\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Bestand is te groot: {{ size }}, maximale uploadgrootte is {{ limit }}\",\n \"File too large\": \"Bestand is te groot\",\n \"fileCount_one\": \"1 bestand\",\n \"fileCount_other\": \"{{ count }} bestanden\",\n \"Files\": \"Bestanden\",\n \"Flag\": \"Markeer\",\n \"Generating...\": \"Genereren...\",\n \"giphy-command-args\": \"[tekst]\",\n \"giphy-command-description\": \"Plaats een willekeurige gif in het kanaal\",\n \"Go back\": \"Terug\",\n \"Group info\": \"Groepsinformatie\",\n \"Group name\": \"Groepsnaam\",\n \"Hide who voted\": \"Verberg wie heeft gestemd\",\n \"Image\": \"Afbeelding\",\n \"imageCount_one\": \"Afbeelding\",\n \"imageCount_other\": \"{{ count }} afbeeldingen\",\n \"Instant commands\": \"Snelle opdrachten\",\n \"language/af\": \"Afrikaans\",\n \"language/am\": \"Amhaars\",\n \"language/ar\": \"Arabisch\",\n \"language/az\": \"Azerbeidzjaans\",\n \"language/bg\": \"Bulgaars\",\n \"language/bn\": \"Bengaals\",\n \"language/bs\": \"Bosnisch\",\n \"language/cs\": \"Tsjechisch\",\n \"language/da\": \"Deens\",\n \"language/de\": \"Duits\",\n \"language/el\": \"Grieks\",\n \"language/en\": \"Engels\",\n \"language/es\": \"Spaans\",\n \"language/es-MX\": \"Spaans (Mexico)\",\n \"language/et\": \"Estlands\",\n \"language/fa\": \"Perzisch\",\n \"language/fa-AF\": \"Dari\",\n \"language/fi\": \"Fins\",\n \"language/fr\": \"Frans\",\n \"language/fr-CA\": \"Frans (Canada)\",\n \"language/ha\": \"Hausa\",\n \"language/he\": \"Hebreeuws\",\n \"language/hi\": \"Hindi\",\n \"language/hr\": \"Kroatisch\",\n \"language/ht\": \"Haïtiaans Creools\",\n \"language/hu\": \"Hongaars\",\n \"language/id\": \"Indonesisch\",\n \"language/it\": \"Italiaans\",\n \"language/ja\": \"Japans\",\n \"language/ka\": \"Georgisch\",\n \"language/ko\": \"Koreaans\",\n \"language/lt\": \"Litouws\",\n \"language/lv\": \"Letlands\",\n \"language/ms\": \"Maleis\",\n \"language/nl\": \"Nederlands\",\n \"language/no\": \"Noors\",\n \"language/pl\": \"Pools\",\n \"language/ps\": \"Pasjtoe\",\n \"language/pt\": \"Portugees\",\n \"language/ro\": \"Roemeens\",\n \"language/ru\": \"Russisch\",\n \"language/sk\": \"Slowaaks\",\n \"language/sl\": \"Sloveens\",\n \"language/so\": \"Somali\",\n \"language/sq\": \"Albanees\",\n \"language/sr\": \"Servisch\",\n \"language/sv\": \"Zweeds\",\n \"language/sw\": \"Swahili\",\n \"language/ta\": \"Tamil\",\n \"language/th\": \"Thai\",\n \"language/tl\": \"Tagalog\",\n \"language/tr\": \"Turks\",\n \"language/uk\": \"Oekraïens\",\n \"language/ur\": \"Urdu\",\n \"language/vi\": \"Vietnamees\",\n \"language/zh\": \"Chinees (vereenvoudigd)\",\n \"language/zh-TW\": \"Chinees (traditioneel)\",\n \"Last seen {{ timestamp }}\": \"Laatst gezien {{ timestamp }}\",\n \"Leave Channel\": \"Kanaal verlaten\",\n \"Leave chat\": \"Kanaal verlaten\",\n \"Left channel\": \"Kanaal verlaten\",\n \"Let others add options\": \"Laat anderen opties toevoegen\",\n \"Limit votes per person\": \"Stemmen per persoon beperken\",\n \"Link\": \"Link\",\n \"linkCount_one\": \"Link\",\n \"linkCount_other\": \"{{ count }} links\",\n \"live\": \"live\",\n \"Live for {{duration}}\": \"Live voor {{duration}}\",\n \"Live location\": \"Live locatie\",\n \"Live until {{ timestamp }}\": \"Live tot {{ timestamp }}\",\n \"Load more\": \"Meer laden\",\n \"Local upload attachment missing local id\": \"Lokale uploadbijlage mist lokale id\",\n \"Location\": \"Locatie\",\n \"Location sharing ended\": \"Locatie delen beëindigd\",\n \"Location: {{ coordinates }}\": \"Locatie: {{ coordinates }}\",\n \"Manage channel\": \"Kanaal beheren\",\n \"Manage members\": \"Leden beheren\",\n \"Mark as unread\": \"Markeren als ongelezen\",\n \"Maximum number of votes (from 2 to 10)\": \"Maximaal aantal stemmen (van 2 tot 10)\",\n \"Maximum votes per person\": \"Maximum aantal stemmen per persoon\",\n \"Member detail\": \"Lidgegevens\",\n \"mention/Channel\": \"Kanaal\",\n \"mention/Channel Description\": \"Iedereen in dit kanaal informeren\",\n \"mention/Here\": \"Hier\",\n \"mention/Here Description\": \"Alle online leden in dit kanaal informeren\",\n \"Menu\": \"Menu\",\n \"Message deleted\": \"Bericht verwijderd\",\n \"Message failed to send\": \"Bericht kon niet worden verzonden\",\n \"Message has been successfully flagged\": \"Bericht is succesvol gemarkeerd\",\n \"Message marked as unread\": \"Bericht gemarkeerd als ongelezen\",\n \"Message pinned\": \"Bericht vastgezet\",\n \"Message unpinned\": \"Bericht losgemaakt\",\n \"Message was blocked by moderation policies\": \"Bericht is geblokkeerd door moderatiebeleid\",\n \"Messages have been marked unread.\": \"Berichten zijn gemarkeerd als ongelezen.\",\n \"Missing permissions to upload the attachment\": \"Missende toestemmingen om de bijlage te uploaden\",\n \"Moderator\": \"Moderator\",\n \"Multiple votes\": \"Meerdere stemmen\",\n \"Mute\": \"Dempen\",\n \"Mute chat\": \"Chat dempen\",\n \"Mute user\": \"Gebruiker dempen\",\n \"mute-command-args\": \"[@gebruikersnaam]\",\n \"mute-command-description\": \"Een gebruiker dempen\",\n \"network error\": \"netwerkfout\",\n \"New\": \"Nieuwe\",\n \"New message from {{user}}\": \"Nieuw bericht van {{user}}\",\n \"New Messages!\": \"Nieuwe Berichten!\",\n \"Next\": \"Volgende\",\n \"Next image\": \"Volgende afbeelding\",\n \"No chats here yet…\": \"Nog geen chats hier...\",\n \"No conversations yet\": \"Nog geen gesprekken\",\n \"No files\": \"Geen bestanden\",\n \"No items exist\": \"Er zijn geen items\",\n \"No member found\": \"Geen lid gevonden\",\n \"No messages found\": \"Geen berichten gevonden\",\n \"No photos or videos\": \"Geen foto's of video's\",\n \"No pinned messages\": \"Geen vastgemaakte berichten\",\n \"No results found\": \"Geen resultaten gevonden\",\n \"No user found\": \"Geen gebruiker gevonden\",\n \"Nobody will be able to vote in this poll anymore.\": \"Niemand kan meer stemmen in deze peiling.\",\n \"Nothing yet...\": \"Nog niets ...\",\n \"Notify all {{ role }} members\": \"Alle leden met rol {{ role }} informeren\",\n \"Offline\": \"Offline\",\n \"Ok\": \"Oké\",\n \"Online\": \"Online\",\n \"Only numbers are allowed\": \"Alleen nummers zijn toegestaan\",\n \"Only visible to you\": \"Alleen zichtbaar voor jou\",\n \"Open emoji picker\": \"Emoji-kiezer openen\",\n \"Open gallery at image {{ index }}\": \"Galerij openen bij afbeelding {{ index }}\",\n \"Open image in gallery\": \"Afbeelding openen in galerij\",\n \"Open location in a map\": \"Locatie op een kaart openen\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"Menu openen\",\n \"Option already exists\": \"Optie bestaat al\",\n \"Option is empty\": \"Optie is leeg\",\n \"Options\": \"Opties\",\n \"Original\": \"Origineel\",\n \"Owner\": \"Eigenaar\",\n \"People matching\": \"Mensen die matchen\",\n \"Photo\": \"Foto\",\n \"Photos & videos\": \"Foto's en video's\",\n \"Pin\": \"Vastmaken\",\n \"Pin a message to see it here\": \"Maak een bericht vast om het hier te zien\",\n \"Pinned by {{ name }}\": \"Vastgemaakt door {{ name }}\",\n \"Pinned by You\": \"Door jou vastgezet\",\n \"Pinned message\": \"Vastgemaakt bericht\",\n \"Pinned messages\": \"Vastgemaakte berichten\",\n \"placeholder/PollComment\": \"Jouw reactie\",\n \"placeholder/PollOptionSuggestion\": \"Voer een nieuwe optie in\",\n \"Play video\": \"Video afspelen\",\n \"Playback speed {{ rate }}x\": \"Afspeelsnelheid {{ rate }}x\",\n \"Poll\": \"Peiling\",\n \"Poll comments\": \"Peiling opmerkingen\",\n \"Poll ended\": \"Peiling beëindigd\",\n \"Poll options\": \"Peiling opties\",\n \"Poll results\": \"Peiling resultaten\",\n \"Poll sent\": \"Peiling verzonden\",\n \"Previous\": \"Vorige\",\n \"Previous image\": \"Vorige afbeelding\",\n \"Question\": \"Vraag\",\n \"Question {{ optionOrderNumber}}\": \"Vraag {{ optionOrderNumber}}\",\n \"Question is required\": \"Vraag is verplicht\",\n \"Quote Reply\": \"Citaatantwoord\",\n \"Reached the vote limit. Remove an existing vote first.\": \"Stemlimiet bereikt. Verwijder eerst een bestaande stem.\",\n \"Recording format is not supported and cannot be reproduced\": \"Opnameformaat wordt niet ondersteund en kan niet worden gereproduceerd\",\n \"Remind me\": \"Herinner me\",\n \"Remind Me\": \"Herinner mij\",\n \"Reminder set\": \"Herinnering ingesteld\",\n \"Remove\": \"Verwijderen\",\n \"Remove {{ count }} members_one\": \"{{ count }} lid verwijderen\",\n \"Remove {{ count }} members_other\": \"{{ count }} leden verwijderen\",\n \"Remove {{ member }} from this channel?\": \"{{ member }} uit dit kanaal verwijderen?\",\n \"Remove channel members\": \"Kanaalleden verwijderen\",\n \"Remove reminder\": \"Herinnering verwijderen\",\n \"Remove save for later\": \"Verwijder 'Bewaren voor later'\",\n \"Remove user\": \"Gebruiker verwijderen\",\n \"Removed {{ count }} members_one\": \"{{ count }} lid verwijderd\",\n \"Removed {{ count }} members_other\": \"{{ count }} leden verwijderd\",\n \"Replied to a thread\": \"Heeft gereageerd in een thread\",\n \"Reply\": \"Antwoord\",\n \"Reply to {{ authorName }}\": \"Antwoord aan {{ authorName }}\",\n \"Reply to a message to start a thread\": \"Beantwoord een bericht om een thread te starten\",\n \"Reply to Message\": \"Antwoord op bericht\",\n \"replyCount_one\": \"1 antwoord\",\n \"replyCount_other\": \"{{ count }} antwoorden\",\n \"Resend\": \"Opnieuw verzenden\",\n \"Retry upload\": \"Upload opnieuw proberen\",\n \"Review all options available in this poll\": \"Bekijk alle beschikbare opties in deze poll\",\n \"Review comments submitted with poll answers\": \"Bekijk reacties die met pollantwoorden zijn ingediend\",\n \"Review poll results and open an option to see detailed votes\": \"Bekijk pollresultaten en open een optie om gedetailleerde stemmen te zien\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Bekijk dit bericht en kies of je het verwijdert, bewerkt of toch verstuurt\",\n \"Review who voted for this option\": \"Bekijk wie op deze optie heeft gestemd\",\n \"Save\": \"Opslaan\",\n \"Save for later\": \"Bewaren voor later\",\n \"Saved for later\": \"Bewaard voor later\",\n \"Search\": \"Zoeken\",\n \"Search GIFs\": \"GIF's zoeken\",\n \"search-results-header-filter-source-button-label--channels\": \"kanalen\",\n \"search-results-header-filter-source-button-label--messages\": \"berichten\",\n \"search-results-header-filter-source-button-label--users\": \"gebruikers\",\n \"Searching for {{ searchSourceType }}...\": \"Zoeken naar {{ searchSourceType }}...\",\n \"Searching...\": \"Zoeken...\",\n \"searchResultsCount_one\": \"1 resultaat\",\n \"searchResultsCount_other\": \"{{ count }} resultaten\",\n \"Select a thread to continue the conversation\": \"Selecteer een thread om het gesprek voort te zetten\",\n \"Select more than one option\": \"Selecteer meer dan één optie\",\n \"Select one\": \"Selecteer er een\",\n \"Select one or more\": \"Selecteer een of meer\",\n \"Select up to {{count}}_one\": \"Selecteer tot {{count}}\",\n \"Select up to {{count}}_other\": \"Selecteer tot {{count}}\",\n \"Select your current location and optionally enable live location sharing\": \"Selecteer je huidige locatie en schakel eventueel live locatiedeling in\",\n \"Send\": \"Verstuur\",\n \"Send a message\": \"Stuur een bericht\",\n \"Send a message to start the conversation\": \"Stuur een bericht om het gesprek te beginnen\",\n \"Send Anyway\": \"Toch versturen\",\n \"Send direct message\": \"Direct bericht sturen\",\n \"Send message request failed\": \"Verzoek om bericht te verzenden mislukt\",\n \"Send poll\": \"Peiling versturen\",\n \"Sending...\": \"Aan het verzenden...\",\n \"Sent\": \"Verzonden\",\n \"Share\": \"Delen\",\n \"Share a file to see it here\": \"Deel een bestand om het hier te zien\",\n \"Share a photo or video to see it here\": \"Deel een foto of video om deze hier te zien\",\n \"Share live location for\": \"Live locatie delen voor\",\n \"Share Location\": \"Locatie delen\",\n \"Shared live location\": \"Gedeelde live locatie\",\n \"Shared location\": \"Gedeelde locatie\",\n \"Shuffle\": \"Schudden\",\n \"size limit\": \"grootte limiet\",\n \"Slow Mode ON\": \"Langzame modus aan\",\n \"Slow mode, wait {{ seconds }}s...\": \"Langzame modus, wacht {{ seconds }}s...\",\n \"Slow wait, wait {{ seconds }}s\": \"Langzame modus, wacht {{ seconds }}s\",\n \"Slow wait, wait {{ seconds }}s...\": \"Langzame modus, wacht {{ seconds }}s...\",\n \"Some of the files will not be accepted\": \"Sommige bestanden zullen niet worden geaccepteerd\",\n \"Start typing to search\": \"Begin met typen om te zoeken\",\n \"Stop sharing\": \"Delen stoppen\",\n \"Submit\": \"Versturen\",\n \"Suggest a new option to add to this poll\": \"Stel een nieuwe optie voor om aan deze poll toe te voegen\",\n \"Suggest an option\": \"Stel een optie voor\",\n \"Tap to remove\": \"Tik om te verwijderen\",\n \"Tap to remove: {{ reactionName }}\": \"Tik om te verwijderen: {{ reactionName }}\",\n \"Thinking...\": \"Denken...\",\n \"this content could not be displayed\": \"Deze inhoud kan niet weergegeven worden\",\n \"This field cannot be empty or contain only spaces\": \"Dit veld mag niet leeg zijn of alleen spaties bevatten\",\n \"This message did not meet our content guidelines\": \"Dit bericht voldeed niet aan onze inhoudsrichtlijnen\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"Deze gebruiker kan je weer berichten sturen.\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"Draadje\",\n \"Thread has not been found\": \"Draadje niet gevonden\",\n \"Thread reply\": \"Draadje antwoord\",\n \"Thread Reply\": \"Draadje antwoord\",\n \"ThreadListUnseenThreadsBanner/loading\": \"Laden...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} ongelezen thread\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} ongelezen threads\",\n \"Threads\": \"Discussies\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Gisteren]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Vandaag]\\\", \\\"nextDay\\\": \\\"[Morgen]\\\", \\\"lastDay\\\": \\\"[Gisteren]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Laatste] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"{{ count }} d geleden\",\n \"timestamp/relativeToday\": \"Vandaag\",\n \"timestamp/relativeWeeksAgo\": \"{{ count }} w geleden\",\n \"timestamp/relativeYesterday\": \"Gisteren\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Vandaag] [om] HH:mm\\\", \\\"nextDay\\\": \\\"[Morgen] [om] HH:mm\\\", \\\"lastDay\\\": \\\"[Gisteren] [om] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [om] HH:mm\\\", \\\"lastWeek\\\": \\\"[afgelopen] dddd [om] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [om] HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"Om te beginnen met opnemen, sta toegang tot de camera toe in uw browser\",\n \"To start recording, allow the microphone access in your browser\": \"Om te beginnen met opnemen, sta toegang tot de microfoon toe in uw browser\",\n \"totalVoteCount_one\": \"1 stem in totaal\",\n \"totalVoteCount_other\": \"{{ count }} stemmen in totaal\",\n \"Translated\": \"Vertaald\",\n \"Translated from {{ language }}\": \"Vertaald uit {{ language }}\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"Typ een getal van 2 tot 10\",\n \"Unarchive\": \"Uit archief halen\",\n \"unban-command-args\": \"[@gebruikersnaam]\",\n \"unban-command-description\": \"Een gebruiker debannen\",\n \"Unblock\": \"Deblokkeren\",\n \"Unblock user\": \"Gebruiker deblokkeren\",\n \"Unblock User\": \"Gebruiker deblokkeren\",\n \"unknown error\": \"onbekende fout\",\n \"Unmute\": \"Dempen opheffen\",\n \"Unmute chat\": \"Chat dempen opheffen\",\n \"Unmute user\": \"Gebruiker dempen opheffen\",\n \"unmute-command-args\": \"[@gebruikersnaam]\",\n \"unmute-command-description\": \"Een gebruiker niet meer dempen\",\n \"Unpin\": \"Losmaken\",\n \"Unread messages\": \"Ongelezen berichten\",\n \"Unsupported attachment\": \"Niet-ondersteunde bijlage\",\n \"unsupported file type\": \"niet-ondersteund bestandstype\",\n \"Update\": \"Bijwerken\",\n \"Update the comment attached to your poll answer\": \"Werk de reactie bij die aan je pollantwoord is toegevoegd\",\n \"Update your comment\": \"Werk je opmerking bij\",\n \"Upload blocked\": \"Upload geblokkeerd\",\n \"Upload error\": \"Uploadfout\",\n \"Upload failed\": \"Upload mislukt\",\n \"Upload Picture\": \"Afbeelding uploaden\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Uploadtype: \\\"{{ type }}\\\" is niet toegestaan\",\n \"User blocked\": \"Gebruiker geblokkeerd\",\n \"User muted\": \"Gebruiker gedempt\",\n \"User removed\": \"Gebruiker verwijderd\",\n \"User unblocked\": \"Gebruiker gedeblokkeerd\",\n \"User unmuted\": \"Gebruiker niet meer gedempt\",\n \"User uploaded content\": \"Gebruikersgeüploade inhoud\",\n \"Video\": \"Video\",\n \"videoCount_one\": \"Video\",\n \"videoCount_other\": \"{{ count }} video's\",\n \"View\": \"Bekijken\",\n \"View {{count}} comments_one\": \"Bekijk {{count}} opmerkingen\",\n \"View {{count}} comments_other\": \"Bekijk {{count}} opmerkingen\",\n \"View all\": \"Alles bekijken\",\n \"View member details for {{ member }}\": \"Lidgegevens voor {{ member }} bekijken\",\n \"View original\": \"Origineel bekijken\",\n \"View results\": \"Bekijk resultaten\",\n \"View translation\": \"Vertaling bekijken\",\n \"Voice message\": \"Spraakbericht\",\n \"Voice message {{ duration }}\": \"Spraakbericht {{ duration }}\",\n \"Voice message deleted\": \"Spraakbericht verwijderd\",\n \"voiceMessageCount_one\": \"Spraakbericht\",\n \"voiceMessageCount_other\": \"{{ count }} spraakberichten\",\n \"Vote ended\": \"Stemmen beëindigd\",\n \"Votes\": \"Stemmen\",\n \"Wait until all attachments have uploaded\": \"Wacht tot alle bijlagen zijn geüpload\",\n \"Waiting for network…\": \"Wachten op netwerk…\",\n \"You\": \"Jij\",\n \"You've reached the maximum number of files\": \"Je hebt het maximale aantal bestanden bereikt\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} e mais {{ moreCount }}\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} e {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} arquivo\",\n \"{{ count }} files_many\": \"{{ count }} arquivos\",\n \"{{ count }} files_other\": \"{{ count }} arquivos\",\n \"{{ count }} members_one\": \"{{ count }} membro\",\n \"{{ count }} members_many\": \"{{ count }} membros\",\n \"{{ count }} members_other\": \"{{ count }} membros\",\n \"{{ count }} members added_one\": \"{{ count }} membro adicionado\",\n \"{{ count }} members added_many\": \"{{ count }} membros adicionados\",\n \"{{ count }} members added_other\": \"{{ count }} membros adicionados\",\n \"{{ count }} people are typing_one\": \"{{ count }} pessoa está digitando\",\n \"{{ count }} people are typing_many\": \"{{ count }} pessoas estão digitando\",\n \"{{ count }} people are typing_other\": \"{{ count }} pessoas estão digitando\",\n \"{{ count }} photos_one\": \"{{ count }} foto\",\n \"{{ count }} photos_many\": \"{{ count }} fotos\",\n \"{{ count }} photos_other\": \"{{ count }} fotos\",\n \"{{ count }} reactions_one\": \"{{ count }} reação\",\n \"{{ count }} reactions_many\": \"{{ count }} reações\",\n \"{{ count }} reactions_other\": \"{{ count }} reações\",\n \"{{ count }} videos_one\": \"{{ count }} vídeo\",\n \"{{ count }} videos_many\": \"{{ count }} vídeos\",\n \"{{ count }} videos_other\": \"{{ count }} vídeos\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} e {{ secondUser }}\",\n \"{{ imageCount }} more\": \"{{ imageCount }} mais\",\n \"{{ member }} will be able to message you again.\": \"{{ member }} poderá enviar mensagens para você novamente.\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }} não poderá mais enviar mensagens para você.\",\n \"{{ memberCount }} members\": \"{{ memberCount }} membros\",\n \"{{ typing }} are typing\": \"{{ typing }} estão digitando\",\n \"{{ typing }} is typing\": \"{{ typing }} está digitando\",\n \"{{ user }} has been muted\": \"{{ user }} foi silenciado\",\n \"{{ user }} has been unmuted\": \"{{ user }} foi reativado\",\n \"{{ user }} is typing...\": \"{{ user }} está digitando...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} e {{ user }} estão digitando...\",\n \"{{ users }} and more are typing...\": \"{{ users }} e mais estão digitando...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} online\",\n \"{{count}} new messages_one\": \"{{count}} nova mensagem\",\n \"{{count}} new messages_many\": \"{{count}} novas mensagens\",\n \"{{count}} new messages_other\": \"{{count}} novas mensagens\",\n \"{{count}} unread_one\": \"{{count}} não lido\",\n \"{{count}} unread_many\": \"{{count}} não lidos\",\n \"{{count}} unread_other\": \"{{count}} não lidos\",\n \"{{count}} votes_one\": \"{{count}} voto\",\n \"{{count}} votes_many\": \"{{count}} votos\",\n \"{{count}} votes_other\": \"{{count}} votos\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"+{{count}} opção a mais\",\n \"+{{count}} more options_many\": \"+{{count}} opções a mais\",\n \"+{{count}} more options_other\": \"+{{count}} opções a mais\",\n \"🏙 Attachment...\": \"🏙 Anexo...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} criou: {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} votou: {{pollOptionText}}\",\n \"📍Shared location\": \"📍Localização compartilhada\",\n \"Actions\": \"Actions\",\n \"Add\": \"Adicionar\",\n \"Add {{ count }} members_one\": \"Adicionar {{ count }} membro\",\n \"Add {{ count }} members_many\": \"Adicionar {{ count }} membros\",\n \"Add {{ count }} members_other\": \"Adicionar {{ count }} membros\",\n \"Add a comment\": \"Adicionar um comentário\",\n \"Add a comment to your poll answer\": \"Adicione um comentário à sua resposta da enquete\",\n \"Add an option\": \"Adicionar uma opção\",\n \"Add channel members\": \"Adicionar membros ao canal\",\n \"Add members\": \"Adicionar membros\",\n \"Add reaction\": \"Adicionar reação\",\n \"Admin\": \"Admin\",\n \"All results loaded\": \"Todos os resultados carregados\",\n \"Allow access to camera\": \"Permitir acesso à câmera\",\n \"Allow access to microphone\": \"Permitir acesso ao microfone\",\n \"Allow comments\": \"Permitir comentários\",\n \"Allow option suggestion\": \"Permitir sugestão de opção\",\n \"Allow others to add comments\": \"Permitir que outros adicionem comentários\",\n \"Already a member\": \"Já é membro\",\n \"Also send as a direct message\": \"Também enviar como mensagem direta\",\n \"Also send in channel\": \"Também enviar no canal\",\n \"Also sent in channel\": \"Também enviado no canal\",\n \"An error has occurred during recording\": \"Ocorreu um erro durante a gravação\",\n \"An error has occurred during the recording processing\": \"Ocorreu um erro durante o processamento da gravação\",\n \"Anonymous\": \"Anônimo\",\n \"Anonymous poll\": \"Enquete anônima\",\n \"Archive\": \"Arquivar\",\n \"Are you sure you want to delete this message?\": \"Tem certeza de que deseja excluir esta mensagem?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_one\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_many\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_one\": \"{{ count }} anexo\",\n \"aria/{{ count }} attachment_many\": \"{{ count }} anexos\",\n \"aria/{{ count }} attachment_other\": \"{{ count }} anexos\",\n \"aria/{{ count }} search results_one\": \"{{ count }} resultado de pesquisa\",\n \"aria/{{ count }} search results_many\": \"{{ count }} resultados de pesquisa\",\n \"aria/{{ count }} search results_other\": \"{{ count }} resultados de pesquisa\",\n \"aria/{{ count }} suggestions_one\": \"{{ count }} sugestão\",\n \"aria/{{ count }} suggestions_many\": \"{{ count }} sugestões\",\n \"aria/{{ count }} suggestions_other\": \"{{ count }} sugestões\",\n \"aria/{{ count }} unread message_one\": \"{{ count }} mensagem não lida\",\n \"aria/{{ count }} unread message_many\": \"{{ count }} mensagens não lidas\",\n \"aria/{{ count }} unread message_other\": \"{{ count }} mensagens não lidas\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} desativado\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} ativado\",\n \"aria/Active\": \"Ativo\",\n \"aria/Animated GIF\": \"GIF animado\",\n \"aria/Animated GIF: {{ title }}\": \"GIF animado: {{ title }}\",\n \"aria/Attachment\": \"Anexo\",\n \"aria/Attachment {{ attachmentType }}\": \"Anexo {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"Ações do anexo\",\n \"aria/audio\": \"áudio\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Posição do áudio {{ elapsed }} de {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"Posição do áudio {{ progress }} por cento\",\n \"aria/Back to attachments\": \"Voltar aos anexos\",\n \"aria/Back to parent menu button\": \"Voltar ao menu principal botão\",\n \"aria/Block User\": \"Bloquear usuário\",\n \"aria/Bookmark Message\": \"Marcar mensagem\",\n \"aria/Cancel recording\": \"Cancelar gravação\",\n \"aria/Cancel Reply\": \"Cancelar resposta\",\n \"aria/Channel Actions\": \"Ações do canal\",\n \"aria/Channel details\": \"Detalhes do canal\",\n \"aria/Channel list\": \"Lista de canais\",\n \"aria/Chat view controls\": \"Controles da visualização do chat\",\n \"aria/Chat: {{ channelName }}\": \"Chat: {{ channelName }}\",\n \"aria/Clear search\": \"Limpar pesquisa\",\n \"aria/Close callout dialog\": \"Fechar diálogo de destaque\",\n \"aria/Close thread\": \"Fechar tópico\",\n \"aria/Collapse sidebar\": \"Recolher barra lateral\",\n \"aria/Command activated: {{ command }}\": \"Comando ativado: {{ command }}\",\n \"aria/Command Suggestions\": \"Sugestões de comandos\",\n \"aria/Complete recording\": \"Concluir gravação\",\n \"aria/Copy Message Text\": \"Copiar texto da mensagem\",\n \"aria/Decrease value\": \"Diminuir valor\",\n \"aria/Delete Message\": \"Excluir mensagem\",\n \"aria/Delivered\": \"Entregue\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"Status de entrega: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"Dispensar notificação\",\n \"aria/Download attachment\": \"Baixar anexo\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"\\\"{{ option }}\\\" solto na posição {{ position }}.\",\n \"aria/Edit Message\": \"Editar Mensagem\",\n \"aria/Emoji picker\": \"Seletor de emojis\",\n \"aria/Emoji Suggestions\": \"Sugestões de emojis\",\n \"aria/Exit search\": \"Sair da pesquisa\",\n \"aria/Expand sidebar\": \"Expandir barra lateral\",\n \"aria/file\": \"arquivo\",\n \"aria/File upload\": \"Carregar arquivo\",\n \"aria/Flag Message\": \"Reportar mensagem\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Ações do Giphy\",\n \"aria/Giphy canceled\": \"Giphy cancelado\",\n \"aria/Giphy image changed\": \"Imagem do Giphy alterada\",\n \"aria/Giphy image changed: {{ title }}\": \"Imagem do Giphy alterada: {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Pré-visualização do Giphy, visível apenas para você. Use as ações Enviar, Embaralhar ou Cancelar.\",\n \"aria/Giphy sent\": \"Giphy enviado\",\n \"aria/image\": \"imagem\",\n \"aria/Image failed to load\": \"Falha ao carregar a imagem\",\n \"aria/Increase value\": \"Aumentar valor\",\n \"aria/Jump to latest message\": \"Ir para a mensagem mais recente\",\n \"aria/Jump to quoted message\": \"Ir para a mensagem citada\",\n \"aria/Last activity: {{ time }}\": \"Última atividade: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"Última mensagem de {{ sender }}: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"Última mensagem: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"Marcar como não lida\",\n \"aria/Mark messages as read\": \"Marcar mensagens como lidas\",\n \"aria/Mention Suggestions\": \"Sugestões de menções\",\n \"aria/Message Actions\": \"Ações da mensagem\",\n \"aria/Message from {{ user }},\": \"Mensagem de {{ user }},\",\n \"aria/Message input\": \"Entrada de mensagem\",\n \"aria/Message with attachments\": \"Mensagem com anexos\",\n \"aria/Message,\": \"Mensagem,\",\n \"aria/Mute User\": \"Silenciar usuário\",\n \"aria/Next page\": \"Próxima página\",\n \"aria/No search results found\": \"Nenhum resultado de pesquisa encontrado\",\n \"aria/Notifications\": \"Notificações\",\n \"aria/Open Attachment Selector\": \"Abrir seletor de anexos\",\n \"aria/Open Channel Actions Menu\": \"Abrir menu de ações do canal\",\n \"aria/Open channel details\": \"Abrir detalhes do canal\",\n \"aria/Open channels view\": \"Abrir visualização de canais\",\n \"aria/Open image shared by {{ name }}\": \"Abrir imagem compartilhada por {{ name }}\",\n \"aria/Open Message Actions Menu\": \"Abrir menu de ações de mensagem\",\n \"aria/Open Reaction Selector\": \"Abrir seletor de reações\",\n \"aria/Open Thread\": \"Abrir tópico\",\n \"aria/Open threads view\": \"Abrir visualização de tópicos\",\n \"aria/Open threads view with unread threads_one\": \"Abrir visualização de tópicos, {{ count }} tópico não lido\",\n \"aria/Open threads view with unread threads_many\": \"Abrir visualização de tópicos, {{ count }} tópicos não lidos\",\n \"aria/Open threads view with unread threads_other\": \"Abrir visualização de tópicos, {{ count }} tópicos não lidos\",\n \"aria/Open video shared by {{ name }}\": \"Abrir vídeo compartilhado por {{ name }}\",\n \"aria/Opened channel: {{ name }}\": \"Canal aberto: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"Tópico aberto em {{ name }}\",\n \"aria/Option {{ position }}\": \"Opção {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"As opções agora podem ser reordenadas e removidas.\",\n \"aria/Pause\": \"Pausar\",\n \"aria/Pause recording\": \"Pausar gravação\",\n \"aria/Percent complete\": \"{{percent}} por cento concluído\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"Você pegou \\\"{{ option }}\\\". Use as setas para reordenar. Pressione Espaço ou Tab para soltar.\",\n \"aria/Pin Message\": \"Fixar mensagem\",\n \"aria/Play\": \"Reproduzir\",\n \"aria/Poll dialog opened\": \"Caixa de diálogo da enquete aberta\",\n \"aria/Poll sent\": \"Enquete enviada\",\n \"aria/Poll: {{ pollName }}\": \"Enquete: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Pressione Enter para começar a digitar\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"Pressione Espaço para selecionar esta opção, use as teclas de seta para Cima e para Baixo para movê-la e, em seguida, pressione Espaço novamente para desmarcá-la.\",\n \"aria/Previous page\": \"Página anterior\",\n \"aria/Quote Message\": \"Citar mensagem\",\n \"aria/Reaction list\": \"Lista de reações\",\n \"aria/Read\": \"Lida\",\n \"aria/Recording paused\": \"Gravação pausada\",\n \"aria/Recording resumed\": \"Gravação retomada\",\n \"aria/Recording started\": \"Gravação iniciada\",\n \"aria/Remind Me Message\": \"Lembrar-me\",\n \"aria/Remove attachment\": \"Remover anexo\",\n \"aria/Remove location attachment\": \"Remover anexo de localização\",\n \"aria/Remove option: {{ option }}\": \"Remover opção: {{ option }}\",\n \"aria/Remove Reminder\": \"Remover lembrete\",\n \"aria/Remove Save For Later\": \"Remover Salvar para depois\",\n \"aria/Removed option {{ option }}\": \"Opção {{ option }} removida\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"Reordenar \\\"{{ option }}\\\", posição {{ position }} de {{ total }}\",\n \"aria/Reorder option {{ position }}\": \"Reordenar opção {{ position }}\",\n \"aria/Resend Message\": \"Reenviar mensagem\",\n \"aria/Resume recording\": \"Retomar gravação\",\n \"aria/Retry upload\": \"Tentar upload novamente\",\n \"aria/Review bounced message\": \"Revisar mensagem devolvida\",\n \"aria/Search cleared\": \"Pesquisa limpa\",\n \"aria/Search results\": \"Resultados da pesquisa\",\n \"aria/Search results header filter button for: {{ source }}\": \"Botão de filtro do cabeçalho dos resultados da pesquisa para: {{ source }}\",\n \"aria/Seek audio position\": \"Buscar posição do áudio\",\n \"aria/Select Reaction: {{ reactionName }}\": \"Selecionar reação: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"Selecionar canal do usuário: {{ name }}\",\n \"aria/Send\": \"Enviar\",\n \"aria/Sent\": \"Enviada\",\n \"aria/Shared a link\": \"Link compartilhado\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"Link compartilhado com título: {{ linkTitle }}\",\n \"aria/Shared location\": \"Localização compartilhada\",\n \"aria/Show preview\": \"Mostrar prévia\",\n \"aria/Start recording audio\": \"Iniciar gravação de áudio\",\n \"aria/Stop AI Generation\": \"Parar geração de IA\",\n \"aria/Submenu\": \"Submenu\",\n \"aria/Suggestions\": \"Sugestões\",\n \"aria/There are no messages in this chat.\": \"Não há mensagens neste chat\",\n \"aria/This option can be reordered and removed.\": \"Esta opção pode ser reordenada e removida.\",\n \"aria/Thread list\": \"Lista de tópicos\",\n \"aria/Thread: {{ messagePreview }}\": \"Tópico: {{ messagePreview }}\",\n \"aria/Unblock User\": \"Desbloquear usuário\",\n \"aria/Unmute User\": \"Ativar som\",\n \"aria/Unpin Message\": \"Desfixar mensagem\",\n \"aria/User selected: {{ user }}\": \"Usuário selecionado: {{ user }}\",\n \"aria/video\": \"vídeo\",\n \"aria/voice message\": \"mensagem de voz\",\n \"aria/Voice message sent\": \"Mensagem de voz enviada\",\n \"aria/Voice recording attached\": \"Gravação de voz anexada\",\n \"Ask a question\": \"Faça uma pergunta\",\n \"Attach\": \"Anexar\",\n \"Attach files\": \"Anexar arquivos\",\n \"Attachment\": \"Anexo\",\n \"Attachment upload blocked due to {{reason}}\": \"Upload de anexo bloqueado devido a {{reason}}\",\n \"Attachment upload failed due to {{reason}}\": \"Upload de anexo falhou devido a {{reason}}\",\n \"Back\": \"Voltar\",\n \"ban-command-args\": \"[@nomedeusuário] [texto]\",\n \"ban-command-description\": \"Banir um usuário\",\n \"Block user\": \"Bloquear usuário\",\n \"Block User\": \"Bloquear usuário\",\n \"Browse channel members\": \"Ver membros do canal\",\n \"Browse pinned messages\": \"Ver mensagens fixadas\",\n \"Cancel\": \"Cancelar\",\n \"Cannot seek in the recording\": \"Não é possível buscar na gravação\",\n \"Changes saved\": \"Alterações salvas\",\n \"Channel archived\": \"Canal arquivado\",\n \"Channel members\": \"Membros do canal\",\n \"Channel Missing\": \"Canal ausente\",\n \"Channel muted\": \"Canal silenciado\",\n \"Channel pinned\": \"Canal fixado\",\n \"Channel unarchived\": \"Canal desarquivado\",\n \"Channel unmuted\": \"Silêncio do canal desativado\",\n \"Channel unpinned\": \"Canal desafixado\",\n \"Channels\": \"Canais\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"Conversas\",\n \"Choose between 2 to 10 options\": \"Escolha entre 2 a 10 opções\",\n \"Close\": \"Fechar\",\n \"Close dialog\": \"Fechar diálogo\",\n \"Close emoji picker\": \"Fechar seletor de emoji\",\n \"Command not available while editing\": \"Comando não disponível durante a edição\",\n \"Command not available while replying\": \"Comando não disponível durante a resposta\",\n \"Commands\": \"Comandos\",\n \"Commands matching\": \"Comandos correspondentes\",\n \"Connection failure, reconnecting now...\": \"Falha de conexão, reconectando agora...\",\n \"Contact info\": \"Informações do contato\",\n \"Contact name\": \"Nome do contato\",\n \"Copy Message\": \"Copiar mensagem\",\n \"Create\": \"Criar\",\n \"Create a question, add options, and configure poll settings\": \"Crie uma pergunta, adicione opções e configure as definições da enquete\",\n \"Create poll\": \"Criar enquete\",\n \"Current location\": \"Localização atual\",\n \"Delete\": \"Excluir\",\n \"Delete chat\": \"Excluir chat\",\n \"Delete for me\": \"Excluir para mim\",\n \"Delete message\": \"Excluir mensagem\",\n \"Delivered\": \"Entregue\",\n \"Direct message\": \"Mensagem direta\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Deseja encerrar esta enquete agora? Ninguém poderá mais votar nesta enquete.\",\n \"Download {{ fileName }}\": \"Baixar {{ fileName }}\",\n \"Download All\": \"Baixar tudo\",\n \"Download Attachment\": \"Baixar anexo\",\n \"Download attachment {{ name }}\": \"Baixar anexo {{ name }}\",\n \"Download attachment {{ number }}\": \"Baixar anexo {{ number }}\",\n \"Drag your files here\": \"Arraste seus arquivos aqui\",\n \"Drag your files here to add to your post\": \"Arraste seus arquivos aqui para adicionar ao seu post\",\n \"Due {{ timeLeft }}\": \"Vence em {{ timeLeft }}\",\n \"Due since {{ dueSince }}\": \"Vencido desde {{ dueSince }}\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"Editar\",\n \"Edit chat data\": \"Editar dados do chat\",\n \"Edit contact\": \"Editar contato\",\n \"Edit group\": \"Editar grupo\",\n \"Edit Message\": \"Editar Mensagem\",\n \"Edit message request failed\": \"O pedido de edição da mensagem falhou\",\n \"Edited\": \"Editada\",\n \"Emoji matching\": \"Emoji correspondente\",\n \"Empty message...\": \"Mensagem vazia...\",\n \"End\": \"Fim\",\n \"End poll\": \"Encerrar enquete\",\n \"End this poll?\": \"Encerrar esta enquete?\",\n \"End vote\": \"Encerrar votação\",\n \"Enforce unique vote is enabled\": \"Voto único está habilitado\",\n \"Error\": \"Erro\",\n \"Error adding flag\": \"Erro ao reportar\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"Erro ao bloquear usuário\",\n \"Error connecting to chat, refresh the page to try again.\": \"Erro ao conectar ao bate-papo, atualize a página para tentar novamente.\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"Erro ao deletar mensagem\",\n \"Error fetching reactions\": \"Erro ao carregar reações\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Erro ao marcar a mensagem como não lida. Não é possível marcar mensagens não lidas mais antigas do que as 100 mensagens mais recentes do canal.\",\n \"Error muting a user ...\": \"Erro ao silenciar um usuário...\",\n \"Error muting channel\": \"Erro ao silenciar canal\",\n \"Error muting user\": \"Erro ao silenciar usuário\",\n \"Error opening direct message\": \"Erro ao abrir mensagem direta\",\n \"Error pinning message\": \"Erro ao fixar mensagem\",\n \"Error removing members\": \"Erro ao remover membros\",\n \"Error removing message pin\": \"Erro ao remover o PIN da mensagem\",\n \"Error removing user\": \"Erro ao remover usuário\",\n \"Error reproducing the recording\": \"Erro ao reproduzir a gravação\",\n \"Error starting recording\": \"Erro ao iniciar a gravação\",\n \"Error unblocking user\": \"Erro ao desbloquear usuário\",\n \"Error unmuting a user ...\": \"Erro ao ativar o som de um usuário...\",\n \"Error unmuting channel\": \"Erro ao remover silenciamento do canal\",\n \"Error unmuting user\": \"Erro ao remover silenciamento do usuário\",\n \"Error uploading attachment\": \"Erro ao carregar o anexo\",\n \"Error uploading file\": \"Erro ao enviar arquivo\",\n \"Error uploading image\": \"Erro ao carregar a imagem\",\n \"Error: {{ errorMessage }}\": \"Erro: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"Sair do comando {{ command }}\",\n \"Failed to block user\": \"Falha ao bloquear o usuário\",\n \"Failed to create the poll\": \"Falha ao criar a pesquisa\",\n \"Failed to create the poll due to {{reason}}\": \"Falha ao criar a enquete devido a {{reason}}\",\n \"Failed to delete the message\": \"Falha ao excluir a mensagem\",\n \"Failed to end the poll\": \"Falha ao encerrar a enquete\",\n \"Failed to end the poll due to {{reason}}\": \"Falha ao encerrar a enquete devido a {{reason}}\",\n \"Failed to jump to the first unread message\": \"Falha ao pular para a primeira mensagem não lida\",\n \"Failed to leave channel\": \"Falha ao sair do canal\",\n \"Failed to load channels\": \"Falha ao carregar os canais\",\n \"Failed to load more channels\": \"Falha ao carregar mais canais\",\n \"Failed to mark channel as read\": \"Falha ao marcar o canal como lido\",\n \"Failed to play the recording\": \"Falha ao reproduzir a gravação\",\n \"Failed to retrieve location\": \"Falha ao obter localização\",\n \"Failed to save changes\": \"Falha ao salvar alterações\",\n \"Failed to share location\": \"Falha ao compartilhar localização\",\n \"Failed to update channel archive status\": \"Falha ao atualizar o status de arquivamento do canal\",\n \"Failed to update channel mute status\": \"Falha ao atualizar o status de mudo do canal\",\n \"Failed to update channel pinned status\": \"Falha ao atualizar o status de fixação do canal\",\n \"File\": \"Arquivo\",\n \"File is required for upload attachment\": \"Arquivo é necessário para enviar o anexo\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"O arquivo é muito grande: {{ size }}, o tamanho máximo de upload é {{ limit }}\",\n \"File too large\": \"Arquivo muito grande\",\n \"fileCount_one\": \"1 arquivo\",\n \"fileCount_many\": \"{{ count }} arquivos\",\n \"fileCount_other\": \"{{ count }} arquivos\",\n \"Files\": \"Arquivos\",\n \"Flag\": \"Reportar\",\n \"Generating...\": \"Gerando...\",\n \"giphy-command-args\": \"[texto]\",\n \"giphy-command-description\": \"Postar um gif aleatório no canal\",\n \"Go back\": \"Voltar\",\n \"Group info\": \"Informações do grupo\",\n \"Group name\": \"Nome do grupo\",\n \"Hide who voted\": \"Ocultar quem votou\",\n \"Image\": \"Imagem\",\n \"imageCount_one\": \"Imagem\",\n \"imageCount_many\": \"{{ count }} imagens\",\n \"imageCount_other\": \"{{ count }} imagens\",\n \"Instant commands\": \"Comandos instantâneos\",\n \"language/af\": \"Africâner\",\n \"language/am\": \"Amárico\",\n \"language/ar\": \"Árabe\",\n \"language/az\": \"Azerbaijano\",\n \"language/bg\": \"Búlgaro\",\n \"language/bn\": \"Bengali\",\n \"language/bs\": \"Bósnio\",\n \"language/cs\": \"Tcheco\",\n \"language/da\": \"Dinamarquês\",\n \"language/de\": \"Alemão\",\n \"language/el\": \"Grego\",\n \"language/en\": \"Inglês\",\n \"language/es\": \"Espanhol\",\n \"language/es-MX\": \"Espanhol (México)\",\n \"language/et\": \"Estoniano\",\n \"language/fa\": \"Persa\",\n \"language/fa-AF\": \"Dari\",\n \"language/fi\": \"Finlandês\",\n \"language/fr\": \"Francês\",\n \"language/fr-CA\": \"Francês (Canadá)\",\n \"language/ha\": \"Hauçá\",\n \"language/he\": \"Hebraico\",\n \"language/hi\": \"Hindi\",\n \"language/hr\": \"Croata\",\n \"language/ht\": \"Crioulo haitiano\",\n \"language/hu\": \"Húngaro\",\n \"language/id\": \"Indonésio\",\n \"language/it\": \"Italiano\",\n \"language/ja\": \"Japonês\",\n \"language/ka\": \"Georgiano\",\n \"language/ko\": \"Coreano\",\n \"language/lt\": \"Lituano\",\n \"language/lv\": \"Letão\",\n \"language/ms\": \"Malaio\",\n \"language/nl\": \"Holandês\",\n \"language/no\": \"Norueguês\",\n \"language/pl\": \"Polonês\",\n \"language/ps\": \"Pashto\",\n \"language/pt\": \"Português\",\n \"language/ro\": \"Romeno\",\n \"language/ru\": \"Russo\",\n \"language/sk\": \"Eslovaco\",\n \"language/sl\": \"Esloveno\",\n \"language/so\": \"Somali\",\n \"language/sq\": \"Albanês\",\n \"language/sr\": \"Sérvio\",\n \"language/sv\": \"Sueco\",\n \"language/sw\": \"Suaíli\",\n \"language/ta\": \"Tâmil\",\n \"language/th\": \"Tailandês\",\n \"language/tl\": \"Tagalo\",\n \"language/tr\": \"Turco\",\n \"language/uk\": \"Ucraniano\",\n \"language/ur\": \"Urdu\",\n \"language/vi\": \"Vietnamita\",\n \"language/zh\": \"Chinês (simplificado)\",\n \"language/zh-TW\": \"Chinês (tradicional)\",\n \"Last seen {{ timestamp }}\": \"Visto pela última vez {{ timestamp }}\",\n \"Leave Channel\": \"Sair do canal\",\n \"Leave chat\": \"Sair do canal\",\n \"Left channel\": \"Canal abandonado\",\n \"Let others add options\": \"Permitir que outros adicionem opções\",\n \"Limit votes per person\": \"Limitar votos por pessoa\",\n \"Link\": \"Link\",\n \"linkCount_one\": \"Link\",\n \"linkCount_many\": \"{{ count }} links\",\n \"linkCount_other\": \"{{ count }} links\",\n \"live\": \"ao vivo\",\n \"Live for {{duration}}\": \"Ao vivo por {{duration}}\",\n \"Live location\": \"Localização ao vivo\",\n \"Live until {{ timestamp }}\": \"Ao vivo até {{ timestamp }}\",\n \"Load more\": \"Carregar mais\",\n \"Local upload attachment missing local id\": \"Anexo de envio local sem id local\",\n \"Location\": \"Localização\",\n \"Location sharing ended\": \"Compartilhamento de localização encerrado\",\n \"Location: {{ coordinates }}\": \"Localização: {{ coordinates }}\",\n \"Manage channel\": \"Gerenciar canal\",\n \"Manage members\": \"Gerenciar membros\",\n \"Mark as unread\": \"Marcar como não lida\",\n \"Maximum number of votes (from 2 to 10)\": \"Número máximo de votos (de 2 a 10)\",\n \"Maximum votes per person\": \"Máximo de votos por pessoa\",\n \"Member detail\": \"Detalhes do membro\",\n \"mention/Channel\": \"Canal\",\n \"mention/Channel Description\": \"Notificar todos neste canal\",\n \"mention/Here\": \"Aqui\",\n \"mention/Here Description\": \"Notificar todos os membros online neste canal\",\n \"Menu\": \"Menu\",\n \"Message deleted\": \"Mensagem apagada\",\n \"Message failed to send\": \"Falha ao enviar a mensagem\",\n \"Message has been successfully flagged\": \"A mensagem foi reportada com sucesso\",\n \"Message marked as unread\": \"Mensagem marcada como não lida\",\n \"Message pinned\": \"Mensagem fixada\",\n \"Message unpinned\": \"Mensagem desafixada\",\n \"Message was blocked by moderation policies\": \"A mensagem foi bloqueada pelas políticas de moderação\",\n \"Messages have been marked unread.\": \"Mensagens foram marcadas como não lidas.\",\n \"Missing permissions to upload the attachment\": \"Faltando permissões para enviar o anexo\",\n \"Moderator\": \"Moderador\",\n \"Multiple votes\": \"Votos múltiplos\",\n \"Mute\": \"Silenciar\",\n \"Mute chat\": \"Silenciar chat\",\n \"Mute user\": \"Silenciar usuário\",\n \"mute-command-args\": \"[@nomedeusuário]\",\n \"mute-command-description\": \"Silenciar um usuário\",\n \"network error\": \"erro de rede\",\n \"New\": \"Novo\",\n \"New message from {{user}}\": \"Nova mensagem de {{user}}\",\n \"New Messages!\": \"Novas Mensagens!\",\n \"Next\": \"Próximo\",\n \"Next image\": \"Próxima imagem\",\n \"No chats here yet…\": \"Ainda não há conversas aqui...\",\n \"No conversations yet\": \"Ainda não há conversas\",\n \"No files\": \"Nenhum arquivo\",\n \"No items exist\": \"Não existem itens\",\n \"No member found\": \"Nenhum membro encontrado\",\n \"No messages found\": \"Nenhuma mensagem encontrada\",\n \"No photos or videos\": \"Nenhuma foto ou vídeo\",\n \"No pinned messages\": \"Nenhuma mensagem fixada\",\n \"No results found\": \"Nenhum resultado encontrado\",\n \"No user found\": \"Nenhum usuário encontrado\",\n \"Nobody will be able to vote in this poll anymore.\": \"Ninguém mais poderá votar nesta pesquisa.\",\n \"Nothing yet...\": \"Nada ainda...\",\n \"Notify all {{ role }} members\": \"Notificar todos os membros com a função {{ role }}\",\n \"Offline\": \"Offline\",\n \"Ok\": \"OK\",\n \"Online\": \"Online\",\n \"Only numbers are allowed\": \"Apenas números são permitidos\",\n \"Only visible to you\": \"Visível apenas para você\",\n \"Open emoji picker\": \"Abrir seletor de emoji\",\n \"Open gallery at image {{ index }}\": \"Abrir galeria na imagem {{ index }}\",\n \"Open image in gallery\": \"Abrir imagem na galeria\",\n \"Open location in a map\": \"Abrir localização em um mapa\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"Abrir menu\",\n \"Option already exists\": \"Opção já existe\",\n \"Option is empty\": \"A opção está vazia\",\n \"Options\": \"Opções\",\n \"Original\": \"Original\",\n \"Owner\": \"Proprietário\",\n \"People matching\": \"Pessoas correspondentes\",\n \"Photo\": \"Foto\",\n \"Photos & videos\": \"Fotos e vídeos\",\n \"Pin\": \"Fixar\",\n \"Pin a message to see it here\": \"Fixe uma mensagem para vê-la aqui\",\n \"Pinned by {{ name }}\": \"Fixado por {{ name }}\",\n \"Pinned by You\": \"Fixado por você\",\n \"Pinned message\": \"Mensagem fixada\",\n \"Pinned messages\": \"Mensagens fixadas\",\n \"placeholder/PollComment\": \"O seu comentário\",\n \"placeholder/PollOptionSuggestion\": \"Introduza uma nova opção\",\n \"Play video\": \"Reproduzir vídeo\",\n \"Playback speed {{ rate }}x\": \"Velocidade de reprodução {{ rate }}x\",\n \"Poll\": \"Enquete\",\n \"Poll comments\": \"Comentários da pesquisa\",\n \"Poll ended\": \"Enquete encerrada\",\n \"Poll options\": \"Opções da pesquisa\",\n \"Poll results\": \"Resultados da pesquisa\",\n \"Poll sent\": \"Enquete enviada\",\n \"Previous\": \"Anterior\",\n \"Previous image\": \"Imagem anterior\",\n \"Question\": \"Pergunta\",\n \"Question {{ optionOrderNumber}}\": \"Pergunta {{ optionOrderNumber}}\",\n \"Question is required\": \"A pergunta é obrigatória\",\n \"Quote Reply\": \"Responder com citação\",\n \"Reached the vote limit. Remove an existing vote first.\": \"Limite de votos atingido. Remova um voto existente primeiro.\",\n \"Recording format is not supported and cannot be reproduced\": \"Formato de gravação não é suportado e não pode ser reproduzido\",\n \"Remind me\": \"Lembrar-me\",\n \"Remind Me\": \"Lembrar-me\",\n \"Reminder set\": \"Lembrete definido\",\n \"Remove\": \"Remover\",\n \"Remove {{ count }} members_one\": \"Remover {{ count }} membro\",\n \"Remove {{ count }} members_many\": \"Remover {{ count }} membros\",\n \"Remove {{ count }} members_other\": \"Remover {{ count }} membros\",\n \"Remove {{ member }} from this channel?\": \"Remover {{ member }} deste canal?\",\n \"Remove channel members\": \"Remover membros do canal\",\n \"Remove reminder\": \"Remover lembrete\",\n \"Remove save for later\": \"Remover Salvar para depois\",\n \"Remove user\": \"Remover usuário\",\n \"Removed {{ count }} members_one\": \"{{ count }} membro removido\",\n \"Removed {{ count }} members_many\": \"{{ count }} membros removidos\",\n \"Removed {{ count }} members_other\": \"{{ count }} membros removidos\",\n \"Replied to a thread\": \"Respondeu em um tópico\",\n \"Reply\": \"Responder\",\n \"Reply to {{ authorName }}\": \"Responder a {{ authorName }}\",\n \"Reply to a message to start a thread\": \"Responda a uma mensagem para iniciar um thread\",\n \"Reply to Message\": \"Responder à mensagem\",\n \"replyCount_one\": \"1 resposta\",\n \"replyCount_many\": \"{{ count }} respostas\",\n \"replyCount_other\": \"{{ count }} respostas\",\n \"Resend\": \"Reenviar\",\n \"Retry upload\": \"Tentar enviar novamente\",\n \"Review all options available in this poll\": \"Revise todas as opções disponíveis nesta enquete\",\n \"Review comments submitted with poll answers\": \"Revise comentários enviados com respostas da enquete\",\n \"Review poll results and open an option to see detailed votes\": \"Revise os resultados da enquete e abra uma opção para ver votos detalhados\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Revise esta mensagem e escolha se deseja excluí-la, editá-la ou enviá-la mesmo assim\",\n \"Review who voted for this option\": \"Revise quem votou nesta opção\",\n \"Save\": \"Salvar\",\n \"Save for later\": \"Salvar para depois\",\n \"Saved for later\": \"Salvo para depois\",\n \"Search\": \"Buscar\",\n \"Search GIFs\": \"Pesquisar GIFs\",\n \"search-results-header-filter-source-button-label--channels\": \"canais\",\n \"search-results-header-filter-source-button-label--messages\": \"mensagens\",\n \"search-results-header-filter-source-button-label--users\": \"usuários\",\n \"Searching for {{ searchSourceType }}...\": \"Buscando {{ searchSourceType }}...\",\n \"Searching...\": \"Buscando...\",\n \"searchResultsCount_one\": \"1 resultado\",\n \"searchResultsCount_many\": \"{{ count }} resultados\",\n \"searchResultsCount_other\": \"{{ count }} resultados\",\n \"Select a thread to continue the conversation\": \"Selecione uma thread para continuar a conversa\",\n \"Select more than one option\": \"Selecionar mais de uma opção\",\n \"Select one\": \"Selecionar um\",\n \"Select one or more\": \"Selecionar um ou mais\",\n \"Select up to {{count}}_one\": \"Selecionar até {{count}}\",\n \"Select up to {{count}}_many\": \"Selecionar até {{count}}\",\n \"Select up to {{count}}_other\": \"Selecionar até {{count}}\",\n \"Select your current location and optionally enable live location sharing\": \"Selecione sua localização atual e, opcionalmente, ative o compartilhamento de localização ao vivo\",\n \"Send\": \"Enviar\",\n \"Send a message\": \"Envie uma mensagem\",\n \"Send a message to start the conversation\": \"Envie uma mensagem para iniciar a conversa\",\n \"Send Anyway\": \"Enviar de qualquer forma\",\n \"Send direct message\": \"Enviar mensagem direta\",\n \"Send message request failed\": \"O pedido de envio da mensagem falhou\",\n \"Send poll\": \"Enviar enquete\",\n \"Sending...\": \"Enviando...\",\n \"Sent\": \"Enviado\",\n \"Share\": \"Compartilhar\",\n \"Share a file to see it here\": \"Compartilhe um arquivo para vê-lo aqui\",\n \"Share a photo or video to see it here\": \"Compartilhe uma foto ou vídeo para vê-lo aqui\",\n \"Share live location for\": \"Compartilhar localização ao vivo por\",\n \"Share Location\": \"Compartilhar localização\",\n \"Shared live location\": \"Localização ao vivo compartilhada\",\n \"Shared location\": \"Localização compartilhada\",\n \"Shuffle\": \"Embaralhar\",\n \"size limit\": \"limite de tamanho\",\n \"Slow Mode ON\": \"Modo lento LIGADO\",\n \"Slow mode, wait {{ seconds }}s...\": \"Modo lento, aguarde {{ seconds }} s...\",\n \"Some of the files will not be accepted\": \"Alguns arquivos não serão aceitos\",\n \"Start typing to search\": \"Comece a digitar para pesquisar\",\n \"Stop sharing\": \"Parar de compartilhar\",\n \"Submit\": \"Enviar\",\n \"Suggest a new option to add to this poll\": \"Sugira uma nova opção para adicionar a esta enquete\",\n \"Suggest an option\": \"Sugerir uma opção\",\n \"Tap to remove\": \"Toque para remover\",\n \"Tap to remove: {{ reactionName }}\": \"Toque para remover: {{ reactionName }}\",\n \"Thinking...\": \"Pensando...\",\n \"this content could not be displayed\": \"este conteúdo não pôde ser exibido\",\n \"This field cannot be empty or contain only spaces\": \"Este campo não pode estar vazio ou conter apenas espaços\",\n \"This message did not meet our content guidelines\": \"Esta mensagem não corresponde às nossas diretrizes de conteúdo\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"Este usuário poderá enviar mensagens para você novamente.\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"Fio\",\n \"Thread has not been found\": \"Fio não encontrado\",\n \"Thread reply\": \"Resposta no fio\",\n \"Thread Reply\": \"Resposta no fio\",\n \"ThreadListUnseenThreadsBanner/loading\": \"Carregando...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} tópico não lido\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_many\": \"{{ count }} tópicos não lidos\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} tópicos não lidos\",\n \"Threads\": \"Tópicos\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Ontem]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Hoje]\\\", \\\"nextDay\\\": \\\"[Amanhã]\\\", \\\"lastDay\\\": \\\"[Ontem]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Último] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"há {{ count }} d\",\n \"timestamp/relativeToday\": \"Hoje\",\n \"timestamp/relativeWeeksAgo\": \"há {{ count }} sem\",\n \"timestamp/relativeYesterday\": \"Ontem\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Hoje] [às] HH:mm\\\", \\\"nextDay\\\": \\\"[Amanhã] [às] HH:mm\\\", \\\"lastDay\\\": \\\"[Ontem] [às] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [às] HH:mm\\\", \\\"lastWeek\\\": \\\"dddd [passada às] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [às] HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"Para começar a gravar, permita o acesso à câmera no seu navegador\",\n \"To start recording, allow the microphone access in your browser\": \"Para começar a gravar, permita o acesso ao microfone no seu navegador\",\n \"totalVoteCount_one\": \"1 voto no total\",\n \"totalVoteCount_many\": \"{{ count }} votos no total\",\n \"totalVoteCount_other\": \"{{ count }} votos no total\",\n \"Translated\": \"Traduzido\",\n \"Translated from {{ language }}\": \"Traduzido de {{ language }}\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"Digite um número de 2 a 10\",\n \"Unarchive\": \"Desarquivar\",\n \"unban-command-args\": \"[@nomedeusuário]\",\n \"unban-command-description\": \"Desbanir um usuário\",\n \"Unblock\": \"Desbloquear\",\n \"Unblock user\": \"Desbloquear usuário\",\n \"Unblock User\": \"Desbloquear usuário\",\n \"unknown error\": \"erro desconhecido\",\n \"Unmute\": \"Ativar som\",\n \"Unmute chat\": \"Remover silenciamento do chat\",\n \"Unmute user\": \"Remover silenciamento do usuário\",\n \"unmute-command-args\": \"[@nomedeusuário]\",\n \"unmute-command-description\": \"Retirar o silenciamento de um usuário\",\n \"Unpin\": \"Desfixar\",\n \"Unread messages\": \"Mensagens não lidas\",\n \"Unsupported attachment\": \"Anexo não suportado\",\n \"unsupported file type\": \"tipo de arquivo não suportado\",\n \"Update\": \"Atualizar\",\n \"Update the comment attached to your poll answer\": \"Atualize o comentário anexado à sua resposta da enquete\",\n \"Update your comment\": \"Atualizar seu comentário\",\n \"Upload blocked\": \"Envio bloqueado\",\n \"Upload error\": \"Erro no envio\",\n \"Upload failed\": \"Falha no envio\",\n \"Upload Picture\": \"Enviar imagem\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Tipo de upload: \\\"{{ type }}\\\" não é permitido\",\n \"User blocked\": \"Usuário bloqueado\",\n \"User muted\": \"Usuário silenciado\",\n \"User removed\": \"Usuário removido\",\n \"User unblocked\": \"Usuário desbloqueado\",\n \"User unmuted\": \"Silenciamento do usuário removido\",\n \"User uploaded content\": \"Conteúdo enviado pelo usuário\",\n \"Video\": \"Vídeo\",\n \"videoCount_one\": \"Vídeo\",\n \"videoCount_many\": \"{{ count }} vídeos\",\n \"videoCount_other\": \"{{ count }} vídeos\",\n \"View\": \"Ver\",\n \"View {{count}} comments_one\": \"Ver {{count}} comentário\",\n \"View {{count}} comments_many\": \"Ver {{count}} comentários\",\n \"View {{count}} comments_other\": \"Ver {{count}} comentários\",\n \"View all\": \"Ver tudo\",\n \"View member details for {{ member }}\": \"Ver detalhes do membro {{ member }}\",\n \"View original\": \"Ver original\",\n \"View results\": \"Ver resultados\",\n \"View translation\": \"Ver tradução\",\n \"Voice message\": \"Mensagem de voz\",\n \"Voice message {{ duration }}\": \"Mensagem de voz {{ duration }}\",\n \"Voice message deleted\": \"Mensagem de voz excluída\",\n \"voiceMessageCount_one\": \"Mensagem de voz\",\n \"voiceMessageCount_many\": \"{{ count }} mensagens de voz\",\n \"voiceMessageCount_other\": \"{{ count }} mensagens de voz\",\n \"Vote ended\": \"Votação encerrada\",\n \"Votes\": \"Votos\",\n \"Wait until all attachments have uploaded\": \"Espere até que todos os anexos tenham sido carregados\",\n \"Waiting for network…\": \"Aguardando rede…\",\n \"You\": \"Você\",\n \"You've reached the maximum number of files\": \"Você atingiu o número máximo de arquivos\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} и {{ moreCount }} еще\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} и {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} файл\",\n \"{{ count }} files_few\": \"{{ count }} файла\",\n \"{{ count }} files_many\": \"{{ count }} файлов\",\n \"{{ count }} files_other\": \"{{ count }} файла\",\n \"{{ count }} members_one\": \"{{ count }} участник\",\n \"{{ count }} members_few\": \"{{ count }} участника\",\n \"{{ count }} members_many\": \"{{ count }} участников\",\n \"{{ count }} members_other\": \"{{ count }} участника\",\n \"{{ count }} members added_one\": \"{{ count }} участник добавлен\",\n \"{{ count }} members added_few\": \"{{ count }} участника добавлены\",\n \"{{ count }} members added_many\": \"{{ count }} участников добавлено\",\n \"{{ count }} members added_other\": \"{{ count }} участника добавлены\",\n \"{{ count }} people are typing_one\": \"{{ count }} человек печатает\",\n \"{{ count }} people are typing_few\": \"{{ count }} человека печатают\",\n \"{{ count }} people are typing_many\": \"{{ count }} человек печатают\",\n \"{{ count }} people are typing_other\": \"{{ count }} человека печатают\",\n \"{{ count }} photos_one\": \"{{ count }} фото\",\n \"{{ count }} photos_few\": \"{{ count }} фото\",\n \"{{ count }} photos_many\": \"{{ count }} фото\",\n \"{{ count }} photos_other\": \"{{ count }} фото\",\n \"{{ count }} reactions_one\": \"{{ count }} реакция\",\n \"{{ count }} reactions_few\": \"{{ count }} реакции\",\n \"{{ count }} reactions_many\": \"{{ count }} реакций\",\n \"{{ count }} reactions_other\": \"{{ count }} реакций\",\n \"{{ count }} videos_one\": \"{{ count }} видео\",\n \"{{ count }} videos_few\": \"{{ count }} видео\",\n \"{{ count }} videos_many\": \"{{ count }} видео\",\n \"{{ count }} videos_other\": \"{{ count }} видео\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} и {{ secondUser }}\",\n \"{{ imageCount }} more\": \"Ещё {{ imageCount }}\",\n \"{{ member }} will be able to message you again.\": \"{{ member }} снова сможет отправлять вам сообщения.\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }} больше не сможет отправлять вам сообщения.\",\n \"{{ memberCount }} members\": \"{{ memberCount }} участников\",\n \"{{ typing }} are typing\": \"{{ typing }} печатают\",\n \"{{ typing }} is typing\": \"{{ typing }} печатает\",\n \"{{ user }} has been muted\": \"Вы отписались от уведомлений от {{ user }}\",\n \"{{ user }} has been unmuted\": \"Уведомления от {{ user }} были включены\",\n \"{{ user }} is typing...\": \"{{ user }} печатает...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} и {{ user }} печатают...\",\n \"{{ users }} and more are typing...\": \"{{ users }} и другие печатают...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} в сети\",\n \"{{count}} new messages_one\": \"{{count}} новое сообщение\",\n \"{{count}} new messages_few\": \"{{count}} новых сообщения\",\n \"{{count}} new messages_many\": \"{{count}} новых сообщений\",\n \"{{count}} new messages_other\": \"{{count}} новых сообщений\",\n \"{{count}} unread_one\": \"{{count}} непрочитанное\",\n \"{{count}} unread_few\": \"{{count}} непрочитанных\",\n \"{{count}} unread_many\": \"{{count}} непрочитанных\",\n \"{{count}} unread_other\": \"{{count}} непрочитанных\",\n \"{{count}} votes_one\": \"{{count}} голос\",\n \"{{count}} votes_few\": \"{{count}} голоса\",\n \"{{count}} votes_many\": \"{{count}} голосов\",\n \"{{count}} votes_other\": \"{{count}} голосов\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"+ещё {{count}} вариант\",\n \"+{{count}} more options_few\": \"+ещё {{count}} варианта\",\n \"+{{count}} more options_many\": \"+ещё {{count}} вариантов\",\n \"+{{count}} more options_other\": \"+ещё {{count}} вариантов\",\n \"🏙 Attachment...\": \"🏙 Вложение...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} создал(а): {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} проголосовал(а): {{pollOptionText}}\",\n \"📍Shared location\": \"📍Общее местоположение\",\n \"Actions\": \"Actions\",\n \"Add\": \"Добавить\",\n \"Add {{ count }} members_one\": \"Добавить {{ count }} участника\",\n \"Add {{ count }} members_few\": \"Добавить {{ count }} участников\",\n \"Add {{ count }} members_many\": \"Добавить {{ count }} участников\",\n \"Add {{ count }} members_other\": \"Добавить {{ count }} участника\",\n \"Add a comment\": \"Добавить комментарий\",\n \"Add a comment to your poll answer\": \"Добавьте комментарий к вашему ответу в опросе\",\n \"Add an option\": \"Добавить вариант\",\n \"Add channel members\": \"Добавить участников канала\",\n \"Add members\": \"Добавить участников\",\n \"Add reaction\": \"Добавить реакцию\",\n \"Admin\": \"Администратор\",\n \"All results loaded\": \"Все результаты загружены\",\n \"Allow access to camera\": \"Разрешить доступ к камере\",\n \"Allow access to microphone\": \"Разрешить доступ к микрофону\",\n \"Allow comments\": \"Разрешить комментарии\",\n \"Allow option suggestion\": \"Разрешить предложение вариантов\",\n \"Allow others to add comments\": \"Разрешить другим добавлять комментарии\",\n \"Already a member\": \"Уже участник\",\n \"Also send as a direct message\": \"Также отправить как личное сообщение\",\n \"Also send in channel\": \"Также отправить в канал\",\n \"Also sent in channel\": \"Также отправлено в канал\",\n \"An error has occurred during recording\": \"Произошла ошибка во время записи\",\n \"An error has occurred during the recording processing\": \"Произошла ошибка во время обработки записи\",\n \"Anonymous\": \"Аноним\",\n \"Anonymous poll\": \"Анонимный опрос\",\n \"Archive\": \"Aрхивировать\",\n \"Are you sure you want to delete this message?\": \"Вы уверены, что хотите удалить это сообщение?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_one\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_few\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_many\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_one\": \"{{ count }} вложение\",\n \"aria/{{ count }} attachment_few\": \"{{ count }} вложения\",\n \"aria/{{ count }} attachment_many\": \"{{ count }} вложений\",\n \"aria/{{ count }} attachment_other\": \"{{ count }} вложений\",\n \"aria/{{ count }} search results_one\": \"{{ count }} результат поиска\",\n \"aria/{{ count }} search results_few\": \"{{ count }} результата поиска\",\n \"aria/{{ count }} search results_many\": \"{{ count }} результатов поиска\",\n \"aria/{{ count }} search results_other\": \"{{ count }} результата поиска\",\n \"aria/{{ count }} suggestions_one\": \"{{ count }} подсказка\",\n \"aria/{{ count }} suggestions_few\": \"{{ count }} подсказки\",\n \"aria/{{ count }} suggestions_many\": \"{{ count }} подсказок\",\n \"aria/{{ count }} suggestions_other\": \"{{ count }} подсказки\",\n \"aria/{{ count }} unread message_one\": \"{{ count }} непрочитанное сообщение\",\n \"aria/{{ count }} unread message_few\": \"{{ count }} непрочитанных сообщения\",\n \"aria/{{ count }} unread message_many\": \"{{ count }} непрочитанных сообщений\",\n \"aria/{{ count }} unread message_other\": \"{{ count }} непрочитанных сообщений\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} отключено\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} включено\",\n \"aria/Active\": \"Активно\",\n \"aria/Animated GIF\": \"Анимированный GIF\",\n \"aria/Animated GIF: {{ title }}\": \"Анимированный GIF: {{ title }}\",\n \"aria/Attachment\": \"Вложение\",\n \"aria/Attachment {{ attachmentType }}\": \"Вложение {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"Действия с вложением\",\n \"aria/audio\": \"аудио\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Позиция аудио {{ elapsed }} из {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"Позиция аудио {{ progress }} процентов\",\n \"aria/Back to attachments\": \"Назад к вложениям\",\n \"aria/Back to parent menu button\": \"Назад в родительское меню кнопка\",\n \"aria/Block User\": \"Заблокировать пользователя\",\n \"aria/Bookmark Message\": \"Сохранить сообщение\",\n \"aria/Cancel recording\": \"Отменить запись\",\n \"aria/Cancel Reply\": \"Отменить ответ\",\n \"aria/Channel Actions\": \"Действия канала\",\n \"aria/Channel details\": \"Сведения о канале\",\n \"aria/Channel list\": \"Список каналов\",\n \"aria/Chat view controls\": \"Элементы управления видом чата\",\n \"aria/Chat: {{ channelName }}\": \"Чат: {{ channelName }}\",\n \"aria/Clear search\": \"Очистить поиск\",\n \"aria/Close callout dialog\": \"Закрыть диалог выноски\",\n \"aria/Close thread\": \"Закрыть тему\",\n \"aria/Collapse sidebar\": \"Свернуть боковую панель\",\n \"aria/Command activated: {{ command }}\": \"Команда активирована: {{ command }}\",\n \"aria/Command Suggestions\": \"Подсказки команд\",\n \"aria/Complete recording\": \"Завершить запись\",\n \"aria/Copy Message Text\": \"Копировать текст сообщения\",\n \"aria/Decrease value\": \"Уменьшить значение\",\n \"aria/Delete Message\": \"Удалить сообщение\",\n \"aria/Delivered\": \"Доставлено\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"Статус доставки: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"Закрыть уведомление\",\n \"aria/Download attachment\": \"Скачать вложение\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"Вариант «{{ option }}» помещён на позицию {{ position }}.\",\n \"aria/Edit Message\": \"Редактировать сообщение\",\n \"aria/Emoji picker\": \"Выбор эмодзи\",\n \"aria/Emoji Suggestions\": \"Подсказки эмодзи\",\n \"aria/Exit search\": \"Выйти из поиска\",\n \"aria/Expand sidebar\": \"Развернуть боковую панель\",\n \"aria/file\": \"файл\",\n \"aria/File upload\": \"Загрузка файла\",\n \"aria/Flag Message\": \"Пожаловаться на сообщение\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Действия Giphy\",\n \"aria/Giphy canceled\": \"Giphy отменён\",\n \"aria/Giphy image changed\": \"Giphy-изображение изменено\",\n \"aria/Giphy image changed: {{ title }}\": \"Giphy-изображение изменено: {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Предпросмотр Giphy, виден только вам. Используйте действия «Отправить», «Перемешать» или «Отменить».\",\n \"aria/Giphy sent\": \"Giphy отправлен\",\n \"aria/image\": \"изображение\",\n \"aria/Image failed to load\": \"Не удалось загрузить изображение\",\n \"aria/Increase value\": \"Увеличить значение\",\n \"aria/Jump to latest message\": \"Перейти к последнему сообщению\",\n \"aria/Jump to quoted message\": \"Перейти к цитируемому сообщению\",\n \"aria/Last activity: {{ time }}\": \"Последняя активность: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"Последнее сообщение от {{ sender }}: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"Последнее сообщение: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"Отметить как непрочитанное\",\n \"aria/Mark messages as read\": \"Отметить сообщения как прочитанные\",\n \"aria/Mention Suggestions\": \"Подсказки упоминаний\",\n \"aria/Message Actions\": \"Действия с сообщением\",\n \"aria/Message from {{ user }},\": \"Сообщение от {{ user }},\",\n \"aria/Message input\": \"Поле ввода сообщения\",\n \"aria/Message with attachments\": \"Сообщение с вложениями\",\n \"aria/Message,\": \"Сообщение,\",\n \"aria/Mute User\": \"Отключить уведомления\",\n \"aria/Next page\": \"Следующая страница\",\n \"aria/No search results found\": \"Результаты поиска не найдены\",\n \"aria/Notifications\": \"Уведомления\",\n \"aria/Open Attachment Selector\": \"Открыть выбор вложений\",\n \"aria/Open Channel Actions Menu\": \"Открыть меню действий канала\",\n \"aria/Open channel details\": \"Открыть сведения о канале\",\n \"aria/Open channels view\": \"Открыть вид каналов\",\n \"aria/Open image shared by {{ name }}\": \"Открыть изображение от {{ name }}\",\n \"aria/Open Message Actions Menu\": \"Открыть меню действий с сообщениями\",\n \"aria/Open Reaction Selector\": \"Открыть селектор реакций\",\n \"aria/Open Thread\": \"Открыть тему\",\n \"aria/Open threads view\": \"Открыть вид веток\",\n \"aria/Open threads view with unread threads_one\": \"Открыть вид веток, {{ count }} непрочитанная ветка\",\n \"aria/Open threads view with unread threads_few\": \"Открыть вид веток, {{ count }} непрочитанные ветки\",\n \"aria/Open threads view with unread threads_many\": \"Открыть вид веток, {{ count }} непрочитанных веток\",\n \"aria/Open threads view with unread threads_other\": \"Открыть вид веток, {{ count }} непрочитанных веток\",\n \"aria/Open video shared by {{ name }}\": \"Открыть видео от {{ name }}\",\n \"aria/Opened channel: {{ name }}\": \"Открыт канал: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"Открыт тред в {{ name }}\",\n \"aria/Option {{ position }}\": \"Вариант {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"Теперь варианты можно переупорядочивать и удалять.\",\n \"aria/Pause\": \"Пауза\",\n \"aria/Pause recording\": \"Приостановить запись\",\n \"aria/Percent complete\": \"{{percent}} процентов завершено\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"Вариант «{{ option }}» взят. Используйте клавиши со стрелками, чтобы изменить порядок. Нажмите пробел или Tab, чтобы отпустить.\",\n \"aria/Pin Message\": \"Закрепить сообщение\",\n \"aria/Play\": \"Воспроизвести\",\n \"aria/Poll dialog opened\": \"Диалоговое окно опроса открыто\",\n \"aria/Poll sent\": \"Опрос отправлен\",\n \"aria/Poll: {{ pollName }}\": \"Опрос: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Нажмите Enter, чтобы начать ввод\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"Нажмите пробел, чтобы выбрать этот вариант, используйте клавиши со стрелками вверх и вниз, чтобы переместить его, затем снова нажмите пробел, чтобы снять выбор.\",\n \"aria/Previous page\": \"Предыдущая страница\",\n \"aria/Quote Message\": \"Цитировать сообщение\",\n \"aria/Reaction list\": \"Список реакций\",\n \"aria/Read\": \"Прочитано\",\n \"aria/Recording paused\": \"Запись приостановлена\",\n \"aria/Recording resumed\": \"Запись возобновлена\",\n \"aria/Recording started\": \"Запись начата\",\n \"aria/Remind Me Message\": \"Напомнить мне\",\n \"aria/Remove attachment\": \"Удалить вложение\",\n \"aria/Remove location attachment\": \"Удалить вложение местоположения\",\n \"aria/Remove option: {{ option }}\": \"Удалить вариант: {{ option }}\",\n \"aria/Remove Reminder\": \"Удалить напоминание\",\n \"aria/Remove Save For Later\": \"Удалить «Сохранить на потом»\",\n \"aria/Removed option {{ option }}\": \"Вариант {{ option }} удалён\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"Изменить порядок варианта «{{ option }}», позиция {{ position }} из {{ total }}\",\n \"aria/Reorder option {{ position }}\": \"Изменить порядок варианта {{ position }}\",\n \"aria/Resend Message\": \"Отправить сообщение повторно\",\n \"aria/Resume recording\": \"Возобновить запись\",\n \"aria/Retry upload\": \"Повторить загрузку\",\n \"aria/Review bounced message\": \"Проверить отклонённое сообщение\",\n \"aria/Search cleared\": \"Поиск очищен\",\n \"aria/Search results\": \"Результаты поиска\",\n \"aria/Search results header filter button for: {{ source }}\": \"Кнопка фильтра заголовка результатов поиска для: {{ source }}\",\n \"aria/Seek audio position\": \"Перемотать аудио\",\n \"aria/Select Reaction: {{ reactionName }}\": \"Выбрать реакцию: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"Выбрать пользовательский канал: {{ name }}\",\n \"aria/Send\": \"Отправить\",\n \"aria/Sent\": \"Отправлено\",\n \"aria/Shared a link\": \"Поделились ссылкой\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"Поделились ссылкой с заголовком: {{ linkTitle }}\",\n \"aria/Shared location\": \"Местоположение\",\n \"aria/Show preview\": \"Показать предпросмотр\",\n \"aria/Start recording audio\": \"Начать запись аудио\",\n \"aria/Stop AI Generation\": \"Остановить генерацию ИИ\",\n \"aria/Submenu\": \"Подменю\",\n \"aria/Suggestions\": \"Подсказки\",\n \"aria/There are no messages in this chat.\": \"В этом чате нет сообщений\",\n \"aria/This option can be reordered and removed.\": \"Этот вариант можно переупорядочить и удалить.\",\n \"aria/Thread list\": \"Список тредов\",\n \"aria/Thread: {{ messagePreview }}\": \"Тема: {{ messagePreview }}\",\n \"aria/Unblock User\": \"Разблокировать пользователя\",\n \"aria/Unmute User\": \"Включить уведомления\",\n \"aria/Unpin Message\": \"Открепить сообщение\",\n \"aria/User selected: {{ user }}\": \"Выбран пользователь: {{ user }}\",\n \"aria/video\": \"видео\",\n \"aria/voice message\": \"голосовое сообщение\",\n \"aria/Voice message sent\": \"Голосовое сообщение отправлено\",\n \"aria/Voice recording attached\": \"Голосовая запись прикреплена\",\n \"Ask a question\": \"Задать вопрос\",\n \"Attach\": \"Прикрепить\",\n \"Attach files\": \"Прикрепить файлы\",\n \"Attachment\": \"Вложение\",\n \"Attachment upload blocked due to {{reason}}\": \"Загрузка вложения заблокирована из-за {{reason}}\",\n \"Attachment upload failed due to {{reason}}\": \"Загрузка вложения не удалась из-за {{reason}}\",\n \"Back\": \"Назад\",\n \"ban-command-args\": \"[@имяпользователя] [текст]\",\n \"ban-command-description\": \"Заблокировать пользователя\",\n \"Block user\": \"Заблокировать пользователя\",\n \"Block User\": \"Заблокировать пользователя\",\n \"Browse channel members\": \"Просмотреть участников канала\",\n \"Browse pinned messages\": \"Просмотреть закрепленные сообщения\",\n \"Cancel\": \"Отмена\",\n \"Cannot seek in the recording\": \"Невозможно осуществить поиск в записи\",\n \"Changes saved\": \"Изменения сохранены\",\n \"Channel archived\": \"Канал в архиве\",\n \"Channel members\": \"Участники канала\",\n \"Channel Missing\": \"Канал не найден\",\n \"Channel muted\": \"Канал заглушён\",\n \"Channel pinned\": \"Канал закреплён\",\n \"Channel unarchived\": \"Канал извлечён из архива\",\n \"Channel unmuted\": \"Заглушение канала снято\",\n \"Channel unpinned\": \"Канал откреплён\",\n \"Channels\": \"Каналы\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"Чаты\",\n \"Choose between 2 to 10 options\": \"Выберите от 2 до 10 вариантов\",\n \"Close\": \"Закрыть\",\n \"Close dialog\": \"Закрыть диалог\",\n \"Close emoji picker\": \"Закрыть окно выбора смайлов\",\n \"Command not available while editing\": \"Команда недоступна при редактировании\",\n \"Command not available while replying\": \"Команда недоступна при ответе\",\n \"Commands\": \"Команды\",\n \"Commands matching\": \"Соответствие команд\",\n \"Connection failure, reconnecting now...\": \"Ошибка соединения, переподключение...\",\n \"Contact info\": \"Информация о контакте\",\n \"Contact name\": \"Имя контакта\",\n \"Copy Message\": \"Копировать сообщение\",\n \"Create\": \"Создать\",\n \"Create a question, add options, and configure poll settings\": \"Создайте вопрос, добавьте варианты и настройте параметры опроса\",\n \"Create poll\": \"Создать опрос\",\n \"Current location\": \"Текущее местоположение\",\n \"Delete\": \"Удалить\",\n \"Delete chat\": \"Удалить чат\",\n \"Delete for me\": \"Удалить для меня\",\n \"Delete message\": \"Удалить сообщение\",\n \"Delivered\": \"Отправлено\",\n \"Direct message\": \"Личное сообщение\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Вы хотите завершить этот опрос сейчас? После этого никто не сможет голосовать в этом опросе.\",\n \"Download {{ fileName }}\": \"Скачать {{ fileName }}\",\n \"Download All\": \"Скачать всё\",\n \"Download Attachment\": \"Скачать вложение\",\n \"Download attachment {{ name }}\": \"Скачать вложение {{ name }}\",\n \"Download attachment {{ number }}\": \"Скачать вложение {{ number }}\",\n \"Drag your files here\": \"Перетащите ваши файлы сюда\",\n \"Drag your files here to add to your post\": \"Перетащите ваши файлы сюда, чтобы добавить их в ваш пост\",\n \"Due {{ timeLeft }}\": \"Просрочено в {{ timeLeft }}\",\n \"Due since {{ dueSince }}\": \"Просрочено с {{ dueSince }}\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"Редактировать\",\n \"Edit chat data\": \"Редактировать данные чата\",\n \"Edit contact\": \"Редактировать контакт\",\n \"Edit group\": \"Редактировать группу\",\n \"Edit Message\": \"Редактировать сообщение\",\n \"Edit message request failed\": \"Не удалось изменить запрос сообщения\",\n \"Edited\": \"Отредактировано\",\n \"Emoji matching\": \"Соответствие эмодзи\",\n \"Empty message...\": \"Пустое сообщение...\",\n \"End\": \"Конец\",\n \"End poll\": \"Завершить опрос\",\n \"End this poll?\": \"Завершить этот опрос?\",\n \"End vote\": \"Закончить голосование\",\n \"Enforce unique vote is enabled\": \"Уникальное голосование включено\",\n \"Error\": \"Ошибка\",\n \"Error adding flag\": \"Ошибка добавления флага\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"Ошибка при блокировке пользователя\",\n \"Error connecting to chat, refresh the page to try again.\": \"Ошибка подключения к чату, обновите страницу чтобы попробовать снова.\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"Ошибка при удалении сообщения\",\n \"Error fetching reactions\": \"Ошибка при загрузке реакций\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Ошибка при отметке сообщения как непрочитанного. Невозможно отметить как непрочитанные сообщения старше последних 100 сообщений в канале.\",\n \"Error muting a user ...\": \"Ошибка отключения уведомлений от пользователя...\",\n \"Error muting channel\": \"Ошибка при отключении уведомлений канала\",\n \"Error muting user\": \"Ошибка при отключении уведомлений пользователя\",\n \"Error opening direct message\": \"Ошибка при открытии личного сообщения\",\n \"Error pinning message\": \"Сообщение об ошибке при закреплении\",\n \"Error removing members\": \"Ошибка при удалении участников\",\n \"Error removing message pin\": \"Ошибка при удалении булавки сообщения\",\n \"Error removing user\": \"Ошибка при удалении пользователя\",\n \"Error reproducing the recording\": \"Ошибка воспроизведения записи\",\n \"Error starting recording\": \"Ошибка при запуске записи\",\n \"Error unblocking user\": \"Ошибка при разблокировке пользователя\",\n \"Error unmuting a user ...\": \"Ошибка включения уведомлений...\",\n \"Error unmuting channel\": \"Ошибка при включении уведомлений канала\",\n \"Error unmuting user\": \"Ошибка при включении уведомлений пользователя\",\n \"Error uploading attachment\": \"Ошибка при загрузке вложения\",\n \"Error uploading file\": \"Ошибка при загрузке файла\",\n \"Error uploading image\": \"Ошибка загрузки изображения\",\n \"Error: {{ errorMessage }}\": \"Ошибка: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"Выйти из команды {{ command }}\",\n \"Failed to block user\": \"Не удалось заблокировать пользователя\",\n \"Failed to create the poll\": \"Не удалось создать опрос\",\n \"Failed to create the poll due to {{reason}}\": \"Не удалось создать опрос из-за {{reason}}\",\n \"Failed to delete the message\": \"Не удалось удалить сообщение\",\n \"Failed to end the poll\": \"Не удалось завершить опрос\",\n \"Failed to end the poll due to {{reason}}\": \"Не удалось завершить опрос из-за {{reason}}\",\n \"Failed to jump to the first unread message\": \"Не удалось перейти к первому непрочитанному сообщению\",\n \"Failed to leave channel\": \"Не удалось покинуть канал\",\n \"Failed to load channels\": \"Не удалось загрузить каналы\",\n \"Failed to load more channels\": \"Не удалось загрузить больше каналов\",\n \"Failed to mark channel as read\": \"Не удалось пометить канал как прочитанный\",\n \"Failed to play the recording\": \"Не удалось воспроизвести запись\",\n \"Failed to retrieve location\": \"Не удалось получить местоположение\",\n \"Failed to save changes\": \"Не удалось сохранить изменения\",\n \"Failed to share location\": \"Не удалось поделиться местоположением\",\n \"Failed to update channel archive status\": \"Не удалось обновить статус архивации канала\",\n \"Failed to update channel mute status\": \"Не удалось обновить статус отключения звука канала\",\n \"Failed to update channel pinned status\": \"Не удалось обновить статус закрепления канала\",\n \"File\": \"Файл\",\n \"File is required for upload attachment\": \"Для загрузки вложения требуется файл\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Файл слишком большой: {{ size }}, максимальный размер загрузки составляет {{ limit }}\",\n \"File too large\": \"Файл слишком большой\",\n \"fileCount_one\": \"{{ count }} файл\",\n \"fileCount_few\": \"{{ count }} файла\",\n \"fileCount_four\": \"{{ count }} файла\",\n \"fileCount_two\": \"{{ count }} файла\",\n \"fileCount_many\": \"{{ count }} файлов\",\n \"fileCount_other\": \"{{ count }} файлов\",\n \"fileCount_three\": \"{{ count }} файла\",\n \"Files\": \"Файлы\",\n \"Flag\": \"Пожаловаться\",\n \"Generating...\": \"Генерирую...\",\n \"giphy-command-args\": \"[текст]\",\n \"giphy-command-description\": \"Опубликовать случайную GIF-анимацию в канале\",\n \"Go back\": \"Назад\",\n \"Group info\": \"Информация о группе\",\n \"Group name\": \"Название группы\",\n \"Hide who voted\": \"Скрыть, кто голосовал\",\n \"Image\": \"Изображение\",\n \"imageCount_one\": \"{{ count }} изображение\",\n \"imageCount_few\": \"{{ count }} изображения\",\n \"imageCount_many\": \"{{ count }} изображений\",\n \"imageCount_other\": \"{{ count }} изображений\",\n \"Instant commands\": \"Мгновенные команды\",\n \"language/af\": \"Африкаанс\",\n \"language/am\": \"Амхарский\",\n \"language/ar\": \"Арабский\",\n \"language/az\": \"Азербайджанский\",\n \"language/bg\": \"Болгарский\",\n \"language/bn\": \"Бенгальский\",\n \"language/bs\": \"Боснийский\",\n \"language/cs\": \"Чешский\",\n \"language/da\": \"Датский\",\n \"language/de\": \"Немецкий\",\n \"language/el\": \"Греческий\",\n \"language/en\": \"Английский\",\n \"language/es\": \"Испанский\",\n \"language/es-MX\": \"Испанский (Мексика)\",\n \"language/et\": \"Эстонский\",\n \"language/fa\": \"Персидский\",\n \"language/fa-AF\": \"Дари\",\n \"language/fi\": \"Финский\",\n \"language/fr\": \"Французский\",\n \"language/fr-CA\": \"Французский (Канада)\",\n \"language/ha\": \"Хауса\",\n \"language/he\": \"Иврит\",\n \"language/hi\": \"Хинди\",\n \"language/hr\": \"Хорватский\",\n \"language/ht\": \"Гаитянский креольский\",\n \"language/hu\": \"Венгерский\",\n \"language/id\": \"Индонезийский\",\n \"language/it\": \"Итальянский\",\n \"language/ja\": \"Японский\",\n \"language/ka\": \"Грузинский\",\n \"language/ko\": \"Корейский\",\n \"language/lt\": \"Литовский\",\n \"language/lv\": \"Латышский\",\n \"language/ms\": \"Малайский\",\n \"language/nl\": \"Нидерландский\",\n \"language/no\": \"Норвежский\",\n \"language/pl\": \"Польский\",\n \"language/ps\": \"Пушту\",\n \"language/pt\": \"Португальский\",\n \"language/ro\": \"Румынский\",\n \"language/ru\": \"Русский\",\n \"language/sk\": \"Словацкий\",\n \"language/sl\": \"Словенский\",\n \"language/so\": \"Сомали\",\n \"language/sq\": \"Албанский\",\n \"language/sr\": \"Сербский\",\n \"language/sv\": \"Шведский\",\n \"language/sw\": \"Суахили\",\n \"language/ta\": \"Тамильский\",\n \"language/th\": \"Тайский\",\n \"language/tl\": \"Тагальский\",\n \"language/tr\": \"Турецкий\",\n \"language/uk\": \"Украинский\",\n \"language/ur\": \"Урду\",\n \"language/vi\": \"Вьетнамский\",\n \"language/zh\": \"Китайский (упрощённый)\",\n \"language/zh-TW\": \"Китайский (традиционный)\",\n \"Last seen {{ timestamp }}\": \"Был(а) в сети {{ timestamp }}\",\n \"Leave Channel\": \"Покинуть канал\",\n \"Leave chat\": \"Покинуть канал\",\n \"Left channel\": \"Канал покинут\",\n \"Let others add options\": \"Разрешить другим добавлять варианты\",\n \"Limit votes per person\": \"Ограничить голоса на человека\",\n \"Link\": \"Линк\",\n \"linkCount_one\": \"{{ count }} линк\",\n \"linkCount_few\": \"{{ count }} линка\",\n \"linkCount_many\": \"{{ count }} линков\",\n \"linkCount_other\": \"{{ count }} линков\",\n \"live\": \"В прямом эфире\",\n \"Live for {{duration}}\": \"В прямом эфире {{duration}}\",\n \"Live location\": \"Местоположение в прямом эфире\",\n \"Live until {{ timestamp }}\": \"В прямом эфире до {{ timestamp }}\",\n \"Load more\": \"Загрузить больше\",\n \"Local upload attachment missing local id\": \"У локального вложения нет локального id\",\n \"Location\": \"Местоположение\",\n \"Location sharing ended\": \"Обмен местоположением завершен\",\n \"Location: {{ coordinates }}\": \"Местоположение: {{ coordinates }}\",\n \"Manage channel\": \"Управлять каналом\",\n \"Manage members\": \"Управлять участниками\",\n \"Mark as unread\": \"Отметить как непрочитанное\",\n \"Maximum number of votes (from 2 to 10)\": \"Максимальное количество голосов (от 2 до 10)\",\n \"Maximum votes per person\": \"Максимум голосов на человека\",\n \"Member detail\": \"Сведения об участнике\",\n \"mention/Channel\": \"Канал\",\n \"mention/Channel Description\": \"Уведомить всех в этом канале\",\n \"mention/Here\": \"Здесь\",\n \"mention/Here Description\": \"Уведомить всех онлайн-участников в этом канале\",\n \"Menu\": \"Меню\",\n \"Message deleted\": \"Сообщение удалено\",\n \"Message failed to send\": \"Не удалось отправить сообщение\",\n \"Message has been successfully flagged\": \"Жалоба на сообщение была принята\",\n \"Message marked as unread\": \"Сообщение помечено как непрочитанное\",\n \"Message pinned\": \"Сообщение закреплено\",\n \"Message unpinned\": \"Сообщение откреплено\",\n \"Message was blocked by moderation policies\": \"Сообщение было заблокировано модерацией\",\n \"Messages have been marked unread.\": \"Сообщения были отмечены как непрочитанные.\",\n \"Missing permissions to upload the attachment\": \"Отсутствуют разрешения для загрузки вложения\",\n \"Moderator\": \"Модератор\",\n \"Multiple votes\": \"Несколько голосов\",\n \"Mute\": \"Отключить уведомления\",\n \"Mute chat\": \"Отключить уведомления чата\",\n \"Mute user\": \"Отключить уведомления пользователя\",\n \"mute-command-args\": \"[@имяпользователя]\",\n \"mute-command-description\": \"Выключить микрофон у пользователя\",\n \"network error\": \"ошибка сети\",\n \"New\": \"Новые\",\n \"New message from {{user}}\": \"Новое сообщение от {{user}}\",\n \"New Messages!\": \"Новые сообщения!\",\n \"Next\": \"Далее\",\n \"Next image\": \"Следующее изображение\",\n \"No chats here yet…\": \"Здесь еще нет чатов...\",\n \"No conversations yet\": \"Пока нет бесед\",\n \"No files\": \"Нет файлов\",\n \"No items exist\": \"Элементов нет\",\n \"No member found\": \"Участник не найден\",\n \"No messages found\": \"Сообщения не найдены\",\n \"No photos or videos\": \"Нет фото или видео\",\n \"No pinned messages\": \"Нет закрепленных сообщений\",\n \"No results found\": \"Результаты не найдены\",\n \"No user found\": \"Пользователь не найден\",\n \"Nobody will be able to vote in this poll anymore.\": \"Никто больше не сможет голосовать в этом опросе.\",\n \"Nothing yet...\": \"Пока ничего нет...\",\n \"Notify all {{ role }} members\": \"Уведомить всех участников с ролью {{ role }}\",\n \"Offline\": \"Не в сети\",\n \"Ok\": \"Ок\",\n \"Online\": \"В сети\",\n \"Only numbers are allowed\": \"Разрешены только цифры\",\n \"Only visible to you\": \"Видно только вам\",\n \"Open emoji picker\": \"Открыть выбор смайлов\",\n \"Open gallery at image {{ index }}\": \"Открыть галерею на изображении {{ index }}\",\n \"Open image in gallery\": \"Открыть изображение в галерее\",\n \"Open location in a map\": \"Открыть местоположение на карте\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"Открыть меню\",\n \"Option already exists\": \"Вариант уже существует\",\n \"Option is empty\": \"Вариант пуст\",\n \"Options\": \"Варианты\",\n \"Original\": \"Оригинал\",\n \"Owner\": \"Владелец\",\n \"People matching\": \"Совпадающие люди\",\n \"Photo\": \"Фото\",\n \"Photos & videos\": \"Фото и видео\",\n \"Pin\": \"Закрепить\",\n \"Pin a message to see it here\": \"Закрепите сообщение, чтобы увидеть его здесь\",\n \"Pinned by {{ name }}\": \"Закреплено: {{ name }}\",\n \"Pinned by You\": \"Закреплено вами\",\n \"Pinned message\": \"Закрепленное сообщение\",\n \"Pinned messages\": \"Закрепленные сообщения\",\n \"placeholder/PollComment\": \"Ваш комментарий\",\n \"placeholder/PollOptionSuggestion\": \"Введите новый вариант\",\n \"Play video\": \"Воспроизвести видео\",\n \"Playback speed {{ rate }}x\": \"Скорость воспроизведения {{ rate }}x\",\n \"Poll\": \"Опрос\",\n \"Poll comments\": \"Комментарии к опросу\",\n \"Poll ended\": \"Опрос завершён\",\n \"Poll options\": \"Опции опроса\",\n \"Poll results\": \"Результаты опроса\",\n \"Poll sent\": \"Опрос отправлен\",\n \"Previous\": \"Назад\",\n \"Previous image\": \"Предыдущее изображение\",\n \"Question\": \"Вопрос\",\n \"Question {{ optionOrderNumber}}\": \"Вопрос {{ optionOrderNumber}}\",\n \"Question is required\": \"Вопрос обязателен\",\n \"Quote Reply\": \"Ответ со цитатой\",\n \"Reached the vote limit. Remove an existing vote first.\": \"Достигнут лимит голосов. Сначала удалите существующий голос.\",\n \"Recording format is not supported and cannot be reproduced\": \"Формат записи не поддерживается и не может быть воспроизведен\",\n \"Remind me\": \"Напомнить мне\",\n \"Remind Me\": \"Напомнить мне\",\n \"Reminder set\": \"Напоминание установлено\",\n \"Remove\": \"Удалить\",\n \"Remove {{ count }} members_one\": \"Удалить {{ count }} участника\",\n \"Remove {{ count }} members_few\": \"Удалить {{ count }} участника\",\n \"Remove {{ count }} members_many\": \"Удалить {{ count }} участников\",\n \"Remove {{ count }} members_other\": \"Удалить {{ count }} участника\",\n \"Remove {{ member }} from this channel?\": \"Удалить {{ member }} из этого канала?\",\n \"Remove channel members\": \"Удалить участников канала\",\n \"Remove reminder\": \"Удалить напоминание\",\n \"Remove save for later\": \"Удалить «Сохранить на потом»\",\n \"Remove user\": \"Удалить пользователя\",\n \"Removed {{ count }} members_one\": \"Удалён {{ count }} участник\",\n \"Removed {{ count }} members_few\": \"Удалены {{ count }} участника\",\n \"Removed {{ count }} members_many\": \"Удалено {{ count }} участников\",\n \"Removed {{ count }} members_other\": \"Удалено {{ count }} участников\",\n \"Replied to a thread\": \"Ответил в ветке\",\n \"Reply\": \"Ответить\",\n \"Reply to {{ authorName }}\": \"Ответить {{ authorName }}\",\n \"Reply to a message to start a thread\": \"Ответьте на сообщение, чтобы начать тред\",\n \"Reply to Message\": \"Ответить на сообщение\",\n \"replyCount_one\": \"1 ответ\",\n \"replyCount_few\": \"{{ count }} ответов\",\n \"replyCount_many\": \"{{ count }} ответов\",\n \"replyCount_other\": \"{{ count }} ответов\",\n \"Resend\": \"Отправить повторно\",\n \"Retry upload\": \"Повторить загрузку\",\n \"Review all options available in this poll\": \"Просмотрите все варианты, доступные в этом опросе\",\n \"Review comments submitted with poll answers\": \"Просмотрите комментарии, отправленные вместе с ответами в опросе\",\n \"Review poll results and open an option to see detailed votes\": \"Просмотрите результаты опроса и откройте вариант, чтобы увидеть подробные голоса\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Просмотрите это сообщение и выберите, удалить его, отредактировать или отправить все равно\",\n \"Review who voted for this option\": \"Просмотрите, кто проголосовал за этот вариант\",\n \"Save\": \"Сохранить\",\n \"Save for later\": \"Сохранить на потом\",\n \"Saved for later\": \"Сохранено на потом\",\n \"Search\": \"Поиск\",\n \"Search GIFs\": \"Поиск GIF\",\n \"search-results-header-filter-source-button-label--channels\": \"каналы\",\n \"search-results-header-filter-source-button-label--messages\": \"сообщения\",\n \"search-results-header-filter-source-button-label--users\": \"пользователи\",\n \"Searching for {{ searchSourceType }}...\": \"Поиск {{ searchSourceType }}...\",\n \"Searching...\": \"Ищем...\",\n \"searchResultsCount_one\": \"1 результат\",\n \"searchResultsCount_few\": \"{{ count }} результата\",\n \"searchResultsCount_many\": \"{{ count }} результатов\",\n \"searchResultsCount_other\": \"{{ count }} результатов\",\n \"Select a thread to continue the conversation\": \"Выберите тред, чтобы продолжить беседу\",\n \"Select more than one option\": \"Выберите более одного варианта\",\n \"Select one\": \"Выберите один\",\n \"Select one or more\": \"Выберите один или несколько\",\n \"Select up to {{count}}_one\": \"Выберите до {{count}}\",\n \"Select up to {{count}}_few\": \"Выберите до {{count}}\",\n \"Select up to {{count}}_many\": \"Выберите до {{count}}\",\n \"Select up to {{count}}_other\": \"Выберите до {{count}}\",\n \"Select your current location and optionally enable live location sharing\": \"Выберите ваше текущее местоположение и при необходимости включите передачу геопозиции в реальном времени\",\n \"Send\": \"Отправить\",\n \"Send a message\": \"Отправьте сообщение\",\n \"Send a message to start the conversation\": \"Отправьте сообщение, чтобы начать разговор\",\n \"Send Anyway\": \"Мне всё равно, отправить\",\n \"Send direct message\": \"Отправить личное сообщение\",\n \"Send message request failed\": \"Не удалось отправить запрос на отправку сообщения\",\n \"Send poll\": \"Отправить опрос\",\n \"Sending...\": \"Отправка...\",\n \"Sent\": \"Отправлено\",\n \"Share\": \"Поделиться\",\n \"Share a file to see it here\": \"Поделитесь файлом, чтобы увидеть его здесь\",\n \"Share a photo or video to see it here\": \"Поделитесь фото или видео, чтобы увидеть их здесь\",\n \"Share live location for\": \"Поделиться местоположением в прямом эфире на\",\n \"Share Location\": \"Поделиться местоположением\",\n \"Shared live location\": \"Общее местоположение в прямом эфире\",\n \"Shared location\": \"Общее местоположение\",\n \"Shuffle\": \"Перемешать\",\n \"size limit\": \"ограничение размера\",\n \"Slow Mode ON\": \"Медленный режим включен\",\n \"Slow mode, wait {{ seconds }}s...\": \"Медленный режим: подождите {{ seconds }} с...\",\n \"Some of the files will not be accepted\": \"Некоторые файлы не будут приняты\",\n \"Start typing to search\": \"Начните вводить для поиска\",\n \"Stop sharing\": \"Прекратить делиться\",\n \"Submit\": \"Отправить\",\n \"Suggest a new option to add to this poll\": \"Предложите новый вариант для добавления в этот опрос\",\n \"Suggest an option\": \"Предложить вариант\",\n \"Tap to remove\": \"Нажмите, чтобы удалить\",\n \"Tap to remove: {{ reactionName }}\": \"Нажмите, чтобы удалить: {{ reactionName }}\",\n \"Thinking...\": \"Думаю...\",\n \"this content could not be displayed\": \"Этот контент не может быть отображен в данный момент\",\n \"This field cannot be empty or contain only spaces\": \"Это поле не может быть пустым или содержать только пробелы\",\n \"This message did not meet our content guidelines\": \"Сообщение не соответствует правилам\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"Этот пользователь снова сможет отправлять вам сообщения.\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"Ветка\",\n \"Thread has not been found\": \"Ветка не найдена\",\n \"Thread reply\": \"Ответ в ветке\",\n \"Thread Reply\": \"Ответ в ветке\",\n \"ThreadListUnseenThreadsBanner/loading\": \"Загрузка...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} непрочитанная ветка\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_few\": \"{{ count }} непрочитанные ветки\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_many\": \"{{ count }} непрочитанных веток\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} непрочитанных веток\",\n \"Threads\": \"Треды\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Вчера]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Сегодня]\\\", \\\"nextDay\\\": \\\"[Завтра]\\\", \\\"lastDay\\\": \\\"[Вчера]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[В прошлый] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"{{ count }} дн. назад\",\n \"timestamp/relativeToday\": \"Сегодня\",\n \"timestamp/relativeWeeksAgo\": \"{{ count }} нед. назад\",\n \"timestamp/relativeYesterday\": \"Вчера\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Сегодня] [в] HH:mm\\\", \\\"nextDay\\\": \\\"[Завтра] [в] HH:mm\\\", \\\"lastDay\\\": \\\"[Вчера] [в] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [в] HH:mm\\\", \\\"lastWeek\\\": \\\"dddd [в] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [в] HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"Для начала записи разрешите доступ к камере в вашем браузере\",\n \"To start recording, allow the microphone access in your browser\": \"Для начала записи разрешите доступ к микрофону в вашем браузере\",\n \"totalVoteCount_one\": \"1 голос всего\",\n \"totalVoteCount_few\": \"{{ count }} голоса всего\",\n \"totalVoteCount_many\": \"{{ count }} голосов всего\",\n \"totalVoteCount_other\": \"{{ count }} голосов всего\",\n \"Translated\": \"Переведено\",\n \"Translated from {{ language }}\": \"Переведено с {{ language }}\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"Введите число от 2 до 10\",\n \"Unarchive\": \"Удалить из архива\",\n \"unban-command-args\": \"[@имяпользователя]\",\n \"unban-command-description\": \"Разблокировать пользователя\",\n \"Unblock\": \"Разблокировать\",\n \"Unblock user\": \"Разблокировать пользователя\",\n \"Unblock User\": \"Разблокировать пользователя\",\n \"unknown error\": \"неизвестная ошибка\",\n \"Unmute\": \"Включить уведомления\",\n \"Unmute chat\": \"Включить уведомления чата\",\n \"Unmute user\": \"Включить уведомления пользователя\",\n \"unmute-command-args\": \"[@имяпользователя]\",\n \"unmute-command-description\": \"Включить микрофон у пользователя\",\n \"Unpin\": \"Открепить\",\n \"Unread messages\": \"Непрочитанные сообщения\",\n \"Unsupported attachment\": \"Неподдерживаемое вложение\",\n \"unsupported file type\": \"неподдерживаемый тип файла\",\n \"Update\": \"Обновить\",\n \"Update the comment attached to your poll answer\": \"Обновите комментарий, прикрепленный к вашему ответу в опросе\",\n \"Update your comment\": \"Обновите ваш комментарий\",\n \"Upload blocked\": \"Загрузка заблокирована\",\n \"Upload error\": \"Ошибка загрузки\",\n \"Upload failed\": \"Загрузка не удалась\",\n \"Upload Picture\": \"Загрузить изображение\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Тип загрузки: \\\"{{ type }}\\\" не разрешен\",\n \"User blocked\": \"Пользователь заблокирован\",\n \"User muted\": \"Уведомления пользователя отключены\",\n \"User removed\": \"Пользователь удалён\",\n \"User unblocked\": \"Пользователь разблокирован\",\n \"User unmuted\": \"Уведомления пользователя включены\",\n \"User uploaded content\": \"Пользователь загрузил контент\",\n \"Video\": \"Видео\",\n \"videoCount_one\": \"{{ count }} видео\",\n \"videoCount_few\": \"{{ count }} видео\",\n \"videoCount_many\": \"{{ count }} видео\",\n \"videoCount_other\": \"{{ count }} видео\",\n \"View\": \"Просмотр\",\n \"View {{count}} comments_one\": \"Просмотреть {{count}} комментарий\",\n \"View {{count}} comments_few\": \"Просмотреть {{count}} комментариев\",\n \"View {{count}} comments_many\": \"Просмотреть {{count}} комментариев\",\n \"View {{count}} comments_other\": \"Просмотреть {{count}} комментариев\",\n \"View all\": \"Показать все\",\n \"View member details for {{ member }}\": \"Просмотреть сведения об участнике {{ member }}\",\n \"View original\": \"Показать оригинал\",\n \"View results\": \"Посмотреть результаты\",\n \"View translation\": \"Показать перевод\",\n \"Voice message\": \"Голосовое сообщение\",\n \"Voice message {{ duration }}\": \"Голосовое сообщение {{ duration }}\",\n \"Voice message deleted\": \"Голосовое сообщение удалено\",\n \"voiceMessageCount_one\": \"{{ count }} голосовое сообщение\",\n \"voiceMessageCount_few\": \"{{ count }} голосовых сообщения\",\n \"voiceMessageCount_many\": \"{{ count }} голосовых сообщений\",\n \"voiceMessageCount_other\": \"{{ count }} голосовых сообщений\",\n \"Vote ended\": \"Голосование завершено\",\n \"Votes\": \"Голоса\",\n \"Wait until all attachments have uploaded\": \"Подождите, пока все вложения загрузятся\",\n \"Waiting for network…\": \"Ожидание сети…\",\n \"You\": \"Вы\",\n \"You've reached the maximum number of files\": \"Вы достигли максимального количества файлов\"\n}\n","{\n \"{{ commaSeparatedUsers }} and {{ moreCount }} more\": \"{{ commaSeparatedUsers }} ve {{ moreCount }} daha\",\n \"{{ commaSeparatedUsers }}, and {{ lastUser }}\": \"{{ commaSeparatedUsers }} ve {{ lastUser }}\",\n \"{{ count }} files_one\": \"{{ count }} dosya\",\n \"{{ count }} files_other\": \"{{ count }} dosya\",\n \"{{ count }} members_one\": \"{{ count }} üye\",\n \"{{ count }} members_other\": \"{{ count }} üye\",\n \"{{ count }} members added_one\": \"{{ count }} üye eklendi\",\n \"{{ count }} members added_other\": \"{{ count }} üye eklendi\",\n \"{{ count }} people are typing_one\": \"{{ count }} kişi yazıyor\",\n \"{{ count }} people are typing_many\": \"{{ count }} kişi yazıyor\",\n \"{{ count }} people are typing_other\": \"{{ count }} kişi yazıyor\",\n \"{{ count }} photos_one\": \"{{ count }} fotoğraf\",\n \"{{ count }} photos_other\": \"{{ count }} fotoğraf\",\n \"{{ count }} reactions_one\": \"{{ count }} tepki\",\n \"{{ count }} reactions_other\": \"{{ count }} tepki\",\n \"{{ count }} videos_one\": \"{{ count }} video\",\n \"{{ count }} videos_other\": \"{{ count }} video\",\n \"{{ firstUser }} and {{ secondUser }}\": \"{{ firstUser }} ve {{ secondUser }}\",\n \"{{ imageCount }} more\": \"{{ imageCount }} adet daha\",\n \"{{ member }} will be able to message you again.\": \"{{ member }} size tekrar mesaj gönderebilecek.\",\n \"{{ member }} won't be able to message you anymore.\": \"{{ member }} artık size mesaj gönderemeyecek.\",\n \"{{ memberCount }} members\": \"{{ memberCount }} üye\",\n \"{{ typing }} are typing\": \"{{ typing }} yazıyor\",\n \"{{ typing }} is typing\": \"{{ typing }} yazıyor\",\n \"{{ user }} has been muted\": \"{{ user }} sessize alındı\",\n \"{{ user }} has been unmuted\": \"{{ user }} sesi açıldı\",\n \"{{ user }} is typing...\": \"{{ user }} yazıyor...\",\n \"{{ users }} and {{ user }} are typing...\": \"{{ users }} ve {{ user }} yazıyor...\",\n \"{{ users }} and more are typing...\": \"{{ users }} ve diğerleri yazıyor...\",\n \"{{ watcherCount }} online\": \"{{ watcherCount }} çevrimiçi\",\n \"{{count}} new messages_one\": \"{{count}} yeni mesaj\",\n \"{{count}} new messages_other\": \"{{count}} yeni mesaj\",\n \"{{count}} unread_one\": \"{{count}} okunmamış\",\n \"{{count}} unread_other\": \"{{count}} okunmamış\",\n \"{{count}} votes_one\": \"{{count}} oy\",\n \"{{count}} votes_other\": \"{{count}} oy\",\n \"+{{ imageCount }}\": \"+{{ imageCount }}\",\n \"+{{count}} more options_one\": \"+{{count}} seçenek daha\",\n \"+{{count}} more options_other\": \"+{{count}} seçenek daha\",\n \"🏙 Attachment...\": \"🏙 Ek...\",\n \"📊 {{createdBy}} created: {{ pollName}}\": \"📊 {{createdBy}} oluşturdu: {{ pollName}}\",\n \"📊 {{votedBy}} voted: {{pollOptionText}}\": \"📊 {{votedBy}} oy verdi: {{pollOptionText}}\",\n \"📍Shared location\": \"📍Paylaşılan konum\",\n \"Actions\": \"Actions\",\n \"Add\": \"Ekle\",\n \"Add {{ count }} members_one\": \"{{ count }} üye ekle\",\n \"Add {{ count }} members_other\": \"{{ count }} üye ekle\",\n \"Add a comment\": \"Yorum ekle\",\n \"Add a comment to your poll answer\": \"Anket yanıtınıza bir yorum ekleyin\",\n \"Add an option\": \"Bir seçenek ekle\",\n \"Add channel members\": \"Kanal üyeleri ekle\",\n \"Add members\": \"Üye ekle\",\n \"Add reaction\": \"Tepki ekle\",\n \"Admin\": \"Yönetici\",\n \"All results loaded\": \"Tüm sonuçlar yüklendi\",\n \"Allow access to camera\": \"Kameraya erişime izin ver\",\n \"Allow access to microphone\": \"Mikrofona erişime izin ver\",\n \"Allow comments\": \"Yorumlara izin ver\",\n \"Allow option suggestion\": \"Seçenek önerisine izin ver\",\n \"Allow others to add comments\": \"Diğerlerinin yorum eklemesine izin ver\",\n \"Already a member\": \"Zaten üye\",\n \"Also send as a direct message\": \"Ayrıca doğrudan mesaj olarak gönder\",\n \"Also send in channel\": \"Ayrıca kanala gönder\",\n \"Also sent in channel\": \"Kanala da gönderildi\",\n \"An error has occurred during recording\": \"Kayıt sırasında bir hata oluştu\",\n \"An error has occurred during the recording processing\": \"Kayıt işlemi sırasında bir hata oluştu\",\n \"Anonymous\": \"Anonim\",\n \"Anonymous poll\": \"Anonim anket\",\n \"Archive\": \"Arşivle\",\n \"Are you sure you want to delete this message?\": \"Bu mesajı silmek istediğinizden emin misiniz?\",\n \"Are you sure you want to leave this channel?\": \"Are you sure you want to leave this channel?\",\n \"aria/{{ count }} {{ suggestionsLabel }}_one\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} {{ suggestionsLabel }}_other\": \"{{ count }} {{ suggestionsLabel }}\",\n \"aria/{{ count }} attachment_one\": \"{{ count }} ek\",\n \"aria/{{ count }} attachment_other\": \"{{ count }} ek\",\n \"aria/{{ count }} search results_one\": \"{{ count }} arama sonucu\",\n \"aria/{{ count }} search results_other\": \"{{ count }} arama sonucu\",\n \"aria/{{ count }} suggestions_one\": \"{{ count }} öneri\",\n \"aria/{{ count }} suggestions_other\": \"{{ count }} öneri\",\n \"aria/{{ count }} unread message_one\": \"{{ count }} okunmamış mesaj\",\n \"aria/{{ count }} unread message_other\": \"{{ count }} okunmamış mesaj\",\n \"aria/{{ setting }} disabled\": \"{{ setting }} devre dışı bırakıldı\",\n \"aria/{{ setting }} enabled\": \"{{ setting }} etkinleştirildi\",\n \"aria/Active\": \"Etkin\",\n \"aria/Animated GIF\": \"Hareketli GIF\",\n \"aria/Animated GIF: {{ title }}\": \"Hareketli GIF: {{ title }}\",\n \"aria/Attachment\": \"Ek\",\n \"aria/Attachment {{ attachmentType }}\": \"Ek {{ attachmentType }}\",\n \"aria/Attachment Actions\": \"Ek işlemleri\",\n \"aria/audio\": \"ses\",\n \"aria/Audio position {{ elapsed }} of {{ duration }}\": \"Ses konumu {{ elapsed }} / {{ duration }}\",\n \"aria/Audio position {{ progress }} percent\": \"Ses konumu yüzde {{ progress }}\",\n \"aria/Back to attachments\": \"Eklere geri dön\",\n \"aria/Back to parent menu button\": \"Üst menüye geri dön düğme\",\n \"aria/Block User\": \"Kullanıcıyı engelle\",\n \"aria/Bookmark Message\": \"Mesajı yer imi ekle\",\n \"aria/Cancel recording\": \"Kaydı iptal et\",\n \"aria/Cancel Reply\": \"Cevabı İptal Et\",\n \"aria/Channel Actions\": \"Kanal işlemleri\",\n \"aria/Channel details\": \"Kanal ayrıntıları\",\n \"aria/Channel list\": \"Kanal listesi\",\n \"aria/Chat view controls\": \"Sohbet görünümü kontrolleri\",\n \"aria/Chat: {{ channelName }}\": \"Sohbet: {{ channelName }}\",\n \"aria/Clear search\": \"Aramayı temizle\",\n \"aria/Close callout dialog\": \"Bilgi balonu iletişim kutusunu kapat\",\n \"aria/Close thread\": \"Konuyu kapat\",\n \"aria/Collapse sidebar\": \"Kenar çubuğunu daralt\",\n \"aria/Command activated: {{ command }}\": \"Komut etkinleştirildi: {{ command }}\",\n \"aria/Command Suggestions\": \"Komut önerileri\",\n \"aria/Complete recording\": \"Kaydı tamamla\",\n \"aria/Copy Message Text\": \"Mesaj metnini kopyala\",\n \"aria/Decrease value\": \"Değeri azalt\",\n \"aria/Delete Message\": \"Mesajı sil\",\n \"aria/Delivered\": \"İletildi\",\n \"aria/Delivery status: {{ deliveryStatus }}\": \"Teslim durumu: {{ deliveryStatus }}\",\n \"aria/Dismiss notification\": \"Bildirimi kapat\",\n \"aria/Download attachment\": \"Ek indir\",\n \"aria/Dropped \\\"{{ option }}\\\" at position {{ position }}.\": \"\\\"{{ option }}\\\" {{ position }}. konuma bırakıldı.\",\n \"aria/Edit Message\": \"Mesajı Düzenle\",\n \"aria/Emoji picker\": \"Emoji seçici\",\n \"aria/Emoji Suggestions\": \"Emoji önerileri\",\n \"aria/Exit search\": \"Aramadan çık\",\n \"aria/Expand sidebar\": \"Kenar çubuğunu genişlet\",\n \"aria/file\": \"dosya\",\n \"aria/File upload\": \"Dosya yükleme\",\n \"aria/Flag Message\": \"Mesajı bayrakla\",\n \"aria/GIF\": \"GIF\",\n \"aria/Giphy actions\": \"Giphy işlemleri\",\n \"aria/Giphy canceled\": \"Giphy iptal edildi\",\n \"aria/Giphy image changed\": \"Giphy görseli değişti\",\n \"aria/Giphy image changed: {{ title }}\": \"Giphy görseli değişti: {{ title }}\",\n \"aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.\": \"Giphy önizlemesi, yalnızca size görünür. Gönder, Karıştır veya İptal işlemlerini kullanın.\",\n \"aria/Giphy sent\": \"Giphy gönderildi\",\n \"aria/image\": \"görsel\",\n \"aria/Image failed to load\": \"Görsel yüklenemedi\",\n \"aria/Increase value\": \"Değeri artır\",\n \"aria/Jump to latest message\": \"En son mesaja git\",\n \"aria/Jump to quoted message\": \"Alıntılanan mesaja git\",\n \"aria/Last activity: {{ time }}\": \"Son etkinlik: {{ time }}\",\n \"aria/Last message from {{ sender }}: {{ messagePreview }}\": \"{{ sender }} kişisinden son mesaj: {{ messagePreview }}\",\n \"aria/Last message: {{ messagePreview }}\": \"Son mesaj: {{ messagePreview }}\",\n \"aria/Mark Message Unread\": \"Okunmamış olarak işaretle\",\n \"aria/Mark messages as read\": \"Mesajları okundu olarak işaretle\",\n \"aria/Mention Suggestions\": \"Bahsetme önerileri\",\n \"aria/Message Actions\": \"Mesaj eylemleri\",\n \"aria/Message from {{ user }},\": \"{{ user }} adlı kullanıcıdan mesaj,\",\n \"aria/Message input\": \"Mesaj girişi\",\n \"aria/Message with attachments\": \"Ekli mesaj\",\n \"aria/Message,\": \"Mesaj,\",\n \"aria/Mute User\": \"Kullanıcıyı sustur\",\n \"aria/Next page\": \"Sonraki sayfa\",\n \"aria/No search results found\": \"Arama sonucu bulunamadı\",\n \"aria/Notifications\": \"Bildirimler\",\n \"aria/Open Attachment Selector\": \"Ek Seçiciyi Aç\",\n \"aria/Open Channel Actions Menu\": \"Kanal işlemleri menüsünü aç\",\n \"aria/Open channel details\": \"Kanal ayrıntılarını aç\",\n \"aria/Open channels view\": \"Kanal görünümünü aç\",\n \"aria/Open image shared by {{ name }}\": \"{{ name }} tarafından paylaşılan resmi aç\",\n \"aria/Open Message Actions Menu\": \"Mesaj İşlemleri Menüsünü Aç\",\n \"aria/Open Reaction Selector\": \"Tepki Seçiciyi Aç\",\n \"aria/Open Thread\": \"Konuyu Aç\",\n \"aria/Open threads view\": \"Konu görünümünü aç\",\n \"aria/Open threads view with unread threads_one\": \"Konu görünümünü aç, {{ count }} okunmamış konu\",\n \"aria/Open threads view with unread threads_other\": \"Konu görünümünü aç, {{ count }} okunmamış konu\",\n \"aria/Open video shared by {{ name }}\": \"{{ name }} tarafından paylaşılan videoyu aç\",\n \"aria/Opened channel: {{ name }}\": \"Kanal açıldı: {{ name }}\",\n \"aria/Opened thread in {{ name }}\": \"{{ name }} içinde konu açıldı\",\n \"aria/Option {{ position }}\": \"Seçenek {{ position }}\",\n \"aria/Options can now be reordered and removed.\": \"Seçenekler artık yeniden sıralanabilir ve kaldırılabilir.\",\n \"aria/Pause\": \"Duraklat\",\n \"aria/Pause recording\": \"Kaydı duraklat\",\n \"aria/Percent complete\": \"Yüzde {{percent}} tamamlandı\",\n \"aria/Picked up \\\"{{ option }}\\\". Use arrow keys to reorder. Press Space or Tab to drop.\": \"\\\"{{ option }}\\\" alındı. Yeniden sıralamak için ok tuşlarını kullanın. Bırakmak için Boşluk veya Sekme tuşuna basın.\",\n \"aria/Pin Message\": \"Mesajı sabitle\",\n \"aria/Play\": \"Oynat\",\n \"aria/Poll dialog opened\": \"Anket iletişim kutusu açıldı\",\n \"aria/Poll sent\": \"Anket gönderildi\",\n \"aria/Poll: {{ pollName }}\": \"Anket: {{ pollName }}\",\n \"aria/Press Enter to start typing\": \"Yazmaya başlamak için Enter'a basın\",\n \"aria/Press Space to select this option, use the Up and Down arrow keys to move it, then press Space again to deselect it.\": \"Bu seçeneği seçmek için Boşluk tuşuna basın, taşımak için Yukarı ve Aşağı ok tuşlarını kullanın, ardından seçimi kaldırmak için Boşluk tuşuna tekrar basın.\",\n \"aria/Previous page\": \"Önceki sayfa\",\n \"aria/Quote Message\": \"Mesajı alıntıla\",\n \"aria/Reaction list\": \"Tepki listesi\",\n \"aria/Read\": \"Okundu\",\n \"aria/Recording paused\": \"Kayıt duraklatıldı\",\n \"aria/Recording resumed\": \"Kayıt devam ettirildi\",\n \"aria/Recording started\": \"Kayıt başladı\",\n \"aria/Remind Me Message\": \"Hatırlat\",\n \"aria/Remove attachment\": \"Eki kaldır\",\n \"aria/Remove location attachment\": \"Konum ekini kaldır\",\n \"aria/Remove option: {{ option }}\": \"Seçeneği kaldır: {{ option }}\",\n \"aria/Remove Reminder\": \"Hatırlatıcıyı kaldır\",\n \"aria/Remove Save For Later\": \"Sonraya kaydet'i kaldır\",\n \"aria/Removed option {{ option }}\": \"{{ option }} seçeneği kaldırıldı\",\n \"aria/Reorder \\\"{{ option }}\\\" at position {{ position }} of {{ total }}\": \"\\\"{{ option }}\\\" sırasını değiştir, {{ total }} konumdan {{ position }}.\",\n \"aria/Reorder option {{ position }}\": \"Seçenek {{ position }} sırasını değiştir\",\n \"aria/Resend Message\": \"Mesajı tekrar gönder\",\n \"aria/Resume recording\": \"Kaydı devam ettir\",\n \"aria/Retry upload\": \"Yüklemeyi Tekrar Dene\",\n \"aria/Review bounced message\": \"Geri dönen mesajı incele\",\n \"aria/Search cleared\": \"Arama temizlendi\",\n \"aria/Search results\": \"Arama sonuçları\",\n \"aria/Search results header filter button for: {{ source }}\": \"{{ source }} için arama sonuçları başlık filtre düğmesi\",\n \"aria/Seek audio position\": \"Ses konumunu ara\",\n \"aria/Select Reaction: {{ reactionName }}\": \"Tepki seç: {{ reactionName }}\",\n \"aria/Select User Channel: {{ name }}\": \"Kullanıcı kanalını seç: {{ name }}\",\n \"aria/Send\": \"Gönder\",\n \"aria/Sent\": \"Gönderildi\",\n \"aria/Shared a link\": \"Bağlantı paylaşıldı\",\n \"aria/Shared a link with title: {{ linkTitle }}\": \"Başlıklı bağlantı paylaşıldı: {{ linkTitle }}\",\n \"aria/Shared location\": \"Paylaşılan konum\",\n \"aria/Show preview\": \"Önizlemeyi göster\",\n \"aria/Start recording audio\": \"Ses kaydını başlat\",\n \"aria/Stop AI Generation\": \"Yapay Zeka Üretimini Durdur\",\n \"aria/Submenu\": \"Alt menü\",\n \"aria/Suggestions\": \"Öneriler\",\n \"aria/There are no messages in this chat.\": \"Bu sohbette mesaj yok\",\n \"aria/This option can be reordered and removed.\": \"Bu seçenek yeniden sıralanabilir ve kaldırılabilir.\",\n \"aria/Thread list\": \"İleti dizisi listesi\",\n \"aria/Thread: {{ messagePreview }}\": \"Konu: {{ messagePreview }}\",\n \"aria/Unblock User\": \"Kullanıcının engelini kaldır\",\n \"aria/Unmute User\": \"Sesini aç\",\n \"aria/Unpin Message\": \"Sabitlemeyi kaldır\",\n \"aria/User selected: {{ user }}\": \"Seçilen kullanıcı: {{ user }}\",\n \"aria/video\": \"video\",\n \"aria/voice message\": \"sesli mesaj\",\n \"aria/Voice message sent\": \"Sesli mesaj gönderildi\",\n \"aria/Voice recording attached\": \"Ses kaydı eklendi\",\n \"Ask a question\": \"Bir soru sor\",\n \"Attach\": \"Ekle\",\n \"Attach files\": \"Dosya ekle\",\n \"Attachment\": \"Ek\",\n \"Attachment upload blocked due to {{reason}}\": \"{{reason}} nedeniyle ek yükleme engellendi\",\n \"Attachment upload failed due to {{reason}}\": \"{{reason}} nedeniyle ek yükleme başarısız oldu\",\n \"Back\": \"Geri\",\n \"ban-command-args\": \"[@kullanıcıadı] [metin]\",\n \"ban-command-description\": \"Bir kullanıcıyı yasakla\",\n \"Block user\": \"Kullanıcıyı engelle\",\n \"Block User\": \"Kullanıcıyı engelle\",\n \"Browse channel members\": \"Kanal üyelerine göz at\",\n \"Browse pinned messages\": \"Sabitlenmiş mesajlara göz at\",\n \"Cancel\": \"İptal\",\n \"Cannot seek in the recording\": \"Kayıtta arama yapılamıyor\",\n \"Changes saved\": \"Değişiklikler kaydedildi\",\n \"Channel archived\": \"Kanal arşivlendi\",\n \"Channel members\": \"Kanal üyeleri\",\n \"Channel Missing\": \"Kanal bulunamıyor\",\n \"Channel muted\": \"Kanal sessize alındı\",\n \"Channel pinned\": \"Kanal sabitlendi\",\n \"Channel unarchived\": \"Kanal arşivden çıkarıldı\",\n \"Channel unmuted\": \"Kanal sesi açıldı\",\n \"Channel unpinned\": \"Kanal sabitlemesi kaldırıldı\",\n \"Channels\": \"Kanallar\",\n \"Chat deleted\": \"Chat deleted\",\n \"Chats\": \"Sohbetler\",\n \"Choose between 2 to 10 options\": \"2 ile 10 seçenek arasından seçin\",\n \"Close\": \"Kapat\",\n \"Close dialog\": \"İletişim kutusunu kapat\",\n \"Close emoji picker\": \"Emoji seçiciyi kapat\",\n \"Command not available while editing\": \"Düzenleme sırasında komut kullanılamaz\",\n \"Command not available while replying\": \"Yanıtlama sırasında komut kullanılamaz\",\n \"Commands\": \"Komutlar\",\n \"Commands matching\": \"Eşleşen komutlar\",\n \"Connection failure, reconnecting now...\": \"Bağlantı hatası, tekrar bağlanılıyor...\",\n \"Contact info\": \"İletişim bilgileri\",\n \"Contact name\": \"Kişi adı\",\n \"Copy Message\": \"Mesajı kopyala\",\n \"Create\": \"Oluştur\",\n \"Create a question, add options, and configure poll settings\": \"Bir soru oluşturun, seçenekler ekleyin ve anket ayarlarını yapılandırın\",\n \"Create poll\": \"Anket oluştur\",\n \"Current location\": \"Mevcut konum\",\n \"Delete\": \"Sil\",\n \"Delete chat\": \"Sohbeti sil\",\n \"Delete for me\": \"Benim için sil\",\n \"Delete message\": \"Mesajı sil\",\n \"Delivered\": \"İletildi\",\n \"Direct message\": \"Doğrudan mesaj\",\n \"Do you want to end this poll now? Nobody will be able to vote in this poll anymore.\": \"Bu anketi şimdi sonlandırmak istiyor musunuz? Sonlandırdıktan sonra bu ankette kimse oy kullanamayacak.\",\n \"Download {{ fileName }}\": \"{{ fileName }} dosyasını indir\",\n \"Download All\": \"Tümünü indir\",\n \"Download Attachment\": \"Eki indir\",\n \"Download attachment {{ name }}\": \"Ek {{ name }}'i indir\",\n \"Download attachment {{ number }}\": \"{{ number }} numaralı eki indir\",\n \"Drag your files here\": \"Dosyalarınızı buraya sürükleyin\",\n \"Drag your files here to add to your post\": \"Gönderinize eklemek için dosyalarınızı buraya sürükleyin\",\n \"Due {{ timeLeft }}\": \"{{ timeLeft }} içinde süresi dolacak\",\n \"Due since {{ dueSince }}\": \"{{ dueSince }}'den beri süresi dolmuş\",\n \"duration/Message reminder\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Remind Me\": \"{{ milliseconds | durationFormatter(withSuffix: true) }}\",\n \"duration/Share Location\": \"{{ milliseconds | durationFormatter }}\",\n \"Edit\": \"Düzenle\",\n \"Edit chat data\": \"Sohbet verilerini düzenle\",\n \"Edit contact\": \"Kişiyi düzenle\",\n \"Edit group\": \"Grubu düzenle\",\n \"Edit Message\": \"Mesajı Düzenle\",\n \"Edit message request failed\": \"Mesaj düzenleme isteği başarısız oldu\",\n \"Edited\": \"Düzenlendi\",\n \"Emoji matching\": \"Emoji eşleştirme\",\n \"Empty message...\": \"Boş mesaj...\",\n \"End\": \"Son\",\n \"End poll\": \"Anketi sonlandır\",\n \"End this poll?\": \"Bu anketi sonlandır?\",\n \"End vote\": \"Oyu bitir\",\n \"Enforce unique vote is enabled\": \"Benzersiz oy etkinleştirildi\",\n \"Error\": \"Hata\",\n \"Error adding flag\": \"Bayrak eklenirken hata oluştu\",\n \"Error adding members\": \"Error adding members\",\n \"Error blocking user\": \"Kullanıcı engellenirken hata oluştu\",\n \"Error connecting to chat, refresh the page to try again.\": \"Bağlantı hatası, sayfayı yenileyip tekrar deneyin.\",\n \"Error deleting chat\": \"Error deleting chat\",\n \"Error deleting message\": \"Mesaj silinirken hata oluştu\",\n \"Error fetching reactions\": \"Reaksiyonlar alınırken hata oluştu\",\n \"Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.\": \"Mesajı okunmamış olarak işaretleme hatası. En yeni 100 kanal mesajından daha eski okunmamış mesajları işaretleme yapılamaz.\",\n \"Error muting a user ...\": \"Kullanıcıyı sessize alırken hata oluştu ...\",\n \"Error muting channel\": \"Kanal sessize alınırken hata oluştu\",\n \"Error muting user\": \"Kullanıcı sessize alınırken hata oluştu\",\n \"Error opening direct message\": \"Direkt mesaj açılırken hata oluştu\",\n \"Error pinning message\": \"Mesaj sabitlenirken hata oluştu\",\n \"Error removing members\": \"Üyeler kaldırılırken hata oluştu\",\n \"Error removing message pin\": \"Mesaj PIN'i kaldırılırken hata oluştu\",\n \"Error removing user\": \"Kullanıcı kaldırılırken hata oluştu\",\n \"Error reproducing the recording\": \"Kaydı yeniden üretme hatası\",\n \"Error starting recording\": \"Kayıt başlatılırken hata oluştu\",\n \"Error unblocking user\": \"Kullanıcının engeli kaldırılırken hata oluştu\",\n \"Error unmuting a user ...\": \"Kullanıcının sesini açarken hata oluştu ...\",\n \"Error unmuting channel\": \"Kanalın sesi açılırken hata oluştu\",\n \"Error unmuting user\": \"Kullanıcının sesi açılırken hata oluştu\",\n \"Error uploading attachment\": \"Ek yüklenirken hata oluştu\",\n \"Error uploading file\": \"Dosya yüklenirken hata oluştu\",\n \"Error uploading image\": \"Resmi yüklerken hata\",\n \"Error: {{ errorMessage }}\": \"Hata: {{ errorMessage }}\",\n \"Exit command {{ command }}\": \"Komuttan çık {{ command }}\",\n \"Failed to block user\": \"Kullanıcı engellenemedi\",\n \"Failed to create the poll\": \"Anket oluşturulurken hata oluştu\",\n \"Failed to create the poll due to {{reason}}\": \"{{reason}} nedeniyle anket oluşturulamadı\",\n \"Failed to delete the message\": \"Mesaj silinemedi\",\n \"Failed to end the poll\": \"Anket sonlandırılamadı\",\n \"Failed to end the poll due to {{reason}}\": \"{{reason}} nedeniyle anket sonlandırılamadı\",\n \"Failed to jump to the first unread message\": \"İlk okunmamış mesaja atlamada hata oluştu\",\n \"Failed to leave channel\": \"Kanaldan çıkılamadı\",\n \"Failed to load channels\": \"Kanallar yüklenemedi\",\n \"Failed to load more channels\": \"Daha fazla kanal yüklenemedi\",\n \"Failed to mark channel as read\": \"Kanalı okundu olarak işaretleme başarısız oldu\",\n \"Failed to play the recording\": \"Kayıt oynatılamadı\",\n \"Failed to retrieve location\": \"Konum alınamadı\",\n \"Failed to save changes\": \"Değişiklikler kaydedilemedi\",\n \"Failed to share location\": \"Konum paylaşılamadı\",\n \"Failed to update channel archive status\": \"Kanalın arşiv durumu güncellenemedi\",\n \"Failed to update channel mute status\": \"Kanalın sessiz durumu güncellenemedi\",\n \"Failed to update channel pinned status\": \"Kanalın sabitleme durumu güncellenemedi\",\n \"File\": \"Dosya\",\n \"File is required for upload attachment\": \"Ek yüklemek için dosya gerekli\",\n \"File is too large: {{ size }}, maximum upload size is {{ limit }}\": \"Dosya çok büyük: {{ size }}, maksimum yükleme boyutu {{ limit }}\",\n \"File too large\": \"Dosya çok büyük\",\n \"fileCount_one\": \"1 dosya\",\n \"fileCount_other\": \"{{ count }} dosya\",\n \"Files\": \"Dosyalar\",\n \"Flag\": \"Bayrak\",\n \"Generating...\": \"Oluşturuluyor...\",\n \"giphy-command-args\": \"[metin]\",\n \"giphy-command-description\": \"Rastgele bir gif'i kanala gönder\",\n \"Go back\": \"Geri dön\",\n \"Group info\": \"Grup bilgileri\",\n \"Group name\": \"Grup adı\",\n \"Hide who voted\": \"Kimin oy verdiğini gizle\",\n \"Image\": \"Görsel\",\n \"imageCount_one\": \"Görsel\",\n \"imageCount_other\": \"{{ count }} görsel\",\n \"Instant commands\": \"Anlık komutlar\",\n \"language/af\": \"Afrikanca\",\n \"language/am\": \"Amharca\",\n \"language/ar\": \"Arapça\",\n \"language/az\": \"Azerice\",\n \"language/bg\": \"Bulgarca\",\n \"language/bn\": \"Bengalce\",\n \"language/bs\": \"Boşnakça\",\n \"language/cs\": \"Çekçe\",\n \"language/da\": \"Danca\",\n \"language/de\": \"Almanca\",\n \"language/el\": \"Yunanca\",\n \"language/en\": \"İngilizce\",\n \"language/es\": \"İspanyolca\",\n \"language/es-MX\": \"İspanyolca (Meksika)\",\n \"language/et\": \"Estonyaca\",\n \"language/fa\": \"Farsça\",\n \"language/fa-AF\": \"Darice\",\n \"language/fi\": \"Fince\",\n \"language/fr\": \"Fransızca\",\n \"language/fr-CA\": \"Fransızca (Kanada)\",\n \"language/ha\": \"Hausaca\",\n \"language/he\": \"İbranice\",\n \"language/hi\": \"Hintçe\",\n \"language/hr\": \"Hırvatça\",\n \"language/ht\": \"Haiti Kreolcesi\",\n \"language/hu\": \"Macarca\",\n \"language/id\": \"Endonezce\",\n \"language/it\": \"İtalyanca\",\n \"language/ja\": \"Japonca\",\n \"language/ka\": \"Gürcüce\",\n \"language/ko\": \"Korece\",\n \"language/lt\": \"Litvanca\",\n \"language/lv\": \"Letonca\",\n \"language/ms\": \"Malayca\",\n \"language/nl\": \"Felemenkçe\",\n \"language/no\": \"Norveççe\",\n \"language/pl\": \"Lehçe\",\n \"language/ps\": \"Peştuca\",\n \"language/pt\": \"Portekizce\",\n \"language/ro\": \"Romence\",\n \"language/ru\": \"Rusça\",\n \"language/sk\": \"Slovakça\",\n \"language/sl\": \"Slovence\",\n \"language/so\": \"Somalice\",\n \"language/sq\": \"Arnavutça\",\n \"language/sr\": \"Sırpça\",\n \"language/sv\": \"İsveççe\",\n \"language/sw\": \"Svahilice\",\n \"language/ta\": \"Tamilce\",\n \"language/th\": \"Tayca\",\n \"language/tl\": \"Tagalogca\",\n \"language/tr\": \"Türkçe\",\n \"language/uk\": \"Ukraynaca\",\n \"language/ur\": \"Urduca\",\n \"language/vi\": \"Vietnamca\",\n \"language/zh\": \"Çince (basitleştirilmiş)\",\n \"language/zh-TW\": \"Çince (geleneksel)\",\n \"Last seen {{ timestamp }}\": \"Son görülme {{ timestamp }}\",\n \"Leave Channel\": \"Kanaldan ayrıl\",\n \"Leave chat\": \"Kanaldan ayrıl\",\n \"Left channel\": \"Kanaldan ayrıldınız\",\n \"Let others add options\": \"Başkalarının seçenek eklemesine izin ver\",\n \"Limit votes per person\": \"Kişi başına oy sınırı\",\n \"Link\": \"Bağlantı\",\n \"linkCount_one\": \"Bağlantı\",\n \"linkCount_other\": \"{{ count }} bağlantı\",\n \"live\": \"canlı\",\n \"Live for {{duration}}\": \"{{duration}} boyunca canlı\",\n \"Live location\": \"Canlı konum\",\n \"Live until {{ timestamp }}\": \"{{ timestamp }}'e kadar canlı\",\n \"Load more\": \"Daha fazla yükle\",\n \"Local upload attachment missing local id\": \"Yerel yükleme ekinde yerel kimlik eksik\",\n \"Location\": \"Konum\",\n \"Location sharing ended\": \"Konum paylaşımı sona erdi\",\n \"Location: {{ coordinates }}\": \"Konum: {{ coordinates }}\",\n \"Manage channel\": \"Kanalı yönet\",\n \"Manage members\": \"Üyeleri yönet\",\n \"Mark as unread\": \"Okunmamış olarak işaretle\",\n \"Maximum number of votes (from 2 to 10)\": \"Maksimum oy sayısı (2 ile 10 arası)\",\n \"Maximum votes per person\": \"Kişi başına maksimum oy\",\n \"Member detail\": \"Üye detayı\",\n \"mention/Channel\": \"Kanal\",\n \"mention/Channel Description\": \"Bu kanaldaki herkesi bildir\",\n \"mention/Here\": \"Burada\",\n \"mention/Here Description\": \"Bu kanaldaki tüm çevrimiçi üyeleri bildir\",\n \"Menu\": \"Menü\",\n \"Message deleted\": \"Mesaj silindi\",\n \"Message failed to send\": \"Mesaj gönderilemedi\",\n \"Message has been successfully flagged\": \"Mesaj başarıyla bayraklandı\",\n \"Message marked as unread\": \"Mesaj okunmadı olarak işaretlendi\",\n \"Message pinned\": \"Mesaj sabitlendi\",\n \"Message unpinned\": \"Mesaj sabitlemesi kaldırıldı\",\n \"Message was blocked by moderation policies\": \"Mesaj moderasyon politikaları tarafından engellendi\",\n \"Messages have been marked unread.\": \"Mesajlar okunmamış olarak işaretlendi.\",\n \"Missing permissions to upload the attachment\": \"Ek yüklemek için izinler eksik\",\n \"Moderator\": \"Moderatör\",\n \"Multiple votes\": \"Çoklu oy\",\n \"Mute\": \"Sessiz\",\n \"Mute chat\": \"Sohbeti sessize al\",\n \"Mute user\": \"Kullanıcıyı sessize al\",\n \"mute-command-args\": \"[@kullanıcıadı]\",\n \"mute-command-description\": \"Bir kullanıcının sesini kapat\",\n \"network error\": \"ağ hatası\",\n \"New\": \"Yeni\",\n \"New message from {{user}}\": \"{{user}} adlı kullanıcıdan yeni mesaj\",\n \"New Messages!\": \"Yeni Mesajlar!\",\n \"Next\": \"İleri\",\n \"Next image\": \"Sonraki görsel\",\n \"No chats here yet…\": \"Henüz burada sohbet yok...\",\n \"No conversations yet\": \"Henüz konuşma yok\",\n \"No files\": \"Dosya yok\",\n \"No items exist\": \"Hiç öğe yok\",\n \"No member found\": \"Üye bulunamadı\",\n \"No messages found\": \"Mesaj bulunamadı\",\n \"No photos or videos\": \"Fotoğraf veya video yok\",\n \"No pinned messages\": \"Sabitlenmiş mesaj yok\",\n \"No results found\": \"Sonuç bulunamadı\",\n \"No user found\": \"Kullanıcı bulunamadı\",\n \"Nobody will be able to vote in this poll anymore.\": \"Artık bu ankette kimse oy kullanamayacak.\",\n \"Nothing yet...\": \"Şimdilik hiçbir şey...\",\n \"Notify all {{ role }} members\": \"{{ role }} rolündeki tüm üyelere bildir\",\n \"Offline\": \"Çevrimdışı\",\n \"Ok\": \"Tamam\",\n \"Online\": \"Çevrimiçi\",\n \"Only numbers are allowed\": \"Sadece sayılar kullanılabilir\",\n \"Only visible to you\": \"Sadece sana görünür\",\n \"Open emoji picker\": \"Emoji klavyesini aç\",\n \"Open gallery at image {{ index }}\": \"Galeriyi {{ index }}. görselde aç\",\n \"Open image in gallery\": \"Görseli galeride aç\",\n \"Open location in a map\": \"Konumu haritada aç\",\n \"Open members actions\": \"Open members actions\",\n \"Open menu\": \"Menüyü aç\",\n \"Option already exists\": \"Seçenek zaten mevcut\",\n \"Option is empty\": \"Seçenek boş\",\n \"Options\": \"Seçenekler\",\n \"Original\": \"Orijinal\",\n \"Owner\": \"Sahip\",\n \"People matching\": \"Eşleşen kişiler\",\n \"Photo\": \"Fotoğraf\",\n \"Photos & videos\": \"Fotoğraflar ve videolar\",\n \"Pin\": \"Sabitle\",\n \"Pin a message to see it here\": \"Burada görmek için bir mesaj sabitle\",\n \"Pinned by {{ name }}\": \"{{ name }} sabitledi\",\n \"Pinned by You\": \"Sizin sabitlediğiniz\",\n \"Pinned message\": \"Sabitlenmiş mesaj\",\n \"Pinned messages\": \"Sabitlenmiş mesajlar\",\n \"placeholder/PollComment\": \"Yorumunuz\",\n \"placeholder/PollOptionSuggestion\": \"Yeni bir seçenek girin\",\n \"Play video\": \"Videoyu oynat\",\n \"Playback speed {{ rate }}x\": \"Oynatma hızı {{ rate }}x\",\n \"Poll\": \"Anket\",\n \"Poll comments\": \"Anket yorumları\",\n \"Poll ended\": \"Anket sonlandı\",\n \"Poll options\": \"Anket seçenekleri\",\n \"Poll results\": \"Anket sonuçları\",\n \"Poll sent\": \"Anket gönderildi\",\n \"Previous\": \"Geri\",\n \"Previous image\": \"Önceki görsel\",\n \"Question\": \"Soru\",\n \"Question {{ optionOrderNumber}}\": \"Soru {{ optionOrderNumber}}\",\n \"Question is required\": \"Soru gereklidir\",\n \"Quote Reply\": \"Alıntıyla yanıtla\",\n \"Reached the vote limit. Remove an existing vote first.\": \"Oylama sınırına ulaşıldı. Önce mevcut bir oyu kaldırın.\",\n \"Recording format is not supported and cannot be reproduced\": \"Kayıt formatı desteklenmiyor ve çoğaltılamıyor\",\n \"Remind me\": \"Bana hatırlat\",\n \"Remind Me\": \"Hatırlat\",\n \"Reminder set\": \"Hatırlatıcı ayarlandı\",\n \"Remove\": \"Kaldır\",\n \"Remove {{ count }} members_one\": \"{{ count }} üyeyi kaldır\",\n \"Remove {{ count }} members_other\": \"{{ count }} üyeyi kaldır\",\n \"Remove {{ member }} from this channel?\": \"{{ member }} bu kanaldan kaldırılsın mı?\",\n \"Remove channel members\": \"Kanal üyelerini kaldır\",\n \"Remove reminder\": \"Hatırlatıcıyı kaldır\",\n \"Remove save for later\": \"Sonraya kaydet'i kaldır\",\n \"Remove user\": \"Kullanıcıyı kaldır\",\n \"Removed {{ count }} members_one\": \"{{ count }} üye kaldırıldı\",\n \"Removed {{ count }} members_other\": \"{{ count }} üye kaldırıldı\",\n \"Replied to a thread\": \"Bir iş parçacığına yanıt verdi\",\n \"Reply\": \"Cevapla\",\n \"Reply to {{ authorName }}\": \"{{ authorName }} kişisine yanıt ver\",\n \"Reply to a message to start a thread\": \"Bir thread başlatmak için bir mesaja yanıt verin\",\n \"Reply to Message\": \"Mesaja Cevapla\",\n \"replyCount_one\": \"1 cevap\",\n \"replyCount_other\": \"{{ count }} cevap\",\n \"Resend\": \"Tekrar gönder\",\n \"Retry upload\": \"Yüklemeyi yeniden dene\",\n \"Review all options available in this poll\": \"Bu anketteki tüm mevcut seçenekleri inceleyin\",\n \"Review comments submitted with poll answers\": \"Anket yanıtlarıyla gönderilen yorumları inceleyin\",\n \"Review poll results and open an option to see detailed votes\": \"Anket sonuçlarını inceleyin ve ayrıntılı oyları görmek için bir seçenek açın\",\n \"Review this message and choose whether to delete it, edit it, or send it anyway\": \"Bu mesajı inceleyin ve silmeyi, düzenlemeyi veya yine de göndermeyi seçin\",\n \"Review who voted for this option\": \"Bu seçenek için kimlerin oy verdiğini inceleyin\",\n \"Save\": \"Kaydet\",\n \"Save for later\": \"Daha sonra kaydet\",\n \"Saved for later\": \"Daha sonra kaydedildi\",\n \"Search\": \"Arama\",\n \"Search GIFs\": \"GIF ara\",\n \"search-results-header-filter-source-button-label--channels\": \"kanallar\",\n \"search-results-header-filter-source-button-label--messages\": \"mesajlar\",\n \"search-results-header-filter-source-button-label--users\": \"kullanıcılar\",\n \"Searching for {{ searchSourceType }}...\": \"{{ searchSourceType }} aranıyor...\",\n \"Searching...\": \"Aranıyor...\",\n \"searchResultsCount_one\": \"1 sonuç\",\n \"searchResultsCount_other\": \"{{ count }} sonuç\",\n \"Select a thread to continue the conversation\": \"Sohbeti sürdürmek için bir ileti dizisi seçin\",\n \"Select more than one option\": \"Birden fazla seçenek seçin\",\n \"Select one\": \"Birini seçin\",\n \"Select one or more\": \"Bir veya daha fazlasını seçin\",\n \"Select up to {{count}}_one\": \"En fazla {{count}}'yi seçin\",\n \"Select up to {{count}}_other\": \"En fazla {{count}}'yi seçin\",\n \"Select your current location and optionally enable live location sharing\": \"Mevcut konumunuzu seçin ve isteğe bağlı olarak canlı konum paylaşımını etkinleştirin\",\n \"Send\": \"Gönder\",\n \"Send a message\": \"Bir mesaj gönderin\",\n \"Send a message to start the conversation\": \"Sohbete başlamak için bir mesaj gönderin\",\n \"Send Anyway\": \"Yine de gönder\",\n \"Send direct message\": \"Direkt mesaj gönder\",\n \"Send message request failed\": \"Mesaj gönderme isteği başarısız oldu\",\n \"Send poll\": \"Anketi gönder\",\n \"Sending...\": \"Gönderiliyor...\",\n \"Sent\": \"Gönderildi\",\n \"Share\": \"Paylaş\",\n \"Share a file to see it here\": \"Burada görmek için bir dosya paylaşın\",\n \"Share a photo or video to see it here\": \"Burada görmek için bir fotoğraf veya video paylaşın\",\n \"Share live location for\": \"Canlı konum paylaş\",\n \"Share Location\": \"Konum Paylaş\",\n \"Shared live location\": \"Paylaşılan canlı konum\",\n \"Shared location\": \"Paylaşılan konum\",\n \"Shuffle\": \"Karıştır\",\n \"size limit\": \"boyut sınırı\",\n \"Slow Mode ON\": \"Yavaş Mod Açık\",\n \"Slow mode, wait {{ seconds }}s...\": \"Yavaş mod, {{ seconds }} sn bekleyin...\",\n \"Some of the files will not be accepted\": \"Bazı dosyalar kabul edilmeyecek\",\n \"Start typing to search\": \"Aramak için yazmaya başlayın\",\n \"Stop sharing\": \"Paylaşımı durdur\",\n \"Submit\": \"Gönder\",\n \"Suggest a new option to add to this poll\": \"Bu ankete eklenecek yeni bir seçenek önerin\",\n \"Suggest an option\": \"Bir seçenek önerin\",\n \"Tap to remove\": \"Kaldırmak için dokunun\",\n \"Tap to remove: {{ reactionName }}\": \"Kaldırmak için dokunun: {{ reactionName }}\",\n \"Thinking...\": \"Düşünüyor...\",\n \"this content could not be displayed\": \"bu içerik gösterilemiyor\",\n \"This field cannot be empty or contain only spaces\": \"Bu alan boş olamaz veya sadece boşluk içeremez\",\n \"This message did not meet our content guidelines\": \"Bu mesaj içerik yönergelerimize uygun değil\",\n \"This permanently deletes your message history with {{ user }}. This can't be undone.\": \"This permanently deletes your message history with {{ user }}. This can't be undone.\",\n \"This user will be able to message you again.\": \"Bu kullanıcı size tekrar mesaj gönderebilecek.\",\n \"This user won't be able to message you anymore. You can unblock them anytime.\": \"This user won't be able to message you anymore. You can unblock them anytime.\",\n \"Thread\": \"Konu\",\n \"Thread has not been found\": \"Konu bulunamadı\",\n \"Thread reply\": \"Konu yanıtı\",\n \"Thread Reply\": \"Konu yanıtı\",\n \"ThreadListUnseenThreadsBanner/loading\": \"Yükleniyor...\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_one\": \"{{ count }} okunmamış ileti dizisi\",\n \"ThreadListUnseenThreadsBanner/unreadThreads_other\": \"{{ count }} okunmamış ileti dizisi\",\n \"Threads\": \"İleti dizileri\",\n \"timestamp/ChannelDetailPinnedMessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Yesterday]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/ChannelMembersLastActive\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/ChannelPreviewTimestamp\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"LT\\\", \\\"lastDay\\\": \\\"[Dün]\\\", \\\"lastWeek\\\": \\\"dddd\\\", \\\"sameElse\\\": \\\"L\\\" }) }}\",\n \"timestamp/DateSeparator\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Bugün]\\\", \\\"nextDay\\\": \\\"[Yarın]\\\", \\\"lastDay\\\": \\\"[Dün]\\\", \\\"nextWeek\\\": \\\"dddd\\\", \\\"lastWeek\\\": \\\"[Geçen] dddd\\\", \\\"sameElse\\\": \\\"ddd, D MMM\\\" }) }}\",\n \"timestamp/LiveLocation\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/MessageTimestamp\": \"{{ timestamp | timestampFormatter(calendar: false; format: HH:mm) }}\",\n \"timestamp/PollVote\": \"{{ timestamp | timestampFormatter(relativeCompact: true) }}\",\n \"timestamp/PollVoteTooltip\": \"{{ timestamp | timestampFormatter(calendar: true) }}\",\n \"timestamp/relativeDaysAgo\": \"{{ count }} g önce\",\n \"timestamp/relativeToday\": \"Bugün\",\n \"timestamp/relativeWeeksAgo\": \"{{ count }} hf önce\",\n \"timestamp/relativeYesterday\": \"Dün\",\n \"timestamp/ReminderNotification\": \"{{ timestamp | timestampFormatter(calendar: true; calendarFormats: { \\\"sameDay\\\": \\\"[Bugün] [saat] HH:mm\\\", \\\"nextDay\\\": \\\"[Yarın] [saat] HH:mm\\\", \\\"lastDay\\\": \\\"[Dün] [saat] HH:mm\\\", \\\"nextWeek\\\": \\\"dddd [saat] HH:mm\\\", \\\"lastWeek\\\": \\\"[Geçen] dddd [saat] HH:mm\\\", \\\"sameElse\\\": \\\"ddd, D MMM [saat] HH:mm\\\" }) }}\",\n \"timestamp/SystemMessage\": \"{{ timestamp | timestampFormatter(format: dddd L) }}\",\n \"To start recording, allow the camera access in your browser\": \"Kayıt yapmaya başlamak için tarayıcınızda kameraya erişime izin verin\",\n \"To start recording, allow the microphone access in your browser\": \"Kayıt yapmaya başlamak için tarayıcınızda mikrofona erişime izin verin\",\n \"totalVoteCount_one\": \"toplam 1 oy\",\n \"totalVoteCount_other\": \"toplam {{ count }} oy\",\n \"Translated\": \"Çevrildi\",\n \"Translated from {{ language }}\": \"{{ language }} dilinden çevrildi\",\n \"translationBuilderTopic/notification\": \"{{value, notification}}\",\n \"Type a number from 2 to 10\": \"2 ile 10 arasında bir sayı yazın\",\n \"Unarchive\": \"Arşivden çıkar\",\n \"unban-command-args\": \"[@kullanıcıadı]\",\n \"unban-command-description\": \"Bir kullanıcının yasağını kaldır\",\n \"Unblock\": \"Engeli kaldır\",\n \"Unblock user\": \"Kullanıcının engelini kaldır\",\n \"Unblock User\": \"Kullanıcının engelini kaldır\",\n \"unknown error\": \"bilinmeyen hata\",\n \"Unmute\": \"Sesini aç\",\n \"Unmute chat\": \"Sohbetin sesini aç\",\n \"Unmute user\": \"Kullanıcının sesini aç\",\n \"unmute-command-args\": \"[@kullanıcıadı]\",\n \"unmute-command-description\": \"Bir kullanıcının sesini aç\",\n \"Unpin\": \"Sabitlemeyi kaldır\",\n \"Unread messages\": \"Okunmamış mesajlar\",\n \"Unsupported attachment\": \"Desteklenmeyen ek\",\n \"unsupported file type\": \"desteklenmeyen dosya türü\",\n \"Update\": \"Güncelle\",\n \"Update the comment attached to your poll answer\": \"Anket yanıtınıza ekli yorumu güncelleyin\",\n \"Update your comment\": \"Yorumunuzu güncelleyin\",\n \"Upload blocked\": \"Yükleme engellendi\",\n \"Upload error\": \"Yükleme hatası\",\n \"Upload failed\": \"Yükleme başarısız oldu\",\n \"Upload Picture\": \"Resim yükle\",\n \"Upload type: \\\"{{ type }}\\\" is not allowed\": \"Yükleme türü: \\\"{{ type }}\\\" izin verilmez\",\n \"User blocked\": \"Kullanıcı engellendi\",\n \"User muted\": \"Kullanıcı sessize alındı\",\n \"User removed\": \"Kullanıcı kaldırıldı\",\n \"User unblocked\": \"Kullanıcının engeli kaldırıldı\",\n \"User unmuted\": \"Kullanıcının sesi açıldı\",\n \"User uploaded content\": \"Kullanıcı tarafından yüklenen içerik\",\n \"Video\": \"Video\",\n \"videoCount_one\": \"Video\",\n \"videoCount_other\": \"{{ count }} video\",\n \"View\": \"Görüntüle\",\n \"View {{count}} comments_one\": \"{{count}} yorumu görüntüle\",\n \"View {{count}} comments_other\": \"{{count}} yorumu görüntüle\",\n \"View all\": \"Tümünü görüntüle\",\n \"View member details for {{ member }}\": \"{{ member }} için üye detaylarını görüntüle\",\n \"View original\": \"Orijinali görüntüle\",\n \"View results\": \"Sonuçları görüntüle\",\n \"View translation\": \"Çeviriyi görüntüle\",\n \"Voice message\": \"Sesli mesaj\",\n \"Voice message {{ duration }}\": \"Sesli mesaj {{ duration }}\",\n \"Voice message deleted\": \"Sesli mesaj silindi\",\n \"voiceMessageCount_one\": \"Sesli mesaj\",\n \"voiceMessageCount_other\": \"{{ count }} sesli mesaj\",\n \"Vote ended\": \"Oylama sona erdi\",\n \"Votes\": \"Oylar\",\n \"Wait until all attachments have uploaded\": \"Tüm ekler yüklenene kadar bekleyin\",\n \"Waiting for network…\": \"Ağ bekleniyor…\",\n \"You\": \"Sen\",\n \"You've reached the maximum number of files\": \"Maksimum dosya sayısına ulaştınız\"\n}\n","import type { i18n, TFunction } from 'i18next';\n\ntype TopicName = string;\ntype TranslatorName = string;\n\nexport type Translator<O extends Record<string, unknown> = Record<string, unknown>> =\n (params: { key: string; value: string; t: TFunction; options: O }) => string | null;\n\nexport type TranslationTopicOptions<\n O extends Record<string, unknown> = Record<string, unknown>,\n> = {\n i18next: i18n;\n translators?: Record<string, Translator<O>>;\n};\n\nexport abstract class TranslationTopic<\n O extends Record<string, unknown> = Record<string, unknown>,\n> {\n protected translators: Map<string, Translator<O>> = new Map();\n protected i18next: i18n;\n\n constructor(protected options: TranslationTopicOptions<O>) {\n this.i18next = options.i18next;\n if (options.translators) {\n Object.entries(options.translators).forEach(([name, translator]) => {\n this.setTranslator(name, translator);\n });\n }\n }\n\n abstract translate(value: string, key: string, options: O): string;\n\n setTranslator = (name: string, translator: Translator<O>) => {\n this.translators.set(name, translator);\n };\n\n removeTranslator = (name: string) => {\n this.translators.delete(name);\n };\n}\n\nconst forwardTranslation: Translator = ({ value }) => value;\n\nexport type TranslationTopicConstructor = new (\n options: TranslationTopicOptions,\n) => TranslationTopic;\n\nexport class TranslationBuilder {\n private topics = new Map<string, TranslationTopic>();\n // need to keep a registration buffer so that translators can be registered once a topic is registered\n // what does not happen when Streami18n is instantiated but rather once Streami18n.init() is invoked\n private translatorRegistrationsBuffer: Record<\n TopicName,\n Record<TranslatorName, Translator>\n > = {};\n\n constructor(private i18next: i18n) {}\n\n registerTopic = (name: TopicName, Topic: TranslationTopicConstructor) => {\n let topic = this.topics.get(name);\n\n if (!topic) {\n topic = new Topic({ i18next: this.i18next });\n this.topics.set(name, topic);\n this.i18next.use({\n name,\n process: (value: string, key: string, options: Record<string, unknown>) => {\n const topic = this.topics.get(name);\n if (!topic) return value;\n return topic.translate(value, key, options);\n },\n type: 'postProcessor' as const,\n });\n }\n\n const additionalTranslatorsToRegister = this.translatorRegistrationsBuffer[name];\n if (additionalTranslatorsToRegister) {\n Object.entries(additionalTranslatorsToRegister).forEach(\n ([translatorName, translator]) => {\n topic.setTranslator(translatorName, translator);\n },\n );\n delete this.translatorRegistrationsBuffer[name];\n }\n return topic;\n };\n\n disableTopic = (topicName: TopicName) => {\n const topic = this.topics.get(topicName);\n if (!topic) return;\n this.i18next.use({\n name: topicName,\n process: forwardTranslation,\n type: 'postProcessor',\n });\n this.topics.delete(topicName);\n };\n\n getTopic = (topicName: TopicName) => this.topics.get(topicName);\n\n registerTranslators(\n topicName: TopicName,\n translators: Record<TranslatorName, Translator>,\n ) {\n const topic = this.getTopic(topicName);\n if (!topic) {\n if (!this.translatorRegistrationsBuffer[topicName])\n this.translatorRegistrationsBuffer[topicName] = {};\n\n Object.entries(translators).forEach(([translatorName, translator]) => {\n this.translatorRegistrationsBuffer[topicName][translatorName] = translator;\n });\n return;\n }\n Object.entries(translators).forEach(([name, translator]) => {\n topic.setTranslator(name, translator);\n });\n }\n\n removeTranslators(topicName: TopicName, translators: TranslatorName[]) {\n const topic = this.getTopic(topicName);\n if (this.translatorRegistrationsBuffer[topicName]) {\n translators.forEach((translatorName) => {\n delete this.translatorRegistrationsBuffer[topicName][translatorName];\n });\n }\n if (!topic) return;\n translators.forEach((name) => {\n topic.removeTranslator(name);\n });\n }\n}\n","import type { Notification } from 'stream-chat';\n\nimport type { NotificationTranslatorOptions } from './types';\nimport type { TranslationTopicOptions, Translator } from '../../index';\n\nconst normalizeReason = (notification?: Notification) => {\n const reason = notification?.metadata?.reason;\n if (typeof reason !== 'string' || !reason.length) return undefined;\n return reason.toLowerCase();\n};\n\nconst withReasonFallback = ({\n fallbackTranslationKey,\n notification,\n reasonTranslationKey,\n t,\n}: {\n fallbackTranslationKey: string;\n notification?: Notification;\n reasonTranslationKey: string;\n t: TranslationTopicOptions['i18next']['t'];\n}) => {\n const reason = normalizeReason(notification);\n if (!reason) return t(fallbackTranslationKey);\n return t(reasonTranslationKey, { reason });\n};\n\nexport const translateAttachmentUploadBlocked: Translator<\n NotificationTranslatorOptions\n> = ({ options: { notification }, t }) => {\n const rawReason = notification?.metadata?.reason;\n let reason = t('unsupported file type');\n if (typeof rawReason !== 'string') reason = t('unknown error');\n if (rawReason === 'size_limit') reason = t('size limit');\n return t('Attachment upload blocked due to {{reason}}', { reason });\n};\n\nexport const translateAttachmentUploadFailed: Translator<\n NotificationTranslatorOptions\n> = ({ options: { notification }, t }) =>\n withReasonFallback({\n fallbackTranslationKey: 'Error uploading attachment',\n notification,\n reasonTranslationKey: 'Attachment upload failed due to {{reason}}',\n t,\n });\n\nexport const translatePollCreateFailed: Translator<NotificationTranslatorOptions> = ({\n options: { notification },\n t,\n}) =>\n withReasonFallback({\n fallbackTranslationKey: 'Failed to create the poll',\n notification,\n reasonTranslationKey: 'Failed to create the poll due to {{reason}}',\n t,\n });\n\nexport const translatePollEndFailed: Translator<NotificationTranslatorOptions> = ({\n options: { notification },\n t,\n}) =>\n withReasonFallback({\n fallbackTranslationKey: 'Failed to end the poll',\n notification,\n reasonTranslationKey: 'Failed to end the poll due to {{reason}}',\n t,\n });\n\nexport const translateBrowserAudioPlaybackError: Translator<\n NotificationTranslatorOptions\n> = ({ options: { notification }, t }) =>\n notification?.message ? t(notification.message) : t('Error reproducing the recording');\n\nexport const translateCommandDisabled: Translator<NotificationTranslatorOptions> = ({\n options: { notification },\n t,\n}) => {\n const reason = normalizeReason(notification);\n\n if (reason === 'editing') {\n return t('Command not available while editing');\n }\n\n if (reason === 'quoted_message') {\n return t('Command not available while replying');\n }\n\n return t(notification?.message || 'Command not available');\n};\n","import type { NotificationTranslatorOptions } from './types';\nimport {\n translateAttachmentUploadBlocked,\n translateAttachmentUploadFailed,\n translateBrowserAudioPlaybackError,\n translateCommandDisabled,\n translatePollCreateFailed,\n translatePollEndFailed,\n} from './translators';\nimport type { Translator } from '../../index';\n\nexport const translatorsByNotificationType: Record<\n string,\n Translator<NotificationTranslatorOptions>\n> = {\n 'api:attachment:upload:failed': translateAttachmentUploadFailed,\n 'api:location:create:failed': ({ t }) => t('Failed to share location'),\n 'api:location:share:failed': ({ t }) => t('Failed to share location'),\n 'api:poll:create:failed': translatePollCreateFailed,\n 'api:poll:end:failed': translatePollEndFailed,\n 'api:poll:end:success': ({ t }) => t('Poll ended'),\n 'api:reply:search:failed': ({ t }) => t('Thread has not been found'),\n 'browser:audio:playback:error': translateBrowserAudioPlaybackError,\n 'browser:location:get:failed': ({ t }) => t('Failed to retrieve location'),\n 'channel:jumpToFirstUnread:failed': ({ t }) =>\n t('Failed to jump to the first unread message'),\n 'validation:attachment:file:missing': ({ t }) =>\n t('File is required for upload attachment'),\n 'validation:attachment:id:missing': ({ t }) =>\n t('Local upload attachment missing local id'),\n 'validation:attachment:upload:blocked': translateAttachmentUploadBlocked,\n 'validation:attachment:upload:in-progress': ({ t }) =>\n t('Wait until all attachments have uploaded'),\n 'validation:command:disabled': translateCommandDisabled,\n 'validation:poll:castVote:limit': ({ t }) =>\n t('Reached the vote limit. Remove an existing vote first.'),\n};\n","import { TranslationTopic } from '../../TranslationBuilder';\nimport type { Notification } from 'stream-chat';\nimport type { NotificationTranslatorOptions } from './types';\nimport { translatorsByNotificationType } from './translatorsByNotificationType';\nimport type { TranslationTopicOptions, Translator } from '../../index';\n\nconst translateByNotificationType: Translator<NotificationTranslatorOptions> = ({\n options: { notification },\n ...params\n}) => {\n if (!notification?.type) return null;\n const translator = translatorsByNotificationType[notification.type];\n if (!translator) return null;\n return translator({ ...params, options: { notification } });\n};\n\nexport const defaultNotificationTranslators: Record<\n string,\n Translator<NotificationTranslatorOptions>\n> = {\n '*': translateByNotificationType,\n};\n\nexport class NotificationTranslationTopic extends TranslationTopic<NotificationTranslatorOptions> {\n constructor({ i18next, translators }: TranslationTopicOptions) {\n super({ i18next, translators: defaultNotificationTranslators });\n if (translators) {\n Object.entries(translators).forEach(([name, translator]) => {\n this.setTranslator(name, translator);\n });\n }\n }\n\n translate = (value: string, key: string, options: { notification?: Notification }) => {\n const { notification } = options;\n if (!notification) return value;\n const byType = notification.type\n ? this.translators.get(notification.type)\n : undefined;\n if (byType) return byType({ key, options, t: this.i18next.t, value }) || value;\n\n const byFallback = this.translators.get('*');\n const translated = byFallback?.({ key, options, t: this.i18next.t, value }) ?? null;\n if (translated) return translated;\n if (!notification.message) return value;\n\n // Final fallback: attempt to translate message as natural key.\n return this.i18next.t(notification.message, {\n ...(notification.metadata ?? {}),\n value: notification.message,\n });\n };\n}\n","import i18n from 'i18next';\nimport Dayjs from 'dayjs';\nimport calendar from 'dayjs/plugin/calendar.js';\nimport updateLocale from 'dayjs/plugin/updateLocale.js';\nimport LocalizedFormat from 'dayjs/plugin/localizedFormat.js';\nimport localeData from 'dayjs/plugin/localeData.js';\nimport relativeTime from 'dayjs/plugin/relativeTime.js';\nimport duration from 'dayjs/plugin/duration.js';\nimport utc from 'dayjs/plugin/utc.js';\nimport timezone from 'dayjs/plugin/timezone.js';\nimport { NotificationTranslationTopic, TranslationBuilder } from './TranslationBuilder';\nimport { defaultTranslatorFunction, predefinedFormatters } from './utils';\n\nimport type { i18n as I18n, TFunction } from 'i18next';\nimport type momentTimezone from 'moment-timezone';\nimport type { TranslationLanguages } from 'stream-chat';\n\nimport type { TranslationTopicConstructor } from './TranslationBuilder';\nimport type { UnknownType } from '../types/types';\nimport type { CustomFormatters, PredefinedFormatters, TDateTimeParser } from './types';\n\nimport {\n deTranslations,\n enTranslations,\n esTranslations,\n frTranslations,\n hiTranslations,\n itTranslations,\n jaTranslations,\n koTranslations,\n nlTranslations,\n ptTranslations,\n ruTranslations,\n trTranslations,\n} from './translations';\n\nimport 'dayjs/locale/de.js';\nimport 'dayjs/locale/es.js';\nimport 'dayjs/locale/fr.js';\nimport 'dayjs/locale/hi.js';\nimport 'dayjs/locale/it.js';\nimport 'dayjs/locale/ja.js';\nimport 'dayjs/locale/ko.js';\nimport 'dayjs/locale/nl.js';\nimport 'dayjs/locale/pt.js';\nimport 'dayjs/locale/ru.js';\nimport 'dayjs/locale/tr.js';\n// These locale imports also set these locale globally.\n// So As a last step I am going to import english locale\n// to make sure I don't mess up language at other places in app.\nimport 'dayjs/locale/en.js';\n\nconst defaultNS = 'translation';\nconst defaultLng = 'en';\n\ntype CalendarLocaleConfig = {\n lastDay: string;\n lastWeek: string;\n nextDay: string;\n nextWeek: string;\n sameDay: string;\n sameElse: string;\n};\n\nDayjs.extend(updateLocale);\nDayjs.extend(utc);\nDayjs.extend(timezone);\n\nDayjs.updateLocale('de', {\n calendar: {\n lastDay: '[gestern um] LT',\n lastWeek: '[letzten] dddd [um] LT',\n nextDay: '[morgen um] LT',\n nextWeek: 'dddd [um] LT',\n sameDay: '[heute um] LT',\n sameElse: 'L',\n },\n});\n\nDayjs.updateLocale('es', {\n calendar: {\n lastDay: '[ayer a las] LT',\n lastWeek: '[pasado] dddd [a] LT',\n nextDay: '[mañana a] LT',\n nextWeek: 'dddd [a] LT',\n sameDay: '[hoy a las] LT',\n sameElse: 'L',\n },\n});\n\nDayjs.updateLocale('fr', {\n calendar: {\n lastDay: '[Hier à] LT',\n lastWeek: 'dddd [dernier à] LT',\n nextDay: '[Demain à] LT',\n nextWeek: 'dddd [à] LT',\n sameDay: \"[Aujourd'hui à] LT\",\n sameElse: 'L',\n },\n});\n\nDayjs.updateLocale('hi', {\n calendar: {\n lastDay: '[कल] LT',\n lastWeek: '[पिछले] dddd, LT',\n nextDay: '[कल] LT',\n nextWeek: 'dddd, LT',\n sameDay: '[आज] LT',\n sameElse: 'L',\n },\n // Hindi notation for meridiems are quite fuzzy in practice. While there exists\n // a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi.\n meridiem(hour: number) {\n if (hour < 4) {\n return 'रात';\n } else if (hour < 10) {\n return 'सुबह';\n } else if (hour < 17) {\n return 'दोपहर';\n } else if (hour < 20) {\n return 'शाम';\n } else {\n return 'रात';\n }\n },\n meridiemHour(hour: number, meridiem: string) {\n if (hour === 12) {\n hour = 0;\n }\n if (meridiem === 'रात') {\n return hour < 4 ? hour : hour + 12;\n } else if (meridiem === 'सुबह') {\n return hour;\n } else if (meridiem === 'दोपहर') {\n return hour >= 10 ? hour : hour + 12;\n } else if (meridiem === 'शाम') {\n return hour + 12;\n }\n return hour;\n },\n meridiemParse: /रात|सुबह|दोपहर|शाम/,\n});\n\nDayjs.updateLocale('it', {\n calendar: {\n lastDay: '[Ieri alle] LT',\n lastWeek: '[lo scorso] dddd [alle] LT',\n nextDay: '[Domani alle] LT',\n nextWeek: 'dddd [alle] LT',\n sameDay: '[Oggi alle] LT',\n sameElse: 'L',\n },\n});\n\nDayjs.updateLocale('ja', {\n calendar: {\n lastDay: '[昨日] LT',\n lastWeek: 'dddd LT',\n nextDay: '[明日] LT',\n nextWeek: '[次の] dddd LT',\n sameDay: '[今日] LT',\n sameElse: 'L',\n },\n});\n\nDayjs.updateLocale('ko', {\n calendar: {\n lastDay: '[어제] LT',\n lastWeek: '[지난] dddd LT',\n nextDay: '[내일] LT',\n nextWeek: 'dddd LT',\n sameDay: '[오늘] LT',\n sameElse: 'L',\n },\n});\n\nDayjs.updateLocale('nl', {\n calendar: {\n lastDay: '[gisteren om] LT',\n lastWeek: '[afgelopen] dddd [om] LT',\n nextDay: '[morgen om] LT',\n nextWeek: 'dddd [om] LT',\n sameDay: '[vandaag om] LT',\n sameElse: 'L',\n },\n});\n\nDayjs.updateLocale('pt', {\n calendar: {\n lastDay: '[ontem às] LT',\n lastWeek: 'dddd [passada às] LT',\n nextDay: '[amanhã às] LT',\n nextWeek: 'dddd [às] LT',\n sameDay: '[hoje às] LT',\n sameElse: 'L',\n },\n});\n\nDayjs.updateLocale('ru', {\n calendar: {\n lastDay: '[Вчера, в] LT',\n nextDay: '[Завтра, в] LT',\n sameDay: '[Сегодня, в] LT',\n },\n});\n\nDayjs.updateLocale('tr', {\n calendar: {\n lastDay: '[dün] LT',\n lastWeek: '[geçen] dddd [saat] LT',\n nextDay: '[yarın saat] LT',\n nextWeek: '[gelecek] dddd [saat] LT',\n sameDay: '[bugün saat] LT',\n sameElse: 'L',\n },\n});\n\nconst en_locale = {\n formats: {},\n months: [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n ],\n relativeTime: {},\n weekdays: [\n 'Sunday',\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n ],\n};\n\ntype DateTimeParserModule = typeof Dayjs | typeof momentTimezone;\n// Type guards to check DayJs\nconst isDayJs = (dateTimeParser: DateTimeParserModule): dateTimeParser is typeof Dayjs =>\n (dateTimeParser as typeof Dayjs).extend !== undefined;\n\ntype TimezoneParser = {\n tz: momentTimezone.MomentTimezone | Dayjs.Dayjs;\n};\nconst supportsTz = (dateTimeParser: unknown): dateTimeParser is TimezoneParser =>\n (dateTimeParser as TimezoneParser).tz !== undefined;\n\nexport type Streami18nOptions = {\n DateTimeParser?: DateTimeParserModule;\n dayjsLocaleConfigForLanguage?: Partial<ILocale> & { calendar?: CalendarLocaleConfig };\n debug?: boolean;\n disableDateTimeTranslations?: boolean;\n formatters?: Partial<PredefinedFormatters> & CustomFormatters;\n language?: TranslationLanguages;\n logger?: (message?: string) => void;\n translationBuilderTopics?: Record<string, TranslationTopicConstructor>;\n parseMissingKeyHandler?: (key: string, defaultValue?: string) => string;\n timezone?: string;\n translationsForLanguage?: Partial<typeof enTranslations>;\n};\n\n/**\n * Wrapper around [i18next](https://www.i18next.com/) class for Stream related i18n.\n * Instance of this class should be provided to Chat component to handle i18n.\n * Stream provides following list of in-built i18n:\n * 1. English (en)\n * 2. Dutch (nl)\n * 3. Russian (ru)\n * 4. Turkish (tr)\n * 5. French (fr)\n * 6. Italian (it)\n * 7. Hindi (hi)\n * 8. Spanish (es)\n * 9. Portuguese (pt)\n * 10. German (de)\n * 11. Japanese (ja)\n * 12. Korean (ko)\n *\n * Simplest way to start using chat components in one of the in-built languages would be following:\n *\n * ```\n * const i18n = new Streami18n({ language 'nl' });\n * <Chat client={chatClient} i18nInstance={i18n}>\n * ...\n * </Chat>\n * ```\n *\n * If you would like to override certain keys in in-built translation.\n * UI will be automatically updated in this case.\n *\n * ```\n * const i18n = new Streami18n({\n * language: 'nl',\n * translationsForLanguage: {\n * 'Nothing yet...': 'Nog Niet ...',\n * '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} en {{ secondUser }} zijn aan het typen...',\n * }\n * });\n *\n * If you would like to register additional languages, use registerTranslation. You can add as many languages as you want:\n *\n * i18n.registerTranslation('zh', {\n * 'Nothing yet...': 'Nog Niet ...',\n * '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} en {{ secondUser }} zijn aan het typen...',\n * });\n *\n * <Chat client={chatClient} i18nInstance={i18n}>\n * ...\n * </Chat>\n * ```\n *\n * You can use the same function to add whole new language as well.\n *\n * ```\n * const i18n = new Streami18n();\n *\n * i18n.registerTranslation('mr', {\n * 'Nothing yet...': 'काहीही नाही ...',\n * '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} आणि {{ secondUser }} टीपी करत आहेत ',\n * });\n *\n * // Make sure to call setLanguage to reflect new language in UI.\n * i18n.setLanguage('it');\n * <Chat client={chatClient} i18nInstance={i18n}>\n * ...\n * </Chat>\n * ```\n *\n * ## Datetime i18n\n *\n * Stream react chat components uses [dayjs](https://day.js.org/en/) internally by default to format datetime stamp.\n * e.g., in ChannelPreview, MessageContent components.\n * Dayjs has locale support as well - https://day.js.org/docs/en/i18n/i18n\n * Dayjs is a lightweight alternative to Momentjs with the same modern API.\n *\n * Dayjs provides locale config for plenty of languages, you can check the whole list of locale configs at following url\n * https://github.com/iamkun/dayjs/tree/dev/src/locale\n *\n * You can either provide the dayjs locale config while registering\n * language with Streami18n (either via constructor or registerTranslation()) or you can provide your own Dayjs or Moment instance\n * to Streami18n constructor, which will be then used internally (using the language locale) in components.\n *\n * 1. Via language registration\n *\n * e.g.,\n * ```\n * const i18n = new Streami18n({\n * language: 'nl',\n * dayjsLocaleConfigForLanguage: {\n * months: [...],\n * monthsShort: [...],\n * calendar: {\n * sameDay: ...'\n * }\n * }\n * });\n * ```\n *\n * Similarly, you can add locale config for moment while registering translation via `registerTranslation` function.\n *\n * e.g.,\n * ```\n * const i18n = new Streami18n();\n *\n * i18n.registerTranslation(\n * 'mr',\n * {\n * 'Nothing yet...': 'काहीही नाही ...',\n * '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} आणि {{ secondUser }} टीपी करत आहेत ',\n * },\n * {\n * months: [...],\n * monthsShort: [...],\n * calendar: {\n * sameDay: ...'\n * }\n * }\n * );\n *```\n * 2. Provide your own Moment object\n *\n * ```js\n * import 'moment/locale/nl';\n * import 'moment/locale/it';\n * // or if you want to include all locales\n * import 'moment/min/locales';\n *\n * import Moment from moment\n *\n * const i18n = new Streami18n({\n * language: 'nl',\n * DateTimeParser: Moment\n * })\n * ```\n *\n * 3. Provide your own Dayjs object\n *\n * ```js\n * import Dayjs from 'dayjs'\n *\n * import 'dayjs/locale/nl.js';\n * import 'dayjs/locale/it.js';\n *\n * const i18n = new Streami18n({\n * language: 'nl',\n * DateTimeParser: Dayjs\n * })\n * ```\n * If you would like to stick with english language for datetimes in Stream components, you can set `disableDateTimeTranslations` to true.\n *\n */\nconst defaultStreami18nOptions = {\n DateTimeParser: Dayjs,\n dayjsLocaleConfigForLanguage: null,\n debug: false,\n disableDateTimeTranslations: false,\n language: 'en' as TranslationLanguages,\n logger: (message?: string) => console.warn(message),\n /**\n * Key in the translationBuilderTopics has to match postProcessorName in the translation value.\n *\n * {\n * \"key\": \"{{value, postProcessorName}}\"\n * }\n *\n * At least the default topics will be supported.\n */\n translationBuilderTopics: {\n notification: NotificationTranslationTopic,\n },\n};\n\nexport class Streami18n {\n i18nInstance: I18n = i18n.createInstance();\n translationBuilder: TranslationBuilder;\n private translationBuilderTopics: Record<string, TranslationTopicConstructor> = {};\n Dayjs = null;\n setLanguageCallback: (t: TFunction) => void = () => null;\n initialized = false;\n\n t: TFunction = defaultTranslatorFunction;\n tDateTimeParser: TDateTimeParser;\n\n translations: {\n [key: string]: {\n [key: string]: typeof enTranslations | UnknownType;\n };\n } = {\n de: { [defaultNS]: deTranslations },\n en: { [defaultNS]: enTranslations },\n es: { [defaultNS]: esTranslations },\n fr: { [defaultNS]: frTranslations },\n hi: { [defaultNS]: hiTranslations },\n it: { [defaultNS]: itTranslations },\n ja: { [defaultNS]: jaTranslations },\n ko: { [defaultNS]: koTranslations },\n nl: { [defaultNS]: nlTranslations },\n pt: { [defaultNS]: ptTranslations },\n ru: { [defaultNS]: ruTranslations },\n tr: { [defaultNS]: trTranslations },\n };\n\n /**\n * dayjs.defineLanguage('nl') also changes the global locale. We don't want to do that\n * when user calls registerTranslation() function. So instead we will store the locale configs\n * given to registerTranslation() function in `dayjsLocales` object, and register the required locale\n * with moment, when setLanguage is called.\n * */\n dayjsLocales: { [key: string]: Partial<ILocale> } = {};\n // dayjsLocales = {};\n\n /**\n * Initialize properties used in constructor\n */\n logger: (msg?: string) => void;\n currentLanguage: TranslationLanguages;\n DateTimeParser: DateTimeParserModule;\n formatters: PredefinedFormatters & CustomFormatters = predefinedFormatters;\n isCustomDateTimeParser: boolean;\n i18nextConfig: {\n debug: boolean;\n fallbackLng: false;\n interpolation: { escapeValue: boolean; formatSeparator: string };\n keySeparator: false;\n lng: string;\n nsSeparator: false;\n parseMissingKeyHandler?: (key: string, defaultValue?: string) => string;\n postProcess?: string[];\n };\n /**\n * A valid TZ identifier string (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)\n */\n timezone?: string;\n /**\n * Constructor accepts following options:\n * - language (String) default: 'en'\n * Language code e.g., en, tr\n *\n * - translationsForLanguage (object)\n * Translations object. Please check src/i18n/en.json for example.\n *\n * - disableDateTimeTranslations (boolean) default: false\n * Disable translations for date-times\n *\n * - debug (boolean) default: false\n * Enable debug mode in internal i18n class\n *\n * - logger (function) default: () => {}\n * Logger function to log warnings/errors from this class\n *\n * - dayjsLocaleConfigForLanguage (object) default: 'enConfig'\n * [Config object](https://momentjs.com/docs/#/i18n/changing-locale/) for internal moment object,\n * corresponding to language (param)\n *\n * - DateTimeParser (function) Moment or Dayjs instance/function.\n * Make sure to load all the required locales in this Moment or Dayjs instance that you will be provide to Streami18n\n *\n * @param {*} options\n */\n constructor(options: Streami18nOptions = {}) {\n const finalOptions = {\n ...defaultStreami18nOptions,\n ...options,\n };\n // Prepare the i18next configuration.\n this.logger = finalOptions.logger;\n this.currentLanguage = finalOptions.language;\n this.DateTimeParser = finalOptions.DateTimeParser;\n this.timezone = finalOptions.timezone;\n this.formatters = { ...predefinedFormatters, ...options?.formatters };\n this.translationBuilder = new TranslationBuilder(this.i18nInstance);\n this.translationBuilderTopics = {\n ...defaultStreami18nOptions.translationBuilderTopics,\n ...options.translationBuilderTopics,\n };\n\n try {\n if (this.DateTimeParser && isDayJs(this.DateTimeParser)) {\n this.DateTimeParser.extend(LocalizedFormat);\n this.DateTimeParser.extend(calendar);\n this.DateTimeParser.extend(localeData);\n this.DateTimeParser.extend(relativeTime);\n this.DateTimeParser.extend(duration);\n }\n } catch (error) {\n throw Error(\n `Streami18n: Looks like you wanted to provide Dayjs instance, but something went wrong while adding plugins ${error}`,\n );\n }\n\n this.isCustomDateTimeParser = !!options.DateTimeParser;\n const translationsForLanguage = finalOptions.translationsForLanguage;\n\n if (translationsForLanguage) {\n this.translations[this.currentLanguage] = {\n [defaultNS]:\n this.translations[this.currentLanguage] &&\n this.translations[this.currentLanguage][defaultNS]\n ? {\n ...this.translations[this.currentLanguage][defaultNS],\n ...translationsForLanguage,\n }\n : translationsForLanguage,\n };\n }\n\n // If translations don't exist for given language, then set it as empty object.\n if (!this.translations[this.currentLanguage]) {\n this.translations[this.currentLanguage] = {\n [defaultNS]: {},\n };\n }\n\n this.i18nextConfig = {\n debug: finalOptions.debug,\n fallbackLng: false,\n interpolation: { escapeValue: false, formatSeparator: '|' },\n keySeparator: false,\n lng: this.currentLanguage,\n nsSeparator: false,\n };\n\n const postProcess = Object.keys(this.translationBuilderTopics);\n\n if (postProcess.length > 0) {\n this.i18nextConfig.postProcess = postProcess;\n }\n\n if (finalOptions.parseMissingKeyHandler) {\n this.i18nextConfig.parseMissingKeyHandler = finalOptions.parseMissingKeyHandler;\n }\n\n this.validateCurrentLanguage();\n\n const dayjsLocaleConfigForLanguage = finalOptions.dayjsLocaleConfigForLanguage;\n\n if (dayjsLocaleConfigForLanguage) {\n this.addOrUpdateLocale(this.currentLanguage, {\n ...dayjsLocaleConfigForLanguage,\n });\n } else if (!this.localeExists(this.currentLanguage)) {\n this.logger(\n `Streami18n: Streami18n(...) - Locale config for ${this.currentLanguage} does not exist in momentjs.` +\n `Please import the locale file using \"import 'moment/locale/${this.currentLanguage}';\" in your app or ` +\n `register the locale config with Streami18n using registerTranslation(language, translation, customDayjsLocale)`,\n );\n }\n\n this.tDateTimeParser = (timestamp) => {\n const language =\n finalOptions.disableDateTimeTranslations ||\n !this.localeExists(this.currentLanguage)\n ? defaultLng\n : this.currentLanguage;\n\n if (isDayJs(this.DateTimeParser)) {\n return supportsTz(this.DateTimeParser)\n ? this.DateTimeParser(timestamp).tz(this.timezone).locale(language)\n : this.DateTimeParser(timestamp).locale(language);\n }\n\n if (supportsTz(this.DateTimeParser) && this.timezone) {\n return this.DateTimeParser(timestamp).tz(this.timezone).locale(language);\n }\n return this.DateTimeParser(timestamp).locale(language);\n };\n }\n\n /**\n * Initializes the i18next instance with configuration (which enables natural language as default keys)\n */\n async init() {\n this.validateCurrentLanguage();\n\n try {\n this.t = await this.i18nInstance.init({\n ...this.i18nextConfig,\n lng: this.currentLanguage,\n resources: this.translations,\n });\n this.initialized = true;\n if (this.formatters) {\n Object.entries(this.formatters).forEach(([name, formatterFactory]) => {\n if (!formatterFactory) return;\n this.i18nInstance.services.formatter?.add(name, formatterFactory(this));\n });\n }\n // Register post-processors after initialization\n Object.entries(this.translationBuilderTopics).forEach(\n ([topic, TranslationTopic]) => {\n this.translationBuilder.registerTopic(topic, TranslationTopic);\n },\n );\n } catch (error) {\n this.logger(`Something went wrong with init: ${JSON.stringify(error)}`);\n }\n\n return {\n t: this.t,\n tDateTimeParser: this.tDateTimeParser,\n };\n }\n\n localeExists = (language: TranslationLanguages) => {\n if (this.isCustomDateTimeParser) return true;\n\n return Object.keys(Dayjs.Ls).indexOf(language) > -1;\n };\n\n validateCurrentLanguage = () => {\n const availableLanguages = Object.keys(this.translations);\n if (availableLanguages.indexOf(this.currentLanguage) === -1) {\n this.logger(\n `Streami18n: '${this.currentLanguage}' language is not registered.` +\n ` Please make sure to call streami18n.registerTranslation('${this.currentLanguage}', {...}) or ` +\n `use one the built-in supported languages - ${this.getAvailableLanguages()}`,\n );\n\n this.currentLanguage = defaultLng;\n }\n };\n\n /** Returns an instance of i18next used within this class instance */\n geti18Instance = (): I18n => this.i18nInstance;\n\n /** Returns list of available languages. */\n getAvailableLanguages = () => Object.keys(this.translations);\n\n /** Returns all the translation dictionary for all inbuilt-languages */\n getTranslations = () => this.translations;\n\n /**\n * Returns current version translator function.\n */\n async getTranslators() {\n if (!this.initialized) {\n if (this.dayjsLocales[this.currentLanguage]) {\n this.addOrUpdateLocale(\n this.currentLanguage,\n this.dayjsLocales[this.currentLanguage],\n );\n }\n\n return await this.init();\n } else {\n return {\n t: this.t,\n tDateTimeParser: this.tDateTimeParser,\n };\n }\n }\n\n registerTranslation(\n language: TranslationLanguages,\n translation: typeof enTranslations,\n customDayjsLocale?: Partial<ILocale>,\n ) {\n if (!translation) {\n this.logger(\n `Streami18n: registerTranslation(language, translation, customDayjsLocale) called without translation`,\n );\n return;\n }\n\n if (!this.translations[language]) {\n this.translations[language] = { [defaultNS]: translation };\n } else {\n this.translations[language][defaultNS] = translation;\n }\n\n if (customDayjsLocale) {\n this.dayjsLocales[language] = { ...customDayjsLocale };\n } else if (!this.localeExists(language)) {\n this.logger(\n `Streami18n: registerTranslation(language, translation, customDayjsLocale) - ` +\n `Locale config for ${language} does not exist in Dayjs.` +\n `Please import the locale file using \"import 'dayjs/locale/${language}.js';\" in your app or ` +\n `register the locale config with Streami18n using registerTranslation(language, translation, customDayjsLocale)`,\n );\n }\n\n if (this.initialized) {\n this.i18nInstance.addResources(language, defaultNS, translation);\n }\n }\n\n addOrUpdateLocale(key: TranslationLanguages, config: Partial<ILocale>) {\n if (this.localeExists(key)) {\n Dayjs.updateLocale(key, { ...config });\n } else {\n // Merging the custom locale config with en config, so missing keys can default to english.\n Dayjs.locale({ name: key, ...en_locale, ...config }, undefined, true);\n }\n }\n\n async setLanguage(language: TranslationLanguages) {\n this.currentLanguage = language;\n\n if (!this.initialized) return;\n\n try {\n const t = await this.i18nInstance.changeLanguage(language);\n if (this.dayjsLocales[language]) {\n this.addOrUpdateLocale(\n this.currentLanguage,\n this.dayjsLocales[this.currentLanguage],\n );\n }\n\n this.setLanguageCallback(t);\n return t;\n } catch (error) {\n this.logger(`Failed to set language: ${JSON.stringify(error)}`);\n return this.t;\n }\n }\n\n registerSetLanguageCallback(callback: (t: TFunction) => void) {\n this.setLanguageCallback = callback;\n }\n}\n","import React from 'react';\n\nconst LoadingItems = () => (\n <div className='str-chat__channel-list-item-container'>\n <div\n aria-hidden='true'\n className='str-chat__channel-list-item str-chat__channel-list-item--loading'\n >\n <div className='str-chat__loading-channels-avatar' />\n <div className='str-chat__channel-list-item-data str-chat__channel-list-item-data--loading'>\n <div className='str-chat__loading-channels-username' />\n <div className='str-chat__loading-channels-status' />\n </div>\n </div>\n </div>\n);\n\nexport const LoadingChannels = () => (\n <div className='str-chat__loading-channels'>\n <LoadingItems />\n <LoadingItems />\n <LoadingItems />\n <LoadingItems />\n <LoadingItems />\n </div>\n);\n","import { useChannelActionContext } from '../../../context/ChannelActionContext';\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\n\nimport type React from 'react';\nimport type { LocalMessage } from 'stream-chat';\nimport { useStableCallback } from '../../../utils/useStableCallback';\n\nexport type FormData = Record<string, string>;\n\nexport type ActionHandlerReturnType = (\n dataOrName?: string | FormData,\n value?: string,\n event?: React.BaseSyntheticEvent,\n) => Promise<void> | void;\n\nexport const handleActionWarning = `Action handler was called, but it is missing one of its required arguments. \nMake sure the ChannelAction and ChannelState contexts are properly set and the hook is initialized with a valid message.`;\n\nexport function useActionHandler(message?: LocalMessage): ActionHandlerReturnType {\n const { removeMessage, updateMessage } = useChannelActionContext('useActionHandler');\n const { channel } = useChannelStateContext('useActionHandler');\n\n return useStableCallback(async (dataOrName, value, event) => {\n if (event) event.preventDefault();\n\n if (!message || !updateMessage || !removeMessage || !channel) {\n console.warn(handleActionWarning);\n return;\n }\n\n const messageId = message.id;\n let formData: FormData = {};\n\n // deprecated: value&name should be removed in favor of data obj\n if (typeof dataOrName === 'string') {\n formData[dataOrName] = value as string;\n } else {\n formData = { ...dataOrName };\n }\n\n if (messageId) {\n const data = await channel.sendAction(messageId, formData);\n\n if (data?.message) {\n updateMessage(data.message);\n } else {\n removeMessage(message);\n }\n }\n });\n}\n","import { isNetworkSendFailure } from '../utils';\n\nimport { useChannelActionContext } from '../../../context/ChannelActionContext';\nimport { useChatContext } from '../../../context/ChatContext';\n\nimport type { DeleteMessageOptions, LocalMessage } from 'stream-chat';\nimport type { MessageContextValue } from '../../../context';\n\nexport const useDeleteHandler = (\n message?: LocalMessage,\n): MessageContextValue['handleDelete'] => {\n const { deleteMessage, removeMessage, updateMessage } =\n useChannelActionContext('useDeleteHandler');\n const { client } = useChatContext('useDeleteHandler');\n\n return async (options?: DeleteMessageOptions) => {\n if (!message) {\n return;\n }\n\n if (message.type === 'error' || isNetworkSendFailure(message)) {\n removeMessage?.(message);\n return;\n }\n\n if (!message.id || !client || !updateMessage) {\n return;\n }\n\n const deletedMessage = await deleteMessage(message, options);\n updateMessage(deletedMessage);\n };\n};\n","import { useChatContext } from '../../../context/ChatContext';\nimport { useTranslationContext } from '../../../context/TranslationContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ReactEventHandler } from '../types';\n\nexport const missingUseFlagHandlerParameterWarning =\n 'useFlagHandler was called but it is missing one or more necessary parameters.';\n\nexport const useFlagHandler = (message?: LocalMessage): ReactEventHandler => {\n const { client } = useChatContext('useFlagHandler');\n const { t } = useTranslationContext('useFlagHandler');\n\n return async (event) => {\n event.preventDefault();\n\n if (!client || !t || !message?.id) {\n console.warn(missingUseFlagHandlerParameterWarning);\n return;\n }\n\n await client.flagMessage(message.id);\n };\n};\n","import { useChannelActionContext } from '../../../context/ChannelActionContext';\n\nimport type React from 'react';\nimport type { LocalMessage, UserResponse } from 'stream-chat';\n\nimport type { ReactEventHandler } from '../types';\n\nexport type CustomMentionHandler = (\n event: React.BaseSyntheticEvent,\n /**\n * @deprecated Use the third `message` argument to access mention metadata instead.\n * FIXME: Remove this argument in the next major release.\n */\n mentioned_users: UserResponse[],\n message: LocalMessage,\n) => void;\n\nexport type MentionedUserEventHandler = (\n event: React.BaseSyntheticEvent,\n mentionedUsers: UserResponse[],\n) => void;\n\nfunction createEventHandler(\n fn?: CustomMentionHandler,\n message?: LocalMessage,\n): ReactEventHandler {\n return (event) => {\n const hasMentions = Boolean(\n message?.mentioned_users?.length ||\n message?.mentioned_channel ||\n message?.mentioned_here ||\n message?.mentioned_roles?.length ||\n message?.mentioned_groups?.length,\n );\n\n if (typeof fn !== 'function' || !message || !hasMentions) {\n return;\n }\n fn(event, message?.mentioned_users ?? [], message);\n };\n}\n\nexport const useMentionsHandler = (\n message?: LocalMessage,\n customMentionHandler?: {\n onMentionsClick?: CustomMentionHandler;\n onMentionsHover?: CustomMentionHandler;\n },\n) => {\n const {\n onMentionsClick: contextOnMentionsClick,\n onMentionsHover: contextOnMentionsHover,\n } = useChannelActionContext('useMentionsHandler');\n\n const onMentionsClick =\n customMentionHandler?.onMentionsClick || contextOnMentionsClick || (() => null);\n\n const onMentionsHover =\n customMentionHandler?.onMentionsHover || contextOnMentionsHover || (() => null);\n\n return {\n onMentionsClick: createEventHandler(onMentionsClick, message),\n onMentionsHover: createEventHandler(onMentionsHover, message),\n };\n};\n","import { useChannelStateContext } from '../../../context';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ReactEventHandler } from '../types';\n\nexport const useMarkUnreadHandler = (message?: LocalMessage): ReactEventHandler => {\n const { channel } = useChannelStateContext('useMarkUnreadHandler');\n\n return async (event) => {\n event.preventDefault();\n if (!message?.id) {\n console.warn('Mark unread handler does not have access to message id');\n return;\n }\n\n await channel.markUnread({ message_id: message.id });\n };\n};\n","import { isUserMuted } from '../utils';\n\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\nimport { useChatContext } from '../../../context/ChatContext';\nimport { useTranslationContext } from '../../../context/TranslationContext';\n\nimport type { LocalMessage } from 'stream-chat';\n\nimport type { ReactEventHandler } from '../types';\n\nexport const missingUseMuteHandlerParamsWarning =\n 'useMuteHandler was called but it is missing one or more necessary parameter.';\n\nexport const useMuteHandler = (message?: LocalMessage): ReactEventHandler => {\n const { mutes } = useChannelStateContext('useMuteHandler');\n const { client } = useChatContext('useMuteHandler');\n const { t } = useTranslationContext('useMuteHandler');\n\n return async (event) => {\n event.preventDefault();\n\n if (!t || !message?.user || !client) {\n console.warn(missingUseMuteHandlerParamsWarning);\n return;\n }\n\n if (!isUserMuted(message, mutes)) {\n await client.muteUser(message.user.id);\n } else {\n await client.unmuteUser(message.user.id);\n }\n };\n};\n","import { useChannelActionContext } from '../../../context/ChannelActionContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ReactEventHandler } from '../types';\n\nexport const useOpenThreadHandler = (\n message?: LocalMessage,\n customOpenThread?: (message: LocalMessage, event: React.BaseSyntheticEvent) => void,\n): ReactEventHandler => {\n const { openThread: channelOpenThread } =\n useChannelActionContext('useOpenThreadHandler');\n\n const openThread = customOpenThread || channelOpenThread;\n\n return (event) => {\n if (!openThread || !message) {\n console.warn(\n 'Open thread handler was called but it is missing one of its parameters',\n );\n return;\n }\n\n openThread(message, event);\n };\n};\n","import { useChannelActionContext } from '../../../context/ChannelActionContext';\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\nimport { useChatContext } from '../../../context/ChatContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ReactEventHandler } from '../types';\n\nexport const usePinHandler = (message: LocalMessage) => {\n const { updateMessage } = useChannelActionContext('usePinHandler');\n const { channelCapabilities = {} } = useChannelStateContext('usePinHandler');\n const { client } = useChatContext('usePinHandler');\n\n const canPin = !!channelCapabilities['pin-message'];\n\n const handlePin: ReactEventHandler = async (event) => {\n event.preventDefault();\n\n if (!message) return;\n\n if (!message.pinned) {\n try {\n const optimisticMessage: LocalMessage = {\n ...message,\n pinned: true,\n pinned_at: new Date(),\n pinned_by: client.user,\n };\n\n updateMessage(optimisticMessage);\n\n await client.pinMessage(message);\n } catch (e) {\n updateMessage(message);\n }\n } else {\n try {\n const optimisticMessage = {\n ...message,\n pin_expires: null,\n pinned: false,\n pinned_at: null,\n pinned_by: null,\n };\n\n updateMessage(optimisticMessage);\n\n await client.unpinMessage(message);\n } catch (e) {\n updateMessage(message);\n }\n }\n };\n\n return { canPin, handlePin };\n};\n","/* eslint-disable sort-keys */\n\nimport React from 'react';\n\ntype LegacyReactionOptions = Array<{\n Component: React.ComponentType;\n type: string;\n name?: string;\n}>;\n\ntype ReactionOptionData = {\n Component: React.ComponentType;\n name?: string;\n unicode?: string;\n};\n\nexport type ReactionOptions =\n | LegacyReactionOptions\n | {\n quick: {\n [key: string]: ReactionOptionData;\n };\n extended?: {\n [key: string]: ReactionOptionData;\n };\n };\n\nexport const mapEmojiMartData = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n emojiMartData: any,\n): NonNullable<Exclude<ReactionOptions, LegacyReactionOptions>['extended']> => {\n if (!emojiMartData || !emojiMartData.emojis) {\n return {};\n }\n\n const newMap: ReturnType<typeof mapEmojiMartData> = {};\n\n for (const emojiId in emojiMartData.emojis) {\n const emojiData = emojiMartData.emojis[emojiId];\n const [firstEmoji] = emojiData.skins;\n\n if (!firstEmoji || !firstEmoji.native) continue;\n\n const nativeEmoji = firstEmoji.native as string;\n\n const unicode = emojiToUnicode(nativeEmoji);\n\n newMap[unicode] = {\n Component: () => <>{nativeEmoji}</>,\n name: emojiData.name,\n unicode,\n };\n }\n\n return newMap;\n};\n\nexport type AdvancedReactionOptions = {\n quick: ReactionOptions;\n extended: ReactionOptions;\n};\n\nexport const emojiToUnicode = (emoji: string) => {\n const unicodeStrings = [];\n for (const c of emoji) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const codePoint = c.codePointAt(0)!;\n unicodeStrings.push(`U+${codePoint.toString(16).toUpperCase().padStart(4, '0')}`);\n }\n\n return unicodeStrings.join('-');\n};\n\nexport const unicodeToEmoji = (unicode: string) =>\n unicode\n .split('-')\n .map((code) => String.fromCodePoint(parseInt(code.replace('U+', ''), 16)))\n .join('');\n\nexport const defaultReactionOptions: ReactionOptions = {\n quick: {\n haha: {\n Component: () => <>😂</>,\n name: 'Joy',\n unicode: emojiToUnicode('😂'),\n },\n like: {\n Component: () => <>👍</>,\n name: 'Thumbs up',\n unicode: emojiToUnicode('👍'),\n },\n love: {\n Component: () => <>❤️</>,\n name: 'Heart',\n unicode: emojiToUnicode('❤️'),\n },\n sad: { Component: () => <>😔</>, name: 'Sad', unicode: emojiToUnicode('😔') },\n wow: {\n Component: () => <>😮</>,\n name: 'Astonished',\n unicode: emojiToUnicode('😮'),\n },\n fire: {\n Component: () => <>🔥</>,\n name: 'Fire',\n unicode: emojiToUnicode('🔥'),\n },\n },\n};\n\nexport const getHasExtendedReactions = (reactionOptions: ReactionOptions) =>\n !Array.isArray(reactionOptions) &&\n typeof reactionOptions.extended !== 'undefined' &&\n Object.keys(reactionOptions.extended).length > 0;\n\n/**\n * Resolves the native emoji character (e.g. \"👍\") for a given reaction type from\n * the configured reaction options. The value is used as the `emoji_code` sent\n * with a reaction so that push notifications can render the emoji.\n *\n * Returns `undefined` when no `unicode` is available for the type (e.g. legacy\n * array reaction options or custom options that omit `unicode`).\n */\nexport const getEmojiCodeByReactionType = (\n reactionOptions: ReactionOptions,\n reactionType: string,\n): string | undefined => {\n // Legacy array reaction options carry no unicode data.\n if (Array.isArray(reactionOptions)) return undefined;\n\n const unicode =\n reactionOptions.quick[reactionType]?.unicode ??\n reactionOptions.extended?.[reactionType]?.unicode;\n\n return unicode ? unicodeToEmoji(unicode) : undefined;\n};\n","import type React from 'react';\nimport { useCallback } from 'react';\nimport throttle from 'lodash.throttle';\n\nimport { useThreadContext } from '../../Threads';\nimport { useChannelActionContext } from '../../../context/ChannelActionContext';\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\nimport { useChatContext } from '../../../context/ChatContext';\nimport { useComponentContext } from '../../../context/ComponentContext';\nimport {\n defaultReactionOptions,\n getEmojiCodeByReactionType,\n} from '../../Reactions/reactionOptions';\n\nimport type { LocalMessage, Reaction, ReactionResponse } from 'stream-chat';\n\nexport const reactionHandlerWarning = `Reaction handler was called, but it is missing one of its required arguments.\nMake sure the ChannelAction and ChannelState contexts are properly set and the hook is initialized with a valid message.`;\n\nexport const useReactionHandler = (message?: LocalMessage) => {\n const thread = useThreadContext();\n const { updateMessage } = useChannelActionContext('useReactionHandler');\n const { channel, channelCapabilities } = useChannelStateContext('useReactionHandler');\n const { client } = useChatContext('useReactionHandler');\n const { reactionOptions = defaultReactionOptions } =\n useComponentContext('useReactionHandler');\n\n const createMessagePreview = useCallback(\n (add: boolean, reaction: ReactionResponse, message: LocalMessage): LocalMessage => {\n const newReactionGroups = message?.reaction_groups || {};\n const reactionType = reaction.type;\n const hasReaction = !!newReactionGroups[reactionType];\n\n if (add) {\n const timestamp = new Date().toISOString();\n newReactionGroups[reactionType] = hasReaction\n ? {\n ...newReactionGroups[reactionType],\n count: newReactionGroups[reactionType].count + 1,\n }\n : {\n count: 1,\n first_reaction_at: timestamp,\n last_reaction_at: timestamp,\n sum_scores: 1,\n };\n } else {\n if (hasReaction && newReactionGroups[reactionType].count > 1) {\n newReactionGroups[reactionType] = {\n ...newReactionGroups[reactionType],\n count: newReactionGroups[reactionType].count - 1,\n };\n } else {\n delete newReactionGroups[reactionType];\n }\n }\n\n const newReactions: ReactionResponse[] | undefined = add\n ? [reaction, ...(message?.latest_reactions || [])]\n : message.latest_reactions?.filter(\n (item) => !(item.type === reaction.type && item.user_id === reaction.user_id),\n );\n\n const newOwnReactions = add\n ? [reaction, ...(message?.own_reactions || [])]\n : message?.own_reactions?.filter((item) => item.type !== reaction.type);\n\n return {\n ...message,\n latest_reactions: newReactions || message.latest_reactions,\n own_reactions: newOwnReactions,\n reaction_groups: newReactionGroups,\n };\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [client.user, client.userID],\n );\n\n const createReactionPreview = (type: string, emojiCode?: string) => ({\n message_id: message?.id,\n score: 1,\n type,\n user: client.user,\n user_id: client.user?.id,\n ...(emojiCode && { emoji_code: emojiCode }),\n });\n\n const toggleReaction = throttle(async (id: string, type: string, add: boolean) => {\n if (!message || !channelCapabilities['send-reaction']) return;\n\n // Native emoji (e.g. \"👍\") for this reaction type, sent as `emoji_code` so\n // push notifications in mobile SDKs can render the emoji.\n const emojiCode = getEmojiCodeByReactionType(reactionOptions, type);\n const newReaction = createReactionPreview(type, emojiCode) as ReactionResponse;\n const tempMessage = createMessagePreview(add, newReaction, message);\n\n try {\n updateMessage(tempMessage);\n thread?.upsertReplyLocally({ message: tempMessage });\n\n const messageResponse = add\n ? await channel.sendReaction(id, {\n type,\n ...(emojiCode && { emoji_code: emojiCode }),\n } as Reaction)\n : await channel.deleteReaction(id, type);\n\n // seems useless as we're expecting WS event to come in and replace this anyway\n updateMessage(messageResponse.message);\n } catch (error) {\n // revert to the original message if the API call fails\n updateMessage(message);\n thread?.upsertReplyLocally({ message });\n }\n }, 1000);\n\n return async (reactionType: string, event?: React.BaseSyntheticEvent) => {\n if (event?.preventDefault) {\n event.preventDefault();\n }\n\n if (!message) {\n return console.warn(reactionHandlerWarning);\n }\n\n let userExistingReaction = null as unknown as ReactionResponse;\n\n if (message.own_reactions) {\n message.own_reactions.forEach((reaction) => {\n // own user should only ever contain the current user id\n // just in case we check to prevent bugs with message updates from breaking reactions\n if (\n reaction.user &&\n client.userID === reaction.user.id &&\n reaction.type === reactionType\n ) {\n userExistingReaction = reaction;\n } else if (reaction.user && client.userID !== reaction.user.id) {\n console.warn(\n `message.own_reactions contained reactions from a different user, this indicates a bug`,\n );\n }\n });\n }\n\n try {\n if (userExistingReaction) {\n await toggleReaction(message.id, userExistingReaction.type, false);\n } else {\n await toggleReaction(message.id, reactionType, true);\n }\n } catch (error) {\n console.log({ error });\n }\n };\n};\n","import type { RetrySendMessage } from '../../../context/ChannelActionContext';\nimport { useChannelActionContext } from '../../../context/ChannelActionContext';\n\nexport const useRetryHandler = (\n customRetrySendMessage?: RetrySendMessage,\n): RetrySendMessage => {\n const { retrySendMessage: contextRetrySendMessage } =\n useChannelActionContext('useRetryHandler');\n\n const retrySendMessage = customRetrySendMessage || contextRetrySendMessage;\n\n return async (message) => {\n if (message) {\n await retrySendMessage(message);\n }\n };\n};\n","import type { User } from 'stream-chat';\n\nimport type { ReactEventHandler } from '../types';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type UserEventHandler = (event: React.BaseSyntheticEvent, user: User) => void;\n\nexport const useUserHandler = (\n message?: LocalMessage,\n eventHandlers?: {\n onUserClickHandler?: UserEventHandler;\n onUserHoverHandler?: UserEventHandler;\n },\n): {\n onUserClick: ReactEventHandler;\n onUserHover: ReactEventHandler;\n} => ({\n onUserClick: (event) => {\n if (typeof eventHandlers?.onUserClickHandler !== 'function' || !message?.user) {\n return;\n }\n eventHandlers.onUserClickHandler(event, message.user);\n },\n onUserHover: (event) => {\n if (typeof eventHandlers?.onUserHoverHandler !== 'function' || !message?.user) {\n return;\n }\n\n eventHandlers.onUserHoverHandler(event, message.user);\n },\n});\n","import { useChannelStateContext } from '../../../context/ChannelStateContext';\nimport { useChatContext } from '../../../context/ChatContext';\nimport type { LocalMessage } from 'stream-chat';\n\nexport const useUserRole = (message: LocalMessage, disableQuotedMessages?: boolean) => {\n const { channel, channelCapabilities = {} } = useChannelStateContext('useUserRole');\n const { client } = useChatContext('useUserRole');\n\n /**\n * @deprecated as it relies on `membership.role` check which is already deprecated and shouldn't be used anymore.\n * `isAdmin` will be removed in future release. See `channelCapabilities`.\n */\n const isAdmin =\n client.user?.role === 'admin' || channel.state.membership.role === 'admin';\n\n /**\n * @deprecated as it relies on `membership.role` check which is already deprecated and shouldn't be used anymore.\n * `isOwner` will be removed in future release. See `channelCapabilities`.\n */\n const isOwner = channel.state.membership.role === 'owner';\n\n /**\n * @deprecated as it relies on `membership.role` check which is already deprecated and shouldn't be used anymore.\n * `isModerator` will be removed in future release. See `channelCapabilities`.\n */\n const isModerator =\n client.user?.role === 'channel_moderator' ||\n channel.state.membership.role === 'channel_moderator' ||\n channel.state.membership.role === 'moderator' ||\n channel.state.membership.is_moderator === true ||\n channel.state.membership.channel_role === 'channel_moderator';\n\n const isMyMessage = client.userID === message.user?.id;\n\n const canEdit =\n !message.poll &&\n message.command !== 'giphy' &&\n (channelCapabilities['update-any-message'] ||\n (isMyMessage && channelCapabilities['update-own-message']));\n\n const canDelete =\n channelCapabilities['delete-any-message'] ||\n (isMyMessage && channelCapabilities['delete-own-message']);\n\n const canFlag = !isMyMessage && channelCapabilities['flag-message'];\n const canMute = !isMyMessage && channelCapabilities['mute-channel'];\n const canBlockUser = !isMyMessage;\n const canMarkUnread = !isMyMessage && channelCapabilities['read-events'];\n const canQuote = !disableQuotedMessages && channelCapabilities['quote-message'];\n const canReact = channelCapabilities['send-reaction'];\n const canReply = channelCapabilities['send-reply'];\n const canSendMessage = channelCapabilities['send-message'];\n\n return {\n canBlockUser,\n canDelete,\n canEdit,\n canFlag,\n canMarkUnread,\n canMute,\n canQuote,\n canReact,\n canReply,\n canSendMessage,\n isAdmin,\n isModerator,\n isMyMessage,\n isOwner,\n };\n};\n","import { useChatContext } from '../../../context';\nimport { useStableCallback } from '../../../utils/useStableCallback';\nimport type {\n LocalMessage,\n ReactionResponse,\n ReactionSort,\n StreamChat,\n} from 'stream-chat';\nimport type { ReactionType } from '../../Reactions/types';\n\nexport const MAX_MESSAGE_REACTIONS_TO_FETCH = 1000;\n\nexport function useReactionsFetcher(message: LocalMessage) {\n const { client } = useChatContext('useRectionsFetcher');\n\n return useStableCallback((reactionType?: ReactionType, sort?: ReactionSort) =>\n fetchMessageReactions(client, message.id, reactionType, sort),\n );\n}\n\nasync function fetchMessageReactions(\n client: StreamChat,\n messageId: string,\n reactionType?: ReactionType,\n sort?: ReactionSort,\n) {\n const reactions: ReactionResponse[] = [];\n const limit = 25;\n let next: string | undefined;\n let hasNext = true;\n\n while (hasNext && reactions.length < MAX_MESSAGE_REACTIONS_TO_FETCH) {\n const response = await client.queryReactions(\n messageId,\n reactionType ? { type: reactionType } : {},\n sort,\n { limit, next },\n );\n\n reactions.push(...response.reactions);\n next = response.next;\n hasNext = Boolean(next);\n }\n\n return reactions;\n}\n","import { useEffect, useRef, useState } from 'react';\n\nimport { useStableCallback } from '../../../utils/useStableCallback';\nimport type { StreamedMessageTextProps } from '../StreamedMessageText';\n\nexport type UseMessageTextStreamingProps = Pick<\n StreamedMessageTextProps,\n 'streamingLetterIntervalMs' | 'renderingLetterCount'\n> & { text: string };\n\nconst DEFAULT_LETTER_INTERVAL = 30;\nconst DEFAULT_RENDERING_LETTER_COUNT = 2;\n\n/**\n * A hook that returns text in a streamed, typewriter fashion. The speed of streaming is\n * configurable.\n * @param {number} [streamingLetterIntervalMs=30] - The timeout between each typing animation in milliseconds.\n * @param {number} [renderingLetterCount=2] - The number of letters to be rendered each time we update.\n * @param {string} text - The text that we want to render in a typewriter fashion.\n * @returns {{ streamedMessageText: string }} - A substring of the text property, up until we've finished rendering the typewriter animation.\n */\nexport const useMessageTextStreaming = ({\n renderingLetterCount = DEFAULT_RENDERING_LETTER_COUNT,\n streamingLetterIntervalMs = DEFAULT_LETTER_INTERVAL,\n text,\n}: UseMessageTextStreamingProps) => {\n const [streamedMessageText, setStreamedMessageText] = useState<string>(text);\n const textCursor = useRef<number>(text.length);\n\n useEffect(() => {\n const textLength = text.length;\n\n const interval = setInterval(() => {\n if (!text || textCursor.current >= textLength) {\n clearInterval(interval);\n return;\n }\n const newCursorValue = textCursor.current + renderingLetterCount;\n const newText = text.substring(0, newCursorValue);\n textCursor.current += newText.length - textCursor.current;\n setStreamedMessageText(newText);\n }, streamingLetterIntervalMs);\n\n return () => {\n clearInterval(interval);\n };\n }, [streamingLetterIntervalMs, renderingLetterCount, text]);\n\n const skipAnimation = useStableCallback(() => {\n textCursor.current = text.length;\n setStreamedMessageText(text);\n });\n\n return { skipAnimation, streamedMessageText } as const;\n};\n","import { useCallback } from 'react';\nimport { useChatContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport type { ReminderManagerState } from 'stream-chat';\n\nexport const useMessageReminder = (messageId: string) => {\n const { client } = useChatContext();\n const reminderSelector = useCallback(\n (state: ReminderManagerState) => ({\n reminder: state.reminders.get(messageId),\n }),\n [messageId],\n );\n const { reminder } = useStateStore(client.reminders.state, reminderSelector);\n return reminder;\n};\n","import React, { type ComponentProps, type ElementType, useMemo } from 'react';\nimport { useComponentContext } from '../../context';\nimport { type AvatarProps, Avatar as DefaultAvatar } from './Avatar';\nimport clsx from 'clsx';\nimport { Badge, type BadgeSize } from '../Badge';\n\nexport function AvatarStack({\n badgeSize,\n capLimit = 3,\n component: Component = 'div',\n displayInfo = [],\n size,\n}: {\n component?: ElementType;\n displayInfo?: (Pick<AvatarProps, 'imageUrl' | 'userName'> & { id?: string })[];\n size: 'md' | 'sm' | 'xs' | null;\n badgeSize?: BadgeSize;\n capLimit?: number;\n}) {\n const { Avatar = DefaultAvatar } = useComponentContext(AvatarStack.name);\n\n const displayInfoToRender = useMemo(\n () => (displayInfo.length > capLimit ? displayInfo.slice(0, capLimit) : displayInfo),\n [displayInfo, capLimit],\n );\n const overflowCount = displayInfo.length - displayInfoToRender.length;\n\n if (!displayInfo.length) {\n return null;\n }\n\n return (\n <Component\n className={clsx('str-chat__avatar-stack', {\n [`str-chat__avatar-stack--size-${size}`]: typeof size === 'string',\n })}\n data-testid='avatar-stack'\n >\n {displayInfoToRender.map((info, index) => (\n <Avatar\n imageUrl={info.imageUrl}\n key={info.id ?? `${info.userName}-${info.imageUrl}-${index}`}\n size={size}\n userName={info.userName}\n />\n ))}\n {typeof overflowCount === 'number' && overflowCount > 0 && (\n <Badge\n className='str-chat__avatar-stack__count-badge'\n data-testid='avatar-stack-count-badge'\n size={badgeSize ?? size}\n variant='counter'\n >\n +{overflowCount}\n </Badge>\n )}\n </Component>\n );\n}\n\nexport type AvatarStackProps = ComponentProps<typeof AvatarStack>;\n","import React, { type ComponentProps, type PropsWithChildren } from 'react';\nimport clsx from 'clsx';\nimport { Button, type ButtonProps } from '../../Button';\nimport {\n useComponentContextIcons,\n useModalContext,\n useTranslationContext,\n} from '../../../context';\nimport { useAriaIdentifiers } from '../../../a11y/hooks/useAriaIdentifiers';\n\nconst ViewerRoot = ({ children, className, ...props }: ComponentProps<'div'>) => (\n <div {...props} className={clsx('str-chat__viewer', className)}>\n {children}\n </div>\n);\n\nexport type ViewerHeaderProps = {\n title: string;\n description?: string;\n className?: string;\n close?: () => void;\n goBack?: () => void;\n descriptionId?: string;\n titleId?: string;\n};\n\nconst ViewerHeader = ({\n className,\n close,\n description,\n descriptionId,\n goBack,\n title,\n titleId,\n}: ViewerHeaderProps) => {\n const { t } = useTranslationContext();\n const { dialogId } = useModalContext();\n const { IconArrowLeft, IconXmark } = useComponentContextIcons();\n const { descriptionId: derivedDescriptionId, titleId: derivedTitleId } =\n useAriaIdentifiers(dialogId);\n const resolvedTitleId = titleId ?? derivedTitleId;\n const resolvedDescriptionId = descriptionId ?? derivedDescriptionId;\n\n return (\n <div className={clsx('str-chat__viewer__header', className)}>\n {goBack && (\n <Button\n appearance='ghost'\n aria-describedby={\n description != null && description !== '' ? resolvedDescriptionId : undefined\n }\n aria-label={t('Back')}\n circular\n className='str-chat__viewer__header__go-back-button'\n onClick={goBack}\n size='sm'\n variant='secondary'\n >\n <IconArrowLeft />\n </Button>\n )}\n <div className='str-chat__viewer__header__title-group'>\n <h2 className='str-chat__viewer__header__title' id={resolvedTitleId}>\n {title}\n </h2>\n {description != null && description !== '' && (\n <p className='str-chat__viewer__header__description' id={resolvedDescriptionId}>\n {description}\n </p>\n )}\n </div>\n {close && (\n <Button\n appearance='ghost'\n aria-describedby={\n description != null && description !== '' ? resolvedDescriptionId : undefined\n }\n aria-label={t('Close dialog')}\n circular\n className='str-chat__viewer__header__close-button'\n onClick={close}\n size='sm'\n variant='secondary'\n >\n <IconXmark />\n </Button>\n )}\n </div>\n );\n};\n\nexport type ViewerBodyProps = PropsWithChildren<{\n className?: string;\n}>;\n\nconst ViewerBody = ({ children, className }: ViewerBodyProps) => (\n <div className={clsx('str-chat__viewer__body', className)}>{children}</div>\n);\n\nexport type ViewerFooterProps = PropsWithChildren<{\n className?: string;\n}>;\n\nconst ViewerFooter = ({ children, className }: ViewerFooterProps) => (\n <div className={clsx('str-chat__viewer__footer', className)}>{children}</div>\n);\n\ntype ViewerFooterControlsProps = PropsWithChildren<{\n className?: string;\n}>;\n\nconst ViewerFooterControls = ({ children, className }: ViewerFooterControlsProps) => (\n <div className={clsx('str-chat__viewer__footer__controls', className)}>{children}</div>\n);\n\nconst ViewerFooterControlsButtonSecondary = ({ className, ...props }: ButtonProps) => (\n <Button\n appearance='ghost'\n className={clsx('str-chat__viewer__footer__controls-button', className)}\n size='md'\n variant='secondary'\n {...props}\n />\n);\n\nconst ViewerFooterControlsButtonPrimary = ({ className, ...props }: ButtonProps) => (\n <Button\n appearance='solid'\n className={clsx('str-chat__viewer__footer__controls-button', className)}\n size='md'\n variant='primary'\n {...props}\n />\n);\n\nexport const Viewer = {\n Body: ViewerBody,\n Footer: ViewerFooter,\n FooterControls: ViewerFooterControls,\n FooterControlsButtonPrimary: ViewerFooterControlsButtonPrimary,\n FooterControlsButtonSecondary: ViewerFooterControlsButtonSecondary,\n Header: ViewerHeader,\n Root: ViewerRoot,\n};\n","import type { ComponentType, PropsWithChildren } from 'react';\nimport React from 'react';\nimport { GlobalModal, type ModalProps } from '../Modal';\nimport { MessageBounceProvider, useComponentContext } from '../../context';\nimport type { MessageBouncePromptProps } from './MessageBouncePrompt';\n\nexport type MessageBounceModalProps = PropsWithChildren<\n ModalProps & {\n MessageBouncePrompt: ComponentType<MessageBouncePromptProps>;\n }\n>;\n\nexport function MessageBounceModal({\n MessageBouncePrompt,\n ...modalProps\n}: MessageBounceModalProps) {\n const { Modal = GlobalModal } = useComponentContext();\n return (\n <Modal className='str-chat__message-bounce-modal' {...modalProps}>\n <MessageBounceProvider>\n <MessageBouncePrompt />\n </MessageBounceProvider>\n </Modal>\n );\n}\n","import type { MouseEventHandler } from 'react';\nimport React from 'react';\nimport {\n useComponentContextIcons,\n useMessageBounceContext,\n useModalContext,\n useTranslationContext,\n} from '../../context';\nimport { Button } from '../Button';\nimport { Alert } from '../Dialog';\nimport type { PropsWithChildrenOnly } from '../../types/types';\n\nexport type MessageBouncePromptProps = PropsWithChildrenOnly;\n\n// todo: shall we rename this to MessageBounceAlert?\nexport function MessageBouncePrompt({ children }: MessageBouncePromptProps) {\n const { IconExclamationMark } = useComponentContextIcons();\n\n const { handleDelete, handleEdit, handleRetry } = useMessageBounceContext();\n const { t } = useTranslationContext();\n const { close } = useModalContext();\n\n function createHandler(\n handle: MouseEventHandler<HTMLButtonElement>,\n ): MouseEventHandler<HTMLButtonElement> {\n return (e) => {\n handle(e);\n close();\n };\n }\n\n return (\n <Alert.Root\n className='str-chat__message-bounce-alert'\n data-testid='message-bounce-prompt'\n >\n <Alert.Header\n className='str-chat__message-bounce-alert-header'\n description={\n !children\n ? t(\n 'Review this message and choose whether to delete it, edit it, or send it anyway',\n )\n : undefined\n }\n Icon={IconExclamationMark}\n title={\n !children ? t('This message did not meet our content guidelines') : undefined\n }\n >\n {children}\n </Alert.Header>\n <Alert.Actions className={'str-chat__message-bounce-actions'}>\n <Button\n appearance='outline'\n className='str-chat__message-bounce-delete'\n data-testid='message-bounce-delete'\n onClick={createHandler(handleDelete)}\n size='md'\n variant='danger'\n >\n {t('Delete')}\n </Button>\n <Button\n appearance='outline'\n className='str-chat__message-bounce-edit'\n data-testid='message-bounce-edit'\n onClick={createHandler(handleEdit)}\n size='md'\n variant='secondary'\n >\n {t('Edit Message')}\n </Button>\n <Button\n appearance='outline'\n className='str-chat__message-bounce-send'\n data-testid='message-bounce-send'\n onClick={createHandler(handleRetry)}\n size='md'\n variant='secondary'\n >\n {t('Send Anyway')}\n </Button>\n </Alert.Actions>\n </Alert.Root>\n );\n}\n","import React, { type ComponentProps } from 'react';\nimport clsx from 'clsx';\n\nexport const MessageBubble = ({ className, ...props }: ComponentProps<'div'>) => (\n <div {...props} className={clsx('str-chat__message-bubble', className)} />\n);\n","import React from 'react';\n\nimport { useComponentContextIcons } from '../../context';\nimport { useTranslationContext } from '../../context/TranslationContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport { MessageBubble } from './MessageBubble';\n\nexport type MessageDeletedProps = {\n message: LocalMessage;\n};\n\nexport const MessageDeletedBubble = () => {\n const { IconNoSign } = useComponentContextIcons();\n\n const { t } = useTranslationContext();\n\n return (\n <MessageBubble data-testid={'message-deleted-bubble'}>\n <div className='str-chat__message-text'>\n <IconNoSign />\n <span>{t('Message deleted')}</span>\n </div>\n </MessageBubble>\n );\n};\n","import React from 'react';\nimport clsx from 'clsx';\n\nimport { useUserRole } from './hooks/useUserRole';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useMessageContext } from '../../context';\n\nexport const MessageBlocked = () => {\n const { message } = useMessageContext();\n const { t } = useTranslationContext('MessageBlocked');\n\n const { isMyMessage } = useUserRole(message);\n\n const messageClasses = clsx(\n 'str-chat__message str-chat__message--blocked',\n message.type,\n {\n 'str-chat__message--me': isMyMessage,\n 'str-chat__message--other': !isMyMessage,\n },\n );\n\n return (\n <div\n className={messageClasses}\n data-testid='message-blocked-component'\n key={message.id}\n >\n <div className='str-chat__message--blocked-inner'>\n {t('Message was blocked by moderation policies')}\n </div>\n </div>\n );\n};\n","import { useMemo } from 'react';\n\nimport { useChannelStateContext, useMessageContext } from '../../../context';\nimport { useUserRole } from '../../Message/hooks';\nimport {\n ACTIONS_NOT_WORKING_IN_THREAD,\n isMessageBounced,\n isMessageDeleted,\n isMessageErrorRetryable,\n isNetworkSendFailure,\n} from '../../Message/utils';\n\nimport type { MessageActionSetItem } from '../MessageActions';\nimport {\n isAudioAttachment,\n isFileAttachment,\n isImageAttachment,\n isVideoAttachment,\n isVoiceRecordingAttachment,\n} from 'stream-chat';\n\n/**\n * Base filter hook which covers actions of type `delete`, `edit`,\n * `flag`, `markUnread`, `mute`, `quote`, `react` and `reply`, whether\n * the rendered message is a reply (replies are limited to certain actions) and\n * whether the message has appropriate type and status (including soft-deleted).\n */\nexport const useBaseMessageActionSetFilter = (\n messageActionSet: MessageActionSetItem[],\n disable = false,\n) => {\n const { initialMessage: isInitialMessage, message } = useMessageContext();\n const { channelConfig } = useChannelStateContext();\n const messageIsDeleted = isMessageDeleted(message);\n const {\n canBlockUser,\n canDelete,\n canEdit,\n canFlag,\n canMarkUnread,\n canMute,\n canQuote,\n canReact,\n canReply,\n canSendMessage,\n } = useUserRole(message);\n const isMessageThreadReply = typeof message.parent_id === 'string';\n const isBounced = isMessageBounced(message);\n const allowRetry = isMessageErrorRetryable(message);\n const hasNetworkSendFailure = isNetworkSendFailure(message);\n\n return useMemo(() => {\n if (disable) return messageActionSet;\n\n // filter out all actions if any of these are true\n if (\n isBounced ||\n isInitialMessage || // not sure whether this thing even works anymore\n !message.type ||\n message.type === 'system' ||\n message.type === 'ephemeral' ||\n message.status === 'sending'\n )\n return [];\n\n return messageActionSet.filter((action) => {\n if (action.placement === 'quick-dropdown-toggle') return true;\n\n const type = action.type;\n\n // filter out actions with types that do not work in thread\n if (ACTIONS_NOT_WORKING_IN_THREAD.includes(type) && isMessageThreadReply)\n return false;\n\n // failed message menu has special treatment\n if (message.error) {\n return (\n (type === 'resendMessage' && canSendMessage && (allowRetry || isBounced)) ||\n (type === 'edit' && ((isBounced && canEdit) || hasNetworkSendFailure)) ||\n (type === 'delete' &&\n !messageIsDeleted &&\n ((isBounced && canDelete) || hasNetworkSendFailure))\n );\n }\n\n if (\n type === 'resendMessage' ||\n (type === 'blockUser' && !canBlockUser) ||\n (type === 'copyMessageText' && !message.text) ||\n (type === 'download' &&\n !message.attachments?.some(\n (attachment) =>\n isFileAttachment(attachment) ||\n isImageAttachment(attachment) ||\n isVideoAttachment(attachment) ||\n isAudioAttachment(attachment) ||\n isVoiceRecordingAttachment(attachment),\n )) ||\n (type === 'delete' && (!canDelete || messageIsDeleted)) ||\n (type === 'edit' && !canEdit) ||\n (type === 'flag' && !canFlag) ||\n (type === 'markUnread' && !canMarkUnread) ||\n (type === 'mute' && !canMute) ||\n (type === 'quote' && !canQuote) ||\n (type === 'react' && !canReact) ||\n (type === 'reply' && !canReply) ||\n (type === 'remindMe' && !channelConfig?.['user_message_reminders']) ||\n (type === 'saveForLater' && !channelConfig?.['user_message_reminders'])\n )\n return false;\n\n return true;\n });\n }, [\n allowRetry,\n canBlockUser,\n canDelete,\n canEdit,\n canFlag,\n canMarkUnread,\n canMute,\n canQuote,\n canReact,\n canReply,\n canSendMessage,\n channelConfig,\n isBounced,\n isInitialMessage,\n messageIsDeleted,\n isMessageThreadReply,\n message.error,\n message.attachments,\n message.status,\n message.text,\n message.type,\n disable,\n hasNetworkSendFailure,\n messageActionSet,\n ]);\n};\n","import React, { useEffect, useRef } from 'react';\n\nimport { useNotificationApi } from '../Notifications';\nimport {\n useChannelActionContext,\n useChannelStateContext,\n useComponentContextIcons,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\nimport { formatMessage, type LocalMessage } from 'stream-chat';\n\n/**\n * Indicator shown when the message was also sent to the main channel (show_in_channel === true).\n */\nexport const MessageAlsoSentInChannelIndicator = () => {\n const { IconArrowUpRight } = useComponentContextIcons();\n\n const { addNotification } = useNotificationApi();\n const { t } = useTranslationContext();\n const { channel } = useChannelStateContext();\n const { jumpToMessage, openThread } = useChannelActionContext();\n const { message, threadList } = useMessageContext('MessageAlsoSentInChannelIndicator');\n const targetMessageRef = useRef<LocalMessage | null | undefined>(undefined);\n\n const queryParent = () =>\n channel\n .getClient()\n .search({ cid: channel.cid }, { id: message.parent_id })\n .then(({ results }) => {\n if (!results.length) {\n throw new Error('Thread has not been found');\n }\n targetMessageRef.current = formatMessage(results[0].message);\n })\n .catch((error: Error) => {\n addNotification({\n context: { threadReply: message },\n emitter: 'MessageIsThreadReplyInChannelButtonIndicator',\n error,\n message: t('Thread has not been found'),\n severity: 'error',\n type: 'api:reply:search:failed',\n });\n });\n\n // todo: it is not possible to jump to a message in thread\n const jumpToReplyInChannelMessages = async (id: string) => {\n await jumpToMessage(id);\n // todo: we do not have API to control, whether thread of channel message list is show - on mobile devices important\n };\n\n useEffect(() => {\n if (\n targetMessageRef.current ||\n targetMessageRef.current === null ||\n !message.parent_id\n )\n return;\n const localMessage = channel.state.findMessage(message.parent_id);\n if (localMessage) {\n targetMessageRef.current = localMessage;\n return;\n }\n }, [channel, message]);\n\n const handleClickViewReference = async () => {\n if (!targetMessageRef.current) {\n // search query is performed here in order to prevent multiple search queries in useEffect\n // due to the message list 3x remounting its items\n if (threadList) {\n await jumpToReplyInChannelMessages(message.id); // we are in thread, and we want to jump to this reply in the main message list\n return;\n } else await queryParent(); // we are in the main list and need to query the thread\n }\n const target = targetMessageRef.current;\n if (!target) {\n // prevent further search queries if the message is not found in the DB\n targetMessageRef.current = null;\n return;\n }\n\n if (threadList) await jumpToReplyInChannelMessages(message.id);\n else openThread(target);\n };\n\n if (!message?.show_in_channel) return null;\n\n return (\n <div className='str-chat__message-also-sent-in-channel' role='status'>\n <IconArrowUpRight />\n <span>{threadList ? t('Also sent in channel') : t('Replied to a thread')}</span>\n <span> · </span>\n <button\n className='str-chat__message-also-sent-in-channel__link-button'\n onClick={handleClickViewReference}\n type='button'\n >\n {t('View')}\n </button>\n </div>\n );\n};\n","import type { MouseEventHandler } from 'react';\nimport type { UserResponse } from 'stream-chat';\nimport React, { useMemo } from 'react';\n\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useChannelStateContext, useComponentContext } from '../../context';\nimport { AvatarStack as DefaultAvatarStack } from '../Avatar';\nimport { extractDisplayInfo as defaultExtractDisplayInfo } from '../Avatar/utils';\n\nexport type MessageRepliesCountButtonProps = {\n /* If supplied, adds custom text to the end of a multiple replies message */\n labelPlural?: string;\n /* If supplied, adds custom text to the end of a single reply message */\n labelSingle?: string;\n /* Function to navigate into an existing thread on a message */\n onClick?: MouseEventHandler;\n /* The amount of replies (i.e., threaded messages) on a message */\n reply_count?: number;\n thread_participants?: UserResponse[];\n};\n\nfunction UnMemoizedMessageRepliesCountButton(props: MessageRepliesCountButtonProps) {\n const {\n AvatarStack = DefaultAvatarStack,\n extractDisplayInfo = defaultExtractDisplayInfo,\n } = useComponentContext(MessageRepliesCountButton.name);\n const {\n labelPlural,\n labelSingle,\n onClick,\n reply_count: replyCount = 0,\n thread_participants: threadParticipants = [],\n } = props;\n const { channelCapabilities } = useChannelStateContext();\n\n const { t } = useTranslationContext('MessageRepliesCountButton');\n\n const avatarStackDisplayInfo = useMemo(\n () => threadParticipants.slice(0, 3).map((user) => extractDisplayInfo({ user })),\n [extractDisplayInfo, threadParticipants],\n );\n\n if (!replyCount) return null;\n\n let replyCountText = t('replyCount', { count: replyCount });\n\n if (labelPlural && replyCount > 1) {\n replyCountText = `${replyCount} ${labelPlural}`;\n } else if (labelSingle) {\n replyCountText = `1 ${labelSingle}`;\n }\n\n return (\n <div className='str-chat__message-replies-count-button-wrapper'>\n <button\n className='str-chat__message-replies-count-button'\n data-testid='replies-count-button'\n disabled={!channelCapabilities['send-reply']}\n onClick={onClick}\n >\n {replyCountText}\n\n <AvatarStack displayInfo={avatarStackDisplayInfo} size='xs' />\n </button>\n </div>\n );\n}\n\nexport const MessageRepliesCountButton = React.memo(\n UnMemoizedMessageRepliesCountButton,\n) as typeof UnMemoizedMessageRepliesCountButton;\n","import React from 'react';\n\nimport {\n useChatContext,\n useComponentContextIcons,\n useTranslationContext,\n} from '../../context';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type PinIndicatorProps = {\n message?: LocalMessage;\n};\n\n/**\n * Default pinned message indicator. Renders \"Pinned by [name]\" with pin icon above the message bubble.\n * Name is taken from message.pinned_by (who pinned).\n */\nexport const PinIndicator = ({ message }: PinIndicatorProps) => {\n const { t } = useTranslationContext();\n const { client } = useChatContext();\n const { IconPin } = useComponentContextIcons();\n\n if (!message) return null;\n\n const isOwnPin = !!message.pinned_by?.id && message.pinned_by.id === client.user?.id;\n const name = message.pinned_by?.name ?? message.pinned_by?.id ?? '';\n\n const label = isOwnPin\n ? t('Pinned by You')\n : name\n ? t('Pinned by {{ name }}', { name })\n : t('Message pinned');\n\n return (\n <div className='str-chat__message-pin-indicator'>\n <div className='str-chat__message-pin-indicator__content'>\n <span aria-hidden className='str-chat__message-pin-indicator__icon'>\n <IconPin />\n </span>\n <span>{label}</span>\n </div>\n </div>\n );\n};\n","import React, { useState } from 'react';\nimport clsx from 'clsx';\nimport type { TooltipUsernameMapper } from './utils';\nimport { getReadByTooltipText, mapToUserNameOrId } from './utils';\nimport { PopperTooltip } from '../Tooltip';\nimport { useEnterLeaveHandlers } from '../Tooltip/hooks';\n\nimport { useChatContext } from '../../context/ChatContext';\nimport { useComponentContextIcons } from '../../context';\nimport { useMessageContext } from '../../context/MessageContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\n\nexport type MessageStatusProps = {\n /* Custom component to render when message is considered delivered, not read. The default UI renders MessageDeliveredIcon and a tooltip with string 'Delivered'. */\n MessageDeliveredStatus?: React.ComponentType;\n /* Custom component to render when message is considered delivered and read. The default UI renders the last reader's Avatar and a tooltip with string readers' names. */\n MessageReadStatus?: React.ComponentType;\n /* Custom component to render when message is considered as being the in the process of delivery. The default UI renders a clock icon and a tooltip with string 'Sending...'. */\n MessageSendingStatus?: React.ComponentType;\n /* Custom component to render when message is considered created on the server, but not delivered. The default UI renders MessageSentIcon and a tooltip with string 'Sent'. */\n MessageSentStatus?: React.ComponentType;\n /* Message type string to be added to CSS class names. */\n messageType?: string;\n /* Allows to customize the username(s) that appear on the message status tooltip */\n tooltipUserNameMapper?: TooltipUsernameMapper;\n};\n\nconst UnMemoizedMessageStatus = (props: MessageStatusProps) => {\n const {\n MessageDeliveredStatus,\n MessageReadStatus,\n MessageSendingStatus,\n MessageSentStatus,\n messageType = 'simple',\n tooltipUserNameMapper = mapToUserNameOrId,\n } = props;\n\n const { handleEnter, handleLeave, tooltipVisible } =\n useEnterLeaveHandlers<HTMLSpanElement>();\n\n const { client } = useChatContext('MessageStatus');\n const {\n deliveredTo,\n isMyMessage,\n lastOwnMessage,\n message,\n readBy,\n returnAllReadData,\n threadList,\n } = useMessageContext('MessageStatus');\n const { t } = useTranslationContext('MessageStatus');\n const { IconCheckmark1Small, IconChecks, IconClock } = useComponentContextIcons();\n const [referenceElement, setReferenceElement] = useState<HTMLSpanElement | null>(null);\n\n if (!isMyMessage() || message.type === 'error') return null;\n\n const justReadByMe = readBy?.length === 1 && readBy[0].id === client.user?.id;\n const deliveredOnlyToMe =\n deliveredTo?.length === 1 && deliveredTo[0].id === client.user?.id;\n const sending = message.status === 'sending';\n const read = !!(readBy?.length && !justReadByMe && !threadList);\n const delivered = !!(deliveredTo?.length && !deliveredOnlyToMe && !read && !threadList);\n const sent =\n (returnAllReadData || lastOwnMessage?.id === message.id) &&\n message.status === 'received' &&\n !delivered &&\n !read &&\n !threadList;\n\n const readersWithoutOwnUser = read\n ? readBy.filter((item) => item.id !== client.user?.id)\n : [];\n\n return (\n <span\n className={clsx(\n `str-chat__message-${messageType}-status str-chat__message-status`,\n {\n 'str-chat__message-status-delivered': delivered,\n 'str-chat__message-status-read-by': read,\n 'str-chat__message-status-sending': sending,\n 'str-chat__message-status-sent': sent,\n },\n )}\n data-testid={clsx({\n 'message-status-delivered': delivered,\n 'message-status-read-by': read,\n 'message-status-sending': sending,\n 'message-status-sent': sent,\n })}\n onMouseEnter={handleEnter}\n onMouseLeave={handleLeave}\n ref={setReferenceElement}\n >\n {sending &&\n (MessageSendingStatus ? (\n <MessageSendingStatus />\n ) : (\n <>\n <PopperTooltip\n offset={[0, 5]}\n referenceElement={referenceElement}\n visible={tooltipVisible}\n >\n {t('Sending...')}\n </PopperTooltip>\n <IconClock className='str-chat__message-status-sending' />\n </>\n ))}\n\n {sent &&\n (MessageSentStatus ? (\n <MessageSentStatus />\n ) : (\n <>\n <PopperTooltip\n offset={[0, 5]}\n referenceElement={referenceElement}\n visible={tooltipVisible}\n >\n {t('Sent')}\n </PopperTooltip>\n <IconCheckmark1Small className='str-chat__message-status-sent' />\n </>\n ))}\n\n {delivered &&\n (MessageDeliveredStatus ? (\n <MessageDeliveredStatus />\n ) : (\n <>\n <PopperTooltip\n offset={[0, 5]}\n referenceElement={referenceElement}\n visible={tooltipVisible}\n >\n {t('Delivered')}\n </PopperTooltip>\n <IconChecks className='str-chat__message-status-delivered' />\n </>\n ))}\n\n {read &&\n (MessageReadStatus ? (\n <MessageReadStatus />\n ) : (\n <>\n <PopperTooltip\n offset={[0, 5]}\n referenceElement={referenceElement}\n visible={tooltipVisible}\n >\n {getReadByTooltipText(readBy, t, client, tooltipUserNameMapper)}\n </PopperTooltip>\n\n <IconChecks className='str-chat__message-status-read' />\n\n {readersWithoutOwnUser.length > 1 && (\n <span\n className={`str-chat__message-${messageType}-status-number`}\n data-testid='message-status-read-by-many'\n >\n {readersWithoutOwnUser.length}\n </span>\n )}\n </>\n ))}\n </span>\n );\n};\n\nexport const MessageStatus = React.memo(\n UnMemoizedMessageStatus,\n) as typeof UnMemoizedMessageStatus;\n","import type { ReplaceFunction } from 'hast-util-find-and-replace';\nimport { findAndReplace } from 'hast-util-find-and-replace';\nimport { u } from 'unist-builder';\nimport type { Nodes } from 'hast';\n\nimport { EMOJI_REGEX } from '../../emojiRegex';\n\nexport const emojiMarkdownPlugin = () => {\n const replace: ReplaceFunction = (match) =>\n u('element', { properties: {}, tagName: 'emoji' }, [u('text', match)]);\n\n const transform = (node: Nodes) => findAndReplace(node, [EMOJI_REGEX, replace]);\n\n return transform;\n};\n","import type { Plugin } from 'unified';\nimport { visit } from 'unist-util-visit';\nimport type { Node, Parent as UnistParent } from 'unist';\nimport type { Root, RootContent, ThematicBreak } from 'mdast';\n\n/** Type guard: does the node have mdast children? */\nfunction isParentWithChildren(\n node: Node,\n): node is UnistParent & { children: RootContent[] } {\n const maybe = node as unknown as { children?: unknown };\n return Array.isArray(maybe.children);\n}\n\n/** Build a single <br> by mapping a standard mdast node via data.hName */\nfunction brNode(): ThematicBreak {\n return { data: { hName: 'br' }, type: 'thematicBreak' };\n}\n\n/**\n * Inserts runs of <br> between sibling block nodes to preserve the exact\n * number of *blank source lines* between them. No paragraph wrappers are added.\n *\n * Works because `mdast-util-to-hast` respects `data.hName`, turning our\n * `thematicBreak` into `<br>`. Multiple blank lines -> multiple `<br>` siblings.\n */\nexport const keepLineBreaksPlugin: Plugin<[], Root> = () => (tree) => {\n visit(\n tree as unknown as UnistParent, // visit needs a Unist parent-like root\n isParentWithChildren, // limit to parents with children\n (parent) => {\n const children = parent.children as RootContent[];\n if (children.length < 2) return;\n\n const out: RootContent[] = [];\n\n for (let i = 0; i < children.length; i++) {\n const curr = children[i];\n out.push(curr);\n\n if (i === children.length - 1) break;\n\n const next = children[i + 1];\n\n const currEndLine =\n curr.position && curr.position.end ? curr.position.end.line : undefined;\n const nextStartLine =\n next.position && next.position.start ? next.position.start.line : undefined;\n\n if (typeof currEndLine !== 'number' || typeof nextStartLine !== 'number') {\n continue;\n }\n\n // Markdown already separates blocks by at least one visual gap.\n // We add back only the *extra* blank lines from the source.\n const extraBlankLines = Math.max(0, nextStartLine - currEndLine - 1);\n if (extraBlankLines > 0) {\n for (let k = 0; k < extraBlankLines; k++) {\n out.push(brNode());\n }\n }\n }\n\n parent.children = out;\n },\n );\n};\n","import type { Plugin } from 'unified';\nimport type { Paragraph, Root, Text } from 'mdast';\n\n/**\n * Replace the parsed Markdown tree with a single paragraph containing the\n * original source as a plain text node. No Markdown formatting is interpreted.\n * React will escape it.\n */\nexport const remarkIgnoreMarkdown: Plugin<[], Root> = () => (tree, file) => {\n const source = String(file.value ?? '');\n\n const text: Text = { type: 'text', value: source };\n const paragraph: Paragraph = { children: [text], type: 'paragraph' };\n\n tree.children = [paragraph];\n};\n","import clsx from 'clsx';\nimport type { ComponentProps } from 'react';\nimport React from 'react';\n\nexport const Anchor = ({ children, href }: ComponentProps<'a'>) => {\n const isEmail = href?.startsWith('mailto:');\n const isUrl = href?.toLowerCase().startsWith('http');\n\n if (!href || (!isEmail && !isUrl)) return <>{children}</>;\n\n return (\n <a\n className={clsx({ 'str-chat__message-url-link': isUrl })}\n href={href}\n rel='nofollow noreferrer noopener'\n target='_blank'\n >\n {children}\n </a>\n );\n};\n","import React from 'react';\nimport type { PropsWithChildrenOnly } from '../../../../types/types';\n\nexport const Emoji = ({ children }: PropsWithChildrenOnly) => (\n <span className='inline-text-emoji' data-testid='inline-text-emoji'>\n {children}\n </span>\n);\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\n\nimport type { UserResponse } from 'stream-chat';\nimport type { RenderTextMentionEntity } from '../rehypePlugins/mentionsMarkdownPlugin';\n\ntype UserMentionNode = {\n mentionedEntity: Extract<RenderTextMentionEntity, { mentionType: 'user' }>;\n /**\n * @deprecated Use `mentionedEntity` instead.\n */\n mentionedUser: UserResponse;\n};\n\ntype NonUserMentionNode = {\n mentionedEntity: Exclude<RenderTextMentionEntity, { mentionType: 'user' }>;\n /**\n * @deprecated Use `mentionedEntity` instead.\n */\n mentionedUser?: undefined;\n};\n\nexport type MentionProps = PropsWithChildren<{\n node: UserMentionNode | NonUserMentionNode;\n}>;\n\nexport const Mention = ({ children, node: { mentionedEntity } }: MentionProps) => (\n <span\n className='str-chat__message-mention'\n data-mention-id={mentionedEntity.id}\n data-mention-type={mentionedEntity.mentionType}\n data-user-id={mentionedEntity.mentionType === 'user' ? mentionedEntity.id : undefined}\n >\n {children}\n </span>\n);\n","export const NullComponent = () => null;\n","import { Component } from 'react';\nimport type { PropsWithChildren, ReactNode } from 'react';\n\ntype ErrorBoundaryProps = PropsWithChildren<{ fallback?: ReactNode }>;\n\nexport class ErrorBoundary extends Component<ErrorBoundaryProps, { hasError: boolean }> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError() {\n return { hasError: true };\n }\n\n componentDidCatch(error: unknown, information: unknown) {\n console.error(error, information);\n }\n\n render() {\n if (this.state.hasError) {\n return this.props.fallback;\n }\n\n return this.props.children;\n }\n}\n","import React from 'react';\nimport ReactMarkdown, { defaultUrlTransform } from 'react-markdown';\nimport { find } from 'linkifyjs';\nimport remarkGfm from 'remark-gfm';\nimport type { ComponentType, JSX, ReactNode } from 'react';\nimport type { Options } from 'react-markdown';\nimport type { UserResponse } from 'stream-chat';\nimport type { PluggableList } from 'unified'; // A sub-dependency of react-markdown. The type is not declared or re-exported from anywhere else\n\nimport { Anchor, Emoji, Mention } from './componentRenderers';\nimport { detectHttp, matchMarkdownLinks, messageCodeBlocks } from './regex';\nimport {\n createMentionPluginAndDisplayTextSet,\n emojiMarkdownPlugin,\n getRenderTextMentionEntities,\n} from './rehypePlugins';\nimport {\n htmlToTextPlugin,\n imageToLink,\n keepLineBreaksPlugin,\n plusPlusToEmphasis,\n} from './remarkPlugins';\nimport { ErrorBoundary } from '../../UtilityComponents';\nimport type { MentionProps } from './componentRenderers/Mention';\nimport type { RenderTextMentionEntity } from './rehypePlugins';\n\nexport type RenderTextPluginConfigurator = (\n defaultPlugins: PluggableList,\n) => PluggableList;\n\ntype IntrinsicElementTagName = keyof JSX.IntrinsicElements & string;\n\nexport const defaultAllowedTagNames: Array<\n IntrinsicElementTagName | 'emoji' | 'mention'\n> = [\n 'html',\n 'text',\n 'br',\n 'p',\n 'em',\n 'strong',\n 'a',\n 'ol',\n 'ul',\n 'li',\n 'code',\n 'pre',\n 'blockquote',\n 'del',\n 'table',\n 'thead',\n 'tbody',\n 'th',\n 'tr',\n 'td',\n 'tfoot',\n // custom types (tagNames)\n 'emoji',\n 'mention',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'ins',\n];\n\nfunction formatUrlForDisplay(url: string) {\n try {\n return decodeURIComponent(url).replace(detectHttp, '');\n } catch (e) {\n return url;\n }\n}\n\nfunction encodeDecode(url: string) {\n try {\n return encodeURI(decodeURIComponent(url));\n } catch (error) {\n return url;\n }\n}\n\nconst urlTransform = (uri: string) =>\n uri.startsWith('app://') ? uri : defaultUrlTransform(uri);\n\nconst getPluginsForward: RenderTextPluginConfigurator = (plugins: PluggableList) =>\n plugins;\n\nexport const markDownRenderers: RenderTextOptions['customMarkDownRenderers'] = {\n a: Anchor,\n emoji: Emoji,\n mention: Mention,\n};\n\nexport type RenderTextOptions = {\n allowedTagNames?: Array<IntrinsicElementTagName | 'emoji' | 'mention' | (string & {})>;\n customMarkDownRenderers?: Options['components'] &\n Partial<{\n emoji: ComponentType;\n mention: ComponentType<MentionProps>;\n }>;\n getRehypePlugins?: RenderTextPluginConfigurator;\n getRemarkPlugins?: RenderTextPluginConfigurator;\n /**\n * Additive mention metadata for rendered message text.\n *\n * Prefer this over the deprecated `mentionedUsers` argument. Use it whenever\n * the message contains mention kinds beyond direct-user mentions\n * (for example `@channel`, `@here`, roles, or user groups) and `renderText`\n * needs the exact mention entities that should be highlighted in the rendered\n * markdown output.\n */\n messageMentionEntities?: RenderTextMentionEntity[];\n};\n\nexport type RenderTextFunction = (\n text?: string,\n /**\n * @deprecated Pass mention metadata through `options.messageMentionEntities`\n * instead. This argument only supports direct-user mentions. Will be removed in next major version.\n */\n mentionedUsers?: UserResponse[],\n options?: RenderTextOptions,\n) => ReactNode;\n\nexport function renderText(\n text?: string,\n /**\n * @deprecated Pass mention metadata through `options.messageMentionEntities`\n * instead. This argument only supports direct-user mentions.\n */\n mentionedUsers?: UserResponse[],\n {\n allowedTagNames = defaultAllowedTagNames,\n customMarkDownRenderers,\n getRehypePlugins = getPluginsForward,\n getRemarkPlugins = getPluginsForward,\n messageMentionEntities,\n }: RenderTextOptions = {},\n) {\n // take the @ mentions and turn them into markdown?\n // translate links\n if (!text) return null;\n if (text.trim().length === 1) return <>{text}</>;\n\n let newText = text;\n const renderTextMentionEntities =\n messageMentionEntities ??\n getRenderTextMentionEntities({ mentioned_users: mentionedUsers });\n const { mentionDisplayTextSet, plugin: mentionsPlugin } =\n createMentionPluginAndDisplayTextSet(renderTextMentionEntities);\n const markdownLinks = matchMarkdownLinks(newText);\n const codeBlocks = messageCodeBlocks(newText);\n\n // Extract all valid links/emails within text and replace it with proper markup\n // Revert the link order to avoid getting out of sync of the original start and end positions of links\n // - due to the addition of new characters when creating Markdown links\n const links = [...find(newText, 'email'), ...find(newText, 'url')];\n for (let i = links.length - 1; i >= 0; i--) {\n const { end, href, start, type, value } = links[i];\n const linkIsInBlock = codeBlocks.some((block) => block?.includes(value));\n\n // check if message is already markdown\n const noParsingNeeded =\n markdownLinks &&\n markdownLinks.filter((text) => {\n const strippedHref = href?.replace(detectHttp, '');\n const strippedText = text?.replace(detectHttp, '');\n\n if (!strippedHref || !strippedText) return false;\n\n return strippedHref.includes(strippedText) || strippedText.includes(strippedHref);\n });\n\n if (noParsingNeeded.length > 0 || linkIsInBlock) continue;\n\n try {\n // special case for mentions:\n // it could happen that a mention display text matches with an e-mail-like pattern.\n // in that case, we check whether the found e-mail is actually a mention\n // by naively checking for an existence of @ sign in front of it.\n if (type === 'email') {\n const mentionDisplayText = `@${value}`;\n if (mentionDisplayTextSet.has(mentionDisplayText)) {\n // FIXME: breaks if the mention symbol is not '@'\n const isMention = newText.charAt(start - 1) === '@';\n // in case of mention, we leave the match in its original form,\n // and we let `mentionsMarkdownPlugin` to do its job\n newText =\n newText.slice(0, start) +\n (isMention ? value : `[${value}](${encodeDecode(href)})`) +\n newText.slice(end);\n }\n } else {\n const displayLink = type === 'email' ? value : formatUrlForDisplay(href);\n\n newText =\n newText.slice(0, start) +\n `[${displayLink}](${encodeDecode(href)})` +\n newText.slice(end);\n }\n } catch (e) {\n void e;\n }\n }\n\n const remarkPlugins: PluggableList = [\n htmlToTextPlugin,\n keepLineBreaksPlugin,\n [remarkGfm, { singleTilde: false }],\n plusPlusToEmphasis,\n imageToLink,\n ];\n const rehypePlugins: PluggableList = [emojiMarkdownPlugin];\n\n if (renderTextMentionEntities.length) {\n rehypePlugins.push(mentionsPlugin);\n }\n\n return (\n <ErrorBoundary fallback={<>{text}</>}>\n <ReactMarkdown\n allowedElements={allowedTagNames}\n components={{\n ...markDownRenderers,\n ...customMarkDownRenderers,\n }}\n rehypePlugins={getRehypePlugins(rehypePlugins)}\n remarkPlugins={getRemarkPlugins(remarkPlugins)}\n skipHtml\n unwrapDisallowed\n urlTransform={urlTransform}\n >\n {newText}\n </ReactMarkdown>\n </ErrorBoundary>\n );\n}\n","import clsx from 'clsx';\nimport React, { useMemo } from 'react';\nimport { messageHasAttachments, messageTextHasEmojisOnly } from './utils';\nimport { useStableId } from '../UtilityComponents/useStableId';\n\nimport type { MessageContextValue } from '../../context';\nimport { useMessageContext, useTranslationContext } from '../../context';\nimport { VisuallyHidden } from '../VisuallyHidden';\nimport { renderText as defaultRenderText } from './renderText';\nimport { getRenderTextMentionEntities } from './renderText/rehypePlugins';\n\nimport type { LocalMessage } from 'stream-chat';\nimport { getTranslatedMessageText } from '../../context/MessageTranslationViewContext';\n\nexport type MessageTextProps = {\n /* Replaces the CSS class name placed on the component's inner `div` container */\n customInnerClass?: string;\n /* Adds a CSS class name to the component's outer `div` container */\n customWrapperClass?: string;\n /* The `StreamChat` message object, which provides necessary data to the underlying UI components (overrides the value stored in `MessageContext`) */\n message?: LocalMessage;\n} & Pick<MessageContextValue, 'renderText'>;\n\nconst UnMemoizedMessageTextComponent = (props: MessageTextProps) => {\n const {\n customInnerClass,\n customWrapperClass = '',\n message: propMessage,\n renderText: propsRenderText,\n } = props;\n\n const {\n message: contextMessage,\n onMentionsClickMessage,\n onMentionsHoverMessage,\n renderText: contextRenderText,\n translationView = 'translated',\n unsafeHTML,\n } = useMessageContext('MessageText');\n\n const renderText = propsRenderText ?? contextRenderText ?? defaultRenderText;\n\n const { t, userLanguage } = useTranslationContext('MessageText');\n const message = propMessage || contextMessage;\n const hasAttachment = messageHasAttachments(message);\n const messageContextId = useStableId();\n const messageTextId = useStableId();\n\n const messageTextToRender =\n translationView === 'original'\n ? message.text\n : getTranslatedMessageText({ language: userLanguage, message }) || message.text;\n const renderTextMentionEntities = useMemo(\n () =>\n getRenderTextMentionEntities({\n mentioned_channel: message.mentioned_channel,\n mentioned_groups: message.mentioned_groups,\n mentioned_here: message.mentioned_here,\n mentioned_roles: message.mentioned_roles,\n mentioned_users: message.mentioned_users,\n }),\n [\n message.mentioned_channel,\n message.mentioned_groups,\n message.mentioned_here,\n message.mentioned_roles,\n message.mentioned_users,\n ],\n );\n\n const messageText = useMemo(\n () =>\n renderText(messageTextToRender, message.mentioned_users, {\n messageMentionEntities: renderTextMentionEntities,\n }),\n [message.mentioned_users, messageTextToRender, renderText, renderTextMentionEntities],\n );\n\n const wrapperClass = customWrapperClass || 'str-chat__message-text';\n const innerClass = customInnerClass;\n const hasMentions = Boolean(renderTextMentionEntities.length);\n const isMentionsInteractionEnabled =\n hasMentions && typeof onMentionsClickMessage === 'function';\n const senderName = message.user?.name;\n const messageContext = senderName\n ? t('aria/Message from {{ user }},', { user: senderName })\n : t('aria/Message,');\n // `aria-labelledby` accepts a space-separated list of element ids. We point to the\n // hidden message context and the rendered message text so screen readers announce both.\n const messageLabelledBy = `${messageContextId} ${messageTextId}`;\n\n const handleMentionsKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!isMentionsInteractionEnabled || (event.key !== 'Enter' && event.key !== ' ')) {\n return;\n }\n\n event.preventDefault();\n onMentionsClickMessage(event);\n };\n\n if (!messageTextToRender) return null;\n\n /**\n * The component has two mutually exclusive focus models. The reason is this bit of behavior:\n *\n * if mentions are not interactive:\n * - the whole message text block is just a readable focus stop\n * - outer wrapper gets tabIndex={0}\n * - inner wrapper is not focusable\n * if mentions are interactive:\n * - keyboard interaction needs to land on the inner element, because that’s where onClick, onKeyDown, and mention hover/click behavior live\n * - inner wrapper gets tabIndex={0}\n * - outer wrapper must stop being focusable, otherwise you create an extra dead focus stop before the actual interactive target\n */\n return (\n <div\n aria-labelledby={isMentionsInteractionEnabled ? undefined : messageLabelledBy}\n className={wrapperClass}\n tabIndex={isMentionsInteractionEnabled ? undefined : 0}\n >\n <VisuallyHidden id={messageContextId}>{messageContext}</VisuallyHidden>\n <div\n aria-labelledby={isMentionsInteractionEnabled ? messageLabelledBy : undefined}\n className={clsx(innerClass, {\n [` str-chat__message-text-inner--is-emoji`]:\n messageTextHasEmojisOnly(message) && !message.quoted_message,\n [`str-chat__message-text-inner--has-attachment`]: hasAttachment,\n })}\n data-testid='message-text-inner-wrapper'\n onClick={onMentionsClickMessage}\n onKeyDown={isMentionsInteractionEnabled ? handleMentionsKeyDown : undefined}\n onMouseOver={onMentionsHoverMessage}\n tabIndex={isMentionsInteractionEnabled ? 0 : undefined}\n >\n {unsafeHTML && message.html ? (\n <div dangerouslySetInnerHTML={{ __html: message.html }} id={messageTextId} />\n ) : (\n <div id={messageTextId}>{messageText}</div>\n )}\n </div>\n </div>\n );\n};\n\nexport const MessageText = React.memo(\n UnMemoizedMessageTextComponent,\n) as typeof UnMemoizedMessageTextComponent;\n","import React, { useState } from 'react';\nimport type { LocalMessage } from 'stream-chat';\nimport type { TimestampFormatterOptions } from '../../i18n/types';\nimport { PopperTooltip } from '../Tooltip';\nimport { useEnterLeaveHandlers } from '../Tooltip/hooks';\nimport { Timestamp as DefaultTimestamp } from './Timestamp';\nimport {\n useComponentContext,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\n\nexport type MessageEditedIndicatorProps = TimestampFormatterOptions & {\n /* Adds a CSS class name to the component's outer container. */\n customClass?: string;\n /* The `StreamChat` message object, which provides necessary data to the underlying UI components (overrides the value from `MessageContext`) */\n message?: LocalMessage;\n};\n\nconst UnMemoizedMessageEditedIndicator = (props: MessageEditedIndicatorProps) => {\n const { customClass, message: propMessage, ...timestampProps } = props;\n const { message: contextMessage } = useMessageContext('MessageEditedIndicator');\n const { t } = useTranslationContext('MessageEditedIndicator');\n const { Timestamp = DefaultTimestamp } = useComponentContext('MessageEditedIndicator');\n const message = propMessage ?? contextMessage;\n\n const [referenceElement, setReferenceElement] = useState<HTMLSpanElement | null>(null);\n const { handleEnter, handleLeave, tooltipVisible } =\n useEnterLeaveHandlers<HTMLSpanElement>();\n\n if (!message?.message_text_updated_at) {\n return null;\n }\n\n return (\n <span\n className={customClass ?? 'str-chat__message-edited-indicator'}\n data-testid='message-edited-indicator'\n onMouseEnter={handleEnter}\n onMouseLeave={handleLeave}\n ref={setReferenceElement}\n >\n {t('Edited')}\n <PopperTooltip\n offset={[0, 5]}\n placement='top'\n referenceElement={referenceElement}\n visible={tooltipVisible}\n >\n <Timestamp timestamp={message.message_text_updated_at} {...timestampProps} />\n </PopperTooltip>\n </span>\n );\n};\n\nexport const MessageEditedIndicator = React.memo(\n UnMemoizedMessageEditedIndicator,\n) as typeof UnMemoizedMessageEditedIndicator;\n","import type { LocalMessage } from 'stream-chat';\nimport React, { useCallback, useMemo } from 'react';\nimport {\n getTranslatedMessageText,\n useComponentContextIcons,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\nimport { Button } from '../Button';\n\nexport type TranslationIndicatorProps = {\n message?: LocalMessage;\n};\n\nexport const MessageTranslationIndicator = ({\n message: propMessage,\n}: TranslationIndicatorProps) => {\n const { IconTranslate } = useComponentContextIcons();\n\n const { t, userLanguage } = useTranslationContext();\n const {\n message: contextMessage,\n setTranslationView,\n translationView,\n } = useMessageContext('MessageTranslationIndicator');\n const message = propMessage ?? contextMessage;\n\n const translatedTextForUser = useMemo(\n () => getTranslatedMessageText({ language: userLanguage, message }),\n [userLanguage, message],\n );\n\n const hasTranslationForUserLanguage = useMemo(\n () =>\n translatedTextForUser != null &&\n message?.text !== undefined &&\n translatedTextForUser !== message.text,\n [translatedTextForUser, message?.text],\n );\n\n const viewingOriginal = useMemo(\n () =>\n translationView === 'original' ||\n (translationView === undefined && !hasTranslationForUserLanguage),\n [translationView, hasTranslationForUserLanguage],\n );\n\n const handleToggle = useCallback(() => {\n setTranslationView?.(viewingOriginal ? 'translated' : 'original');\n }, [setTranslationView, viewingOriginal]);\n\n const sourceLanguageName = useMemo(() => {\n const sourceLanguageCode = message?.i18n?.language;\n if (!sourceLanguageCode) return '';\n const languageKey = 'language/' + sourceLanguageCode;\n const translatedName = t(languageKey);\n return translatedName && translatedName !== languageKey\n ? translatedName\n : sourceLanguageCode;\n }, [message?.i18n?.language, t]);\n\n if (!message?.i18n || !setTranslationView) return null;\n if (!hasTranslationForUserLanguage) return null;\n\n return (\n <div className='str-chat__message-translation-indicator'>\n <IconTranslate />\n <span className='str-chat__message-translation-indicator__sign'>\n {viewingOriginal\n ? t('Original')\n : sourceLanguageName\n ? t('Translated from {{ language }}', { language: sourceLanguageName })\n : t('Translated')}\n </span>\n <span> · </span>\n <Button\n className='str-chat__message-translation-indicator__translation-toggle'\n onClick={handleToggle}\n type='button'\n >\n {viewingOriginal ? t('View translation') : t('View original')}\n </Button>\n </div>\n );\n};\n","import clsx from 'clsx';\nimport React from 'react';\nimport { handleProgressBarKeyboardSeek } from './keyboardSeek';\nimport { getAudioTrackSliderAriaValueText } from './progressBarA11y';\nimport { useInteractiveProgressBar } from './useInteractiveProgressBar';\nimport type { SeekFn as AudioPlayerSeekFn } from '../AudioPlayer';\nimport { useTranslationContext } from '../../../context';\n\ntype SeekParams = Parameters<AudioPlayerSeekFn>[0];\n\nexport type ProgressBarProps = {\n /** Progress expressed in fractional number value btw 0 and 100. */\n progress: number;\n /** Total track duration in seconds. */\n durationSeconds?: number;\n /** Current elapsed position in seconds. */\n secondsElapsed?: number;\n seek: (params: SeekParams) => void;\n} & Pick<React.ComponentProps<'div'>, 'className'>;\n\nexport const ProgressBar = ({\n className,\n durationSeconds,\n progress,\n secondsElapsed,\n seek,\n}: ProgressBarProps) => {\n const { t } = useTranslationContext('ProgressBar');\n const {\n handleDrag,\n handleDragStart,\n handleDragStop,\n indicatorLeft,\n setProgressIndicator,\n setRoot,\n } = useInteractiveProgressBar({ progress, seek });\n const normalizedProgress = Math.max(0, Math.min(100, progress));\n const ariaValueText = getAudioTrackSliderAriaValueText({\n durationSeconds,\n progress: normalizedProgress,\n secondsElapsed,\n t,\n });\n\n return (\n <div\n aria-label={t('aria/Seek audio position')}\n aria-orientation='horizontal'\n aria-valuemax={100}\n aria-valuemin={0}\n aria-valuenow={Math.round(normalizedProgress)}\n aria-valuetext={ariaValueText}\n className={clsx(\n 'str-chat__message-attachment-audio-widget--progress-track',\n className,\n )}\n data-progress={normalizedProgress}\n data-testid='audio-progress'\n onClick={seek}\n onKeyDown={(event) =>\n handleProgressBarKeyboardSeek({ event, progress: normalizedProgress, seek })\n }\n onPointerDown={handleDragStart}\n onPointerMove={handleDrag}\n onPointerUp={handleDragStop}\n ref={setRoot}\n role='slider'\n style={\n {\n '--str-chat__message-attachment-audio-widget-progress':\n normalizedProgress + '%',\n } as React.CSSProperties\n }\n tabIndex={0}\n >\n <div\n aria-hidden='true'\n className='str-chat__message-attachment-audio-widget--progress-indicator'\n ref={setProgressIndicator}\n style={{ insetInlineStart: `${indicatorLeft}px` }}\n />\n </div>\n );\n};\n","import React from 'react';\nimport type { Attachment } from 'stream-chat';\n\nimport {\n FileSizeIndicator as DefaultFileSizeIndicator,\n DownloadButton,\n} from './components';\nimport type { AudioPlayerState } from '../AudioPlayback/AudioPlayer';\nimport { useAudioPlayer } from '../AudioPlayback/WithAudioPlayback';\nimport { useStateStore } from '../../store';\nimport { useComponentContext, useMessageContext } from '../../context';\nimport type { AudioPlayer } from '../AudioPlayback/AudioPlayer';\nimport { PlayButton } from '../Button/PlayButton';\nimport { FileIcon } from '../FileIcon';\nimport { DurationDisplay, ProgressBar } from '../AudioPlayback';\n\ntype AudioAttachmentUIProps = {\n audioPlayer: AudioPlayer;\n};\n\n// todo: finish creating a BaseAudioPlayer derived from VoiceRecordingPlayerUI and AudioAttachmentUI\nconst AudioAttachmentUI = ({ audioPlayer }: AudioAttachmentUIProps) => {\n const { FileSizeIndicator = DefaultFileSizeIndicator } = useComponentContext();\n const dataTestId = 'audio-widget';\n const rootClassName = 'str-chat__message-attachment-audio-widget';\n\n const { durationSeconds, isPlaying, progress, secondsElapsed } =\n useStateStore(audioPlayer?.state, audioPlayerStateSelector) ?? {};\n\n return (\n <div className={rootClassName} data-testid={dataTestId}>\n <div className='str-chat__message-attachment-audio-widget--play-controls'>\n <PlayButton isPlaying={!!isPlaying} onClick={audioPlayer.togglePlay} />\n </div>\n <div className='str-chat__message-attachment-audio-widget--data'>\n <div className='str-chat__message-attachment-audio-widget--text-first-row'>\n <div className='str-chat__message-attachment-audio-widget--title'>\n {audioPlayer.title}\n </div>\n </div>\n <div className='str-chat__message-attachment-audio-widget--text-second-row'>\n {durationSeconds ? (\n <>\n <DurationDisplay\n duration={durationSeconds}\n isPlaying={!!isPlaying}\n secondsElapsed={secondsElapsed}\n />\n <ProgressBar\n durationSeconds={durationSeconds}\n progress={progress ?? 0}\n secondsElapsed={secondsElapsed}\n seek={audioPlayer.seek}\n />\n </>\n ) : (\n <>\n <FileSizeIndicator fileSize={audioPlayer.fileSize} />\n <ProgressBar\n durationSeconds={durationSeconds}\n progress={progress ?? 0}\n secondsElapsed={secondsElapsed}\n seek={audioPlayer.seek}\n />\n </>\n )}\n </div>\n </div>\n <FileIcon className='str-chat__file-icon' mimeType={audioPlayer.mimeType} />\n <DownloadButton assetUrl={audioPlayer.src} suggestedFileName={audioPlayer.title} />\n </div>\n );\n};\n\nexport type AudioProps = {\n attachment: Attachment;\n};\n\nconst audioPlayerStateSelector = (state: AudioPlayerState) => ({\n durationSeconds: state.durationSeconds,\n isPlaying: state.isPlaying,\n progress: state.progressPercent,\n secondsElapsed: state.secondsElapsed,\n});\n\n/**\n * Audio attachment with play/pause button and progress bar\n */\nexport const Audio = (props: AudioProps) => {\n const {\n attachment: { asset_url, duration, file_size, mime_type, title },\n } = props;\n\n /**\n * Introducing message context. This could be breaking change, therefore the fallback to {} is provided.\n * If this component is used outside the message context, then there will be no audio player namespacing\n * => scrolling away from the message in virtualized ML would create a new AudioPlayer instance.\n *\n * Edge case: the requester (message) has multiple attachments with the same assetURL - does not happen\n * with the default SDK components, but can be done with custom API calls.In this case all the Audio\n * widgets will share the state.\n */\n const { message, threadList } = useMessageContext() ?? {};\n\n const audioPlayer = useAudioPlayer({\n durationSeconds: duration,\n fileSize: file_size,\n mimeType: mime_type,\n requester:\n message?.id &&\n `${threadList ? (message.parent_id ?? message.id) : ''}${message.id}`,\n src: asset_url,\n title,\n waveformData: props.attachment.waveform_data,\n });\n\n return audioPlayer ? <AudioAttachmentUI audioPlayer={audioPlayer} /> : null;\n};\n","/** True when a string looks like a media URL (so it must NOT be used as an accessible name). */\nexport const looksLikeUrl = (value?: string | null): boolean =>\n !!value && /^(https?:|\\/\\/)/i.test(value);\n\n/**\n * Resolve a human, non-URL giphy title for accessible naming/announcements, or `undefined`.\n * Giphy payloads rarely carry a real title (they often fall back to a media URL), so callers\n * should provide a generic label when this returns `undefined`. Shared by `Giphy` (the image's\n * accessible name) and `AttachmentActions` (the shuffle announcement) so the\n * two stay in sync.\n */\nexport const getGiphyDescriptiveTitle = (title?: string | null): string | undefined =>\n looksLikeUrl(title) ? undefined : (title ?? undefined);\n","import React, { useEffect, useMemo, useRef } from 'react';\nimport type { Action, Attachment } from 'stream-chat';\n\nimport { useTranslationContext } from '../../context';\n\nimport { useFocusReturn, useInteractionAnnouncements } from '../Accessibility';\nimport { getGiphyDescriptiveTitle } from './giphyAccessibility';\nimport type { ActionHandlerReturnType } from '../Message/hooks/useActionHandler';\nimport { Button } from '../Button';\nimport { VisuallyHidden } from '../VisuallyHidden';\nimport { useStableId } from '../UtilityComponents/useStableId';\nimport clsx from 'clsx';\n\nexport type AttachmentActionsProps = Attachment & {\n /** A list of actions */\n actions: Action[];\n /** Unique id for action button key. Key is generated by concatenating this id with action value - {`${id}-${action.value}`} */\n id: string;\n /** The text for the form input */\n text: string;\n /** Click event handler */\n actionHandler?: ActionHandlerReturnType;\n /** Which action should be focused on initial render (match by action.value) */\n defaultFocusedActionValue?: string;\n};\n\nexport type AttachmentActionsDefaultFocusByType = Partial<\n Record<NonNullable<Attachment['type']>, string>\n>;\n\nexport const defaultAttachmentActionsDefaultFocus: AttachmentActionsDefaultFocusByType = {\n giphy: 'send',\n};\n\nconst UnMemoizedAttachmentActions = (props: AttachmentActionsProps) => {\n const {\n actionHandler,\n actions,\n defaultFocusedActionValue,\n giphy,\n id,\n image_url: imageUrl,\n text,\n thumb_url: thumbUrl,\n title,\n type,\n } = props;\n const { t } = useTranslationContext('UnMemoizedAttachmentActions');\n const { announceInteraction } = useInteractionAnnouncements();\n const { reserve: reserveFocusReturn, restore: restoreFocusReturn } = useFocusReturn();\n const buttonRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const isGiphy = type === 'giphy';\n // The giphy preview auto-focuses its primary action, so its purpose + available actions are\n // FOCUS-COUPLED: describe them on the focused control (aria-describedby) so the text rides\n // the focus event. A live-region announcement here would be preempted by that same focus\n // change and never heard. See `.cursor/skills/accessibility/SKILL.md` §3 (focus-coupled vs\n // decoupled) and specs/a11y-react-web/decisions.md.\n const giphyDescriptionId = useStableId();\n\n // A human, non-URL title for this giphy (usually absent — see RW6), reused for both the\n // preview description and the shuffle announcement.\n const descriptiveTitle = isGiphy ? getGiphyDescriptiveTitle(title) : undefined;\n // Identity used to detect the GIF changing on Shuffle. A giphy attachment carries the unique\n // GIF URL in `giphy.original.url` / `thumb_url` (there is usually no `image_url`); both change\n // on every shuffle, so the canonical GIF URL is the identity.\n const giphyImageIdentity = isGiphy\n ? (giphy?.original?.url ?? thumbUrl ?? imageUrl ?? null)\n : null;\n const previousGiphyImageRef = useRef<string | null>(null);\n const giphyImageInitializedRef = useRef(false);\n\n const handleActionClick = (\n event: React.MouseEvent<HTMLButtonElement, MouseEvent>,\n name?: string,\n value?: string,\n ) => {\n actionHandler?.(name, value, event);\n\n // For giphy actions, return focus to wherever it was before the preview stole it (the\n // composer — but this code never names it; see useFocusReturn) and announce the outcome.\n //\n // Order matters: restore focus FIRST, then announce on the next frame. The screen reader\n // speaks the focus change (\"Message input\") immediately and synchronously; a polite\n // live-region message fired in the same tick races with it (and can be dropped). Deferring\n // the announce to rAF makes the sequence deterministic — \"Message input\" then \"Giphy sent\" —\n // and guarantees the confirmation is heard. The gap between the two utterances is governed\n // by the screen reader's speech queue and is not controllable here. The rAF is intentionally\n // NOT cancelled on unmount: the preview unmounts when the giphy is sent, but the announcer\n // lives at the Chat root, so the confirmation must still fire.\n if (isGiphy && (value === 'send' || value === 'cancel')) {\n restoreFocusReturn();\n const interaction = value === 'send' ? 'giphy.sent' : 'giphy.canceled';\n requestAnimationFrame(() => announceInteraction(interaction));\n }\n };\n\n const knownActionText = useMemo<Record<string, string>>(\n () => ({\n Cancel: t('Cancel'),\n Send: t('Send'),\n Shuffle: t('Shuffle'),\n }),\n [t],\n );\n\n const focusIndex = useMemo(() => {\n if (!defaultFocusedActionValue) return null;\n const index = actions.findIndex(\n (action) => action.value === defaultFocusedActionValue,\n );\n return index >= 0 ? index : null;\n }, [actions, defaultFocusedActionValue]);\n\n useEffect(() => {\n if (focusIndex === null) return;\n const button = buttonRefs.current[focusIndex];\n if (button && document.activeElement !== button) {\n // Capture where focus is (e.g. the composer) BEFORE stealing it, so a terminal\n // action can return focus there via restoreFocusReturn() — without this component\n // knowing what that element is.\n reserveFocusReturn();\n button.focus();\n }\n }, [focusIndex, reserveFocusReturn]);\n\n // Shuffle swaps the GIF in place without moving focus (it stays on the Shuffle button), so\n // this is a DECOUPLED change → announce it via the live region (no focus/rAF dance). Skip the\n // initial mount: the preview's appearance is conveyed by the focused control's description\n // (RW4a), not a live announcement.\n useEffect(() => {\n if (!isGiphy) return;\n if (!giphyImageInitializedRef.current) {\n giphyImageInitializedRef.current = true;\n previousGiphyImageRef.current = giphyImageIdentity;\n return;\n }\n if (giphyImageIdentity === previousGiphyImageRef.current) return;\n previousGiphyImageRef.current = giphyImageIdentity;\n // Giphy payloads rarely have a human title, so this usually announces just \"Giphy image\n // changed\"; the title is included only when one genuinely exists.\n announceInteraction('giphy.shuffled', { title: descriptiveTitle });\n }, [announceInteraction, descriptiveTitle, giphyImageIdentity, isGiphy]);\n\n const groupProps = isGiphy\n ? { 'aria-label': t('aria/Giphy actions'), role: 'group' as const }\n : {};\n\n return (\n <div className='str-chat__message-attachment-actions'>\n <div className='str-chat__message-attachment-actions-form' {...groupProps}>\n <span>{text}</span>\n {actions.map((action, index) => {\n const label = action.text\n ? (knownActionText[action.text] ?? t(action.text))\n : null;\n\n return (\n <Button\n appearance='ghost'\n // aria-describedby: the auto-focused primary action carries the preview\n // description so it is spoken as part of the focus announcement (focus-coupled,\n // not a live region).\n aria-describedby={\n isGiphy && action.value === defaultFocusedActionValue\n ? giphyDescriptionId\n : undefined\n }\n // aria-label: for giphy actions, give each button a self-contained accessible\n // name so it is not announced with surrounding list/group context (e.g.\n // \"list 3 items\") swallowing the actual action label. Non-giphy untouched.\n aria-label={isGiphy ? (label ?? undefined) : undefined}\n className={clsx(\n `str-chat__message-attachment-actions-button str-chat__message-attachment-actions-button--${action.style}`,\n )}\n data-testid={`${action.name}`}\n data-value={action.value}\n key={`${id}-${action.value}`}\n onClick={(event) => handleActionClick(event, action.name, action.value)}\n ref={(element) => {\n buttonRefs.current[index] = element;\n }}\n variant='secondary'\n >\n {label}\n </Button>\n );\n })}\n {isGiphy && (\n <VisuallyHidden id={giphyDescriptionId}>\n {t(\n 'aria/Giphy preview, only visible to you. Use the Send, Shuffle, or Cancel actions.',\n )}\n </VisuallyHidden>\n )}\n </div>\n </div>\n );\n};\n\n/**\n * A component for rendering the actions you can take on an attachment.\n */\nexport const AttachmentActions = React.memo(\n UnMemoizedAttachmentActions,\n) as typeof UnMemoizedAttachmentActions;\n","import React from 'react';\nimport type { Attachment } from 'stream-chat';\n\nimport { FileSizeIndicator as DefaultFileSizeIndicator } from './components';\nimport { FileIcon } from '../FileIcon';\nimport {\n useComponentContext,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\nimport {\n type AudioPlayer,\n type AudioPlayerState,\n DurationDisplay,\n PlaybackRateButton,\n WaveProgressBar,\n} from '../AudioPlayback';\nimport { useAudioPlayer } from '../AudioPlayback/WithAudioPlayback';\nimport { useStateStore } from '../../store';\nimport { PlayButton } from '../Button';\n\nconst rootClassName = 'str-chat__message-attachment__voice-recording-widget';\n\nconst audioPlayerStateSelector = (state: AudioPlayerState) => ({\n canPlayRecord: state.canPlayRecord,\n durationSeconds: state.durationSeconds,\n isPlaying: state.isPlaying,\n playbackRate: state.currentPlaybackRate,\n progress: state.progressPercent,\n secondsElapsed: state.secondsElapsed,\n});\n\ntype VoiceRecordingPlayerUIProps = {\n audioPlayer: AudioPlayer;\n};\n\n// todo: finish creating a BaseAudioPlayer derived from VoiceRecordingPlayerUI and AudioAttachmentUI\nconst VoiceRecordingPlayerUI = ({ audioPlayer }: VoiceRecordingPlayerUIProps) => {\n const { FileSizeIndicator = DefaultFileSizeIndicator } = useComponentContext();\n const { t } = useTranslationContext();\n const {\n canPlayRecord,\n durationSeconds,\n isPlaying,\n playbackRate,\n progress,\n secondsElapsed,\n } = useStateStore(audioPlayer?.state, audioPlayerStateSelector) ?? {};\n\n return (\n <div className={rootClassName} data-testid='voice-recording-widget'>\n <div className='str-chat__message-attachment__voice-recording-widget__play-button-container'>\n <PlayButton isPlaying={!!isPlaying} onClick={audioPlayer.togglePlay} />\n </div>\n <div className='str-chat__message-attachment__voice-recording-widget__metadata'>\n <div className='str-chat__message-attachment__voice-recording-widget__audio-state'>\n <div className='str-chat__message-attachment__voice-recording-widget__timer'>\n {durationSeconds ? (\n <DurationDisplay\n duration={durationSeconds}\n isPlaying={!!isPlaying}\n secondsElapsed={secondsElapsed}\n showRemaining\n />\n ) : (\n <FileSizeIndicator\n fileSize={audioPlayer.fileSize}\n maximumFractionDigits={0}\n />\n )}\n </div>\n <WaveProgressBar\n durationSeconds={durationSeconds}\n progress={progress}\n secondsElapsed={secondsElapsed}\n seek={audioPlayer.seek}\n waveformData={audioPlayer.waveformData || []}\n />\n </div>\n </div>\n <div className='str-chat__message-attachment__voice-recording-widget__right-section'>\n <PlaybackRateButton\n aria-label={t('Playback speed {{ rate }}x', {\n rate: playbackRate?.toString() ?? '1',\n })}\n disabled={!canPlayRecord}\n onClick={audioPlayer.increasePlaybackRate}\n >\n x{playbackRate?.toString()}\n </PlaybackRateButton>\n </div>\n </div>\n );\n};\n\nexport type VoiceRecordingPlayerProps = Pick<VoiceRecordingProps, 'attachment'> & {\n /** An array of fractional numeric values of playback speed to override the defaults (1.0, 1.5, 2.0) */\n playbackRates?: number[];\n};\n\nexport const VoiceRecordingPlayer = ({\n attachment,\n playbackRates,\n}: VoiceRecordingPlayerProps) => {\n const { t } = useTranslationContext();\n const {\n asset_url,\n duration = 0,\n file_size,\n mime_type,\n title = t('Voice message'),\n waveform_data,\n } = attachment;\n\n /**\n * Introducing message context. This could be breaking change, therefore the fallback to {} is provided.\n * If this component is used outside the message context, then there will be no audio player namespacing\n * => scrolling away from the message in virtualized ML would create a new AudioPlayer instance.\n *\n * Edge case: the requester (message) has multiple attachments with the same assetURL - does not happen\n * with the default SDK components, but can be done with custom API calls.In this case all the Audio\n * widgets will share the state.\n */\n const { message, threadList } = useMessageContext() ?? {};\n\n const audioPlayer = useAudioPlayer({\n durationSeconds: duration ?? 0,\n fileSize: file_size,\n mimeType: mime_type,\n playbackRates,\n requester:\n message?.id &&\n `${threadList ? (message.parent_id ?? message.id) : ''}${message.id}`,\n src: asset_url,\n title,\n waveformData: waveform_data,\n });\n\n return audioPlayer ? <VoiceRecordingPlayerUI audioPlayer={audioPlayer} /> : null;\n};\n\nexport type QuotedVoiceRecordingProps = Pick<VoiceRecordingProps, 'attachment'>;\n\nexport const QuotedVoiceRecording = ({ attachment }: QuotedVoiceRecordingProps) => {\n const { FileSizeIndicator = DefaultFileSizeIndicator } = useComponentContext();\n return (\n <div className={rootClassName} data-testid='quoted-voice-recording-widget'>\n <div className='str-chat__message-attachment__voice-recording-widget__metadata'>\n <div className='str-chat__message-attachment__voice-recording-widget__audio-state'>\n <div className='str-chat__message-attachment__voice-recording-widget__timer'>\n {attachment.duration ? (\n <DurationDisplay\n duration={attachment.duration}\n isPlaying={false}\n secondsElapsed={undefined}\n />\n ) : (\n <FileSizeIndicator\n fileSize={attachment.file_size}\n maximumFractionDigits={0}\n />\n )}\n </div>\n </div>\n </div>\n <FileIcon mimeType={attachment.mime_type} />\n </div>\n );\n};\n\nexport type VoiceRecordingProps = {\n /** The attachment object from the message's attachment list. */\n attachment: Attachment;\n /** A boolean flag to signal whether the attachment will be rendered inside the quoted reply. */\n isQuoted?: boolean;\n};\n\nexport const VoiceRecording = ({ attachment, isQuoted }: VoiceRecordingProps) =>\n isQuoted ? (\n <QuotedVoiceRecording attachment={attachment} />\n ) : (\n <VoiceRecordingPlayer attachment={attachment} />\n );\n","import React, { useCallback, useState } from 'react';\nimport clsx from 'clsx';\n\nimport type { BaseImageProps } from '../BaseImage';\nimport type { GalleryItem } from '../Gallery/GalleryContext';\nimport { BaseImage as DefaultBaseImage } from '../BaseImage';\nimport { Gallery as DefaultGallery, GalleryUI } from '../Gallery';\nimport { LoadingIndicator } from '../Loading';\nimport { GlobalModal, type ModalCloseSource } from '../Modal';\nimport {\n useComponentContext,\n useComponentContextIcons,\n useTranslationContext,\n} from '../../context';\nimport { VideoThumbnail } from '../VideoPlayer/VideoThumbnail';\n\nconst MAX_VISIBLE_THUMBNAILS = 4;\nconst BASE_IMAGE_PROP_KEYS = [\n 'className',\n 'crossOrigin',\n 'decoding',\n 'draggable',\n 'fetchPriority',\n 'height',\n 'loading',\n 'onError',\n 'onLoad',\n 'ref',\n 'showDownloadButtonOnError',\n 'sizes',\n 'srcSet',\n 'style',\n 'title',\n 'useMap',\n 'width',\n] as const satisfies ReadonlyArray<keyof Omit<BaseImageProps, 'src'>>;\ntype BaseImagePropsWithoutSrc = Omit<BaseImageProps, 'src'>;\ntype PartialBaseImagePropMap = Partial<\n Record<(typeof BASE_IMAGE_PROP_KEYS)[number], unknown>\n>;\n\nexport type ModalGalleryProps = {\n /** Array of media attachments to display */\n items: GalleryItem[];\n className?: string;\n /** Whether clicking the empty gallery background should close the modal (default: true) */\n closeOnBackgroundClick?: boolean;\n modalClassName?: string;\n};\n\nexport const ModalGallery = ({\n className,\n closeOnBackgroundClick = true,\n items,\n modalClassName,\n}: ModalGalleryProps) => {\n const {\n BaseImage = DefaultBaseImage,\n Gallery = DefaultGallery,\n Modal = GlobalModal,\n } = useComponentContext();\n const [modalOpen, setModalOpen] = useState(false);\n const [selectedIndex, setSelectedIndex] = useState(0);\n const usesDefaultBaseImage = BaseImage === DefaultBaseImage;\n\n const closeModal = useCallback(() => {\n setModalOpen(false);\n }, []);\n const preventOverlayClose = useCallback(\n (source: ModalCloseSource) => source !== 'overlay',\n [],\n );\n\n const handleThumbnailClick = useCallback((index: number) => {\n setSelectedIndex(index);\n setModalOpen(true);\n }, []);\n\n const itemCount = items.length;\n const visibleItems = items.slice(0, MAX_VISIBLE_THUMBNAILS);\n const overflowCount = itemCount - MAX_VISIBLE_THUMBNAILS;\n\n return (\n <>\n <div\n className={clsx('str-chat__modal-gallery', className, {\n 'str-chat__modal-gallery--three-images': itemCount === 3,\n 'str-chat__modal-gallery--two-images': itemCount === 2,\n })}\n >\n {visibleItems.map((item, index) => {\n const isLastVisible = index === MAX_VISIBLE_THUMBNAILS - 1;\n const showOverlay = isLastVisible && overflowCount > 0;\n\n return (\n <ThumbnailButton\n BaseImage={BaseImage}\n baseImageUsesDefaultBehavior={usesDefaultBaseImage}\n index={index}\n item={item}\n itemCount={itemCount}\n key={index}\n onClick={() => handleThumbnailClick(index)}\n overflowCount={overflowCount}\n showOverlay={showOverlay}\n />\n );\n })}\n </div>\n <Modal\n className={clsx('str-chat__gallery-modal', modalClassName)}\n onClose={closeModal}\n onCloseAttempt={preventOverlayClose}\n open={modalOpen}\n >\n <Gallery\n closeOnBackgroundClick={closeOnBackgroundClick}\n GalleryUI={GalleryUI}\n initialIndex={selectedIndex}\n items={items}\n onRequestClose={closeModal}\n />\n </Modal>\n </>\n );\n};\n\ntype ThumbnailButtonProps = {\n BaseImage: React.ComponentType<BaseImageProps>;\n baseImageUsesDefaultBehavior: boolean;\n index: number;\n item: GalleryItem;\n itemCount: number;\n onClick: () => void;\n overflowCount: number;\n showOverlay: boolean;\n};\n\nconst ThumbnailButton = ({\n BaseImage,\n baseImageUsesDefaultBehavior,\n index,\n item,\n itemCount,\n onClick,\n overflowCount,\n showOverlay,\n}: ThumbnailButtonProps) => {\n const { t } = useTranslationContext();\n const { IconRetry } = useComponentContextIcons();\n const imageUrl = item.imageUrl;\n const [isLoadFailed, setIsLoadFailed] = useState(false);\n const [isImageLoading, setIsImageLoading] = useState(Boolean(imageUrl));\n // Cache-busting suffix appended to image src on retry. Using a suffix instead of\n // a React key remount keeps the component (and its placeholder) mounted, preventing\n // layout shifts and height collapse during the reload attempt.\n const [retrySuffix, setRetrySuffix] = useState('');\n\n const {\n onError: itemOnError,\n onLoad: itemOnLoad,\n ...baseImageProps\n } = getBaseImageProps(item);\n const showRetryIndicator = isLoadFailed && !showOverlay;\n const showLoadingIndicator = isImageLoading && !showRetryIndicator && !showOverlay;\n\n const handleButtonClick = () => {\n if (showRetryIndicator) {\n setIsLoadFailed(false);\n setIsImageLoading(true);\n setRetrySuffix(`&retry=${Date.now()}`);\n return;\n }\n\n onClick();\n };\n\n const buttonLabel = showRetryIndicator\n ? t('aria/Retry upload')\n : itemCountAwareLabel({ imageIndex: index + 1, itemCount, t });\n\n return (\n <button\n aria-label={buttonLabel}\n className={clsx('str-chat__modal-gallery__image', {\n 'str-chat__modal-gallery__image--load-failed': showRetryIndicator,\n 'str-chat__modal-gallery__image--loading': showLoadingIndicator,\n })}\n onClick={handleButtonClick}\n type='button'\n >\n {item.videoThumbnailUrl ? (\n <VideoThumbnail alt={t('User uploaded content')} src={item.videoThumbnailUrl} />\n ) : (\n <BaseImage\n {...baseImageProps}\n alt={item.alt ?? t('User uploaded content')}\n onError={(event) => {\n setIsImageLoading(false);\n setIsLoadFailed(true);\n itemOnError?.(event);\n }}\n onLoad={(event) => {\n setIsImageLoading(false);\n setIsLoadFailed(false);\n itemOnLoad?.(event);\n }}\n src={imageUrl ? `${imageUrl}${retrySuffix}` : imageUrl}\n {...(baseImageUsesDefaultBehavior ? { showDownloadButtonOnError: false } : {})}\n />\n )}\n {showLoadingIndicator && (\n <div\n aria-hidden='true'\n className='str-chat__modal-gallery__image-loading-overlay'\n data-testid='str-chat__modal-gallery__image-loading-overlay'\n >\n <LoadingIndicator />\n </div>\n )}\n {showRetryIndicator && (\n <div\n aria-hidden='true'\n className='str-chat__modal-gallery__image-load-failed-overlay'\n data-testid='str-chat__modal-gallery__image-load-failed-overlay'\n >\n <div className='str-chat__modal-gallery__image-retry-indicator'>\n <IconRetry />\n </div>\n </div>\n )}\n {showOverlay && (\n <div className='str-chat__modal-gallery__placeholder'>+{overflowCount}</div>\n )}\n </button>\n );\n};\n\nconst itemCountAwareLabel = ({\n imageIndex,\n itemCount,\n t,\n}: {\n imageIndex: number;\n itemCount: number;\n t: ReturnType<typeof useTranslationContext>['t'];\n}) =>\n itemCount === 1\n ? t('Open image in gallery')\n : t('Open gallery at image {{ index }}', {\n index: imageIndex,\n });\n\nconst getBaseImageProps = (item: GalleryItem): BaseImagePropsWithoutSrc => {\n const baseImageProps: PartialBaseImagePropMap = {};\n for (const key of BASE_IMAGE_PROP_KEYS) {\n const value = item[key];\n if (value !== undefined) {\n baseImageProps[key] = value;\n }\n }\n\n return baseImageProps as BaseImagePropsWithoutSrc;\n};\n","import React from 'react';\nimport { ModalGallery as DefaultModalGallery } from './ModalGallery';\nimport { useComponentContext } from '../../context';\nimport type { GalleryItem } from '../Gallery/GalleryContext';\n\nexport type ImageProps = GalleryItem;\n\n/**\n * Display image with tap-to-expand modal gallery.\n */\nexport const ImageComponent = (galleryItem: ImageProps) => {\n const { ModalGallery = DefaultModalGallery } = useComponentContext();\n\n return <ModalGallery items={[galleryItem]} modalClassName='str-chat__image-modal' />;\n};\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\nimport { sanitizeUrl } from '@braintree/sanitize-url';\n\n/**\n * Similar to a regular anchor tag, but it sanitizes the href value and prevents XSS\n */\nexport type SafeAnchorProps = {\n /** Set the className for the anchor tag element */\n className?: string;\n /** Specifies that the target (href attribute) will be downloaded instead of navigating to a file */\n download?: boolean;\n /** Set the href attribute for the anchor tag element */\n href?: string;\n /** Set the rel attribute for the anchor tag element */\n rel?: string;\n /** Set the target attribute for the anchor tag element */\n target?: string;\n};\n\nconst UnMemoizedSafeAnchor = (props: PropsWithChildren<SafeAnchorProps>) => {\n const { children, className, download, href, rel, target } = props;\n if (!href) return null;\n const sanitized = sanitizeUrl(href);\n return (\n <a\n className={className}\n download={download}\n href={sanitized}\n rel={rel}\n target={target}\n >\n {children}\n </a>\n );\n};\n\nexport const SafeAnchor = React.memo(UnMemoizedSafeAnchor) as typeof UnMemoizedSafeAnchor;\n","import type { Attachment } from 'stream-chat';\nimport { useTranslationContext } from '../../../context';\nimport clsx from 'clsx';\nimport React from 'react';\n\nexport const UnableToRenderCard = ({ type }: { type?: Attachment['type'] }) => {\n const { t } = useTranslationContext('Card');\n\n return (\n <div\n className={clsx('str-chat__message-attachment-card', {\n [`str-chat__message-attachment-card--${type}`]: type,\n })}\n >\n <div className='str-chat__message-attachment-card--content'>\n <div className='str-chat__message-attachment-card--text'>\n {t('this content could not be displayed')}\n </div>\n </div>\n </div>\n );\n};\n","import React from 'react';\nimport { BaseImage } from '../../BaseImage';\nimport { SafeAnchor } from '../../SafeAnchor';\nimport { useChannelStateContext } from '../../../context/ChannelStateContext';\nimport { useComponentContextIcons } from '../../../context';\n\nimport type { Attachment } from 'stream-chat';\nimport type { RenderAttachmentProps } from '../utils';\nimport type { Dimensions } from '../../../types/types';\nimport { UnableToRenderCard } from './UnableToRenderCard';\nimport clsx from 'clsx';\n\ntype CardRootProps = {\n cardUrl: string | undefined;\n children: React.ReactNode;\n type?: CardProps['type'];\n};\n\nconst CardRoot = ({ cardUrl, children, type }: CardRootProps) => {\n const className = clsx(\n `str-chat__message-attachment-card str-chat__message-attachment-card--${type}`,\n );\n\n return cardUrl ? (\n <SafeAnchor\n className={className}\n href={cardUrl}\n rel='noopener noreferrer'\n target='_blank'\n >\n {children}\n </SafeAnchor>\n ) : (\n <div className={className}>{children}</div>\n );\n};\n\ntype CardHeaderProps = Pick<CardProps, 'title' | 'type' | 'image_url' | 'thumb_url'> & {\n dimensions: Dimensions;\n image?: string;\n};\n\nconst CardHeader = (props: CardHeaderProps) => {\n const { dimensions, image, image_url, thumb_url, title } = props;\n\n return image ? (\n <div\n className='str-chat__message-attachment-card--header str-chat__message-attachment-card-react--header'\n data-testid={'card-header'}\n >\n <BaseImage\n alt={title || image}\n data-testid='image-test'\n src={image_url ?? thumb_url}\n title={title || image}\n {...dimensions}\n />\n </div>\n ) : null;\n};\n\ntype CardContentProps = RenderAttachmentProps['attachment'];\n\nconst CardContent = (props: CardContentProps) => {\n const { og_scrape_url, text, title, title_link } = props;\n const url = title_link || og_scrape_url;\n const { IconLink } = useComponentContextIcons();\n\n return (\n <div className='str-chat__message-attachment-card--content'>\n {title && <div className='str-chat__message-attachment-card--title'>{title}</div>}\n {text && <div className='str-chat__message-attachment-card--text'>{text}</div>}\n {url && (\n <div\n className='str-chat__message-attachment-card--source-link'\n data-testid='card-source-link'\n >\n <IconLink />\n <div className='str-chat__message-attachment-card--url'>{url}</div>\n </div>\n )}\n </div>\n );\n};\n\nexport type CardProps = RenderAttachmentProps['attachment'] & {\n compact?: boolean;\n};\n\nconst UnMemoizedCard = (props: CardProps) => {\n const { giphy, image_url, og_scrape_url, thumb_url, title, title_link, type } = props;\n const { giphyVersion: giphyVersionName } = useChannelStateContext('');\n const cardUrl = title_link || og_scrape_url;\n\n let image = thumb_url || image_url;\n const dimensions: { height?: string; width?: string } = {};\n\n if (type === 'giphy' && typeof giphy !== 'undefined') {\n const giphyVersion =\n giphy[giphyVersionName as keyof NonNullable<Attachment['giphy']>];\n image = giphyVersion.url;\n dimensions.height = giphyVersion.height;\n dimensions.width = giphyVersion.width;\n }\n\n if (!title && !cardUrl && !image) {\n return <UnableToRenderCard />;\n }\n\n return (\n <CardRoot cardUrl={cardUrl} type={type}>\n <CardHeader {...props} dimensions={dimensions} image={image} />\n <CardContent {...props} />\n </CardRoot>\n );\n};\n\n/**\n * Simple Card Layout for displaying links\n */\nexport const Card = React.memo(UnMemoizedCard) as typeof UnMemoizedCard;\n","import React from 'react';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { FileIcon } from '../FileIcon';\nimport type { Attachment } from 'stream-chat';\n\nimport {\n FileSizeIndicator as DefaultFileSizeIndicator,\n DownloadButton,\n} from './components';\n\nexport type FileAttachmentProps = {\n attachment: Attachment;\n};\n\nexport const FileAttachment = ({ attachment }: FileAttachmentProps) => {\n const { AttachmentFileIcon, FileSizeIndicator = DefaultFileSizeIndicator } =\n useComponentContext();\n const FileIconComponent = AttachmentFileIcon ?? FileIcon;\n return (\n <div\n className='str-chat__message-attachment-file--item'\n data-testid='attachment-file'\n >\n <FileIconComponent\n className='str-chat__file-icon'\n fileName={attachment.title}\n mimeType={attachment.mime_type}\n />\n <div className='str-chat__message-attachment-file--item__info'>\n <div className='str-chat__message-attachment-file--item__first-row'>\n <div\n className='str-chat__message-attachment-file--item__name'\n data-testid='file-title'\n >\n {attachment.title}\n </div>\n </div>\n <div className='str-chat__message-attachment-file--item__data'>\n <FileSizeIndicator fileSize={attachment.file_size} />\n </div>\n </div>\n <DownloadButton\n assetUrl={attachment.asset_url}\n suggestedFileName={attachment.title}\n />\n </div>\n );\n};\n","import type { Attachment } from 'stream-chat';\nimport { BaseImage as DefaultBaseImage } from '../BaseImage';\nimport { toGalleryItemDescriptors } from '../Gallery';\nimport { getGiphyDescriptiveTitle } from './giphyAccessibility';\nimport clsx from 'clsx';\nimport {\n useChannelStateContext,\n useComponentContext,\n useComponentContextIcons,\n useTranslationContext,\n} from '../../context';\nimport { type CSSProperties, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport type { ImageAttachmentConfiguration } from '../../types/types';\n\nexport type GiphyAttachmentProps = {\n attachment: Attachment;\n};\n\nexport const Giphy = ({ attachment }: GiphyAttachmentProps) => {\n const { giphyVersion: giphyVersionName, imageAttachmentSizeHandler } =\n useChannelStateContext();\n const { BaseImage = DefaultBaseImage } = useComponentContext();\n const { t } = useTranslationContext();\n const usesDefaultBaseImage = BaseImage === DefaultBaseImage;\n const imageElement = useRef<HTMLImageElement>(null);\n const [attachmentConfiguration, setAttachmentConfiguration] = useState<\n ImageAttachmentConfiguration | undefined\n >(undefined);\n\n const imageDescriptors = useMemo(\n () => toGalleryItemDescriptors(attachment, { giphyVersionName }),\n [attachment, giphyVersionName],\n );\n const dimensions = imageDescriptors && imageDescriptors.dimensions;\n const imageUrl = imageDescriptors && imageDescriptors.imageUrl;\n const title = imageDescriptors && imageDescriptors.title;\n const resolvedImageUrl = attachmentConfiguration?.url || imageUrl;\n // For giphy attachments `imageDescriptors.alt`/`title` may both resolve to a raw\n // media URL (Giphy payloads rarely carry a human title), which is useless to\n // screen-reader users. Prefer a real, non-URL title; otherwise fall back to a\n // localized generic label instead of exposing the URL as the accessible name.\n const descriptiveTitle = getGiphyDescriptiveTitle(title);\n const accessibleName = descriptiveTitle\n ? t('aria/Animated GIF: {{ title }}', { title: descriptiveTitle })\n : t('aria/Animated GIF');\n const imageStyleVariables = useMemo(() => {\n const originalHeight = Number(dimensions?.height);\n const originalWidth = Number(dimensions?.width);\n\n return {\n '--original-height': String(originalHeight > 1 ? originalHeight : 1000000),\n '--original-width': String(originalWidth > 1 ? originalWidth : 1000000),\n } as CSSProperties;\n }, [dimensions?.height, dimensions?.width]);\n\n useLayoutEffect(() => {\n if (!imageElement.current || !imageAttachmentSizeHandler) return;\n\n const config = imageAttachmentSizeHandler(attachment, imageElement.current);\n setAttachmentConfiguration(config);\n }, [attachment, imageAttachmentSizeHandler]);\n\n if (!imageUrl) return null;\n\n return (\n <div className={clsx(`str-chat__message-attachment-giphy`)}>\n <BaseImage\n alt={accessibleName}\n height={dimensions?.height}\n ref={imageElement}\n src={resolvedImageUrl}\n style={imageStyleVariables}\n width={dimensions?.width}\n {...(usesDefaultBaseImage ? { showDownloadButtonOnError: false } : {})}\n />\n <GiphyBadge />\n </div>\n );\n};\n\nconst GiphyBadge = () => {\n const { IconGiphy } = useComponentContextIcons();\n return (\n <div className='str-chat__giphy-badge'>\n <IconGiphy />\n Giphy\n </div>\n );\n};\n","import React from 'react';\nimport type { IconProps } from '../../types/types';\n\nexport const DownloadIcon = ({ className }: IconProps) => (\n <svg\n className={className}\n data-testid='download'\n fill='none'\n height='24'\n viewBox='0 0 24 24'\n width='24'\n xmlns='http://www.w3.org/2000/svg'\n >\n <path\n d='M19.35 10.04C18.67 6.59 15.64 4 12 4C9.11 4 6.6 5.64 5.35 8.04C2.34 8.36 0 10.91 0 14C0 17.31 2.69 20 6 20H19C21.76 20 24 17.76 24 15C24 12.36 21.95 10.22 19.35 10.04ZM19 18H6C3.79 18 2 16.21 2 14C2 11.95 3.53 10.24 5.56 10.03L6.63 9.92L7.13 8.97C8.08 7.14 9.94 6 12 6C14.62 6 16.88 7.86 17.39 10.43L17.69 11.93L19.22 12.04C20.78 12.14 22 13.45 22 15C22 16.65 20.65 18 19 18ZM13.45 10H10.55V13H8L12 17L16 13H13.45V10Z'\n fill='black'\n />\n </svg>\n);\n\nexport const ExternalLinkIcon = () => (\n <svg fill='currentColor' viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'>\n <path d='M12.586 2H10a1 1 0 1 1 0-2h5a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0V3.414l-6.793 6.793a1 1 0 0 1-1.414-1.414L12.586 2zM6 1a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v9a1 1 0 0 0 1 1h8.967a1 1 0 0 0 1-.99L13 9.99a1 1 0 1 1 2 .02l-.033 3.023a3 3 0 0 1-3 2.967H3a3 3 0 0 1-3-3V4a3 3 0 0 1 3-3h3z' />\n </svg>\n);\n","import type { ComponentType } from 'react';\nimport { useEffect } from 'react';\nimport { useRef, useState } from 'react';\nimport React from 'react';\nimport type { Coords, SharedLocationResponse } from 'stream-chat';\nimport {\n useChatContext,\n useComponentContextIcons,\n useTranslationContext,\n} from '../../context';\nimport { ExternalLinkIcon } from './icons';\nimport { Button } from '../Button';\n\nexport type GeolocationMapProps = Coords;\n\nexport type GeolocationProps = {\n location: SharedLocationResponse;\n GeolocationAttachmentMapPlaceholder?: ComponentType<GeolocationAttachmentMapPlaceholderProps>;\n GeolocationMap?: ComponentType<GeolocationMapProps>;\n};\n\nexport const Geolocation = ({\n GeolocationAttachmentMapPlaceholder = DefaultGeolocationAttachmentMapPlaceholder,\n GeolocationMap,\n location,\n}: GeolocationProps) => {\n const { channel, client } = useChatContext();\n const { t } = useTranslationContext();\n\n const [stoppedSharing, setStoppedSharing] = useState(\n !!location.end_at && new Date(location.end_at).getTime() < new Date().getTime(),\n );\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n const isMyLocation = location.user_id === client.userID;\n const isLiveLocation = !!location.end_at;\n\n useEffect(() => {\n if (!location.end_at) return;\n clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(\n () => setStoppedSharing(true),\n new Date(location.end_at).getTime() - Date.now(),\n );\n }, [location.end_at]);\n\n return (\n <div\n className='str-chat__message-attachment-geolocation'\n data-testid='attachment-geolocation'\n >\n <div className='str-chat__message-attachment-geolocation__location-preview'>\n {GeolocationMap ? (\n <GeolocationMap latitude={location.latitude} longitude={location.longitude} />\n ) : (\n <GeolocationAttachmentMapPlaceholder location={location} />\n )}\n </div>\n <div className='str-chat__message-attachment-geolocation__status'>\n {isLiveLocation ? (\n stoppedSharing ? (\n t('Location sharing ended')\n ) : isMyLocation ? (\n <div className='str-chat__message-attachment-geolocation__status--active'>\n <Button\n appearance='outline'\n className='str-chat__message-attachment-geolocation__stop-sharing-button'\n onClick={() => channel?.stopLiveLocationSharing(location)}\n size='sm'\n variant='secondary'\n >\n {t('Stop sharing')}\n </Button>\n <div className='str-chat__message-attachment-geolocation__status--active-until'>\n {t('Live until {{ timestamp }}', {\n timestamp: t('timestamp/LiveLocation', { timestamp: location.end_at }),\n })}\n </div>\n </div>\n ) : (\n <div className='str-chat__message-attachment-geolocation__status--active'>\n <div className='str-chat__message-attachment-geolocation__status--active-status'>\n {t('Live location')}\n </div>\n <div className='str-chat__message-attachment-geolocation__status--active-until'>\n {t('Live until {{ timestamp }}', {\n timestamp: t('timestamp/LiveLocation', { timestamp: location.end_at }),\n })}\n </div>\n </div>\n )\n ) : (\n t('Current location')\n )}\n </div>\n </div>\n );\n};\n\nexport type GeolocationAttachmentMapPlaceholderProps = {\n location: SharedLocationResponse;\n};\n\nconst DefaultGeolocationAttachmentMapPlaceholder = ({\n location,\n}: GeolocationAttachmentMapPlaceholderProps) => {\n const { t } = useTranslationContext();\n const { IconLocation } = useComponentContextIcons();\n\n return (\n <div\n className='str-chat__message-attachment-geolocation__placeholder'\n data-testid='geolocation-attachment-map-placeholder'\n >\n <IconLocation />\n <a\n aria-label={t('Open location in a map')}\n className='str-chat__message-attachment-geolocation__placeholder-link'\n href={`https://maps.google.com?q=${[location.latitude, location.longitude].join()}`}\n rel='noreferrer'\n target='_blank'\n >\n <ExternalLinkIcon />\n </a>\n </div>\n );\n};\n","import React from 'react';\nimport type { Attachment } from 'stream-chat';\nimport { useComponentContextIcons, useTranslationContext } from '../../context';\n\nexport type UnsupportedAttachmentProps = {\n attachment: Attachment;\n};\n\nexport const UnsupportedAttachment = () => {\n const { IconUnsupportedAttachment } = useComponentContextIcons();\n\n const { t } = useTranslationContext('UnsupportedAttachment');\n return (\n <div\n className='str-chat__message-attachment-unsupported'\n data-testid='attachment-unsupported'\n >\n <IconUnsupportedAttachment />\n <div className='str-chat__message-attachment-unsupported__metadata'>\n <div\n className='str-chat__message-attachment-unsupported__title'\n data-testid='unsupported-attachment-title'\n >\n {t('Unsupported attachment')}\n </div>\n </div>\n </div>\n );\n};\n","import React from 'react';\nimport { useComponentContextIcons, useTranslationContext } from '../../context';\n\nexport const VisibilityDisclaimer = () => {\n const { IconEyeFill } = useComponentContextIcons();\n\n const { t } = useTranslationContext();\n return (\n <div className='str-chat__visibility-disclaimer'>\n <IconEyeFill />\n {t('Only visible to you')}\n </div>\n );\n};\n","import type { VideoAttachment as VideoAttachmentType } from 'stream-chat';\nimport { useChannelStateContext } from '../../context';\nimport React, { type ComponentType, useLayoutEffect, useRef, useState } from 'react';\nimport type { VideoAttachmentConfiguration } from '../../types/types';\nimport { getCssDimensionsVariables } from './utils';\nimport type { VideoPlayerProps } from '../VideoPlayer';\nimport { VideoPlayer as DefaultVideoPlayer } from '../VideoPlayer';\nimport { VideoThumbnail } from '../VideoPlayer/VideoThumbnail';\n\nexport type VideoAttachmentProps = {\n attachment: VideoAttachmentType;\n VideoPlayer?: ComponentType<VideoPlayerProps>;\n};\n\nexport const VideoAttachment = ({\n attachment,\n VideoPlayer = DefaultVideoPlayer,\n}: VideoAttachmentProps) => {\n const { shouldGenerateVideoThumbnail, videoAttachmentSizeHandler } =\n useChannelStateContext();\n const videoElement = useRef<HTMLDivElement>(null);\n const [attachmentConfiguration, setAttachmentConfiguration] =\n useState<VideoAttachmentConfiguration>();\n const [showVideo, setShowVideo] = React.useState(!shouldGenerateVideoThumbnail);\n\n useLayoutEffect(() => {\n if (videoElement.current && videoAttachmentSizeHandler) {\n const config = videoAttachmentSizeHandler(\n attachment,\n videoElement.current,\n shouldGenerateVideoThumbnail,\n );\n setAttachmentConfiguration(config);\n }\n }, [\n videoElement,\n videoAttachmentSizeHandler,\n attachment,\n shouldGenerateVideoThumbnail,\n ]);\n\n const renderThumbnailFirst = Boolean(\n attachment.thumb_url && shouldGenerateVideoThumbnail,\n );\n\n // todo: handle failed thumbnail loading\n return (\n <div\n className='str-chat__player-wrapper'\n data-testid='video-wrapper'\n ref={videoElement}\n style={getCssDimensionsVariables(attachment.thumb_url || '')}\n >\n {renderThumbnailFirst && !showVideo ? (\n <VideoThumbnail\n alt={attachment.title}\n data-testid='image-test'\n onPlay={() => setShowVideo(true)}\n src={attachment.thumb_url}\n title={attachment.title}\n />\n ) : (\n <VideoPlayer\n isPlaying={renderThumbnailFirst}\n thumbnailUrl={attachmentConfiguration?.thumbUrl}\n videoUrl={attachmentConfiguration?.url}\n />\n )}\n </div>\n );\n};\n","import React, {\n type PropsWithChildren,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport clsx from 'clsx';\nimport type {\n Attachment,\n LocalAttachment,\n SharedLocationResponse,\n VideoAttachment as VideoAttachmentType,\n} from 'stream-chat';\nimport {\n isAudioAttachment,\n isFileAttachment,\n isSharedLocationResponse,\n isVideoAttachment,\n isVoiceRecordingAttachment,\n} from 'stream-chat';\n\nimport { Audio as DefaultAudioAttachment } from './Audio';\nimport { AttachmentActions as DefaultAttachmentActions } from './AttachmentActions';\nimport { VoiceRecording as DefaultVoiceRecording } from './VoiceRecording';\nimport { type GalleryItem, toGalleryItemDescriptors } from '../Gallery';\nimport { ImageComponent as DefaultImage } from './Image';\nimport { Card as DefaultCard } from './LinkPreview/Card';\nimport { FileAttachment as DefaultFile } from './FileAttachment';\nimport { Giphy as DefaultGiphy } from './Giphy';\nimport { Geolocation as DefaultGeolocation } from './Geolocation';\nimport { ModalGallery as DefaultModalGallery } from './ModalGallery';\nimport { UnsupportedAttachment as DefaultUnsupportedAttachment } from './UnsupportedAttachment';\nimport {\n type AttachmentComponentType,\n type GalleryAttachment,\n type GeolocationContainerProps,\n getCssDimensionsVariables,\n isGalleryAttachmentType,\n isSvgAttachment,\n type RenderAttachmentProps,\n type RenderGalleryProps,\n type RenderMediaProps,\n SUPPORTED_VIDEO_FORMATS,\n} from './utils';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport type { ImageAttachmentConfiguration } from '../../types/types';\nimport { VisibilityDisclaimer } from './VisibilityDisclaimer';\nimport { VideoAttachment } from './VideoAttachment';\nimport type { AttachmentProps } from './Attachment';\n\nexport type AttachmentContainerProps = {\n attachment: Attachment | GalleryAttachment | SharedLocationResponse;\n componentType: AttachmentComponentType;\n};\nexport const AttachmentWithinContainer = ({\n attachment,\n children,\n componentType,\n}: PropsWithChildren<AttachmentContainerProps>) => {\n const isGAT = isGalleryAttachmentType(attachment);\n let extra = '';\n\n if (!isGAT && !isSharedLocationResponse(attachment)) {\n extra =\n componentType === 'card' && !attachment?.image_url && !attachment?.thumb_url\n ? 'no-image'\n : attachment?.actions?.length\n ? 'actions'\n : '';\n }\n\n const classNames = clsx(\n 'str-chat__message-attachment str-chat__message-attachment-dynamic-size',\n {\n [`str-chat__message-attachment--${componentType}`]: componentType,\n [`str-chat__message-attachment--${(attachment as Attachment)?.type}`]: (\n attachment as Attachment\n )?.type,\n [`str-chat__message-attachment--${componentType}--${extra}`]:\n componentType && extra,\n 'str-chat__message-attachment--svg-image': isSvgAttachment(attachment),\n 'str-chat__message-attachment-with-actions': extra === 'actions',\n },\n );\n\n return <div className={classNames}>{children}</div>;\n};\n\nexport const AttachmentActionsContainer = ({\n actionHandler,\n attachment,\n AttachmentActions = DefaultAttachmentActions,\n attachmentActionsDefaultFocus,\n}: RenderAttachmentProps) => {\n if (!attachment.actions?.length) return null;\n\n const defaultFocusedActionValue =\n attachment.type && attachmentActionsDefaultFocus?.[attachment.type];\n\n return (\n <AttachmentActions\n {...attachment}\n actionHandler={actionHandler}\n actions={attachment.actions}\n defaultFocusedActionValue={defaultFocusedActionValue}\n id={(attachment as LocalAttachment).localMetadata?.id || ''}\n text={attachment.text || ''}\n />\n );\n};\n\nexport const MediaContainer = (props: RenderMediaProps) => {\n const { attachments: mediaAttachments } = props;\n if (!mediaAttachments.length) return null;\n\n if (mediaAttachments.length > 1) {\n return (\n <GalleryContainer\n {...props}\n attachment={{ items: mediaAttachments, type: 'gallery' }}\n />\n );\n }\n\n const mediaAttachment = mediaAttachments[0];\n const { attachments: _attachments, ...rest } = props; // eslint-disable-line @typescript-eslint/no-unused-vars\n\n if (isVideoAttachment(mediaAttachment, SUPPORTED_VIDEO_FORMATS)) {\n return <VideoContainer attachment={mediaAttachment} {...rest} />;\n }\n\n return <ImageContainer attachment={mediaAttachment} {...rest} />;\n};\n\nexport const CardContainer = (props: RenderAttachmentProps) => {\n const { attachment, Card = DefaultCard } = props;\n const componentType = 'card';\n\n if (attachment.actions && attachment.actions.length) {\n return (\n <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n <div className='str-chat__attachment'>\n <Card {...attachment} />\n <AttachmentActionsContainer {...props} />\n </div>\n </AttachmentWithinContainer>\n );\n }\n\n return (\n <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n <Card {...attachment} />\n </AttachmentWithinContainer>\n );\n};\n\nexport const GiphyContainer = (props: RenderAttachmentProps) => {\n const { attachment, Giphy = DefaultGiphy } = props;\n const componentType = 'giphy';\n\n if (attachment.actions && attachment.actions.length) {\n return (\n <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n <div className='str-chat__attachment'>\n <VisibilityDisclaimer />\n <Giphy attachment={attachment} />\n <AttachmentActionsContainer {...props} />\n </div>\n </AttachmentWithinContainer>\n );\n }\n\n return (\n <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n <Giphy attachment={attachment} />\n </AttachmentWithinContainer>\n );\n};\n\nexport const FileContainer = (props: RenderAttachmentProps) => {\n const { attachment } = props;\n\n if (isVoiceRecordingAttachment(attachment)) {\n return <VoiceRecordingContainer {...props} />;\n }\n\n if (isAudioAttachment(attachment)) {\n return <AudioContainer {...props} />;\n }\n\n if (!attachment.asset_url || !isFileAttachment(attachment, SUPPORTED_VIDEO_FORMATS)) {\n return null;\n }\n\n return <OtherFilesContainer {...props} />;\n};\n\nexport const GalleryContainer = ({\n attachment,\n ModalGallery = DefaultModalGallery,\n}: RenderGalleryProps) => {\n const items = useMemo<GalleryItem[]>(\n () =>\n attachment.items.reduce<GalleryItem[]>((acc, attachment) => {\n const item = toGalleryItemDescriptors(attachment);\n if (item) acc.push(item);\n return acc;\n }, []),\n [attachment.items],\n );\n return (\n <AttachmentWithinContainer attachment={attachment} componentType='gallery'>\n <ModalGallery items={items} key='gallery' />\n </AttachmentWithinContainer>\n );\n};\n\nexport const ImageContainer = (props: RenderAttachmentProps) => {\n const { attachment, Image = DefaultImage } = props;\n const componentType = 'image';\n const imageElement = useRef<HTMLImageElement>(null);\n const { imageAttachmentSizeHandler } = useChannelStateContext();\n const [attachmentConfiguration, setAttachmentConfiguration] = useState<\n ImageAttachmentConfiguration | undefined\n >(undefined);\n\n useLayoutEffect(() => {\n if (imageElement.current && imageAttachmentSizeHandler) {\n const config = imageAttachmentSizeHandler(attachment, imageElement.current);\n setAttachmentConfiguration(config);\n }\n }, [imageElement, imageAttachmentSizeHandler, attachment]);\n\n const imgUrlFromAttachment = attachment.image_url || attachment.thumb_url || '';\n\n const imageConfig: GalleryItem = {\n ...toGalleryItemDescriptors({\n ...attachment,\n image_url: attachmentConfiguration?.url || imgUrlFromAttachment,\n }),\n ref: imageElement,\n style: getCssDimensionsVariables(imgUrlFromAttachment),\n };\n\n if (attachment.actions && attachment.actions.length) {\n return (\n <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n <div className='str-chat__attachment'>\n <Image {...imageConfig} />\n <AttachmentActionsContainer {...props} />\n </div>\n </AttachmentWithinContainer>\n );\n }\n\n return (\n <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n <Image {...imageConfig} />\n </AttachmentWithinContainer>\n );\n};\n\nexport const OtherFilesContainer = ({\n attachment,\n File = DefaultFile,\n}: RenderAttachmentProps) => {\n if (!attachment.asset_url) return null;\n\n return (\n <AttachmentWithinContainer attachment={attachment} componentType='file'>\n <File attachment={attachment} />\n </AttachmentWithinContainer>\n );\n};\n\nexport const AudioContainer = ({\n attachment,\n Audio = DefaultAudioAttachment,\n}: RenderAttachmentProps) => (\n <AttachmentWithinContainer attachment={attachment} componentType='audio'>\n <div className='str-chat__attachment'>\n <Audio attachment={attachment} />\n </div>\n </AttachmentWithinContainer>\n);\n\nexport const VoiceRecordingContainer = ({\n attachment,\n isQuoted,\n VoiceRecording = DefaultVoiceRecording,\n}: RenderAttachmentProps) => (\n <AttachmentWithinContainer attachment={attachment} componentType='voiceRecording'>\n <div className='str-chat__attachment'>\n <VoiceRecording attachment={attachment} isQuoted={isQuoted} />\n </div>\n </AttachmentWithinContainer>\n);\n\nexport const VideoContainer = (\n props: Omit<AttachmentProps, 'attachments'> & { attachment: VideoAttachmentType },\n) => {\n const { attachment, Media } = props;\n const componentType = 'media';\n\n return attachment.actions?.length ? (\n <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n <div className='str-chat__attachment'>\n <VideoAttachment attachment={attachment} VideoPlayer={Media} />\n <AttachmentActionsContainer {...props} />\n </div>\n </AttachmentWithinContainer>\n ) : (\n <AttachmentWithinContainer attachment={attachment} componentType={componentType}>\n <VideoAttachment attachment={attachment} VideoPlayer={Media} />\n </AttachmentWithinContainer>\n );\n};\n\nexport const GeolocationContainer = ({\n Geolocation = DefaultGeolocation,\n location,\n}: GeolocationContainerProps) => (\n <AttachmentWithinContainer attachment={location} componentType='geolocation'>\n <Geolocation location={location} />\n </AttachmentWithinContainer>\n);\n\nexport const UnsupportedAttachmentContainer = ({\n attachment,\n UnsupportedAttachment = DefaultUnsupportedAttachment,\n}: RenderAttachmentProps) => (\n <AttachmentWithinContainer attachment={attachment} componentType='unsupported'>\n <UnsupportedAttachment attachment={attachment} />\n </AttachmentWithinContainer>\n);\n","import React, { useMemo } from 'react';\nimport type { SharedLocationResponse, Attachment as StreamAttachment } from 'stream-chat';\nimport {\n isAudioAttachment,\n isFileAttachment,\n isImageAttachment,\n isScrapedContent,\n isSharedLocationResponse,\n isVideoAttachment,\n isVoiceRecordingAttachment,\n} from 'stream-chat';\n\nimport {\n CardContainer,\n FileContainer,\n GeolocationContainer,\n GiphyContainer,\n MediaContainer,\n UnsupportedAttachmentContainer,\n} from './AttachmentContainer';\nimport type { GroupedRenderedAttachment } from './utils';\nimport { SUPPORTED_VIDEO_FORMATS } from './utils';\nimport type {\n AttachmentActionsDefaultFocusByType,\n AttachmentActionsProps,\n} from './AttachmentActions';\nimport { defaultAttachmentActionsDefaultFocus } from './AttachmentActions';\nimport type { AudioProps } from './Audio';\nimport type { VoiceRecordingProps } from './VoiceRecording';\nimport type { CardProps } from './LinkPreview/Card';\nimport type { FileAttachmentProps } from './FileAttachment';\nimport type { GalleryItem } from '../Gallery';\nimport type { UnsupportedAttachmentProps } from './UnsupportedAttachment';\nimport type { ActionHandlerReturnType } from '../Message/hooks/useActionHandler';\nimport type { GeolocationProps } from './Geolocation';\nimport type { GiphyAttachmentProps } from './Giphy';\nimport type { VideoPlayerProps } from '../VideoPlayer';\nimport type { ModalGalleryProps } from './ModalGallery';\nimport type { ImageProps } from './Image';\n\nexport const ATTACHMENT_GROUPS_ORDER = [\n 'media',\n 'giphy',\n 'card',\n 'geolocation',\n 'file',\n 'unsupported',\n] as const;\n\nexport type AttachmentProps = {\n /** The message attachments to render, see [attachment structure](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) **/\n attachments: (StreamAttachment | SharedLocationResponse)[];\n /**\tThe handler function to call when an action is performed on an attachment, examples include canceling a \\/giphy command or shuffling the results. */\n actionHandler?: ActionHandlerReturnType;\n /**\n * Which attachment action button receives focus on initial render, keyed by attachment type.\n * Values must match an action's `value` (e.g. `'send'`, `'cancel'`, `'shuffle'` for giphy attachment).\n * Default: `{ giphy: 'send' }`.\n * To disable auto-focus (e.g. when rendering the Giphy preview above the composer so focus\n * stays in the message input), pass an empty object: `attachmentActionsDefaultFocus={{}}`.\n */\n attachmentActionsDefaultFocus?: AttachmentActionsDefaultFocusByType;\n /** Custom UI component for displaying attachment actions, defaults to and accepts same props as: [AttachmentActions](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/AttachmentActions.tsx) */\n AttachmentActions?: React.ComponentType<AttachmentActionsProps>;\n /** Custom UI component for displaying an audio type attachment, defaults to and accepts same props as: [Audio](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Audio.tsx) */\n Audio?: React.ComponentType<AudioProps>;\n /** Custom UI component for displaying a card type attachment, defaults to and accepts same props as: [Card](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Card.tsx) */\n Card?: React.ComponentType<CardProps>;\n /** Custom UI component for displaying a file type attachment, defaults to and accepts same props as: [File](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/FileAttachment.tsx) */\n File?: React.ComponentType<FileAttachmentProps>;\n /** Custom UI component for displaying a gallery of image type attachments, defaults to and accepts same props as: [ModalGallery](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/ModalGallery.tsx) */\n ModalGallery?: React.ComponentType<ModalGalleryProps>;\n Geolocation?: React.ComponentType<GeolocationProps>;\n /** Custom UI component for displaying a Giphy image, defaults to and accepts same props as: [Giphy](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Giphy.tsx) */\n Giphy?: React.ComponentType<GiphyAttachmentProps>;\n /** Custom UI component for displaying an image type attachment, defaults to and accepts same props as: [Image](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/Image.tsx) */\n Image?: React.ComponentType<ImageProps>;\n /** Optional flag to signal that an attachment is a displayed as a part of a quoted message */\n isQuoted?: boolean;\n /** Custom UI component for displaying a media type attachment, defaults to `ReactPlayer` from 'react-player' */\n Media?: React.ComponentType<VideoPlayerProps>;\n /** Custom UI component for displaying unsupported attachment types, defaults to NullComponent */\n UnsupportedAttachment?: React.ComponentType<UnsupportedAttachmentProps>;\n /** Custom UI component for displaying an audio recording attachment, defaults to and accepts same props as: [VoiceRecording](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/VoiceRecording.tsx) */\n VoiceRecording?: React.ComponentType<VoiceRecordingProps>;\n};\n\n/**\n * A component used for rendering message attachments.\n */\nexport const Attachment = (props: AttachmentProps) => {\n const {\n attachmentActionsDefaultFocus = defaultAttachmentActionsDefaultFocus,\n attachments,\n ...rest\n } = props;\n\n const groupedAttachments = useMemo(\n () =>\n renderGroupedAttachments({\n attachmentActionsDefaultFocus,\n attachments,\n ...rest,\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [attachments, attachmentActionsDefaultFocus],\n );\n\n return (\n <div className='str-chat__attachment-list'>\n {ATTACHMENT_GROUPS_ORDER.reduce(\n (acc, groupName) => [...acc, ...groupedAttachments[groupName]],\n [] as React.ReactNode[],\n )}\n </div>\n );\n};\n\nconst renderGroupedAttachments = ({\n attachments,\n ...rest\n}: AttachmentProps): GroupedRenderedAttachment => {\n const mediaAttachments: GalleryItem[] = [];\n const containers = attachments.reduce<GroupedRenderedAttachment>(\n (typeMap, attachment) => {\n if (isSharedLocationResponse(attachment)) {\n typeMap.geolocation.push(\n <GeolocationContainer\n {...rest}\n key={`geolocation-${typeMap.geolocation.length}`}\n location={attachment}\n />,\n );\n } else if (attachment.type === 'giphy') {\n typeMap.card.push(\n <GiphyContainer\n key={`giphy-${typeMap.giphy.length}`}\n {...rest}\n attachment={attachment}\n />,\n );\n } else if (isScrapedContent(attachment)) {\n typeMap.card.push(\n <CardContainer\n key={`card-${typeMap.card.length}`}\n {...rest}\n attachment={attachment}\n />,\n );\n } else if (\n isImageAttachment(attachment) ||\n isVideoAttachment(attachment, SUPPORTED_VIDEO_FORMATS)\n ) {\n mediaAttachments.push(attachment as GalleryItem);\n } else if (\n isAudioAttachment(attachment) ||\n isVoiceRecordingAttachment(attachment) ||\n isFileAttachment(attachment, SUPPORTED_VIDEO_FORMATS)\n ) {\n typeMap.file.push(\n <FileContainer\n key={`file-${typeMap.file.length}`}\n {...rest}\n attachment={attachment}\n />,\n );\n } else {\n typeMap.unsupported.push(\n <UnsupportedAttachmentContainer\n key={`unsupported-${typeMap.unsupported.length}`}\n {...rest}\n attachment={attachment}\n />,\n );\n }\n\n return typeMap;\n },\n {\n card: [],\n file: [],\n geolocation: [],\n giphy: [],\n media: [],\n unsupported: [],\n },\n );\n\n if (mediaAttachments.length) {\n containers.media.push(\n <MediaContainer key='media-container' {...rest} attachments={mediaAttachments} />,\n );\n }\n\n return containers;\n};\n","import { LiveLocationManager } from 'stream-chat';\nimport { useEffect, useMemo } from 'react';\nimport type { LiveLocationManagerConstructorParameters, StreamChat } from 'stream-chat';\n\nconst isMobile = () => /Mobi/i.test(navigator.userAgent);\n/**\n * Checks whether the current browser is Safari.\n */\nexport const isSafari = () => {\n if (typeof navigator === 'undefined') return false;\n return /^((?!chrome|android).)*safari/i.test(navigator.userAgent || '');\n};\n\n/**\n * Checks whether the current browser is Firefox.\n */\nexport const isFirefox = () => {\n if (typeof navigator === 'undefined') return false;\n return navigator.userAgent?.includes('Firefox');\n};\n\n/**\n * Checks whether the current browser is Google Chrome.\n */\nexport const isChrome = () => {\n if (typeof navigator === 'undefined') return false;\n return navigator.userAgent?.includes('Chrome');\n};\n\nconst browser = () => {\n if (isChrome()) return 'chrome';\n if (isFirefox()) return 'firefox';\n if (isSafari()) return 'safari';\n return 'other';\n};\n\nexport const useLiveLocationSharingManager = ({\n client,\n getDeviceId,\n watchLocation,\n}: Omit<LiveLocationManagerConstructorParameters, 'client' | 'getDeviceId'> & {\n client?: StreamChat | null;\n getDeviceId?: () => string;\n}) => {\n const manager = useMemo(() => {\n if (!client) return null;\n\n return new LiveLocationManager({\n client,\n getDeviceId:\n getDeviceId ??\n (() => `web-${isMobile() ? 'mobile' : 'desktop'}-${browser()}-${client.userID}`),\n watchLocation,\n });\n }, [client, getDeviceId, watchLocation]);\n\n useEffect(() => {\n if (!manager) return;\n\n manager.init();\n\n return () => {\n manager.unregisterSubscriptions();\n };\n }, [manager]);\n\n return manager;\n};\n","import React from 'react';\nimport type { MessageContextValue } from '../../context/MessageContext';\nimport { useMessageContext } from '../../context/MessageContext';\nimport { useChannelActionContext } from '../../context/ChannelActionContext';\nimport { QuotedMessagePreviewUI } from '../MessageComposer/QuotedMessagePreview';\n\nexport type QuotedMessageProps = Pick<MessageContextValue, 'renderText'>;\n\nexport const QuotedMessage = ({ renderText: propsRenderText }: QuotedMessageProps) => {\n const { message, renderText: contextRenderText } = useMessageContext('QuotedMessage');\n const { jumpToMessage } = useChannelActionContext('QuotedMessage');\n\n const renderText = propsRenderText ?? contextRenderText;\n\n const { quoted_message } = message;\n\n return quoted_message ? (\n <QuotedMessagePreviewUI\n onClick={(e) => {\n if (!quoted_message) return;\n e.stopPropagation();\n e.preventDefault();\n jumpToMessage(quoted_message.id);\n }}\n quotedMessage={quoted_message}\n renderText={renderText}\n />\n ) : null;\n};\n","import React from 'react';\nimport { useComponentContextIcons, useTranslationContext } from '../../context';\nimport { useStateStore } from '../../store';\nimport type { Reminder, ReminderState } from 'stream-chat';\n\nexport type ReminderNotificationProps = {\n reminder?: Reminder;\n};\n\nconst reminderStateSelector = (state: ReminderState) => ({\n timeLeftMs: state.timeLeftMs,\n});\n\nfunction SavedForLaterContent() {\n const { IconBookmark } = useComponentContextIcons();\n const { t } = useTranslationContext();\n return (\n <div className='str-chat__message-saved-for-later'>\n <IconBookmark />\n <span>{t('Saved for later')}</span>\n </div>\n );\n}\n\nconst THRESHOLD_RELATIVE_MINUTES = 59;\n\nfunction RemindMeContent({ reminder }: { reminder: Reminder }) {\n const { IconBell } = useComponentContextIcons();\n const { t } = useTranslationContext();\n const { timeLeftMs } = useStateStore(reminder?.state, reminderStateSelector) ?? {};\n\n const stopRefreshBoundaryMs = reminder?.timer.stopRefreshBoundaryMs;\n const stopRefreshTimeStamp =\n reminder?.remindAt && stopRefreshBoundaryMs\n ? reminder.remindAt.getTime() + stopRefreshBoundaryMs\n : undefined;\n\n const isBehindRefreshBoundary =\n !!stopRefreshTimeStamp && new Date().getTime() > stopRefreshTimeStamp;\n\n if (timeLeftMs === null || !reminder.remindAt) return null;\n\n const nowMs = Date.now();\n const remindAtMs = reminder.remindAt.getTime();\n const diffMs = remindAtMs - nowMs;\n const diffMinutes = Math.abs(diffMs) / (60 * 1000);\n const useAbsoluteFormat = diffMinutes > THRESHOLD_RELATIVE_MINUTES;\n\n const renderTime = () => {\n if (isBehindRefreshBoundary) {\n // Past: reminder time has passed\n if (useAbsoluteFormat) {\n // > 59 min ago: calendar + time (same as DateSeparator + HH:mm)\n // e.g. \"Due since Today at 15:00\", \"Due since Yesterday at 09:30\"\n return t('Due since {{ dueSince }}', {\n dueSince: t('timestamp/ReminderNotification', {\n timestamp: reminder.remindAt,\n }),\n });\n }\n // Within 59 min ago: relative\n // e.g. \"Due since 5 minutes ago\", \"Due since a minute ago\"\n return t('Due since {{ dueSince }}', {\n dueSince: t('duration/Message reminder', {\n milliseconds: diffMs,\n }),\n });\n }\n // Future: reminder not yet due\n if (useAbsoluteFormat) {\n // > 59 min from now: calendar + time (no \"Due\" prefix)\n // e.g. \"Today at 15:00\", \"Tomorrow at 09:30\"\n return t('timestamp/ReminderNotification', {\n timestamp: reminder.remindAt,\n });\n }\n // Within 59 min from now: relative\n // e.g. \"Due in 30 minutes\", \"Due in a minute\"\n return t('Due {{ timeLeft }}', {\n timeLeft: t('duration/Message reminder', {\n milliseconds: timeLeftMs,\n }),\n });\n };\n\n return (\n <p className='str-chat__message-reminder'>\n <IconBell />\n <span>{t('Reminder set')}</span>\n <span> · </span>\n <span className='str-chat__message-reminder__time-left'>{renderTime()}</span>\n </p>\n );\n}\n\nexport const ReminderNotification = ({ reminder }: ReminderNotificationProps) => {\n if (!reminder) return null;\n\n if (!reminder.remindAt) {\n return <SavedForLaterContent />;\n }\n\n return <RemindMeContent reminder={reminder} />;\n};\n","import React, { useEffect } from 'react';\n\nimport type { MessageTextProps } from './MessageText';\nimport { MessageText } from './MessageText';\n\nimport { useChannelStateContext, useMessageContext } from '../../context';\nimport { useMessageTextStreaming } from './hooks';\n\nexport type StreamedMessageTextProps = Pick<\n MessageTextProps,\n 'message' | 'renderText'\n> & {\n renderingLetterCount?: number;\n streamingLetterIntervalMs?: number;\n};\n\nexport const StreamedMessageText = (props: StreamedMessageTextProps) => {\n const {\n message: messageFromProps,\n renderingLetterCount,\n renderText,\n streamingLetterIntervalMs,\n } = props;\n const { message: messageFromContext } = useMessageContext('StreamedMessageText');\n const { channel } = useChannelStateContext();\n const message = messageFromProps || messageFromContext;\n const { text = '' } = message;\n const { skipAnimation, streamedMessageText } = useMessageTextStreaming({\n renderingLetterCount,\n streamingLetterIntervalMs,\n text,\n });\n\n useEffect(() => {\n channel?.on('ai_indicator.stop', () => {\n skipAnimation();\n });\n }, [channel, skipAnimation]);\n\n return (\n <MessageText\n message={{ ...message, text: streamedMessageText }}\n renderText={renderText}\n />\n );\n};\n","import React, { useMemo } from 'react';\nimport { usePollContext, useTranslationContext } from '../../context';\nimport { useStateStore } from '../../store';\nimport type { PollOption, PollState } from 'stream-chat';\n\ntype PollStateSelectorReturnValue = {\n enforce_unique_vote: boolean;\n is_closed: boolean | undefined;\n max_votes_allowed: number;\n name: string;\n options: PollOption[];\n};\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n enforce_unique_vote: nextValue.enforce_unique_vote,\n is_closed: nextValue.is_closed,\n max_votes_allowed: nextValue.max_votes_allowed,\n name: nextValue.name,\n options: nextValue.options,\n});\n\nexport const PollHeader = () => {\n const { t } = useTranslationContext('PollHeader');\n\n const { poll } = usePollContext();\n const { enforce_unique_vote, is_closed, max_votes_allowed, name, options } =\n useStateStore(poll.state, pollStateSelector);\n\n const selectionInstructions = useMemo(() => {\n if (is_closed) return t('Vote ended');\n if (enforce_unique_vote || options.length === 1) return t('Select one');\n if (max_votes_allowed)\n return t('Select up to {{count}}', {\n count: max_votes_allowed > options.length ? options.length : max_votes_allowed,\n });\n if (options.length > 1) return t('Select one or more');\n return '';\n }, [is_closed, enforce_unique_vote, max_votes_allowed, options.length, t]);\n\n if (!name) return null;\n\n return (\n <div className='str-chat__poll-header'>\n <div className='str-chat__poll-title'>{name}</div>\n <div className='str-chat__poll-subtitle'>{selectionInstructions}</div>\n </div>\n );\n};\n","import clsx from 'clsx';\nimport type { ComponentProps, ReactNode } from 'react';\nimport React from 'react';\n\nexport type FieldErrorProps = ComponentProps<'div'> & {\n /** Error message (string or custom content e.g. icon + text) */\n text?: ReactNode;\n};\n\nexport const FieldError = ({ className, text, ...props }: FieldErrorProps) => (\n <div {...props} className={clsx('str-chat__form-field-error', className)}>\n {text}\n </div>\n);\n","import type { Dispatch, SetStateAction } from 'react';\nimport { useCallback, useState } from 'react';\n\nexport type Validators<V extends Record<string, unknown>> = {\n [K in keyof V]?: (value: V[K]) => Error | undefined;\n};\n\nexport type UseFormStateOptions<V extends Record<string, unknown>> = {\n initialValue: V;\n validators?: Validators<V>;\n onSubmit: (value: V) => Promise<void>;\n};\n\nexport type UseFormStateReturn<V extends Record<string, unknown>> = {\n value: V;\n setValue: Dispatch<SetStateAction<V>>;\n setFieldValue: (field: keyof V, value: V[keyof V]) => void;\n fieldErrors: Record<string, Error>;\n handleSubmit: (e?: React.FormEvent) => void;\n};\n\nexport function useFormState<V extends Record<string, unknown>>(\n options: UseFormStateOptions<V>,\n): UseFormStateReturn<V> {\n const { initialValue, onSubmit, validators = {} as Validators<V> } = options;\n const [value, setValue] = useState<V>(initialValue);\n const [fieldErrors, setFieldErrors] = useState<Record<string, Error>>({});\n\n const setFieldValue = useCallback(\n (field: keyof V, fieldValue: V[keyof V]) => {\n setValue((prev) => ({ ...prev, [field]: fieldValue }) as V);\n const validator = validators[field];\n if (validator) {\n const err = validator(fieldValue);\n setFieldErrors((prev) => {\n const next = { ...prev };\n if (err) next[field as string] = err;\n else delete next[field as string];\n return next;\n });\n }\n },\n [validators],\n );\n\n const handleSubmit = useCallback(\n (e?: React.FormEvent) => {\n e?.preventDefault();\n const errors: Record<string, Error> = {};\n for (const key of Object.keys(value) as (keyof V)[]) {\n const validator = validators[key];\n if (validator) {\n const err = validator(value[key]);\n if (err) errors[key as string] = err;\n }\n }\n if (Object.keys(errors).length > 0) {\n setFieldErrors(errors);\n return;\n }\n setFieldErrors({});\n void onSubmit(value);\n },\n [value, validators, onSubmit],\n );\n\n return {\n fieldErrors,\n handleSubmit,\n setFieldValue,\n setValue,\n value,\n };\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useStateStore } from '../../../store';\nimport { useModalContext, usePollContext, useTranslationContext } from '../../../context';\nimport type { PollAnswer, PollState } from 'stream-chat';\nimport { Prompt } from '../../Dialog';\nimport { TextInput } from '../../Form';\nimport { useFormState } from '../../Form/hooks';\n\ntype PollStateSelectorReturnValue = { ownAnswer: PollAnswer | undefined };\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n ownAnswer: nextValue.ownAnswer,\n});\n\nexport type AddCommentPromptProps = {\n messageId: string;\n};\n\nexport const AddCommentPrompt = ({ messageId }: AddCommentPromptProps) => {\n const { t } = useTranslationContext();\n const { close } = useModalContext();\n const { poll } = usePollContext();\n const { ownAnswer } = useStateStore(poll.state, pollStateSelector);\n const [input, setInput] = useState<HTMLInputElement | null>(null);\n\n const initialComment = ownAnswer?.answer_text ?? '';\n const initialValue = useMemo(() => ({ comment: initialComment }), [initialComment]);\n const validators = useMemo(\n () => ({\n comment: (v: string) => {\n const trimmed = typeof v === 'string' ? v.trim() : '';\n if (!trimmed) {\n return new Error(t('This field cannot be empty or contain only spaces'));\n }\n return undefined;\n },\n }),\n [t],\n );\n const onSubmit = useCallback(\n async (formValue: { comment: string }) => {\n await poll.addAnswer(formValue.comment, messageId);\n close();\n },\n [poll, messageId, close],\n );\n const { fieldErrors, handleSubmit, setFieldValue, value } = useFormState<{\n comment: string;\n }>({\n initialValue,\n onSubmit,\n validators,\n });\n\n useEffect(() => {\n input?.focus();\n }, [input]);\n\n const title = ownAnswer ? t('Update your comment') : t('Add a comment');\n const description = ownAnswer\n ? t('Update the comment attached to your poll answer')\n : t('Add a comment to your poll answer');\n const submitDisabled =\n !value.comment?.trim() || value.comment === ownAnswer?.answer_text;\n\n return (\n <Prompt.Root className='str-chat__modal__poll-add-comment'>\n {title && <Prompt.Header close={close} description={description} title={title} />}\n <form autoComplete='off' onSubmit={handleSubmit}>\n <Prompt.Body>\n <TextInput\n aria-label={title}\n error={!!fieldErrors.comment}\n errorMessage={fieldErrors.comment?.message}\n id='comment'\n name='comment'\n onChange={(e) => setFieldValue('comment', e.target.value)}\n placeholder={t('placeholder/PollComment')}\n ref={setInput}\n required\n type='text'\n value={value.comment}\n />\n </Prompt.Body>\n <Prompt.Footer>\n <Prompt.FooterControls>\n <Prompt.FooterControlsButtonSecondary\n className='str-chat__prompt__footer__controls-button--cancel'\n onClick={close}\n type='button'\n >\n {t('Cancel')}\n </Prompt.FooterControlsButtonSecondary>\n <Prompt.FooterControlsButtonPrimary\n className='str-chat__prompt__footer__controls-button--submit'\n disabled={Object.keys(fieldErrors).length > 0 || submitDisabled}\n type='submit'\n >\n {initialComment ? t('Update') : t('Send')}\n </Prompt.FooterControlsButtonPrimary>\n </Prompt.FooterControls>\n </Prompt.Footer>\n </form>\n </Prompt.Root>\n );\n};\n","import React from 'react';\nimport { Alert } from '../../Dialog';\nimport { useModalContext, usePollContext, useTranslationContext } from '../../../context';\nimport { Button } from '../../Button';\nimport { useNotificationApi } from '../../Notifications';\n\nexport const EndPollAlert = () => {\n const { addNotification } = useNotificationApi();\n const { t } = useTranslationContext();\n const { poll } = usePollContext();\n const { close } = useModalContext();\n\n return (\n <Alert.Root className={'str-chat__end-poll-alert'}>\n <Alert.Header\n description={t(\n 'Do you want to end this poll now? Nobody will be able to vote in this poll anymore.',\n )}\n title={t('End this poll?')}\n ></Alert.Header>\n <Alert.Actions>\n <Button\n appearance='outline'\n className='str-chat__end-poll-alert__end-vote-button'\n data-testid='end-poll-alert-end-vote-button'\n onClick={async () => {\n try {\n await poll.close();\n close();\n addNotification({\n emitter: 'EndPollAlert',\n message: t('Poll ended'),\n severity: 'success',\n type: 'api:poll:end:success',\n });\n } catch (e) {\n addNotification({\n emitter: 'EndPollAlert',\n error: e instanceof Error ? e : undefined,\n message: t('Failed to end the poll'),\n severity: 'error',\n type: 'api:poll:end:failed',\n });\n }\n }}\n size='md'\n variant='danger'\n >\n {t('End poll')}\n </Button>\n <Button\n appearance='outline'\n className='str-chat__end-poll-alert__cancel-button'\n data-testid='end-poll-alert-cancel-button'\n onClick={close}\n size='md'\n variant='secondary'\n >\n {t('Cancel')}\n </Button>\n </Alert.Actions>\n </Alert.Root>\n );\n};\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\nimport { GlobalModal } from '../../Modal';\nimport { useComponentContext } from '../../../context';\nimport { Button } from '../../Button';\nimport clsx from 'clsx';\n\nexport type PollActionProps = {\n buttonText: string;\n closeModal: () => void;\n modalIsOpen: boolean;\n openModal: () => void;\n /**\n * Additional actions are shown based on the poll settings defined by the creator.\n * Examples are \"Suggest an option\", \"Add a comment\", \"View N comment(s)\".\n */\n isAdditionalAction?: boolean;\n modalClassName?: string;\n};\n\nexport const PollAction = ({\n buttonText,\n children,\n closeModal,\n isAdditionalAction,\n modalClassName,\n modalIsOpen,\n openModal,\n}: PropsWithChildren<PollActionProps>) => {\n const { Modal = GlobalModal } = useComponentContext();\n return (\n <>\n <Button\n appearance='outline'\n className={clsx('str-chat__poll-action', {\n 'str-chat__poll-action--additional': isAdditionalAction,\n })}\n onClick={openModal}\n size='md'\n variant='secondary'\n >\n {buttonText}\n </Button>\n <Modal className={modalClassName} onClose={closeModal} open={modalIsOpen}>\n {children}\n </Modal>\n </>\n );\n};\n","import React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport {\n useChatContext,\n useModalContext,\n usePollContext,\n useTranslationContext,\n} from '../../../context';\nimport { useStateStore } from '../../../store';\nimport type { PollOption, PollState } from 'stream-chat';\nimport { Prompt } from '../../Dialog';\nimport { TextInput } from '../../Form';\nimport { useFormState } from '../../Form/hooks';\n\ntype PollStateSelectorReturnValue = { options: PollOption[] };\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n options: nextValue.options,\n});\n\nexport type SuggestPollOptionFormProps = Record<string, never>;\n\nexport const SuggestPollOptionPrompt = () => {\n const { client } = useChatContext();\n const { t } = useTranslationContext();\n const { poll } = usePollContext();\n const { close } = useModalContext();\n const { options } = useStateStore(poll.state, pollStateSelector);\n const [input, setInput] = useState<HTMLInputElement | null>(null);\n\n const initialValue = useMemo(() => ({ optionText: '' }), []);\n const validators = useMemo(\n () => ({\n optionText: (v: string) => {\n const trimmed = typeof v === 'string' ? v.trim() : '';\n if (!trimmed) {\n return new Error(t('This field cannot be empty or contain only spaces'));\n }\n const existingOption = options.find((option) => option.text === trimmed);\n if (existingOption) {\n return new Error(t('Option already exists'));\n }\n return undefined;\n },\n }),\n [t, options],\n );\n\n const onSubmit = useCallback(\n async (formValue: { optionText: string }) => {\n await client.createPollOption(poll.id, {\n text: formValue.optionText,\n });\n close();\n },\n [client, poll, close],\n );\n\n const { fieldErrors, handleSubmit, setFieldValue, value } = useFormState<{\n optionText: string;\n }>({\n initialValue,\n onSubmit,\n validators,\n });\n\n useEffect(() => {\n input?.focus();\n }, [input]);\n\n const submitDisabled = !value.optionText?.trim();\n\n return (\n <Prompt.Root className='str-chat__modal__suggest-poll-option-prompt'>\n <Prompt.Header\n close={close}\n description={t('Suggest a new option to add to this poll')}\n title={t('Suggest an option')}\n />\n <form autoComplete='off' onSubmit={handleSubmit}>\n <Prompt.Body>\n <TextInput\n aria-label={t('Suggest an option')}\n error={!!fieldErrors.optionText}\n errorMessage={fieldErrors.optionText?.message}\n id='optionText'\n name='optionText'\n onChange={(e) => setFieldValue('optionText', e.target.value)}\n placeholder={t('placeholder/PollOptionSuggestion')}\n ref={setInput}\n required\n type='text'\n value={value.optionText}\n />\n </Prompt.Body>\n <Prompt.Footer>\n <Prompt.FooterControls>\n <Prompt.FooterControlsButtonSecondary\n className='str-chat__prompt__footer__controls-button--cancel'\n onClick={close}\n >\n {t('Cancel')}\n </Prompt.FooterControlsButtonSecondary>\n <Prompt.FooterControlsButtonPrimary\n className='str-chat__prompt__footer__controls-button--submit'\n disabled={Object.keys(fieldErrors).length > 0 || submitDisabled}\n type='submit'\n >\n {t('Send')}\n </Prompt.FooterControlsButtonPrimary>\n </Prompt.FooterControls>\n </Prompt.Footer>\n </form>\n </Prompt.Root>\n );\n};\n","import React, { useState } from 'react';\nimport { Avatar as DefaultAvatar } from '../Avatar';\nimport { extractDisplayInfo as defaultExtractDisplayInfo } from '../Avatar/utils';\nimport { PopperTooltip } from '../Tooltip';\nimport { useEnterLeaveHandlers } from '../Tooltip/hooks';\nimport {\n useChatContext,\n useComponentContext,\n useTranslationContext,\n} from '../../context';\n\nimport type { PollVote as PollVoteType } from 'stream-chat';\n\nconst PollVoteTimestamp = ({ timestamp }: { timestamp: string }) => {\n const { t } = useTranslationContext();\n const { handleEnter, handleLeave, tooltipVisible } =\n useEnterLeaveHandlers<HTMLSpanElement>();\n const [referenceElement, setReferenceElement] = useState<HTMLSpanElement | null>(null);\n const timestampDate = new Date(timestamp);\n return (\n <div\n className='str-chat__poll-vote__timestamp'\n onMouseEnter={handleEnter}\n onMouseLeave={handleLeave}\n ref={setReferenceElement}\n >\n {t('timestamp/PollVote', { timestamp: timestampDate })}\n <PopperTooltip\n offset={[0, 5]}\n placement='bottom'\n referenceElement={referenceElement}\n visible={tooltipVisible}\n >\n {t('timestamp/PollVoteTooltip', { timestamp: timestampDate })}\n </PopperTooltip>\n </div>\n );\n};\n\ntype PollVoteProps = {\n vote: PollVoteType;\n};\n\ntype PollVoteAuthor = PollVoteProps;\n\nconst PollVoteAuthor = ({ vote }: PollVoteAuthor) => {\n const { t } = useTranslationContext();\n const { client } = useChatContext();\n const { Avatar = DefaultAvatar, extractDisplayInfo = defaultExtractDisplayInfo } =\n useComponentContext();\n const displayName =\n client.user?.id && client.user.id === vote.user?.id\n ? t('You')\n : vote.user?.name || vote.user?.id || t('Anonymous');\n\n return (\n <div className='str-chat__poll-vote__author'>\n {vote.user && (\n <Avatar\n {...extractDisplayInfo({ user: vote.user })}\n className='str-chat__avatar--poll-vote-author'\n key={`poll-vote-${vote.id}-avatar-${vote.user.id}`}\n size='md'\n />\n )}\n <div className='str-chat__poll-vote__author__name'>{displayName}</div>\n </div>\n );\n};\n\nexport const PollVote = ({ vote }: PollVoteProps) => (\n <div className='str-chat__poll-vote'>\n <PollVoteAuthor vote={vote} />\n <PollVoteTimestamp timestamp={vote.created_at} />\n </div>\n);\n\nexport type PollVoteListingProps = {\n votes: PollVoteType[];\n};\n\nexport const PollVoteListing = ({ votes }: PollVoteListingProps) => (\n <div className='str-chat__poll-vote-listing'>\n {votes.map((vote) => (\n <PollVote key={`poll-vote-${vote.id}`} vote={vote} />\n ))}\n </div>\n);\n","import { useEffect, useState } from 'react';\nimport { isVoteAnswer } from 'stream-chat';\nimport { useChatContext } from '../../../context';\nimport type { Event, PollAnswer, PollVote } from 'stream-chat';\n\nimport type { CursorPaginatorStateStore } from '../../InfiniteScrollPaginator/hooks/useCursorPaginator';\n\nexport function useManagePollVotesRealtime<T extends PollVote | PollAnswer = PollVote>(\n managedVoteType: 'answer' | 'vote',\n cursorPaginatorState?: CursorPaginatorStateStore<T>,\n optionId?: string,\n) {\n const { client } = useChatContext();\n const [votesInRealtime, setVotesInRealtime] = useState<T[]>(\n cursorPaginatorState?.getLatestValue().items ?? [],\n );\n\n useEffect(\n () =>\n cursorPaginatorState?.subscribeWithSelector(\n (state) => [state.latestPageItems],\n ([latestPageItems]) =>\n setVotesInRealtime((prev) => [...prev, ...latestPageItems]),\n ),\n [cursorPaginatorState],\n );\n\n useEffect(() => {\n const handleVoteEvent = (event: Event) => {\n if (!event.poll_vote) return;\n const isAnswer = isVoteAnswer(event.poll_vote);\n if (\n (managedVoteType === 'answer' && !isAnswer) ||\n (managedVoteType === 'vote' &&\n (isAnswer || event.poll_vote.option_id !== optionId))\n )\n return;\n\n if (event.type === 'poll.vote_removed') {\n setVotesInRealtime((prev) =>\n event.poll_vote\n ? prev.filter((vote) => vote.id !== (event.poll_vote as T).id)\n : prev,\n );\n }\n if (event.type === 'poll.vote_changed') {\n setVotesInRealtime((prev) =>\n event.poll_vote\n ? prev.filter((vote) => vote.id !== (event.poll_vote as T).id)\n : prev,\n );\n }\n if (['poll.vote_casted', 'poll.vote_changed'].includes(event.type)) {\n setVotesInRealtime((prev) =>\n event.poll_vote ? [event.poll_vote as T, ...prev] : prev,\n );\n }\n };\n\n const voteCastedSubscription = client.on('poll.vote_casted', handleVoteEvent);\n const voteRemovedSubscription = client.on('poll.vote_removed', handleVoteEvent);\n const voteChangedSubscription = client.on('poll.vote_changed', handleVoteEvent);\n\n return () => {\n voteCastedSubscription.unsubscribe();\n voteRemovedSubscription.unsubscribe();\n voteChangedSubscription.unsubscribe();\n };\n }, [client, optionId, managedVoteType]);\n\n return votesInRealtime;\n}\n","import uniqBy from 'lodash.uniqby';\nimport { useCallback, useEffect, useMemo } from 'react';\nimport { StateStore } from 'stream-chat';\n\nexport type CursorPaginatorState<T> = {\n hasNextPage: boolean;\n items: T[];\n latestPageItems: T[];\n loading: boolean;\n error?: Error;\n next?: string | null;\n};\n\nexport type CursorPaginatorStateStore<T> = StateStore<CursorPaginatorState<T>>;\n\nexport type PaginationFn<T> = (next?: string) => Promise<{ items: T[]; next?: string }>;\n\nexport const useCursorPaginator = <T>(\n paginationFn: PaginationFn<T>,\n loadFirstPage?: boolean,\n) => {\n const cursorPaginatorState = useMemo(\n () =>\n new StateStore<CursorPaginatorState<T>>({\n hasNextPage: true,\n items: [],\n latestPageItems: [],\n loading: false,\n }),\n [],\n );\n\n const loadMore = useCallback(async () => {\n const { loading, next: currentNext } = cursorPaginatorState.getLatestValue();\n if (currentNext === null || loading) return;\n\n cursorPaginatorState.partialNext({ loading: true });\n\n try {\n const { items, next } = await paginationFn(currentNext);\n cursorPaginatorState.next((prev) => ({\n ...prev,\n hasNextPage: !!next,\n items: uniqBy(prev.items.concat(items), 'id'),\n latestPageItems: items,\n next: next || null,\n }));\n } catch (error) {\n cursorPaginatorState.partialNext({ error: error as Error });\n }\n cursorPaginatorState.partialNext({ loading: false });\n }, [cursorPaginatorState, paginationFn]);\n\n useEffect(() => {\n const { items } = cursorPaginatorState.getLatestValue();\n if (!loadFirstPage || items.length) return;\n loadMore();\n }, [cursorPaginatorState, loadFirstPage, loadMore]);\n\n return {\n cursorPaginatorState,\n loadMore,\n };\n};\n","import { useCallback } from 'react';\nimport { useManagePollVotesRealtime } from './useManagePollVotesRealtime';\nimport type {\n CursorPaginatorState,\n PaginationFn,\n} from '../../InfiniteScrollPaginator/hooks/useCursorPaginator';\nimport { useCursorPaginator } from '../../InfiniteScrollPaginator/hooks/useCursorPaginator';\nimport { usePollContext } from '../../../context';\n\nimport { useStateStore } from '../../../store';\nimport type { PollAnswer, PollAnswersQueryParams, PollVote } from 'stream-chat';\n\nconst paginationStateSelector = (\n state: CursorPaginatorState<PollVote>,\n): [Error | undefined, boolean, boolean] => [\n state.error,\n state.hasNextPage,\n state.loading,\n];\n\ntype UsePollAnswerPaginationParams = {\n paginationParams?: PollAnswersQueryParams;\n};\n\nexport const usePollAnswerPagination = ({\n paginationParams,\n}: UsePollAnswerPaginationParams = {}) => {\n const { poll } = usePollContext();\n\n const paginationFn = useCallback<PaginationFn<PollAnswer>>(\n async (next) => {\n const { next: newNext, votes } = await poll.queryAnswers({\n filter: paginationParams?.filter,\n options: !next\n ? paginationParams?.options\n : { ...paginationParams?.options, next },\n sort: { created_at: -1, ...paginationParams?.sort },\n });\n return { items: votes, next: newNext };\n },\n [paginationParams, poll],\n );\n\n const { cursorPaginatorState, loadMore } = useCursorPaginator(paginationFn, true);\n const answers = useManagePollVotesRealtime<PollAnswer>('answer', cursorPaginatorState);\n const [error, hasNextPage, loading] = useStateStore(\n cursorPaginatorState,\n paginationStateSelector,\n );\n\n return {\n answers,\n error,\n hasNextPage,\n loading,\n loadMore,\n };\n};\n","import { useCallback } from 'react';\nimport { useManagePollVotesRealtime } from './useManagePollVotesRealtime';\nimport type {\n CursorPaginatorState,\n PaginationFn,\n} from '../../InfiniteScrollPaginator/hooks/useCursorPaginator';\nimport { useCursorPaginator } from '../../InfiniteScrollPaginator/hooks/useCursorPaginator';\nimport { useStateStore } from '../../../store';\nimport { usePollContext } from '../../../context';\n\nimport type { PollOptionVotesQueryParams, PollVote } from 'stream-chat';\n\nconst paginationStateSelector = (\n state: CursorPaginatorState<PollVote>,\n): [Error | undefined, boolean, boolean] => [\n state.error,\n state.hasNextPage,\n state.loading,\n];\n\ntype UsePollOptionVotesPaginationParams = {\n paginationParams: PollOptionVotesQueryParams;\n};\n\nexport const usePollOptionVotesPagination = ({\n paginationParams,\n}: UsePollOptionVotesPaginationParams) => {\n const { poll } = usePollContext();\n\n const paginationFn = useCallback<PaginationFn<PollVote>>(\n async (next) => {\n const { next: newNext, votes } = await poll.queryOptionVotes({\n filter: paginationParams.filter,\n options: !next\n ? paginationParams?.options\n : { ...paginationParams?.options, next },\n sort: { created_at: -1, ...paginationParams?.sort },\n });\n return { items: votes, next: newNext };\n },\n [paginationParams, poll],\n );\n\n const { cursorPaginatorState, loadMore } = useCursorPaginator(paginationFn, true);\n const votes = useManagePollVotesRealtime<PollVote>(\n 'vote',\n cursorPaginatorState,\n paginationParams.filter.option_id,\n );\n const [error, hasNextPage, loading] = useStateStore(\n cursorPaginatorState,\n paginationStateSelector,\n );\n\n return {\n error,\n hasNextPage,\n loading,\n loadMore,\n votes,\n };\n};\n","import React from 'react';\nimport { Button } from '../../Button';\nimport { Viewer } from '../../Dialog';\nimport { PollVote } from '../PollVote';\nimport { usePollAnswerPagination } from '../hooks';\nimport { InfiniteScrollPaginator } from '../../InfiniteScrollPaginator/InfiniteScrollPaginator';\nimport { LoadingIndicator } from '../../Loading';\nimport { useStateStore } from '../../../store';\nimport {\n useChatContext,\n useModalContext,\n usePollContext,\n useTranslationContext,\n} from '../../../context';\n\nimport type { PollAnswer, PollState } from 'stream-chat';\n\ntype PollStateSelectorReturnValue = {\n is_closed: boolean | undefined;\n ownAnswer: PollAnswer | undefined;\n};\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n is_closed: nextValue.is_closed,\n ownAnswer: nextValue.ownAnswer,\n});\n\nexport type PollAnswerListProps = {\n onUpdateOwnAnswerClick: () => void;\n};\n\nexport const PollAnswerList = ({ onUpdateOwnAnswerClick }: PollAnswerListProps) => {\n const { client } = useChatContext();\n const { t } = useTranslationContext();\n const { poll } = usePollContext();\n const { close } = useModalContext();\n const { is_closed } = useStateStore(poll.state, pollStateSelector);\n\n const { answers, error, hasNextPage, loading, loadMore } = usePollAnswerPagination();\n\n return (\n <Viewer.Root className='str-chat__modal__poll-answer-list'>\n <Viewer.Header\n close={close}\n description={t('Review comments submitted with poll answers')}\n title={t('Poll comments')}\n />\n <Viewer.Body className='str-chat__modal__poll-answer-list__body'>\n <div className='str-chat__poll-answer-list'>\n <InfiniteScrollPaginator loadNextOnScrollToBottom={loadMore} threshold={40}>\n {answers.map((answer) => (\n <div className='str-chat__poll-answer' key={`comment-${answer.id}`}>\n <div className='str-chat__poll-answer__data'>\n {answer.answer_text && (\n <p className='str-chat__poll-answer__text'>{answer.answer_text}</p>\n )}\n <PollVote key={`poll-vote-${answer.id}`} vote={answer} />\n </div>\n {!is_closed && answer.user?.id === client.user?.id && (\n <div className='str-chat__poll-vote__update-vote-button-container'>\n <Button\n appearance='ghost'\n className='str-chat__poll-vote__update-vote-button'\n onClick={onUpdateOwnAnswerClick}\n size='md'\n variant='secondary'\n >\n {t('Update your comment')}\n </Button>\n </div>\n )}\n </div>\n ))}\n\n {hasNextPage && (\n <div className='str-chat__loading-indicator-placeholder'>\n {loading && <LoadingIndicator />}\n </div>\n )}\n </InfiniteScrollPaginator>\n </div>\n {error?.message && <div>{error?.message}</div>}\n </Viewer.Body>\n {/*<Viewer.Footer>*/}\n {/* {answers.length > 0 && !is_closed && (*/}\n {/* <Viewer.FooterControls>*/}\n {/* <Viewer.FooterControlsButtonSecondary*/}\n {/* className='str-chat__poll-action'*/}\n {/* onClick={onUpdateOwnAnswerClick}*/}\n {/* >*/}\n {/* {ownAnswer ? t('Update your comment') : t('Add a comment')}*/}\n {/* </Viewer.FooterControlsButtonSecondary>*/}\n {/* </Viewer.FooterControls>*/}\n {/* )}*/}\n {/*</Viewer.Footer>*/}\n </Viewer.Root>\n );\n};\n","import React from 'react';\nimport { useStateStore } from '../../../../store';\nimport {\n useComponentContextIcons,\n usePollContext,\n useTranslationContext,\n} from '../../../../context';\nimport type { PollOption, PollState } from 'stream-chat';\n\ntype PollStateSelectorReturnValue = {\n maxVotedOptionIds: string[];\n vote_counts_by_option: Record<string, number>;\n};\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n maxVotedOptionIds: nextValue.maxVotedOptionIds,\n vote_counts_by_option: nextValue.vote_counts_by_option,\n});\n\nexport type PollResultOptionVoteCounterProps = {\n optionId: string;\n};\n\nexport const PollResultOptionVoteCounter = ({\n optionId,\n}: PollResultOptionVoteCounterProps) => {\n const { IconTrophy } = useComponentContextIcons();\n\n const { t } = useTranslationContext();\n const { poll } = usePollContext();\n const { maxVotedOptionIds, vote_counts_by_option } = useStateStore(\n poll.state,\n pollStateSelector,\n );\n\n return (\n <div className='str-chat__poll-result-option-vote-counter'>\n {maxVotedOptionIds.length === 1 && maxVotedOptionIds[0] === optionId && (\n <IconTrophy />\n )}\n <span className='str-chat__poll-result-option-vote-count'>\n {t('{{count}} votes', { count: vote_counts_by_option[optionId] ?? 0 })}\n </span>\n </div>\n );\n};\n\nexport type PollOptionWithVotesHeaderProps = {\n option: PollOption;\n optionOrderNumber: number;\n};\n\nexport const PollOptionWithVotesHeader = ({\n option,\n optionOrderNumber,\n}: PollOptionWithVotesHeaderProps) => {\n const { t } = useTranslationContext();\n\n return (\n <div className='str-chat__poll-option__header'>\n <div className='str-chat__poll-option__header__label'>\n {t('Question {{ optionOrderNumber}}', { optionOrderNumber })}\n </div>\n <div className='str-chat__poll-option__header__title'>\n <div className='str-chat__poll-option__option-text'>{option.text}</div>\n <PollResultOptionVoteCounter optionId={option.id} />\n </div>\n </div>\n );\n};\n","import React from 'react';\nimport { PollOptionWithVotesHeader } from './PollOptionWithVotesHeader';\nimport { PollVoteListing } from '../../PollVote';\nimport { useStateStore } from '../../../../store';\nimport {\n useChannelStateContext,\n usePollContext,\n useTranslationContext,\n} from '../../../../context';\nimport type { PollOption, PollState, PollVote } from 'stream-chat';\nimport { Button } from '../../../Button';\nimport clsx from 'clsx';\n\ntype PollStateSelectorReturnValue = {\n latest_votes_by_option: Record<string, PollVote[]>;\n};\n\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n latest_votes_by_option: nextValue.latest_votes_by_option,\n});\n\nexport type PollOptionWithVotesProps = {\n option: PollOption;\n orderNumber: number;\n countVotesPreview?: number;\n showAllVotes?: () => void;\n};\n\nexport const PollOptionWithVotes = ({\n countVotesPreview,\n option,\n orderNumber,\n showAllVotes,\n}: PollOptionWithVotesProps) => {\n const { t } = useTranslationContext();\n const { channelCapabilities = {} } = useChannelStateContext('PollOptionWithVotes');\n const { poll } = usePollContext();\n const { latest_votes_by_option } = useStateStore(poll.state, pollStateSelector);\n\n const votes = latest_votes_by_option && latest_votes_by_option[option.id];\n const voteCount = votes?.length ?? 0;\n const isVotesPreview = typeof countVotesPreview === 'number';\n\n return (\n <div\n className={clsx('str-chat__poll-option', {\n 'str-chat__poll-option--has-more-votes':\n isVotesPreview && voteCount > countVotesPreview,\n 'str-chat__poll-option--has-votes': voteCount,\n })}\n >\n <PollOptionWithVotesHeader option={option} optionOrderNumber={orderNumber} />\n {!!votes && <PollVoteListing votes={votes.slice(0, countVotesPreview)} />}\n {channelCapabilities['query-poll-votes'] &&\n showAllVotes &&\n isVotesPreview &&\n votes?.length > countVotesPreview && (\n <div className='str-chat__poll-option__show-all-votes-button-container'>\n <Button\n appearance='ghost'\n className='str-chat__poll-option__show-all-votes-button'\n onClick={showAllVotes}\n size='md'\n variant='secondary'\n >\n {t('View all')}\n </Button>\n </div>\n )}\n </div>\n );\n};\n","import { useTranslationContext } from '../../../context';\n\nexport type PollQuestionProps = {\n question: string;\n};\n\nexport const PollQuestion = ({ question }: PollQuestionProps) => {\n const { t } = useTranslationContext();\n return (\n <div className='str-chat__modal__poll-question'>\n <div className='str-chat__modal__poll-question__label'>{t('Question')}</div>\n <div className='str-chat__modal__poll-question__text'>{question}</div>\n </div>\n );\n};\n","import React, { useMemo } from 'react';\nimport { PollVoteListing } from '../../PollVote';\nimport { usePollOptionVotesPagination } from '../../hooks';\nimport { LoadingIndicator } from '../../../Loading';\nimport { InfiniteScrollPaginator } from '../../../InfiniteScrollPaginator/InfiniteScrollPaginator';\nimport type { PollOption, PollOptionVotesQueryParams } from 'stream-chat';\nimport { PollOptionWithVotesHeader } from './PollOptionWithVotesHeader';\n\nexport type PollOptionWithVotesListProps = {\n option: PollOption;\n optionOrderNumber: number;\n};\n\nexport const PollOptionWithVotesList = ({\n option,\n optionOrderNumber,\n}: PollOptionWithVotesListProps) => {\n const paginationParams = useMemo<PollOptionVotesQueryParams>(\n () => ({ filter: { option_id: option.id } }),\n [option.id],\n );\n const { hasNextPage, loading, loadMore, votes } = usePollOptionVotesPagination({\n paginationParams,\n });\n\n return (\n <InfiniteScrollPaginator loadNextOnScrollToBottom={loadMore} threshold={40}>\n <div className='str-chat_poll-option-with-votes-list'>\n <div className='str-chat__poll-option'>\n <div className='str-chat__poll-option__votes-paginated-list'>\n <PollOptionWithVotesHeader\n option={option}\n optionOrderNumber={optionOrderNumber}\n />\n <PollVoteListing votes={votes} />\n {hasNextPage && (\n <div className='str-chat__loading-indicator-placeholder'>\n {loading && <LoadingIndicator />}\n </div>\n )}\n </div>\n </div>\n </div>\n </InfiniteScrollPaginator>\n );\n};\n","import clsx from 'clsx';\nimport React, { useCallback, useState } from 'react';\nimport { PollOptionWithVotes } from './PollOptionWithVotes';\nimport { Viewer } from '../../../Dialog';\nimport { useStateStore } from '../../../../store';\nimport {\n useModalContext,\n usePollContext,\n useTranslationContext,\n} from '../../../../context';\nimport type { PollOption, PollState } from 'stream-chat';\nimport { COUNT_OPTION_VOTES_PREVIEW } from '../../constants';\nimport { PollQuestion } from '../PollQuestion';\nimport { PollOptionWithVotesList } from './PollOptionWithVotesList';\n\nconst pollStateSelector = ({\n name,\n options,\n vote_count,\n vote_counts_by_option,\n}: PollState) => ({\n name,\n options: [...options],\n vote_count,\n vote_counts_by_option,\n});\n\nexport const PollResults = () => {\n const { t } = useTranslationContext();\n const { poll } = usePollContext();\n const { close } = useModalContext();\n const { name, options, vote_count, vote_counts_by_option } = useStateStore(\n poll.state,\n pollStateSelector,\n );\n const [optionToView, setOptionToView] = useState<{\n option: PollOption;\n optionOrderNumber: number;\n } | null>(null);\n\n const goBack = useCallback(() => setOptionToView(null), []);\n\n return (\n <Viewer.Root\n className={clsx('str-chat__modal__poll-results', {\n 'str-chat__modal__poll-results--option-detail': optionToView,\n })}\n >\n {optionToView?.option ? (\n <>\n <Viewer.Header\n close={close}\n description={t('Review who voted for this option')}\n goBack={goBack}\n title={t('Votes')}\n />\n <Viewer.Body className='str-chat__modal__poll-results__body'>\n <PollOptionWithVotesList\n option={optionToView?.option}\n optionOrderNumber={optionToView?.optionOrderNumber}\n />\n </Viewer.Body>\n </>\n ) : (\n <>\n <Viewer.Header\n close={close}\n description={t(\n 'Review poll results and open an option to see detailed votes',\n )}\n title={t('Poll results')}\n />\n <Viewer.Body className='str-chat__modal__poll-results__body'>\n <PollQuestion question={name} />\n <div className='str-chat__modal__poll-results__options'>\n <div className='str-chat__modal__poll-results__option-list'>\n {options\n .sort((next, current) =>\n (vote_counts_by_option[current.id] ?? 0) >=\n (vote_counts_by_option[next.id] ?? 0)\n ? 1\n : -1,\n )\n .map((option, i) => {\n const optionOrderNumber = i + 1;\n return (\n <PollOptionWithVotes\n countVotesPreview={COUNT_OPTION_VOTES_PREVIEW}\n key={`poll-option-${option.id}`}\n option={option}\n orderNumber={optionOrderNumber}\n showAllVotes={() =>\n setOptionToView({ option, optionOrderNumber })\n }\n />\n );\n })}\n </div>\n <div className='str-chat__modal__poll-results__options__footer'>\n <div className='str-chat__modal__poll-results__options-total-count'>\n {t('totalVoteCount', { count: vote_count })}\n </div>\n </div>\n </div>\n </Viewer.Body>\n </>\n )}\n </Viewer.Root>\n );\n};\n","import clsx from 'clsx';\nimport React, { useCallback, useState } from 'react';\nimport { PollAction } from './PollAction';\nimport type { AddCommentPromptProps } from './AddCommentPrompt';\nimport { AddCommentPrompt as DefaultAddCommentPrompt } from './AddCommentPrompt';\nimport type { SuggestPollOptionFormProps } from './SuggestPollOptionPrompt';\nimport { SuggestPollOptionPrompt as DefaultSuggestPollOptionForm } from './SuggestPollOptionPrompt';\nimport { EndPollAlert as DefaultEndPollAlert } from './EndPollAlert';\nimport type { PollAnswerListProps } from './PollAnswerList';\nimport { PollAnswerList as DefaultPollAnswerList } from './PollAnswerList';\nimport { PollResults as DefaultPollResults } from './PollResults';\nimport { MAX_POLL_OPTIONS } from '../constants';\nimport {\n useChannelStateContext,\n useChatContext,\n useMessageContext,\n usePollContext,\n useTranslationContext,\n} from '../../../context';\nimport { useStateStore } from '../../../store';\n\nimport type { PollState } from 'stream-chat';\n\nconst COMMON_MODAL_CLASS = 'str-chat__poll-action-modal' as const;\n\ntype ModalName =\n | 'suggest-option'\n | 'add-comment'\n | 'view-comments'\n | 'view-results'\n | 'end-vote';\n\nconst pollStateSelector = (nextValue: PollState) => ({\n allow_answers: nextValue.allow_answers,\n allow_user_suggested_options: nextValue.allow_user_suggested_options,\n answers_count: nextValue.answers_count,\n created_by_id: nextValue.created_by_id,\n is_closed: nextValue.is_closed,\n options: nextValue.options,\n ownAnswer: nextValue.ownAnswer,\n voteCount: nextValue.vote_count,\n});\n\nexport type PollActionsProps = {\n AddCommentPrompt?: React.ComponentType<AddCommentPromptProps>;\n EndPollAlert?: React.ComponentType;\n PollAnswerList?: React.ComponentType<PollAnswerListProps>;\n PollResults?: React.ComponentType;\n SuggestPollOptionForm?: React.ComponentType<SuggestPollOptionFormProps>;\n};\n\nexport const PollActions = ({\n AddCommentPrompt = DefaultAddCommentPrompt,\n EndPollAlert = DefaultEndPollAlert,\n PollAnswerList = DefaultPollAnswerList,\n PollResults = DefaultPollResults,\n SuggestPollOptionForm = DefaultSuggestPollOptionForm,\n}: PollActionsProps) => {\n const { client } = useChatContext();\n const { t } = useTranslationContext('PollActions');\n const { channelCapabilities = {} } = useChannelStateContext('PollActions');\n const { message } = useMessageContext('PollActions');\n const { poll } = usePollContext();\n const {\n allow_answers,\n allow_user_suggested_options,\n answers_count,\n created_by_id,\n is_closed,\n options,\n ownAnswer,\n voteCount,\n } = useStateStore(poll.state, pollStateSelector);\n const [modalOpen, setModalOpen] = useState<ModalName | undefined>();\n\n const canCastVote = channelCapabilities['cast-poll-vote'] && !is_closed;\n const closeModal = useCallback(() => setModalOpen(undefined), []);\n const onUpdateAnswerClick = useCallback(() => setModalOpen('add-comment'), []);\n\n const hasContents =\n (!is_closed && created_by_id === client.user?.id) ||\n !!voteCount ||\n (canCastVote && allow_user_suggested_options && options.length < MAX_POLL_OPTIONS) ||\n (!is_closed && allow_answers) ||\n (answers_count > 0 && channelCapabilities['query-poll-votes']);\n\n if (!hasContents) return null;\n\n return (\n <div className='str-chat__poll-actions'>\n {!is_closed && created_by_id === client.user?.id && (\n <PollAction\n buttonText={t('End poll')}\n closeModal={closeModal}\n modalClassName={clsx(COMMON_MODAL_CLASS, 'str-chat__end-poll-modal')}\n modalIsOpen={modalOpen === 'end-vote'}\n openModal={() => setModalOpen('end-vote')}\n >\n <EndPollAlert />\n </PollAction>\n )}\n\n {!!voteCount && (\n <PollAction\n buttonText={t('View results')}\n closeModal={closeModal}\n modalClassName={clsx(COMMON_MODAL_CLASS, 'str-chat__poll-results-modal')}\n modalIsOpen={modalOpen === 'view-results'}\n openModal={() => setModalOpen('view-results')}\n >\n <PollResults />\n </PollAction>\n )}\n\n {canCastVote &&\n allow_user_suggested_options &&\n options.length < MAX_POLL_OPTIONS && (\n <PollAction\n buttonText={t('Suggest an option')}\n closeModal={closeModal}\n isAdditionalAction\n modalClassName={clsx(\n COMMON_MODAL_CLASS,\n 'str-chat__suggest-poll-option-modal',\n )}\n modalIsOpen={modalOpen === 'suggest-option'}\n openModal={() => setModalOpen('suggest-option')}\n >\n <SuggestPollOptionForm />\n </PollAction>\n )}\n\n {!is_closed && allow_answers && (\n <PollAction\n buttonText={ownAnswer ? t('Update your comment') : t('Add a comment')}\n closeModal={closeModal}\n isAdditionalAction\n modalClassName={clsx(COMMON_MODAL_CLASS, 'str-chat__add-poll-answer-modal')}\n modalIsOpen={modalOpen === 'add-comment'}\n openModal={() => setModalOpen('add-comment')}\n >\n <AddCommentPrompt messageId={message.id} />\n </PollAction>\n )}\n\n {answers_count > 0 && channelCapabilities['query-poll-votes'] && (\n <PollAction\n buttonText={t('View {{count}} comments', { count: answers_count })}\n closeModal={closeModal}\n isAdditionalAction\n modalClassName={clsx(COMMON_MODAL_CLASS, 'str-chat__poll-answer-list-modal')}\n modalIsOpen={modalOpen === 'view-comments'}\n openModal={() => setModalOpen('view-comments')}\n >\n <PollAnswerList onUpdateOwnAnswerClick={onUpdateAnswerClick} />\n </PollAction>\n )}\n </div>\n );\n};\n","import clsx from 'clsx';\nimport debounce from 'lodash.debounce';\nimport React, { useMemo } from 'react';\nimport type { PollOption, PollState, PollVote, VotingVisibility } from 'stream-chat';\nimport { isVoteAnswer } from 'stream-chat';\nimport { AvatarStack as DefaultAvatarStack } from '../Avatar';\nimport { extractDisplayInfo as defaultExtractDisplayInfo } from '../Avatar/utils';\nimport {\n useChannelStateContext,\n useComponentContext,\n useMessageContext,\n usePollContext,\n useTranslationContext,\n} from '../../context';\nimport { useStateStore } from '../../store';\nimport { Checkbox } from '../Form';\n\ntype AmountBarProps = {\n amount: number;\n className?: string;\n};\n\nexport const AmountBar = ({ amount, className }: AmountBarProps) => (\n <div\n aria-hidden='true'\n className={clsx('str-chat__amount-bar', className)}\n data-testid='amount-bar'\n style={\n {\n '--str-chat__amount-bar-fulfillment': amount + '%',\n } as React.CSSProperties\n }\n />\n);\n\ntype PollStateSelectorReturnValue = {\n is_closed: boolean | undefined;\n latest_votes_by_option: Record<string, PollVote[]>;\n maxVotedOptionIds: string[];\n ownVotesByOptionId: Record<string, PollVote>;\n vote_counts_by_option: Record<string, number>;\n voting_visibility: VotingVisibility | undefined;\n};\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n is_closed: nextValue.is_closed,\n latest_votes_by_option: nextValue.latest_votes_by_option,\n maxVotedOptionIds: nextValue.maxVotedOptionIds,\n ownVotesByOptionId: nextValue.ownVotesByOptionId,\n vote_counts_by_option: nextValue.vote_counts_by_option,\n voting_visibility: nextValue.voting_visibility,\n});\n\nexport type PollOptionSelectorProps = {\n option: PollOption;\n displayAvatarCount?: number;\n voteCountVerbose?: boolean;\n};\n\nexport const PollOptionSelector = ({\n displayAvatarCount,\n option,\n voteCountVerbose,\n}: PollOptionSelectorProps) => {\n const { t } = useTranslationContext();\n const { channelCapabilities = {} } = useChannelStateContext('PollOptionsShortlist');\n const { message } = useMessageContext();\n const {\n AvatarStack = DefaultAvatarStack,\n extractDisplayInfo = defaultExtractDisplayInfo,\n } = useComponentContext();\n const { poll } = usePollContext();\n const {\n is_closed,\n latest_votes_by_option,\n maxVotedOptionIds,\n ownVotesByOptionId,\n vote_counts_by_option,\n voting_visibility,\n } = useStateStore(poll.state, pollStateSelector);\n\n const canCastVote = channelCapabilities['cast-poll-vote'] && !is_closed;\n const isInteractive = !!canCastVote;\n const isSelected = !!ownVotesByOptionId[option.id];\n const winningOptionCount = maxVotedOptionIds[0]\n ? vote_counts_by_option[maxVotedOptionIds[0]]\n : 0;\n\n const toggleVote = useMemo(\n () =>\n debounce(() => {\n if (!canCastVote) return;\n const haveVotedForTheOption = !!ownVotesByOptionId[option.id];\n return haveVotedForTheOption\n ? poll.removeVote(ownVotesByOptionId[option.id].id, message.id)\n : poll.castVote(option.id, message.id);\n }, 100),\n [canCastVote, message.id, option.id, ownVotesByOptionId, poll],\n );\n\n const avatarDisplayInfo = useMemo(\n () =>\n latest_votes_by_option?.[option.id] &&\n (latest_votes_by_option[option.id] as PollVote[])\n .filter((vote) => !!vote.user && !isVoteAnswer(vote))\n .slice(0, displayAvatarCount)\n .map(extractDisplayInfo),\n [displayAvatarCount, extractDisplayInfo, latest_votes_by_option, option.id],\n );\n\n return (\n <div\n aria-pressed={isInteractive ? isSelected : undefined}\n className={clsx('str-chat__poll-option', {\n 'str-chat__poll-option--votable': canCastVote,\n })}\n key={`base-poll-option-${option.id}`}\n onClick={isInteractive ? toggleVote : undefined}\n onKeyDown={\n isInteractive\n ? (event) => {\n if (event.key !== 'Enter' && event.key !== ' ') return;\n event.preventDefault();\n toggleVote();\n }\n : undefined\n }\n role={isInteractive ? 'button' : undefined}\n tabIndex={isInteractive ? 0 : undefined}\n >\n {canCastVote && <Checkbox checked={isSelected} />}\n <div className='str-chat__poll-option-data'>\n <p className='str-chat__poll-option-text'>{option.text}</p>\n <div className='str-chat__poll-option-votes'>\n {displayAvatarCount && voting_visibility === 'public' && (\n <div className='str-chat__poll-option-voters'>\n <AvatarStack displayInfo={avatarDisplayInfo} size='xs' />\n </div>\n )}\n <div className='str-chat__poll-option-vote-count'>\n {voteCountVerbose\n ? t('{{count}} votes', {\n count: vote_counts_by_option[option.id] ?? 0,\n })\n : (vote_counts_by_option[option.id] ?? 0)}\n </div>\n </div>\n </div>\n <AmountBar\n amount={\n (winningOptionCount &&\n (vote_counts_by_option[option.id] ?? 0) / winningOptionCount) * 100\n }\n className={clsx('str-chat__poll-option__votes-bar', {\n 'str-chat__poll-option__votes-bar--winner':\n is_closed &&\n maxVotedOptionIds.length === 1 &&\n maxVotedOptionIds[0] === option.id,\n })}\n />\n </div>\n );\n};\n","import clsx from 'clsx';\nimport React, { useCallback, useState } from 'react';\nimport { PollAction } from './PollActions/PollAction';\nimport { PollOptionSelector as DefaultPollOptionSelector } from './PollOptionSelector';\nimport { useStateStore } from '../../store';\nimport {\n useComponentContext,\n usePollContext,\n useTranslationContext,\n} from '../../context';\nimport type { PollOption, PollState } from 'stream-chat';\nimport { PollOptionsFullList as DefaultPollOptionsFullList } from './PollActions/PollOptionsFullList';\n\ntype PollStateSelectorReturnValue = { options: PollOption[] };\n\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n options: nextValue.options,\n});\n\nexport type PollOptionListProps = {\n optionsDisplayCount?: number;\n PollOptionsFullList?: React.ComponentType;\n};\n\nexport const PollOptionList = ({\n optionsDisplayCount,\n PollOptionsFullList = DefaultPollOptionsFullList,\n}: PollOptionListProps) => {\n const { PollOptionSelector = DefaultPollOptionSelector } = useComponentContext();\n const { t } = useTranslationContext('PollOptionList');\n const { poll } = usePollContext();\n const { options } = useStateStore(poll.state, pollStateSelector);\n const [viewAllOptionsOpen, setViewAllOptionsOpen] = useState(false);\n const closeViewAllOptions = useCallback(() => setViewAllOptionsOpen(false), []);\n const openViewAllOptions = useCallback(() => setViewAllOptionsOpen(true), []);\n\n const showMoreOptionsButton =\n typeof optionsDisplayCount === 'number' && options.length > optionsDisplayCount;\n\n return (\n <>\n <div\n className={clsx('str-chat__poll-option-list', {\n 'str-chat__poll-option-list--full': typeof optionsDisplayCount === 'undefined',\n })}\n >\n {options.slice(0, optionsDisplayCount ?? options.length).map((option) => (\n <PollOptionSelector\n displayAvatarCount={3}\n key={`poll-option-${option.id}`}\n option={option}\n />\n ))}\n </div>\n {showMoreOptionsButton && (\n <PollAction\n buttonText={t('+{{count}} more options', {\n count: options.length,\n })}\n closeModal={closeViewAllOptions}\n isAdditionalAction\n modalClassName='str-chat__poll-action-modal'\n modalIsOpen={viewAllOptionsOpen}\n openModal={openViewAllOptions}\n >\n <PollOptionsFullList />\n </PollAction>\n )}\n </>\n );\n};\n","import React from 'react';\nimport { Viewer } from '../../Dialog';\nimport { PollOptionList } from '../PollOptionList';\nimport { useStateStore } from '../../../store';\nimport { useModalContext, usePollContext, useTranslationContext } from '../../../context';\n\nimport type { PollState } from 'stream-chat';\nimport { PollQuestion } from './PollQuestion';\n\ntype PollStateSelectorReturnValue = { name: string };\nconst pollStateSelector = (nextValue: PollState): PollStateSelectorReturnValue => ({\n name: nextValue.name,\n});\n\nexport const PollOptionsFullList = () => {\n const { t } = useTranslationContext();\n const { poll } = usePollContext();\n const { close } = useModalContext();\n const { name } = useStateStore(poll.state, pollStateSelector);\n\n return (\n <Viewer.Root className={'str-chat__modal__poll-option-list'}>\n <Viewer.Header\n close={close}\n description={t('Review all options available in this poll')}\n title={t('Poll options')}\n />\n <Viewer.Body className='str-chat__modal__poll-option-list__body'>\n <PollQuestion question={name} />\n <PollOptionList />\n </Viewer.Body>\n </Viewer.Root>\n );\n};\n","import clsx from 'clsx';\nimport React from 'react';\nimport { PollHeader as DefaultPollHeader } from './PollHeader';\nimport { PollActions as DefaultPollActions } from './PollActions';\nimport { PollOptionList } from './PollOptionList';\nimport { MAX_OPTIONS_DISPLAYED } from './constants';\nimport { useComponentContext, usePollContext } from '../../context';\nimport { useStateStore } from '../../store';\nimport type { PollState } from 'stream-chat';\n\ntype PollStateSelectorPollContentReturnValue = { is_closed: boolean | undefined };\nconst pollStateSelectorPollContent = (\n nextValue: PollState,\n): PollStateSelectorPollContentReturnValue => ({ is_closed: nextValue.is_closed });\nexport const PollContent = () => {\n const { PollActions = DefaultPollActions, PollHeader = DefaultPollHeader } =\n useComponentContext();\n const { poll } = usePollContext();\n const { is_closed } = useStateStore(poll.state, pollStateSelectorPollContent);\n\n return (\n <div className={clsx('str-chat__poll', { 'str-chat__poll--closed': is_closed })}>\n <PollHeader />\n <PollOptionList optionsDisplayCount={MAX_OPTIONS_DISPLAYED} />\n <PollActions />\n </div>\n );\n};\n","import React from 'react';\nimport { PollContent as DefaultPollContent } from './PollContent';\nimport { PollProvider, useComponentContext } from '../../context';\nimport type { Poll as PollClass } from 'stream-chat';\n\nexport const Poll = ({ poll }: { poll: PollClass }) => {\n const { PollContent = DefaultPollContent } = useComponentContext();\n if (!poll) return null;\n return (\n <PollProvider poll={poll}>\n <PollContent />\n </PollProvider>\n );\n};\n","import React from 'react';\n\n/** Three dots for typing indicator; fill and opacity animation come from TypingIndicator.scss (--chat-text-typing-indicator). */\nexport const TypingIndicatorDots = () => (\n <svg\n aria-hidden\n fill='none'\n height='5'\n viewBox='0 0 23 5'\n width='23'\n xmlns='http://www.w3.org/2000/svg'\n >\n <circle cx='2.5' cy='2.5' r='2.5' />\n <circle cx='11.5' cy='2.5' r='2.5' />\n <circle cx='20.5' cy='2.5' r='2.5' />\n </svg>\n);\n","import { useEffect, useMemo, useRef, useState } from 'react';\nimport type { ChannelState } from 'stream-chat';\n\nconst DEFAULT_HIDE_DELAY_MS = 2000;\n\nexport type TypingEntry = ChannelState['typing'][string];\n\n/**\n * Derive a stable key from typing users so that the effect only runs when the\n * actual set of users (by id) changes, not on every render due to new array\n * references.\n *\n * Important: callers must pass entries where `user` is an object with an `id`\n * field (not a plain string). If `user?.id` is undefined for every entry the\n * key degenerates to an empty string, the memo returns a new array each time\n * it is \"invalidated\" by React, and `setDisplayUsers` in the effect below will\n * loop infinitely because it always receives a fresh reference.\n */\nconst useStableTypingUsers = (typingUsers: readonly TypingEntry[]) => {\n const key = typingUsers\n .map((entry) => entry.user?.id ?? '')\n .sort()\n .join(',');\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => [...typingUsers], [key]);\n};\n\n/**\n * Debounces hiding the typing indicator: when typing users go to zero, keep showing for delayMs\n * to avoid flicker when typing stops and starts again quickly. Returns the list to display\n * (current typers or last non-empty list during the debounce period). Show the indicator\n * when displayUsers.length > 0.\n */\nexport function useDebouncedTypingActive(\n typingUsers: readonly TypingEntry[],\n delayMs: number = DEFAULT_HIDE_DELAY_MS,\n): { displayUsers: TypingEntry[] } {\n const stableTypingUsers = useStableTypingUsers(typingUsers);\n const [displayUsers, setDisplayUsers] = useState<TypingEntry[]>([]);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hadTypersRef = useRef(false);\n\n useEffect(() => {\n if (stableTypingUsers.length > 0) {\n if (timerRef.current) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n hadTypersRef.current = true;\n setDisplayUsers(stableTypingUsers);\n return;\n }\n\n if (stableTypingUsers.length === 0 && hadTypersRef.current && !timerRef.current) {\n timerRef.current = setTimeout(() => {\n timerRef.current = null;\n hadTypersRef.current = false;\n setDisplayUsers([]);\n }, delayMs);\n }\n }, [stableTypingUsers, delayMs]);\n\n useEffect(\n () => () => {\n if (timerRef.current) clearTimeout(timerRef.current);\n },\n [],\n );\n\n return { displayUsers };\n}\n","import type { TypingEntry } from '../hooks/useDebouncedTypingActive';\n\ntype TranslationFunction = (\n key: string,\n options?: Record<string, number | string>,\n) => string;\n\n/**\n * Build a localized typing-status message for screen-reader and inline indicator text.\n */\nexport const getTypingStatusMessage = (\n displayUsers: readonly TypingEntry[],\n t: TranslationFunction,\n) => {\n const namedUsers = displayUsers\n .map(({ user }) => user?.name?.trim() || user?.id || '')\n .filter(Boolean);\n const count = displayUsers.length;\n\n if (count === 1 && namedUsers.length === 1) {\n return t('{{ typing }} is typing', { typing: namedUsers[0] });\n }\n\n if (count === 2 && namedUsers.length === 2) {\n return t('{{ typing }} are typing', {\n typing: `${namedUsers[0]} and ${namedUsers[1]}`,\n });\n }\n\n return t('{{ count }} people are typing', { count });\n};\n","import React from 'react';\nimport clsx from 'clsx';\n\nimport { TypingIndicatorDots } from './TypingIndicatorDots';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { useChatContext } from '../../context/ChatContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useTypingContext } from '../../context/TypingContext';\nimport { useThreadContext } from '../Threads';\n\nimport { useDebouncedTypingActive } from './hooks/useDebouncedTypingActive';\nimport { getTypingStatusMessage } from './utils/getTypingStatusMessage';\n\nexport type TypingIndicatorHeaderProps = {\n /** When true, show typing in the current thread only; when false, show typing in the channel. */\n threadList?: boolean;\n};\n\n/**\n * Inline typing indicator for ChannelHeader or ThreadHeader: text (1/2/3+ people) followed by animated dots.\n * Only shows other participants; respects channelConfig.typing_events.\n */\nexport const TypingIndicatorHeader = (props: TypingIndicatorHeaderProps) => {\n const { threadList = false } = props;\n\n const { t } = useTranslationContext();\n const { channelConfig, thread } = useChannelStateContext('TypingIndicatorHeader');\n const threadInstance = useThreadContext();\n const parentId = threadInstance?.id ?? thread?.id;\n const { client } = useChatContext('TypingIndicatorHeader');\n const { typing = {} } = useTypingContext('TypingIndicatorHeader');\n\n const typingInChannel = !threadList\n ? Object.values(typing).filter(\n ({ parent_id, user }) => user?.id !== client.user?.id && !parent_id,\n )\n : [];\n\n const typingInThread = threadList\n ? Object.values(typing).filter(\n ({ parent_id, user }) => user?.id !== client.user?.id && parent_id === parentId,\n )\n : [];\n\n const typingUsers = threadList ? typingInThread : typingInChannel;\n const { displayUsers } = useDebouncedTypingActive(typingUsers);\n const label = getTypingStatusMessage(displayUsers, t);\n\n if (channelConfig?.typing_events === false || displayUsers.length === 0) {\n return null;\n }\n\n return (\n <span\n className={clsx('str-chat__typing-indicator-header', {\n 'str-chat__typing-indicator-header--thread': threadList,\n })}\n data-testid='typing-indicator-header'\n >\n <span className='str-chat__typing-indicator-header__text'>{label}</span>\n <span className='str-chat__typing-indicator__dots str-chat__typing-indicator-header__dots'>\n <TypingIndicatorDots />\n </span>\n </span>\n );\n};\n","import React from 'react';\n\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useStateStore } from '../../store';\nimport { useChannelPreviewInfo } from '../ChannelListItem/hooks/useChannelPreviewInfo';\nimport { TypingIndicatorHeader } from '../TypingIndicator/TypingIndicatorHeader';\nimport { useThreadContext } from '../Threads';\nimport { useChatContext } from '../../context/ChatContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useTypingContext } from '../../context/TypingContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ThreadState } from 'stream-chat';\nimport { Button } from '../Button';\nimport { useChatViewContext } from '../ChatView';\n\nimport { useComponentContextIcons } from '../../context';\nconst threadStateSelector = ({ replyCount }: ThreadState) => ({ replyCount });\n\n/** Fallback when channel has no display title: parent message author (name only). */\nconst displayNameFromParentMessage = (message: LocalMessage): string | undefined =>\n message.user?.name ?? undefined;\n\n/** Subtitle: replyCount, threadDisplayName, defaultSubtitle (name · reply count), and when typing also TypingIndicatorHeader. */\nconst ThreadHeaderSubtitle = ({\n replyCount,\n threadDisplayName,\n threadList,\n}: {\n replyCount: number | undefined;\n threadDisplayName: string | undefined;\n threadList: boolean;\n}) => {\n const { t } = useTranslationContext();\n const { channelConfig, thread } = useChannelStateContext('ThreadHeaderSubtitle');\n const threadInstance = useThreadContext();\n const parentId = threadInstance?.id ?? thread?.id;\n const { client } = useChatContext('ThreadHeaderSubtitle');\n const { typing = {} } = useTypingContext('ThreadHeaderSubtitle');\n const typingInThread = Object.values(typing).filter(\n ({ parent_id, user }) => user?.id !== client.user?.id && parent_id === parentId,\n );\n const hasTyping = channelConfig?.typing_events !== false && typingInThread.length > 0;\n const replyCountText = t('replyCount', { count: replyCount ?? 0 });\n const defaultSubtitle = threadDisplayName\n ? `${threadDisplayName} · ${replyCountText}`\n : replyCountText;\n return (\n <div className='str-chat__thread-header-subtitle'>\n <span\n className='str-chat__subtitle-content-transition'\n key={hasTyping ? 'typing' : 'default'}\n >\n {hasTyping ? (\n <TypingIndicatorHeader threadList={threadList} />\n ) : (\n <>{defaultSubtitle}</>\n )}\n </span>\n </div>\n );\n};\n\nexport type ThreadHeaderProps = {\n /** Callback for closing the thread */\n closeThread: (event?: React.BaseSyntheticEvent) => void;\n /** The thread parent message */\n thread: LocalMessage;\n /** Override the thread display title */\n overrideTitle?: string;\n};\n\nexport const ThreadHeader = (props: ThreadHeaderProps) => {\n const { IconXmark } = useComponentContextIcons();\n\n const { closeThread, overrideTitle, thread } = props;\n\n const { t } = useTranslationContext();\n const { channel } = useChannelStateContext();\n const { HeaderStartContent } = useComponentContext();\n const { activeChatView } = useChatViewContext();\n const { displayTitle: channelDisplayTitle } = useChannelPreviewInfo({ channel });\n\n const threadInstance = useThreadContext();\n const { replyCount: replyCountThreadInstance } =\n useStateStore(threadInstance?.state, threadStateSelector) ?? {};\n\n const replyCount = threadInstance\n ? replyCountThreadInstance\n : thread\n ? (thread.reply_count ?? 0)\n : 0;\n\n // Subtitle: channel display title (from parent or hook), with override and fallback to parent message author\n const threadDisplayName =\n overrideTitle ??\n channelDisplayTitle ??\n displayNameFromParentMessage(thread) ??\n undefined;\n\n return (\n <div className='str-chat__thread-header'>\n <div className='str-chat__thread-header__start'>\n {activeChatView === 'threads' && HeaderStartContent && <HeaderStartContent />}\n </div>\n <div className='str-chat__thread-header-details'>\n <div className='str-chat__thread-header-title'>{t('Thread')}</div>\n <ThreadHeaderSubtitle\n replyCount={replyCount}\n threadDisplayName={threadDisplayName}\n threadList\n />\n </div>\n {!threadInstance && (\n <div className='str-chat__thread-header__end'>\n <Button\n appearance='ghost'\n aria-label={t('aria/Close thread')}\n circular\n className='str-chat__close-thread-button'\n data-testid='close-thread-button'\n onClick={closeThread}\n size='md'\n variant='secondary'\n >\n <IconXmark />\n </Button>\n </div>\n )}\n </div>\n );\n};\n","import React from 'react';\n\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useThreadContext } from '../Threads';\nimport { useStateStore } from '../../store';\nimport type { ThreadState } from 'stream-chat';\n\nconst threadStateSelector = ({ replyCount }: ThreadState) => ({\n replyCount,\n});\n\nexport const ThreadStart = () => {\n const { thread } = useChannelStateContext('ThreadStart');\n const { t } = useTranslationContext('ThreadStart');\n const threadInstance = useThreadContext();\n const { replyCount: replyCountThreadInstance } =\n useStateStore(threadInstance?.state, threadStateSelector) ?? {};\n\n const replyCount = threadInstance\n ? replyCountThreadInstance\n : thread\n ? (thread.reply_count ?? 0)\n : 0;\n\n if (!replyCount) return null;\n\n return (\n <div className='str-chat__thread-start'>{t('replyCount', { count: replyCount })}</div>\n );\n};\n","import clsx from 'clsx';\nimport React from 'react';\n\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { getDateString } from '../../i18n/utils';\n\nimport type { TimestampFormatterOptions } from '../../i18n/types';\n\nexport type DateSeparatorProps = TimestampFormatterOptions & {\n /** Optional className for the root element */\n className?: string;\n /** The date to format */\n date: Date;\n /** When true, applies floating positioning (fixed at top when scrolling) */\n floating?: boolean;\n /** Override the default formatting of the date. This is a function that has access to the original date object. */\n formatDate?: (date: Date) => string;\n // todo: position and unread are not necessary anymore\n /** Set the position of the date in the separator, options are 'left', 'center', 'right', @default right */\n position?: 'left' | 'center' | 'right';\n /** If following messages are not new */\n unread?: boolean;\n};\n\nconst UnMemoizedDateSeparator = (props: DateSeparatorProps) => {\n const {\n calendar,\n className,\n date: messageCreatedAt,\n floating,\n formatDate,\n ...restTimestampFormatterOptions\n } = props;\n\n const { t, tDateTimeParser } = useTranslationContext('DateSeparator');\n\n const formattedDate = getDateString({\n calendar,\n ...restTimestampFormatterOptions,\n formatDate,\n messageCreatedAt,\n t,\n tDateTimeParser,\n timestampTranslationKey: 'timestamp/DateSeparator',\n });\n\n return (\n <div\n className={clsx(\n 'str-chat__date-separator',\n { 'str-chat__date-separator--floating': floating },\n className,\n )}\n data-date={messageCreatedAt.toISOString()}\n data-testid={floating ? 'floating-date-separator' : 'date-separator'}\n >\n <div className='str-chat__date-separator-date'>{formattedDate}</div>\n </div>\n );\n};\n\n/**\n * A simple date separator between messages.\n */\nexport const DateSeparator = React.memo(\n UnMemoizedDateSeparator,\n) as typeof UnMemoizedDateSeparator;\n","import React from 'react';\n\nimport type { MessageProps } from '../Message';\nimport { Message } from '../Message';\nimport { ThreadStart as DefaultThreadStart } from './ThreadStart';\n\nimport { useComponentContext } from '../../context';\nimport { DateSeparator } from '../DateSeparator';\n\nexport const ThreadHead = (props: MessageProps) => {\n const { ThreadStart = DefaultThreadStart } = useComponentContext('ThreadHead');\n return (\n <div className='str-chat__parent-message-li'>\n <DateSeparator date={props.message.created_at} />\n <Message initialMessage threadList {...props} />\n <ThreadStart />\n </div>\n );\n};\n","import React, { useEffect } from 'react';\nimport clsx from 'clsx';\n\nimport { LegacyThreadContext } from './LegacyThreadContext';\nimport { MESSAGE_ACTIONS } from '../Message';\nimport type { MessageComposerProps } from '../MessageComposer';\nimport { MessageComposer } from '../MessageComposer';\nimport type { MessageListProps, VirtualizedMessageListProps } from '../MessageList';\nimport { MessageList, VirtualizedMessageList } from '../MessageList';\nimport { ThreadHeader as DefaultThreadHeader } from './ThreadHeader';\nimport { ThreadHead as DefaultThreadHead } from '../Thread/ThreadHead';\n\nimport {\n useChannelActionContext,\n useChannelStateContext,\n useChatContext,\n useComponentContext,\n} from '../../context';\nimport { useThreadContext } from '../Threads';\nimport { useStateStore } from '../../store';\n\nimport type { MessageProps, MessageUIComponentProps } from '../Message/types';\nimport type { MessageActionsArray } from '../Message/utils';\nimport type { ThreadState } from 'stream-chat';\n\nexport type ThreadProps = {\n /** Additional props for `MessageComposer` component: [available props](https://getstream.io/chat/docs/sdk/react/message-composer-components/message_composer/#props) */\n additionalMessageComposerProps?: MessageComposerProps;\n /** Additional props for `MessageList` component: [available props](https://getstream.io/chat/docs/sdk/react/core-components/message_list/#props) */\n additionalMessageListProps?: MessageListProps;\n /** Additional props for `Message` component of the parent message: [available props](https://getstream.io/chat/docs/sdk/react/message-components/message/#props) */\n additionalParentMessageProps?: Partial<MessageProps>;\n /** Additional props for `VirtualizedMessageList` component: [available props](https://getstream.io/chat/docs/sdk/react/core-components/virtualized_list/#props) */\n additionalVirtualizedMessageListProps?: VirtualizedMessageListProps;\n /** If true, focuses the `MessageComposer` component on opening a thread */\n autoFocus?: boolean;\n /** Injects date separator components into `Thread`, defaults to `false`. To be passed to the underlying `MessageList` or `VirtualizedMessageList` components */\n enableDateSeparator?: boolean;\n /** Custom thread message UI component used to override the default `Message` value stored in `ComponentContext` */\n Message?: React.ComponentType<MessageUIComponentProps>;\n /** Array of allowed message actions (ex: ['edit', 'delete', 'flag', 'mute', 'pin', 'quote', 'react', 'reply']). To disable all actions, provide an empty array. */\n messageActions?: MessageActionsArray;\n /** If true, render the `VirtualizedMessageList` instead of the standard `MessageList` component */\n virtualized?: boolean;\n};\n\n/**\n * The Thread component renders a parent Message with a list of replies\n */\nexport const Thread = (props: ThreadProps) => {\n const { channel, channelConfig, thread } = useChannelStateContext('Thread');\n const threadInstance = useThreadContext();\n\n if (!thread && !threadInstance) return null;\n if (channelConfig?.replies === false) return null;\n\n // the wrapper ensures a key variable is set and the component recreates on thread switch\n return (\n // FIXME: TS is having trouble here as at least one of the two would always be defined\n <ThreadInner\n {...props}\n key={`thread-${(thread ?? threadInstance)?.id}-${channel?.cid}`}\n />\n );\n};\n\nconst selector = (nextValue: ThreadState) => ({\n isLoadingNext: nextValue.pagination.isLoadingNext,\n isLoadingPrev: nextValue.pagination.isLoadingPrev,\n parentMessage: nextValue.parentMessage,\n replies: nextValue.replies,\n});\n\nconst ThreadInner = (props: ThreadProps & { key: string }) => {\n const {\n additionalMessageComposerProps,\n additionalMessageListProps,\n additionalParentMessageProps,\n additionalVirtualizedMessageListProps,\n autoFocus = true,\n enableDateSeparator = false,\n Message: PropMessage,\n messageActions = Object.keys(MESSAGE_ACTIONS),\n virtualized,\n } = props;\n const threadInstance = useThreadContext();\n\n const {\n thread,\n threadHasMore,\n threadLoadingMore,\n threadMessages = [],\n threadSuppressAutoscroll,\n } = useChannelStateContext('Thread');\n const { closeThread, loadMoreThread } = useChannelActionContext('Thread');\n const { customClasses } = useChatContext('Thread');\n const {\n Message: ContextMessage,\n ThreadHead = DefaultThreadHead,\n ThreadHeader = DefaultThreadHeader,\n VirtualMessage,\n } = useComponentContext('Thread');\n\n const { isLoadingNext, isLoadingPrev, parentMessage, replies } =\n useStateStore(threadInstance?.state, selector) ?? {};\n\n const ThreadMessage = PropMessage || additionalMessageListProps?.Message;\n const FallbackMessage = virtualized && VirtualMessage ? VirtualMessage : ContextMessage;\n const MessageUIComponent = ThreadMessage || FallbackMessage;\n\n const ThreadMessageList = virtualized ? VirtualizedMessageList : MessageList;\n\n useEffect(() => {\n if (threadInstance) return;\n\n if ((thread?.reply_count ?? 0) > 0) {\n // FIXME: integrators can customize channel query options but cannot customize channel.getReplies() options\n loadMoreThread();\n }\n }, [thread, loadMoreThread, threadInstance]);\n\n const threadProps: Pick<\n VirtualizedMessageListProps,\n | 'hasMoreNewer'\n | 'loadMoreNewer'\n | 'loadingMoreNewer'\n | 'hasMore'\n | 'loadMore'\n | 'loadingMore'\n | 'messages'\n > = threadInstance\n ? {\n loadingMore: isLoadingPrev,\n loadingMoreNewer: isLoadingNext,\n loadMore: threadInstance.loadPrevPage,\n loadMoreNewer: threadInstance.loadNextPage,\n messages: replies,\n }\n : {\n hasMore: threadHasMore,\n loadingMore: threadLoadingMore,\n loadMore: loadMoreThread,\n messages: threadMessages,\n };\n\n const messageAsThread = thread ?? parentMessage;\n\n if (!messageAsThread) return null;\n\n const threadClass =\n customClasses?.thread ||\n clsx('str-chat__thread-container str-chat__thread', {\n 'str-chat__thread--virtualized': virtualized,\n });\n\n const head = (\n <ThreadHead\n key={messageAsThread.id}\n message={messageAsThread}\n Message={MessageUIComponent}\n {...additionalParentMessageProps}\n />\n );\n\n return (\n // Thread component needs a context which we can use for message composer\n <LegacyThreadContext.Provider\n value={{\n legacyThread: thread ?? undefined,\n }}\n >\n <div className={threadClass}>\n <ThreadHeader closeThread={closeThread} thread={messageAsThread} />\n <ThreadMessageList\n disableDateSeparator={!enableDateSeparator}\n head={head}\n Message={MessageUIComponent}\n messageActions={messageActions}\n suppressAutoscroll={threadSuppressAutoscroll}\n threadList\n {...threadProps}\n {...(virtualized\n ? additionalVirtualizedMessageListProps\n : additionalMessageListProps)}\n />\n <MessageComposer\n focus={autoFocus}\n parent={thread ?? parentMessage}\n {...additionalMessageComposerProps}\n />\n </div>\n </LegacyThreadContext.Provider>\n );\n};\n","import React, { type ReactNode, useMemo, useState } from 'react';\nimport clsx from 'clsx';\n\nimport { useDialogOnNearestManager } from '../Dialog';\nimport { defaultReactionOptions, getHasExtendedReactions } from './reactionOptions';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useMessageContext } from '../../context/MessageContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { Button } from '../Button';\n\nimport type { ReactionResponse } from 'stream-chat';\n\nimport { useComponentContextIcons } from '../../context';\nexport type ReactionSelectorProps = {\n /** Override dialog id used by the selector popover. */\n dialogId?: string;\n /** Function that adds/removes a reaction on a message (overrides the function stored in `MessageContext`) */\n handleReaction?: (\n reactionType: string,\n event: React.BaseSyntheticEvent,\n ) => Promise<void>;\n /** An array of the own reaction objects to distinguish own reactions visually */\n own_reactions?: ReactionResponse[];\n};\n\ninterface ReactionSelectorInterface {\n (props: ReactionSelectorProps): ReactNode;\n getDialogId: (_: { messageId: string; threadList?: boolean }) => string;\n displayName: string;\n ExtendedList: React.ComponentType<ReactionSelectorProps & { dialogId?: string }>;\n}\n\nconst stableOwnReactions: ReactionResponse[] = [];\n\nexport const ReactionSelector: ReactionSelectorInterface = (props) => {\n const {\n dialogId: propDialogId,\n handleReaction: propHandleReaction,\n own_reactions: propOwnReactions,\n } = props;\n const [extendedListOpen, setExtendedListOpen] = useState(false);\n\n const {\n reactionOptions = defaultReactionOptions,\n ReactionSelectorExtendedList = ReactionSelector.ExtendedList,\n } = useComponentContext('ReactionSelector');\n const { IconPlus } = useComponentContextIcons();\n\n const {\n closeReactionSelectorOnClick,\n handleReaction: contextHandleReaction,\n message,\n threadList,\n } = useMessageContext('ReactionSelector');\n const { t } = useTranslationContext('ReactionSelector');\n const dialogId =\n propDialogId ??\n ReactionSelector.getDialogId({\n messageId: message.id,\n threadList,\n });\n const { dialog } = useDialogOnNearestManager({ id: dialogId });\n\n const handleReaction = propHandleReaction ?? contextHandleReaction;\n const ownReactions = propOwnReactions ?? message?.own_reactions ?? stableOwnReactions;\n\n const ownReactionByType = useMemo(() => {\n const map: { [key: string]: ReactionResponse } = {};\n\n for (const reaction of ownReactions) {\n map[reaction.type] ??= reaction;\n }\n\n return map;\n }, [ownReactions]);\n\n const adjustedQuickReactionOptions = useMemo(() => {\n if (Array.isArray(reactionOptions)) return reactionOptions;\n\n return Object.entries(reactionOptions.quick).map(\n ([type, { Component, name, unicode }]) => ({\n Component,\n name,\n type,\n unicode,\n }),\n );\n }, [reactionOptions]);\n\n const hasExtendedReactions = getHasExtendedReactions(reactionOptions);\n\n return (\n <div\n aria-label={t('aria/Reaction list')}\n className='str-chat__reaction-selector'\n data-testid='reaction-selector'\n role='group'\n >\n {!extendedListOpen ? (\n <>\n <ul\n className='str-chat__reaction-selector-list'\n data-testid='reaction-selector-list'\n >\n {adjustedQuickReactionOptions.map(\n ({ Component, name: reactionName, type: reactionType }) => (\n <li className='str-chat__reaction-list-selector__item' key={reactionType}>\n <button\n aria-label={t('aria/Select Reaction: {{ reactionName }}', {\n reactionName: reactionName || reactionType,\n })}\n aria-pressed={typeof ownReactionByType[reactionType] !== 'undefined'}\n className={clsx('str-chat__reaction-selector-list__item-button')}\n data-testid='select-reaction-button'\n data-text={reactionType}\n onClick={(event) => {\n handleReaction(reactionType, event);\n if (closeReactionSelectorOnClick) {\n dialog.close();\n }\n }}\n type='button'\n >\n <span className='str-chat__reaction-icon'>\n <Component />\n </span>\n </button>\n </li>\n ),\n )}\n </ul>\n {hasExtendedReactions && (\n <Button\n appearance='outline'\n aria-label={t('aria/Open Reaction Selector')}\n circular\n className='str-chat__reaction-selector__add-button'\n data-testid='reaction-selector-add-button'\n onClick={() => {\n setExtendedListOpen(true);\n }}\n size='sm'\n variant='secondary'\n >\n <IconPlus />\n </Button>\n )}\n </>\n ) : (\n <ReactionSelectorExtendedList\n {...props}\n dialogId={dialogId}\n handleReaction={async (reactionType, event) => {\n await handleReaction(reactionType, event);\n if (closeReactionSelectorOnClick) {\n dialog.close();\n }\n }}\n />\n )}\n </div>\n );\n};\n\nReactionSelector.getDialogId = ({ messageId, threadList }) => {\n const dialogIdNamespace = threadList ? '-thread' : '';\n return `reaction-selector${dialogIdNamespace}-${messageId}`;\n};\n\nReactionSelector.displayName = 'ReactionSelector';\n\nReactionSelector.ExtendedList = function ReactionSelectorExtendedList({\n dialogId,\n handleReaction: propHandleReaction,\n own_reactions: propOwnReactions,\n}) {\n const { reactionOptions = defaultReactionOptions } = useComponentContext(\n 'ReactionSelector.ExtendedList',\n );\n const {\n closeReactionSelectorOnClick,\n handleReaction: contextHandleReaction,\n message,\n } = useMessageContext('ReactionSelector');\n const { t } = useTranslationContext('ReactionSelector');\n\n const handleReaction = propHandleReaction ?? contextHandleReaction;\n const ownReactions = propOwnReactions ?? message?.own_reactions ?? stableOwnReactions;\n\n const { dialog } = useDialogOnNearestManager({ id: dialogId || '' });\n\n const ownReactionByType = useMemo(() => {\n const map: { [key: string]: ReactionResponse } = {};\n\n for (const reaction of ownReactions) {\n map[reaction.type] ??= reaction;\n }\n\n return map;\n }, [ownReactions]);\n\n if (Array.isArray(reactionOptions) || !reactionOptions.extended) {\n return null;\n }\n\n return (\n <div\n aria-label={t('aria/Reaction list')}\n className='str-chat__reaction-selector-extended-list'\n data-testid='reaction-selector-extended-list'\n role='group'\n >\n {Object.entries(reactionOptions.extended).map(\n ([reactionType, { Component, name: reactionName }]) => (\n <button\n aria-label={t('aria/Select Reaction: {{ reactionName }}', {\n reactionName: reactionName || reactionType,\n })}\n aria-pressed={typeof ownReactionByType[reactionType] !== 'undefined'}\n className='str-chat__reaction-selector-extended-list__button str-chat__button str-chat__button--ghost str-chat__button--size-sm str-chat__button--circular'\n data-testid='select-reaction-button'\n data-text={reactionType}\n key={reactionType}\n onClick={(event) => {\n handleReaction(reactionType, event);\n if (closeReactionSelectorOnClick) {\n dialog.close();\n }\n }}\n type='button'\n >\n <span className='str-chat__reaction-icon'>\n <Component />\n </span>\n </button>\n ),\n )}\n </div>\n );\n};\n","import { useCallback, useEffect, useState } from 'react';\nimport type { ReactionResponse, ReactionSort } from 'stream-chat';\nimport type { MessageContextValue } from '../../../context';\nimport { useMessageContext, useTranslationContext } from '../../../context';\nimport { useNotificationApi } from '../../Notifications';\n\nimport type { ReactionType } from '../types';\n\nexport interface FetchReactionsOptions {\n reactionType: ReactionType | null;\n shouldFetch: boolean;\n handleFetchReactions?: MessageContextValue['handleFetchReactions'];\n sort?: ReactionSort;\n}\n\nexport function useFetchReactions(options: FetchReactionsOptions) {\n const { addNotification } = useNotificationApi();\n const { handleFetchReactions: contextHandleFetchReactions } =\n useMessageContext('useFetchReactions');\n const { t } = useTranslationContext('useFetchReactions');\n const [reactions, setReactions] = useState<ReactionResponse[]>([]);\n const {\n handleFetchReactions: propHandleFetchReactions,\n reactionType,\n shouldFetch,\n sort,\n } = options;\n const [isLoading, setIsLoading] = useState(shouldFetch);\n const handleFetchReactions = propHandleFetchReactions ?? contextHandleFetchReactions;\n const [refetchNonce, setRefetchNonce] = useState<number | null>(null);\n\n useEffect(() => {\n if (!shouldFetch) {\n return;\n }\n\n let cancel = false;\n\n (async () => {\n try {\n setIsLoading(true);\n const reactions = await handleFetchReactions(reactionType ?? undefined, sort);\n\n if (!cancel) {\n setReactions(reactions);\n }\n } catch (e) {\n if (!cancel) {\n setReactions([]);\n addNotification({\n emitter: 'Reactions',\n error: e instanceof Error ? e : undefined,\n message: t('Error fetching reactions'),\n severity: 'error',\n type: 'api:message:reactions:fetch:failed',\n });\n }\n } finally {\n if (!cancel) {\n setIsLoading(false);\n }\n }\n })();\n\n return () => {\n cancel = true;\n };\n }, [\n addNotification,\n handleFetchReactions,\n reactionType,\n refetchNonce,\n shouldFetch,\n sort,\n t,\n ]);\n\n const refetch = useCallback(() => {\n setRefetchNonce(Math.random());\n }, []);\n\n return { isLoading, reactions, refetch };\n}\n","import React, { useMemo, useState } from 'react';\n\nimport type { ReactionSummary, ReactionType } from './types';\n\nimport { useFetchReactions } from './hooks/useFetchReactions';\nimport { Avatar as DefaultAvatar } from '../Avatar';\nimport { extractDisplayInfo as defaultExtractDisplayInfo } from '../Avatar/utils';\nimport type { MessageContextValue } from '../../context';\nimport {\n useChatContext,\n useComponentContext,\n useComponentContextIcons,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\nimport type { ReactionSort } from 'stream-chat';\nimport { defaultReactionOptions, getHasExtendedReactions } from './reactionOptions';\nimport type { useProcessReactions } from './hooks/useProcessReactions';\nimport { ReactionSelector, type ReactionSelectorProps } from './ReactionSelector';\n\nexport type MessageReactionsDetailProps = Partial<\n Pick<MessageContextValue, 'handleFetchReactions' | 'reactionDetailsSort'>\n> & {\n reactions: ReactionSummary[];\n selectedReactionType: ReactionType | null;\n onSelectedReactionTypeChange?: (reactionType: ReactionType | null) => void;\n sort?: ReactionSort;\n totalReactionCount?: number;\n reactionGroups?: ReturnType<typeof useProcessReactions>['reactionGroups'];\n} & ReactionSelectorProps;\n\nconst defaultReactionDetailsSort = { created_at: -1 } as const;\n\nexport const MessageReactionsDetailLoadingIndicator = () => {\n const elements = useMemo(\n () =>\n Array.from({ length: 3 }, (_, index) => (\n <div className='str-chat__message-reactions-detail__skeleton-item' key={index}>\n <div className='str-chat__message-reactions-detail__skeleton-avatar' />\n <div className='str-chat__message-reactions-detail__skeleton-line' />\n </div>\n )),\n [],\n );\n\n return <>{elements}</>;\n};\n\ninterface MessageReactionsDetailInterface {\n (props: MessageReactionsDetailProps): React.ReactNode;\n displayName: string;\n getDialogId: (_: { messageId: string }) => string;\n}\n\nexport const MessageReactionsDetail: MessageReactionsDetailInterface = ({\n handleFetchReactions,\n handleReaction,\n onSelectedReactionTypeChange,\n own_reactions,\n reactionDetailsSort: propReactionDetailsSort,\n reactionGroups,\n reactions,\n selectedReactionType,\n totalReactionCount,\n}) => {\n const [extendedReactionListOpen, setExtendedReactionListOpen] = useState(false);\n const { client } = useChatContext();\n const {\n Avatar = DefaultAvatar,\n extractDisplayInfo = defaultExtractDisplayInfo,\n LoadingIndicator = MessageReactionsDetailLoadingIndicator,\n reactionOptions = defaultReactionOptions,\n ReactionSelectorExtendedList = ReactionSelector.ExtendedList,\n } = useComponentContext(MessageReactionsDetail.name);\n const { IconEmojiAdd } = useComponentContextIcons();\n const { t } = useTranslationContext();\n\n const {\n handleReaction: contextHandleReaction,\n message,\n reactionDetailsSort: contextReactionDetailsSort,\n } = useMessageContext(MessageReactionsDetail.name);\n\n const reactionDetailsSort =\n propReactionDetailsSort ?? contextReactionDetailsSort ?? defaultReactionDetailsSort;\n\n const hasExtendedReactions = getHasExtendedReactions(reactionOptions);\n\n const {\n isLoading: areReactionsLoading,\n reactions: reactionDetails,\n refetch,\n } = useFetchReactions({\n handleFetchReactions,\n reactionType: selectedReactionType,\n shouldFetch: true,\n sort: reactionDetailsSort,\n });\n\n const getReactionName = (reactionType: string) => {\n if (Array.isArray(reactionOptions)) {\n return (\n reactionOptions.find((reactionOption) => reactionOption.type === reactionType)\n ?.name ?? reactionType\n );\n }\n\n return (\n reactionOptions.quick[reactionType]?.name ??\n reactionOptions.extended?.[reactionType]?.name ??\n reactionType\n );\n };\n\n if (extendedReactionListOpen) {\n return (\n <div\n className='str-chat__message-reactions-detail'\n data-testid='message-reactions-detail'\n >\n <ReactionSelectorExtendedList\n dialogId={MessageReactionsDetail.getDialogId({ messageId: message.id })}\n handleReaction={handleReaction}\n own_reactions={own_reactions}\n />\n </div>\n );\n }\n\n return (\n <div\n className='str-chat__message-reactions-detail'\n data-testid='message-reactions-detail'\n >\n {typeof totalReactionCount === 'number' && (\n <div className='str-chat__message-reactions-detail__total-count'>\n {t('{{ count }} reactions', { count: totalReactionCount })}\n </div>\n )}\n <div className='str-chat__message-reactions-detail__reaction-type-list-container'>\n <ul\n className='str-chat__message-reactions-detail__reaction-type-list'\n data-testid='reaction-type-list'\n >\n {hasExtendedReactions && (\n <li className='str-chat__message-reactions-detail__reaction-type-list-item'>\n <button\n aria-label={t('Add reaction')}\n className='str-chat__message-reactions-detail__reaction-type-list-item-button'\n data-testid='add-reaction-button'\n onClick={() => setExtendedReactionListOpen(true)}\n type='button'\n >\n <span className='str-chat__message-reactions-detail__reaction-type-list-item-icon'>\n <IconEmojiAdd />\n </span>\n </button>\n </li>\n )}\n\n {reactions.map(\n ({ EmojiComponent, reactionCount, reactionType }) =>\n EmojiComponent && (\n <li\n className='str-chat__message-reactions-detail__reaction-type-list-item'\n key={reactionType}\n >\n <button\n aria-label={t('aria/Select Reaction: {{ reactionName }}', {\n reactionName: reactionType,\n })}\n aria-pressed={reactionType === selectedReactionType}\n className='str-chat__message-reactions-detail__reaction-type-list-item-button'\n onClick={() =>\n onSelectedReactionTypeChange?.(\n selectedReactionType === reactionType ? null : reactionType,\n )\n }\n type='button'\n >\n <span className='str-chat__message-reactions-detail__reaction-type-list-item-icon'>\n <EmojiComponent />\n </span>\n <span\n className='str-chat__message-reactions-detail__reaction-type-list-item-count'\n data-testid='reaction-type-count'\n >\n {reactionCount}\n </span>\n </button>\n </li>\n ),\n )}\n </ul>\n </div>\n <div className='str-chat__message-reactions-detail__user-list-container'>\n <div\n className='str-chat__message-reactions-detail__user-list'\n data-testid='all-reacting-users'\n >\n {areReactionsLoading && <LoadingIndicator />}\n {!areReactionsLoading && (\n <>\n {reactionDetails.map(({ type, user }) => {\n const belongsToCurrentUser = client.user?.id === user?.id;\n const reactionName = getReactionName(type);\n const EmojiComponent = Array.isArray(reactionOptions)\n ? undefined\n : (reactionOptions.quick[type]?.Component ??\n reactionOptions.extended?.[type]?.Component);\n\n return (\n <div\n className='str-chat__message-reactions-detail__user-list-item'\n key={`${user?.id}-${type}`}\n >\n <Avatar\n {...extractDisplayInfo({ user: user ?? undefined })}\n className='str-chat__avatar--with-border'\n data-testid='avatar'\n size='md'\n />\n <div className='str-chat__message-reactions-detail__user-list-item-info'>\n <span\n className='str-chat__message-reactions-detail__user-list-item-username'\n data-testid='reaction-user-username'\n >\n {belongsToCurrentUser ? t('You') : user?.name || user?.id}\n </span>\n {belongsToCurrentUser && (\n <button\n aria-label={t('Tap to remove: {{ reactionName }}', {\n reactionName,\n })}\n className='str-chat__message-reactions-detail__user-list-item-button'\n data-testid='remove-reaction-button'\n onClick={async (e) => {\n const reactionCountBeforeRemoval =\n reactionGroups?.[type]?.count ?? 0;\n\n await contextHandleReaction(type, e);\n\n // was 1, should be 0 after removal, display all reactions\n if (\n selectedReactionType !== null &&\n reactionCountBeforeRemoval <= 1\n ) {\n onSelectedReactionTypeChange?.(null);\n } else {\n refetch();\n }\n }}\n type='button'\n >\n {t('Tap to remove')}\n </button>\n )}\n </div>\n <span className='str-chat__message-reactions-detail__user-list-item-icon'>\n {!selectedReactionType && EmojiComponent && <EmojiComponent />}\n </span>\n </div>\n );\n })}\n </>\n )}\n </div>\n </div>\n </div>\n );\n};\n\nMessageReactionsDetail.displayName = 'MessageReactionsDetail';\n\nMessageReactionsDetail.getDialogId = ({ messageId }) =>\n `message-reactions-detail-${messageId}`;\n","import { useCallback, useMemo } from 'react';\n\nimport { useComponentContext, useMessageContext } from '../../../context';\nimport { defaultReactionOptions } from '../reactionOptions';\n\nimport type { MessageReactionsProps } from '../MessageReactions';\nimport type { ReactionsComparator, ReactionSummary } from '../types';\n\nexport type UseProcessReactionsParams = Pick<\n MessageReactionsProps,\n 'own_reactions' | 'reaction_groups' | 'reactions'\n> & {\n sortReactions?: ReactionsComparator;\n};\n\nexport const defaultReactionsSort: ReactionsComparator = (a, b) => {\n if (a.firstReactionAt && b.firstReactionAt) {\n return +a.firstReactionAt - +b.firstReactionAt;\n }\n\n return a.reactionType.localeCompare(b.reactionType, 'en');\n};\n\nexport const useProcessReactions = (params: UseProcessReactionsParams) => {\n const {\n own_reactions: propOwnReactions,\n reaction_groups: propReactionGroups,\n reactions: propReactions,\n sortReactions: propSortReactions,\n } = params;\n const { message, sortReactions: contextSortReactions } =\n useMessageContext('useProcessReactions');\n const { reactionOptions = defaultReactionOptions } =\n useComponentContext('useProcessReactions');\n\n const sortReactions = propSortReactions ?? contextSortReactions ?? defaultReactionsSort;\n const latestReactions = propReactions ?? message.latest_reactions;\n const ownReactions = propOwnReactions ?? message?.own_reactions;\n const reactionGroups = propReactionGroups ?? message?.reaction_groups ?? undefined;\n\n const isOwnReaction = useCallback(\n (reactionType: string) =>\n ownReactions?.some((reaction) => reaction.type === reactionType) ?? false,\n [ownReactions],\n );\n\n const getEmojiByReactionType = useCallback(\n (reactionType: string) => {\n if (Array.isArray(reactionOptions)) {\n return (\n reactionOptions.find(({ type }) => type === reactionType)?.Component ?? null\n );\n }\n\n return (\n reactionOptions.quick[reactionType]?.Component ??\n reactionOptions.extended?.[reactionType]?.Component ??\n null\n );\n },\n [reactionOptions],\n );\n\n const isSupportedReaction = useCallback(\n (reactionType: string) => {\n if (Array.isArray(reactionOptions)) {\n return reactionOptions.some(\n (reactionOption) => reactionOption.type === reactionType,\n );\n }\n\n return (\n typeof reactionOptions.quick[reactionType] !== 'undefined' ||\n typeof reactionOptions.extended?.[reactionType] !== 'undefined'\n );\n },\n [reactionOptions],\n );\n\n /**\n * Amount of unique reaction types (\"haha\", \"like\", etc.) on a message.\n */\n const uniqueReactionTypeCount = useMemo(() => {\n if (!reactionGroups) {\n return 0;\n }\n\n return Object.keys(reactionGroups).filter((reactionType) =>\n isSupportedReaction(reactionType),\n ).length;\n }, [isSupportedReaction, reactionGroups]);\n\n // Group the reacting user names by reaction type in a single pass, so each\n // reaction group can look its names up in O(1) instead of re-scanning the\n // whole `latestReactions` array per type (previously O(types × reactions)).\n const latestReactedUserNamesByType = useMemo(() => {\n const namesByType = new Map<string, string[]>();\n if (!latestReactions) return namesByType;\n\n for (const reaction of latestReactions) {\n if (!reaction.type) continue;\n const username = reaction.user?.name || reaction.user?.id;\n if (!username) continue;\n\n const existing = namesByType.get(reaction.type);\n if (existing) {\n existing.push(username);\n } else {\n namesByType.set(reaction.type, [username]);\n }\n }\n\n return namesByType;\n }, [latestReactions]);\n\n const existingReactions: ReactionSummary[] = useMemo(() => {\n if (!reactionGroups) {\n return [];\n }\n\n const unsortedReactions = Object.entries(reactionGroups).flatMap(\n ([reactionType, { count, first_reaction_at, last_reaction_at }]) => {\n if (count === 0 || !isSupportedReaction(reactionType)) {\n return [];\n }\n\n const latestReactedUserNames =\n latestReactedUserNamesByType.get(reactionType) ?? [];\n\n return [\n {\n EmojiComponent: getEmojiByReactionType(reactionType),\n firstReactionAt: first_reaction_at ? new Date(first_reaction_at) : null,\n isOwnReaction: isOwnReaction(reactionType),\n lastReactionAt: last_reaction_at ? new Date(last_reaction_at) : null,\n latestReactedUserNames,\n reactionCount: count,\n reactionType,\n unlistedReactedUserCount: count - latestReactedUserNames.length,\n },\n ];\n },\n );\n\n return unsortedReactions.sort(sortReactions);\n }, [\n getEmojiByReactionType,\n latestReactedUserNamesByType,\n isOwnReaction,\n isSupportedReaction,\n reactionGroups,\n sortReactions,\n ]);\n\n const hasReactions = existingReactions.length > 0;\n\n const totalReactionCount = useMemo(\n () =>\n Object.values(reactionGroups ?? {}).reduce((total, { count }) => total + count, 0),\n\n [reactionGroups],\n );\n\n return {\n existingReactions,\n hasReactions,\n reactionGroups,\n totalReactionCount,\n uniqueReactionTypeCount,\n } as const;\n};\n","import React, {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport clsx from 'clsx';\n\nimport { MessageReactionsDetail as DefaultMessageReactionsDetail } from './MessageReactionsDetail';\nimport { useProcessReactions } from './hooks/useProcessReactions';\nimport type { MessageContextValue } from '../../context';\nimport {\n useComponentContext,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\n\nimport { MAX_MESSAGE_REACTIONS_TO_FETCH } from '../Message/hooks';\n\nimport type { ReactionGroupResponse, ReactionResponse } from 'stream-chat';\nimport type { ReactionsComparator, ReactionType } from './types';\nimport { DialogAnchor, useDialogIsOpen, useDialogOnNearestManager } from '../Dialog';\n\nexport type MessageReactionsProps = Partial<\n Pick<MessageContextValue, 'handleFetchReactions' | 'reactionDetailsSort'>\n> & {\n /** An array of the own reaction objects to distinguish own reactions visually */\n own_reactions?: ReactionResponse[];\n /** An object containing summary for each reaction type on a message */\n reaction_groups?: Record<string, ReactionGroupResponse>;\n /** An array of the reaction objects to display in the list */\n reactions?: ReactionResponse[];\n /** Display the reactions in the list in reverse order, defaults to false */\n reverse?: boolean;\n /** Comparator function to sort reactions, defaults to chronological order */\n sortReactions?: ReactionsComparator;\n /**\n * Positioning of the reactions list relative to the message. Position is flipped by default for the messages of other users.\n */\n flipHorizontalPosition?: boolean;\n verticalPosition?: 'top' | 'bottom' | null;\n visualStyle?: 'clustered' | 'segmented' | null;\n capLimit?: {\n [key in Extract<MessageReactionsProps['visualStyle'], string>]?: number;\n };\n};\n\n/**\n * Renders a button if `buttonIf` is true, otherwise renders a fragment. No props but children are passed to fragment, but all props are passed to button if it's rendered.\n */\nconst FragmentOrButton = ({\n buttonIf: renderButton = false,\n children,\n type = 'button',\n ...props\n}: ComponentPropsWithoutRef<'button'> & { buttonIf?: boolean }) => {\n if (renderButton) {\n return (\n <button {...props} type={type}>\n {children}\n </button>\n );\n }\n\n return <>{children}</>;\n};\n\nconst UnMemoizedMessageReactions = (props: MessageReactionsProps) => {\n const {\n capLimit: { clustered: capLimitClustered = 5, segmented: capLimitSegmented = 4 } = {},\n flipHorizontalPosition = false,\n handleFetchReactions,\n reactionDetailsSort,\n verticalPosition = 'top',\n visualStyle = 'clustered',\n ...rest\n } = props;\n\n const {\n existingReactions,\n hasReactions,\n reactionGroups,\n totalReactionCount,\n uniqueReactionTypeCount,\n } = useProcessReactions(rest);\n const [selectedReactionType, setSelectedReactionType] = useState<ReactionType | null>(\n null,\n );\n const { t } = useTranslationContext('MessageReactions');\n const { MessageReactionsDetail = DefaultMessageReactionsDetail } =\n useComponentContext();\n const { isMyMessage, message } = useMessageContext('MessageReactions');\n\n const divRef = useRef<ComponentRef<'div'>>(null);\n const dialogId = DefaultMessageReactionsDetail.getDialogId({\n messageId: message.id,\n });\n const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });\n const isDialogOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n const handleReactionButtonClick = (reactionType: ReactionType | null) => {\n if (totalReactionCount > MAX_MESSAGE_REACTIONS_TO_FETCH) {\n return;\n }\n\n setSelectedReactionType(reactionType);\n\n dialog.open();\n };\n\n /**\n * In segmented style with top position we show max 4 reactions and a\n * count of the rest, so we need to cap the existing reactions to display\n * at 4 and calculate the count of the rest. For clustered(top/bottom) we cap\n * the existing reactions to 5 but we don't calculate the count of the rest\n * because we show the total count instead. For segmented style with bottom\n * position we don't cap the existing reactions and we show all of them.\n */\n const cappedExistingReactions = useMemo(() => {\n if (visualStyle === 'segmented' && verticalPosition !== 'top') return null;\n\n const capLimit = visualStyle === 'segmented' ? capLimitSegmented : capLimitClustered;\n\n const sliced = existingReactions.slice(0, capLimit);\n\n return {\n /**\n * Accumulated reaction count of capped reaction types, first four in case of\n * segmented(top) and first five in case of clustered(top/bottom) variations.\n */\n reactionCountToDisplay: sliced.reduce(\n (accumulatedCount, { reactionCount }) => accumulatedCount + reactionCount,\n 0,\n ),\n reactionsToDisplay: sliced,\n } as const;\n }, [\n capLimitClustered,\n capLimitSegmented,\n existingReactions,\n verticalPosition,\n visualStyle,\n ]);\n\n if (!hasReactions) return null;\n\n return (\n <>\n <div\n aria-label={t('aria/Reaction list')}\n className={clsx('str-chat__message-reactions', {\n [`str-chat__message-reactions--flipped-horizontally`]: flipHorizontalPosition,\n [`str-chat__message-reactions--${verticalPosition}`]:\n typeof verticalPosition === 'string',\n [`str-chat__message-reactions--${visualStyle}`]:\n typeof visualStyle === 'string',\n })}\n ref={divRef}\n role='figure'\n >\n <FragmentOrButton\n aria-expanded={isDialogOpen}\n aria-label={t('aria/Reaction list')}\n aria-pressed={isDialogOpen}\n buttonIf={visualStyle === 'clustered'}\n className='str-chat__message-reactions__list-button'\n data-testid='message-reactions-list-button'\n onClick={() => handleReactionButtonClick(null)}\n >\n <ul className='str-chat__message-reactions__list'>\n {(cappedExistingReactions?.reactionsToDisplay ?? existingReactions).map(\n ({ EmojiComponent, reactionCount, reactionType }) =>\n EmojiComponent && (\n <li\n className='str-chat__message-reactions__list-item'\n data-testid='message-reactions-list-item'\n key={reactionType}\n >\n <FragmentOrButton\n aria-label={t('aria/Select Reaction: {{ reactionName }}', {\n reactionName: reactionType,\n })}\n buttonIf={visualStyle === 'segmented'}\n className='str-chat__message-reactions__list-item-button'\n onClick={() => handleReactionButtonClick(reactionType)}\n >\n <span\n className='str-chat__message-reactions__list-item-icon'\n data-testid='message-reactions-list-item-icon'\n >\n <EmojiComponent />\n </span>\n {visualStyle === 'segmented' && reactionCount > 1 && (\n <span\n className='str-chat__message-reactions__list-item-count'\n data-testclass='message-reactions-item-count'\n >\n {reactionCount}\n </span>\n )}\n </FragmentOrButton>\n </li>\n ),\n )}\n {uniqueReactionTypeCount > 4 &&\n cappedExistingReactions &&\n visualStyle === 'segmented' && (\n <li className='str-chat__message-reactions__list-item str-chat__message-reactions__list-item--more'>\n <button\n aria-label={t('aria/Reaction list')}\n className='str-chat__message-reactions__list-item-button'\n onClick={() => handleReactionButtonClick(null)}\n type='button'\n >\n <span className='str-chat__message-reactions__overflow-count'>\n +\n {totalReactionCount -\n cappedExistingReactions.reactionCountToDisplay}\n </span>\n </button>\n </li>\n )}\n </ul>\n {visualStyle === 'clustered' && (\n <span\n className='str-chat__message-reactions__total-count'\n data-testid='message-reactions-total-count'\n >\n {totalReactionCount}\n </span>\n )}\n </FragmentOrButton>\n </div>\n\n <DialogAnchor\n dialogManagerId={dialogManager?.id}\n id={dialogId}\n offset={8}\n placement={isMyMessage() ? 'bottom-end' : 'bottom-start'}\n referenceElement={divRef.current}\n trapFocus\n updatePositionOnContentResize\n >\n <MessageReactionsDetail\n handleFetchReactions={handleFetchReactions}\n onSelectedReactionTypeChange={setSelectedReactionType}\n reactionDetailsSort={reactionDetailsSort}\n reactionGroups={reactionGroups}\n reactions={existingReactions}\n selectedReactionType={selectedReactionType}\n totalReactionCount={totalReactionCount}\n />\n </DialogAnchor>\n </>\n );\n};\n\n/**\n * Component that displays a list of reactions on a message.\n */\nexport const MessageReactions = React.memo(\n UnMemoizedMessageReactions,\n) as typeof UnMemoizedMessageReactions;\n","import type { ForwardedRef, MutableRefObject } from 'react';\n\nexport const isMutableRef = <T>(\n ref: ForwardedRef<T> | null,\n): ref is MutableRefObject<T> => {\n if (ref) {\n return (ref as MutableRefObject<T>).current !== undefined;\n }\n return false;\n};\n\nexport const getImageDimensions = (source: string) =>\n new Promise<[number, number]>((resolve, reject) => {\n const image = new Image();\n\n image.addEventListener(\n 'load',\n () => {\n resolve([image.width, image.height]);\n },\n { once: true },\n );\n\n image.addEventListener('error', () => reject(`Couldn't load image from ${source}`), {\n once: true,\n });\n\n image.src = source;\n });\n","import React, { useEffect, useState } from 'react';\n\nimport { getImageDimensions } from './utils/utils';\n\nexport type SpriteImageProps = {\n columns: number;\n position: [number, number];\n rows: number;\n spriteUrl: string;\n fallback?: React.ReactNode;\n height?: number;\n style?: React.CSSProperties;\n width?: number;\n};\n\nexport const SpriteImage = ({\n columns,\n fallback,\n height,\n position,\n rows,\n spriteUrl,\n style,\n width,\n}: SpriteImageProps) => {\n const [[spriteWidth, spriteHeight], setSpriteDimensions] = useState([0, 0]);\n\n useEffect(() => {\n getImageDimensions(spriteUrl).then(setSpriteDimensions).catch(console.error);\n }, [spriteUrl]);\n\n const [x, y] = position;\n\n if (!spriteHeight || !spriteWidth) return <>{fallback}</>;\n\n return (\n <div\n data-testid='sprite-image'\n style={\n {\n ...style,\n '--str-chat__sprite-image-resize-ratio':\n 'var(--str-chat__sprite-image-resize-ratio-x, var(--str-chat__sprite-image-resize-ratio-y, 1))',\n '--str-chat__sprite-image-resize-ratio-x':\n 'calc(var(--str-chat__sprite-image-width) / var(--str-chat__sprite-item-width))',\n '--str-chat__sprite-image-resize-ratio-y':\n 'calc(var(--str-chat__sprite-image-height) / var(--str-chat__sprite-item-height))',\n '--str-chat__sprite-item-height': `${spriteHeight / rows}`,\n '--str-chat__sprite-item-width': `${spriteWidth / columns}`,\n ...(Number.isFinite(height)\n ? { '--str-chat__sprite-image-height': `${height}px` }\n : {}),\n ...(Number.isFinite(width)\n ? { '--str-chat__sprite-image-width': `${width}px` }\n : {}),\n backgroundImage: `url('${spriteUrl}')`,\n backgroundPosition: `${x * (100 / (columns - 1))}% ${y * (100 / (rows - 1))}%`,\n backgroundSize: `${columns * 100}% ${rows * 100}%`,\n height:\n 'var(--str-chat__sprite-image-height, calc(var(--str-chat__sprite-item-height) * var(--str-chat__sprite-image-resize-ratio)))',\n width:\n 'var(--str-chat__sprite-image-width, calc(var(--str-chat__sprite-item-width) * var(--str-chat__sprite-image-resize-ratio)))',\n } as React.CSSProperties\n }\n />\n );\n};\n","import type { ComponentRef } from 'react';\nimport React, { useRef } from 'react';\nimport { ReactionSelector as DefaultReactionSelector } from './ReactionSelector';\nimport { DialogAnchor, useDialogIsOpen, useDialogOnNearestManager } from '../Dialog';\nimport {\n useComponentContext,\n useComponentContextIcons,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\n\nimport type { IconProps } from '../../types/types';\nimport { QuickMessageActionsButton } from '../MessageActions';\n\ntype ReactionSelectorWithButtonProps = {\n /**\n * Custom component rendering the icon used in a button invoking reactions selector for a given message.\n * @deprecated Use the `icons.IconEmoji` slot on `ComponentContext` (via `<WithComponents overrides={{ icons: { IconEmoji: ... } }}>`) instead.\n * Passing this prop still wins over the context slot for backwards compatibility.\n */\n ReactionIcon?: React.ComponentType<IconProps>;\n};\n\n/**\n * Internal convenience component - not to be exported. It just groups the button and the dialog anchor and thus prevents\n * cluttering the parent component.\n */\nexport const ReactionSelectorWithButton = ({\n ReactionIcon,\n}: ReactionSelectorWithButtonProps) => {\n const { t } = useTranslationContext('ReactionSelectorWithButton');\n const { isMyMessage, message, threadList } = useMessageContext('MessageOptions');\n const { ReactionSelector = DefaultReactionSelector } = useComponentContext();\n const { IconEmoji } = useComponentContextIcons();\n const ResolvedReactionIcon = ReactionIcon ?? IconEmoji;\n const buttonRef = useRef<ComponentRef<'button'>>(null);\n const dialogId = DefaultReactionSelector.getDialogId({\n messageId: message.id,\n threadList,\n });\n const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });\n const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n return (\n <>\n <DialogAnchor\n dialogManagerId={dialogManager?.id}\n id={dialogId}\n offset={8}\n placement={isMyMessage() ? 'top-end' : 'top-start'}\n referenceElement={buttonRef.current}\n trapFocus\n updatePositionOnContentResize\n >\n <ReactionSelector />\n </DialogAnchor>\n <QuickMessageActionsButton\n aria-expanded={dialogIsOpen}\n aria-label={t('aria/Open Reaction Selector')}\n className='str-chat__message-reactions-button'\n data-testid='message-reaction-action'\n onClick={() => dialog?.toggle()}\n ref={buttonRef}\n >\n <ResolvedReactionIcon className='str-chat__message-action-icon' />\n </QuickMessageActionsButton>\n </>\n );\n};\n","import React from 'react';\nimport {\n useChatContext,\n useComponentContextIcons,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\nimport { useNotificationApi } from '../Notifications';\nimport {\n ContextMenuBackButton,\n ContextMenuButton,\n ContextMenuHeader,\n useContextMenuContext,\n} from '../Dialog';\n\nconst getErrorMessage = (error: unknown, fallback: string) =>\n error instanceof Error && error.message ? error.message : fallback;\n\nconst getNotificationError = (error: unknown): Error | undefined => {\n if (error instanceof Error) return error;\n if (typeof error === 'string') return new Error(error);\n if (error && typeof error === 'object' && 'message' in error) {\n const message = error.message;\n if (typeof message === 'string') return new Error(message);\n }\n return undefined;\n};\n\nexport const RemindMeSubmenuHeader = () => {\n const { IconChevronLeft } = useComponentContextIcons();\n\n const { t } = useTranslationContext();\n const { returnToParentMenu } = useContextMenuContext();\n return (\n <ContextMenuHeader>\n <ContextMenuBackButton onClick={returnToParentMenu}>\n <IconChevronLeft />\n <span>{t('Remind Me')}</span>\n </ContextMenuBackButton>\n </ContextMenuHeader>\n );\n};\n\nexport const RemindMeSubmenu = () => {\n const { t } = useTranslationContext();\n const { client } = useChatContext();\n const { message } = useMessageContext();\n const { closeMenu } = useContextMenuContext();\n const { addNotification } = useNotificationApi();\n return (\n <div className='str-chat__message-actions-box__submenu'>\n {client.reminders.scheduledOffsetsMs.map((offsetMs) => (\n <ContextMenuButton\n className='str-chat__message-actions-list-item-button'\n key={`reminder-offset-option--${offsetMs}`}\n onClick={async () => {\n try {\n await client.reminders.upsertReminder({\n messageId: message.id,\n remind_at: new Date(new Date().getTime() + offsetMs).toISOString(),\n });\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n message: t('Reminder set'),\n severity: 'success',\n type: 'api:message:reminder:set:success',\n });\n } catch (error) {\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n error: getNotificationError(error),\n message: getErrorMessage(error, 'Error setting reminder'),\n severity: 'error',\n type: 'api:message:reminder:set:failed',\n });\n } finally {\n closeMenu();\n }\n }}\n >\n {t('duration/Remind Me', { milliseconds: offsetMs })}\n </ContextMenuButton>\n ))}\n {/* todo: potential improvement to add a custom option that would trigger rendering modal with custom date picker - we need date picker */}\n </div>\n );\n};\n","import {\n type Attachment,\n isAudioAttachment,\n isFileAttachment,\n isImageAttachment,\n isVideoAttachment,\n isVoiceRecordingAttachment,\n type LocalAttachment,\n type LocalUploadAttachment,\n} from 'stream-chat';\n\n/**\n * Download behavior notes:\n *\n * - Remote attachments prefer `fetch -> blob -> objectURL` instead of direct link clicks.\n * - In Chromium, direct sequential clicks on cross-origin URLs can yield only one actual\n * downloaded file even when multiple anchor clicks are fired.\n * - Blob URLs are same-document downloads and preserve caller-provided `a.download` names\n * more reliably than direct remote URLs.\n * - If remote fetch fails (e.g. CORS/policy/network), the code falls back to direct URL\n * download so the action remains functional.\n */\nexport type DownloadableAttachment = {\n asset_url?: string;\n image_url?: string;\n localMetadata?: LocalUploadAttachment['localMetadata'];\n title?: string;\n};\n\nexport const isDownloadableAttachment = (\n attachment: unknown,\n): attachment is DownloadableAttachment => {\n if (!attachment || typeof attachment !== 'object') return false;\n const typedAttachment = attachment as Attachment | LocalAttachment;\n\n return (\n isFileAttachment(typedAttachment) ||\n isImageAttachment(typedAttachment) ||\n isVideoAttachment(typedAttachment) ||\n isAudioAttachment(typedAttachment) ||\n isVoiceRecordingAttachment(typedAttachment)\n );\n};\n\nconst triggerUrlDownload = ({\n filename,\n openInNewTab,\n revokeObjectUrl,\n url,\n}: {\n openInNewTab?: boolean;\n revokeObjectUrl?: boolean;\n url: string;\n filename: string;\n}) => {\n const anchor = document.createElement('a');\n anchor.download = filename;\n anchor.href = url;\n anchor.rel = 'noopener noreferrer';\n // Keep chat in place for direct remote URLs by opening in a new tab when requested.\n if (openInNewTab && !url.startsWith('blob:')) {\n anchor.target = '_blank';\n }\n document.body.append(anchor);\n anchor.click();\n anchor.remove();\n\n // Revoke object URLs by default; direct network URLs are never revoked.\n const shouldRevokeObjectUrl = revokeObjectUrl ?? url.startsWith('blob:');\n if (shouldRevokeObjectUrl && url.startsWith('blob:')) {\n setTimeout(() => URL.revokeObjectURL(url), 0);\n }\n};\n\nconst fetchRemoteAttachmentAsObjectUrl = async (url: string) => {\n if (typeof fetch !== 'function') return null;\n\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch attachment, status ${response.status}`);\n }\n const blob = await response.blob();\n return URL.createObjectURL(blob);\n};\n\nexport const downloadAttachment = async (\n attachment: DownloadableAttachment,\n options: { openRemoteInNewTab?: boolean; preferRemoteFetch?: boolean } = {},\n) => {\n const { openRemoteInNewTab = true, preferRemoteFetch = true } = options;\n const titleFallback = attachment.title ?? 'downloaded-attachment';\n const rawFile = attachment.localMetadata?.file;\n\n if (rawFile instanceof Blob) {\n const filename =\n rawFile instanceof File && rawFile.name ? rawFile.name : titleFallback;\n triggerUrlDownload({\n filename,\n url: URL.createObjectURL(rawFile),\n });\n return;\n }\n\n const filename =\n rawFile &&\n typeof rawFile === 'object' &&\n 'name' in rawFile &&\n typeof (rawFile as { name: unknown }).name === 'string'\n ? (rawFile as { name: string }).name\n : titleFallback;\n\n const url = attachment.asset_url ?? attachment.image_url;\n if (!url) return;\n\n // Prefer blob-based download for remote files when requested.\n if (preferRemoteFetch) {\n try {\n const objectUrl = await fetchRemoteAttachmentAsObjectUrl(url);\n if (objectUrl) {\n triggerUrlDownload({\n filename,\n url: objectUrl,\n });\n return;\n }\n } catch {\n // Fall back to direct URL download when fetch is blocked (e.g. CORS/policy).\n }\n }\n\n triggerUrlDownload({ filename, openInNewTab: openRemoteInNewTab, url });\n};\n\nexport const downloadAllAttachments = async (attachments: DownloadableAttachment[]) => {\n // Sequential execution keeps user intent clear and avoids bursting simultaneous requests.\n for (const attachment of attachments) {\n await downloadAttachment(attachment, {\n openRemoteInNewTab: true,\n preferRemoteFetch: true,\n });\n }\n};\n","import React from 'react';\nimport {\n useComponentContextIcons,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\nimport {\n ContextMenuBackButton,\n ContextMenuButton,\n ContextMenuHeader,\n useContextMenuContext,\n} from '../Dialog';\nimport {\n downloadAllAttachments,\n downloadAttachment,\n isDownloadableAttachment,\n} from './downloadUtils';\n\nconst msgActionsBoxButtonClassName =\n 'str-chat__message-actions-list-item-button' as const;\n\nexport const DownloadSubmenuHeader = () => {\n const { IconChevronLeft } = useComponentContextIcons();\n\n const { returnToParentMenu: goBack } = useContextMenuContext();\n const { t } = useTranslationContext();\n return (\n <ContextMenuHeader>\n <ContextMenuBackButton onClick={goBack}>\n <IconChevronLeft />\n <span>{t('Download Attachment')}</span>\n </ContextMenuBackButton>\n </ContextMenuHeader>\n );\n};\n\nexport const DownloadSubmenu = () => {\n const { IconDownload } = useComponentContextIcons();\n const { closeMenu } = useContextMenuContext();\n const { message } = useMessageContext();\n const { t } = useTranslationContext();\n\n const downloadableAttachments = (message.attachments ?? []).filter(\n isDownloadableAttachment,\n );\n\n return (\n <div className='str-chat__message-actions-box__submenu str-chat__message-actions-box__submenu--download-attachments'>\n {downloadableAttachments.map((attachment, index) => {\n const fileName = attachment.localMetadata?.file?.name ?? attachment.title;\n const label = fileName\n ? t('Download {{ fileName }}', { fileName })\n : t('Download attachment {{ number }}', { number: index + 1 });\n\n return (\n <ContextMenuButton\n className={msgActionsBoxButtonClassName}\n Icon={IconDownload}\n key={\n attachment.localMetadata?.id ??\n attachment.asset_url ??\n attachment.image_url ??\n `${fileName ?? 'attachment'}-${index}`\n }\n onClick={() => {\n void downloadAttachment(attachment);\n closeMenu();\n }}\n >\n {label}\n </ContextMenuButton>\n );\n })}\n <ContextMenuButton\n className={msgActionsBoxButtonClassName}\n Icon={IconDownload}\n onClick={() => {\n void downloadAllAttachments(downloadableAttachments);\n closeMenu();\n }}\n >\n {t('Download All')}\n </ContextMenuButton>\n </div>\n );\n};\n","import { Button, type ButtonProps } from '../Button';\nimport clsx from 'clsx';\nimport React, { forwardRef } from 'react';\n\nexport const QuickMessageActionsButton = forwardRef<HTMLButtonElement, ButtonProps>(\n function QuickMessageActionsButton({ className, ...props }, ref) {\n return (\n <Button\n appearance='ghost'\n circular\n className={clsx('str-chat__message-actions-box-button', className)}\n ref={ref}\n size='sm'\n variant='secondary'\n {...props}\n />\n );\n },\n);\n","import { Alert } from '../Dialog';\nimport { Button } from '../Button';\nimport React from 'react';\nimport { useModalContext, useTranslationContext } from '../../context';\n\nexport type DeleteMessageAlertProps = {\n onCancel: () => void;\n onDelete: () => void;\n};\n\nexport const DeleteMessageAlert = ({ onCancel, onDelete }: DeleteMessageAlertProps) => {\n const { t } = useTranslationContext();\n const { close } = useModalContext();\n\n return (\n <Alert.Root\n className='str-chat__delete-message-alert'\n data-testid='message-delete-alert'\n >\n <Alert.Header\n description={t('Are you sure you want to delete this message?')}\n title={t('Delete message')}\n />\n <Alert.Actions>\n <Button\n appearance='outline'\n className='str-chat__delete-message-alert__delete-button'\n data-testid='delete-message-alert-delete-button'\n onClick={onDelete}\n size='md'\n variant='danger'\n >\n {t('Delete message')}\n </Button>\n <Button\n appearance='outline'\n autoFocus\n className='str-chat__delete-message-alert__cancel-button'\n data-testid='delete-message-alert-cancel-button'\n onClick={() => {\n onCancel();\n close();\n }}\n size='md'\n variant='secondary'\n >\n {t('Cancel')}\n </Button>\n </Alert.Actions>\n </Alert.Root>\n );\n};\n","/* eslint-disable sort-keys */\nimport React, { forwardRef, useState } from 'react';\n\nimport { GlobalModal } from '../Modal';\nimport { isMessageDeleted, isUserMuted } from '../Message/utils';\nimport { useMessageComposerController } from '../MessageComposer/hooks/useMessageComposerController';\nimport { savePreEditSnapshot } from '../MessageComposer/preEditSnapshot';\nimport { useNotificationApi } from '../Notifications';\nimport { useMessageReminder } from '../Message/hooks/useMessageReminder';\nimport { ReactionSelector as DefaultReactionSelector } from '../Reactions';\nimport { ReactionSelectorWithButton } from '../Reactions/ReactionSelectorWithButton';\nimport {\n useChatContext,\n useComponentContext,\n useComponentContextIcons,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\nimport { RemindMeSubmenu, RemindMeSubmenuHeader } from './RemindMeSubmenu';\nimport { DownloadSubmenu, DownloadSubmenuHeader } from './DownloadSubmenu';\nimport {\n ContextMenuButton,\n DialogAnchor,\n useContextMenuContext,\n useDialogIsOpen,\n useDialogOnNearestManager,\n} from '../Dialog';\nimport { MessageActions, type MessageActionSetItem } from './MessageActions';\nimport { QuickMessageActionsButton } from './QuickMessageActionButton';\nimport clsx from 'clsx';\nimport { DeleteMessageAlert } from './DeleteMessageAlert';\nimport { downloadAttachment, isDownloadableAttachment } from './downloadUtils';\n\nconst msgActionsBoxButtonClassName =\n 'str-chat__message-actions-list-item-button' as const;\n\nconst MessageActionsMenuItemButton = (\n props: React.ComponentProps<typeof ContextMenuButton>,\n) => <ContextMenuButton {...props} />;\n\nconst getErrorMessage = (error: unknown, fallback: string) =>\n error instanceof Error && error.message ? error.message : fallback;\n\nconst getNotificationError = (error: unknown): Error | undefined => {\n if (error instanceof Error) return error;\n if (typeof error === 'string') return new Error(error);\n if (error && typeof error === 'object' && 'message' in error) {\n const message = error.message;\n if (typeof message === 'string') return new Error(message);\n }\n return undefined;\n};\n\nconst DefaultMessageActionComponents = {\n dropdown: {\n React() {\n const { ReactionSelector = DefaultReactionSelector } = useComponentContext();\n const { anchorReferenceElement } = useContextMenuContext();\n const { isMyMessage, message, threadList } = useMessageContext();\n const { t } = useTranslationContext();\n const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(null);\n const dialogId = `${DefaultReactionSelector.getDialogId({\n messageId: message.id,\n threadList,\n })}-dropdown`;\n const { dialog, dialogManager } = useDialogOnNearestManager({\n id: dialogId,\n });\n const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n const { IconEmoji } = useComponentContextIcons();\n return (\n <>\n <DialogAnchor\n dialogManagerId={dialogManager?.id}\n id={dialogId}\n offset={8}\n placement={isMyMessage() ? 'top-end' : 'top-start'}\n referenceElement={referenceElement}\n trapFocus\n updatePositionOnContentResize\n >\n <ReactionSelector dialogId={dialogId} />\n </DialogAnchor>\n <MessageActionsMenuItemButton\n aria-expanded={dialogIsOpen}\n aria-label={t('aria/Open Reaction Selector')}\n className={clsx(\n msgActionsBoxButtonClassName,\n 'str-chat__message-actions-list-item-button--react',\n )}\n data-testid='dropdown-react-action'\n Icon={IconEmoji}\n onClick={(event) => {\n if (dialogIsOpen) {\n dialog.close();\n return;\n }\n setReferenceElement(\n anchorReferenceElement instanceof HTMLElement\n ? anchorReferenceElement\n : event.currentTarget,\n );\n dialog.open();\n }}\n >\n {t('Add reaction')}\n </MessageActionsMenuItemButton>\n </>\n );\n },\n ThreadReply() {\n const { closeMenu } = useContextMenuContext();\n const { handleOpenThread } = useMessageContext();\n const { t } = useTranslationContext();\n\n const { IconThread } = useComponentContextIcons();\n return (\n <MessageActionsMenuItemButton\n aria-label={t('aria/Open Thread')}\n className={msgActionsBoxButtonClassName}\n data-testid='thread-action'\n Icon={IconThread}\n onClick={(e) => {\n handleOpenThread(e);\n closeMenu();\n }}\n >\n {t('Thread Reply')}\n </MessageActionsMenuItemButton>\n );\n },\n Quote() {\n const { closeMenu } = useContextMenuContext();\n const { message } = useMessageContext();\n const { t } = useTranslationContext();\n const messageComposer = useMessageComposerController();\n\n const handleQuote = () => {\n messageComposer.setQuotedMessage(message);\n\n const elements = message.parent_id\n ? document.querySelectorAll('.str-chat__thread .str-chat__textarea__textarea')\n : document.getElementsByClassName('str-chat__textarea__textarea');\n const textarea = elements.item(0);\n\n if (textarea instanceof HTMLTextAreaElement) {\n textarea.focus();\n }\n };\n\n const { IconQuote } = useComponentContextIcons();\n return (\n <MessageActionsMenuItemButton\n aria-label={t('aria/Quote Message')}\n className={msgActionsBoxButtonClassName}\n Icon={IconQuote}\n onClick={() => {\n handleQuote();\n closeMenu();\n }}\n >\n {t('Quote Reply')}\n </MessageActionsMenuItemButton>\n );\n },\n Download() {\n const { closeMenu, openSubmenu } = useContextMenuContext();\n const { message } = useMessageContext();\n const { t } = useTranslationContext();\n const { IconDownload } = useComponentContextIcons();\n\n const downloadableAttachments = (message.attachments ?? []).filter(\n isDownloadableAttachment,\n );\n\n if (!downloadableAttachments.length) return null;\n\n return (\n <MessageActionsMenuItemButton\n aria-label={t('aria/Download attachment')}\n className={msgActionsBoxButtonClassName}\n hasSubMenu={downloadableAttachments.length > 1}\n Icon={IconDownload}\n onClick={(event) => {\n if (downloadableAttachments.length > 1) {\n openSubmenu({\n focusReturnTarget: event.currentTarget,\n Header: DownloadSubmenuHeader,\n Submenu: DownloadSubmenu,\n });\n return;\n }\n\n void downloadAttachment(downloadableAttachments[0]);\n closeMenu();\n }}\n >\n {t('Download Attachment')}\n </MessageActionsMenuItemButton>\n );\n },\n Pin() {\n const { closeMenu } = useContextMenuContext();\n const { handlePin, message } = useMessageContext();\n const { addNotification } = useNotificationApi();\n const { t } = useTranslationContext();\n const isPinned = !!message.pinned;\n const { IconPin, IconUnpin } = useComponentContextIcons();\n return (\n <MessageActionsMenuItemButton\n aria-label={isPinned ? t('aria/Unpin Message') : t('aria/Pin Message')}\n className={msgActionsBoxButtonClassName}\n Icon={isPinned ? IconUnpin : IconPin}\n onClick={async (event) => {\n try {\n await handlePin(event);\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n message: isPinned ? t('Message unpinned') : t('Message pinned'),\n severity: 'success',\n type: isPinned ? 'api:message:unpin:success' : 'api:message:pin:success',\n });\n } catch (error) {\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n error: getNotificationError(error),\n message: getErrorMessage(\n error,\n isPinned ? t('Error removing message pin') : t('Error pinning message'),\n ),\n severity: 'error',\n type: isPinned ? 'api:message:unpin:failed' : 'api:message:pin:failed',\n });\n }\n closeMenu();\n }}\n >\n {isPinned ? t('Unpin') : t('Pin')}\n </MessageActionsMenuItemButton>\n );\n },\n CopyMessageText() {\n const { closeMenu } = useContextMenuContext();\n const { message } = useMessageContext();\n const { t } = useTranslationContext();\n\n const { IconCopy } = useComponentContextIcons();\n return (\n <MessageActionsMenuItemButton\n aria-label={t('aria/Copy Message Text')}\n className={msgActionsBoxButtonClassName}\n Icon={IconCopy}\n onClick={() => {\n if (message.text) navigator.clipboard.writeText(message.text);\n closeMenu();\n }}\n >\n {t('Copy Message')}\n </MessageActionsMenuItemButton>\n );\n },\n Resend() {\n const { closeMenu } = useContextMenuContext();\n const { handleRetry, message } = useMessageContext();\n const { t } = useTranslationContext();\n\n const { IconRetry } = useComponentContextIcons();\n return (\n <MessageActionsMenuItemButton\n aria-label={t('aria/Resend Message')}\n className={msgActionsBoxButtonClassName}\n Icon={IconRetry}\n onClick={() => {\n handleRetry(message);\n closeMenu();\n }}\n >\n {t('Resend')}\n </MessageActionsMenuItemButton>\n );\n },\n Edit() {\n const messageComposer = useMessageComposerController();\n const { message } = useMessageContext();\n const { t } = useTranslationContext();\n const { closeMenu } = useContextMenuContext();\n\n const { IconEdit } = useComponentContextIcons();\n return (\n <MessageActionsMenuItemButton\n aria-label={t('aria/Edit Message')}\n className={msgActionsBoxButtonClassName}\n Icon={IconEdit}\n onClick={() => {\n savePreEditSnapshot(messageComposer);\n messageComposer.initState({ composition: message });\n closeMenu();\n }}\n >\n {t('Edit Message')}\n </MessageActionsMenuItemButton>\n );\n },\n MarkUnread() {\n const { closeMenu } = useContextMenuContext();\n const { handleMarkUnread, message } = useMessageContext();\n const { addNotification } = useNotificationApi();\n const { t } = useTranslationContext();\n\n const { IconNotification } = useComponentContextIcons();\n return (\n <MessageActionsMenuItemButton\n aria-label={t('aria/Mark Message Unread')}\n className={msgActionsBoxButtonClassName}\n Icon={IconNotification}\n onClick={async (event) => {\n try {\n await handleMarkUnread(event);\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n message: t('Message marked as unread'),\n severity: 'success',\n type: 'api:message:markUnread:success',\n });\n } catch (error) {\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n error: getNotificationError(error),\n message: getErrorMessage(\n error,\n t(\n 'Error marking message unread. Cannot mark unread messages older than the newest 100 channel messages.',\n ),\n ),\n severity: 'error',\n type: 'api:message:markUnread:failed',\n });\n }\n closeMenu();\n }}\n >\n {t('Mark as unread')}\n </MessageActionsMenuItemButton>\n );\n },\n RemindMe() {\n const { closeMenu, openSubmenu } = useContextMenuContext();\n const { client } = useChatContext();\n const { addNotification } = useNotificationApi();\n const { t } = useTranslationContext();\n const { message } = useMessageContext();\n const reminder = useMessageReminder(message.id);\n const { IconBell, IconBellOff } = useComponentContextIcons();\n const messageAlreadyBookmarked = reminder && !reminder?.remindAt;\n\n if (messageAlreadyBookmarked) return null;\n\n return (\n <MessageActionsMenuItemButton\n aria-label={reminder ? t('aria/Remind Me Message') : t('aria/Remove Reminder')}\n className={msgActionsBoxButtonClassName}\n hasSubMenu={!reminder}\n Icon={reminder ? IconBellOff : IconBell}\n onClick={async (event) => {\n if (reminder) {\n try {\n await client.reminders.deleteReminder(reminder.id);\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n message: t('Remove reminder'),\n severity: 'success',\n type: 'api:message:reminder:delete:success',\n });\n } catch (error) {\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n error: getNotificationError(error),\n message: getErrorMessage(error, 'Error removing reminder'),\n severity: 'error',\n type: 'api:message:reminder:delete:failed',\n });\n } finally {\n closeMenu();\n }\n } else {\n openSubmenu({\n focusReturnTarget: event.currentTarget,\n Header: RemindMeSubmenuHeader,\n Submenu: RemindMeSubmenu,\n });\n }\n }}\n >\n {reminder ? t('Remove reminder') : t('Remind me')}\n </MessageActionsMenuItemButton>\n );\n },\n SaveForLater() {\n const { closeMenu } = useContextMenuContext();\n const { client } = useChatContext();\n const { addNotification } = useNotificationApi();\n const { message } = useMessageContext();\n const { t } = useTranslationContext();\n const reminder = useMessageReminder(message.id);\n const { IconBookmark, IconBookmarkRemove } = useComponentContextIcons();\n const messageAlreadyHasReminderScheduled = Boolean(reminder && reminder?.remindAt);\n\n if (messageAlreadyHasReminderScheduled) return null;\n\n return (\n <MessageActionsMenuItemButton\n aria-label={\n reminder ? t('aria/Remove Save For Later') : t('aria/Bookmark Message')\n }\n className={msgActionsBoxButtonClassName}\n Icon={reminder ? IconBookmarkRemove : IconBookmark}\n onClick={async () => {\n try {\n if (reminder) {\n await client.reminders.deleteReminder(reminder.id);\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n message: t('Remove save for later'),\n severity: 'success',\n type: 'api:message:saveForLater:delete:success',\n });\n } else {\n await client.reminders.createReminder({ messageId: message.id });\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n message: t('Saved for later'),\n severity: 'success',\n type: 'api:message:saveForLater:create:success',\n });\n }\n } catch (error) {\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n error: getNotificationError(error),\n message: getErrorMessage(\n error,\n reminder\n ? 'Error removing message from saved for later'\n : 'Error saving message for later',\n ),\n severity: 'error',\n type: reminder\n ? 'api:message:saveForLater:delete:failed'\n : 'api:message:saveForLater:create:failed',\n });\n } finally {\n closeMenu();\n }\n }}\n >\n {reminder ? t('Remove save for later') : t('Save for later')}\n </MessageActionsMenuItemButton>\n );\n },\n Flag() {\n const { closeMenu } = useContextMenuContext();\n const { handleFlag, message } = useMessageContext();\n const { addNotification } = useNotificationApi();\n const { t } = useTranslationContext();\n\n const { IconFlag } = useComponentContextIcons();\n return (\n <MessageActionsMenuItemButton\n aria-label={t('aria/Flag Message')}\n className={msgActionsBoxButtonClassName}\n Icon={IconFlag}\n onClick={async (event) => {\n try {\n await handleFlag(event);\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n message: t('Message has been successfully flagged'),\n severity: 'success',\n type: 'api:message:flag:success',\n });\n } catch (error) {\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n error: getNotificationError(error),\n message: getErrorMessage(error, t('Error adding flag')),\n severity: 'error',\n type: 'api:message:flag:failed',\n });\n }\n closeMenu();\n }}\n >\n {t('Flag')}\n </MessageActionsMenuItemButton>\n );\n },\n Mute() {\n const { closeMenu } = useContextMenuContext();\n const { handleMute, message } = useMessageContext();\n const { addNotification } = useNotificationApi();\n const { mutes } = useChatContext();\n const { t } = useTranslationContext();\n\n const isMuted = isUserMuted(message, mutes);\n const { IconAudio, IconMute } = useComponentContextIcons();\n return (\n <MessageActionsMenuItemButton\n aria-label={isMuted ? t('aria/Unmute User') : t('aria/Mute User')}\n className={msgActionsBoxButtonClassName}\n Icon={isMuted ? IconAudio : IconMute}\n onClick={async (event) => {\n try {\n await handleMute(event);\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n message: isMuted\n ? t('{{ user }} has been unmuted', {\n user: message.user?.name || message.user?.id,\n })\n : t('{{ user }} has been muted', {\n user: message.user?.name || message.user?.id,\n }),\n severity: 'success',\n type: isMuted ? 'api:user:unmute:success' : 'api:user:mute:success',\n });\n } catch (error) {\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n error: getNotificationError(error),\n message: getErrorMessage(\n error,\n isMuted ? t('Error unmuting a user ...') : t('Error muting a user ...'),\n ),\n severity: 'error',\n type: isMuted ? 'api:user:unmute:failed' : 'api:user:mute:failed',\n });\n }\n closeMenu();\n }}\n >\n {isMuted ? t('Unmute') : t('Mute')}\n </MessageActionsMenuItemButton>\n );\n },\n Delete() {\n const { closeMenu } = useContextMenuContext();\n const { addNotification } = useNotificationApi();\n const { Modal = GlobalModal } = useComponentContext();\n const { IconDelete } = useComponentContextIcons();\n const { handleDelete, message } = useMessageContext();\n const { t } = useTranslationContext();\n const [openModal, setOpenModal] = useState(false);\n\n if (isMessageDeleted(message)) return null;\n\n return (\n <>\n <MessageActionsMenuItemButton\n aria-label={t('aria/Delete Message')}\n className={msgActionsBoxButtonClassName}\n Icon={IconDelete}\n onClick={() => {\n setOpenModal(true);\n }}\n variant='destructive'\n >\n {t('Delete message')}\n </MessageActionsMenuItemButton>\n <Modal open={openModal} role='alertdialog'>\n <DeleteMessageAlert\n onCancel={() => {\n setOpenModal(false);\n closeMenu();\n }}\n onDelete={async () => {\n try {\n await handleDelete();\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n message: t('Message deleted'),\n severity: 'success',\n type: 'api:message:delete:success',\n });\n } catch (error) {\n addNotification({\n context: {\n message,\n },\n emitter: 'MessageActions',\n error: getNotificationError(error),\n message: getErrorMessage(error, t('Error deleting message')),\n severity: 'error',\n type: 'api:message:delete:failed',\n });\n } finally {\n setOpenModal(false);\n closeMenu();\n }\n }}\n />\n </Modal>\n </>\n );\n },\n BlockUser() {\n const { closeMenu } = useContextMenuContext();\n const { client } = useChatContext();\n const { message } = useMessageContext();\n const { t } = useTranslationContext();\n const isBlocked =\n !message.user?.id ||\n new Set(client.blockedUsers.getLatestValue().userIds).has(message.user?.id);\n\n const { IconNoSign, IconUserCheck } = useComponentContextIcons();\n return (\n <MessageActionsMenuItemButton\n aria-label={isBlocked ? t('Unblock') : t('aria/Block User')}\n className={clsx(msgActionsBoxButtonClassName)}\n Icon={isBlocked ? IconUserCheck : IconNoSign}\n onClick={() => {\n const targetId = message.user?.id;\n if (targetId) {\n if (isBlocked) client.unBlockUser(targetId);\n else client.blockUser(targetId);\n }\n closeMenu();\n }}\n >\n {isBlocked ? t('Unblock') : t('Block User')}\n </MessageActionsMenuItemButton>\n );\n },\n },\n quick: {\n // eslint-disable-next-line react/display-name\n DropdownToggle: forwardRef<HTMLButtonElement>((_, ref) => {\n const { t } = useTranslationContext();\n const { message, threadList } = useMessageContext();\n const dropdownDialogIsOpen = useDialogIsOpen(\n MessageActions.getDialogId({ messageId: message.id }),\n );\n const { dialog } = useDialogOnNearestManager({\n id: MessageActions.getDialogId({ messageId: message.id }),\n });\n const reactionSelectorDialogId = DefaultReactionSelector.getDialogId({\n messageId: message.id,\n threadList,\n });\n const { dialog: dropdownReactionSelectorDialog } = useDialogOnNearestManager({\n id: `${reactionSelectorDialogId}-dropdown`,\n });\n\n const { IconMore } = useComponentContextIcons();\n return (\n <QuickMessageActionsButton\n aria-expanded={dropdownDialogIsOpen}\n aria-haspopup='true'\n aria-label={t('aria/Open Message Actions Menu')}\n className='str-chat__message-actions-box-button'\n data-testid='message-actions-toggle-button'\n onClick={() => {\n // Close dropdown-anchored reaction selectors before toggling actions menu\n // to avoid stale selector re-anchoring.\n dropdownReactionSelectorDialog?.close();\n dialog?.toggle();\n }}\n ref={ref}\n >\n <IconMore className='str-chat__message-action-icon' />\n </QuickMessageActionsButton>\n );\n }),\n React() {\n const { IconEmoji } = useComponentContextIcons();\n return <ReactionSelectorWithButton ReactionIcon={IconEmoji} />;\n },\n Reply() {\n const { handleOpenThread } = useMessageContext();\n const { t } = useTranslationContext();\n\n const { IconReply } = useComponentContextIcons();\n return (\n <QuickMessageActionsButton\n aria-label={t('aria/Open Thread')}\n className='str-chat__message-reply-in-thread-button'\n data-testid='thread-action'\n onClick={handleOpenThread}\n >\n <IconReply className='str-chat__message-action-icon' />\n </QuickMessageActionsButton>\n );\n },\n },\n};\n\nexport const defaultMessageActionSet: MessageActionSetItem[] = [\n {\n Component: DefaultMessageActionComponents.quick.DropdownToggle,\n placement: 'quick-dropdown-toggle',\n },\n {\n Component: DefaultMessageActionComponents.quick.Reply,\n placement: 'quick',\n type: 'reply',\n },\n {\n Component: DefaultMessageActionComponents.quick.React,\n placement: 'quick',\n type: 'react',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.React,\n placement: 'dropdown',\n type: 'react',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.ThreadReply,\n placement: 'dropdown',\n type: 'reply',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.Quote,\n placement: 'dropdown',\n type: 'quote',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.Download,\n placement: 'dropdown',\n type: 'download',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.Pin,\n placement: 'dropdown',\n type: 'pin',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.CopyMessageText,\n placement: 'dropdown',\n type: 'copyMessageText',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.Resend,\n placement: 'dropdown',\n type: 'resendMessage',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.Edit,\n placement: 'dropdown',\n type: 'edit',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.MarkUnread,\n placement: 'dropdown',\n type: 'markUnread',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.RemindMe,\n placement: 'dropdown',\n type: 'remindMe',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.SaveForLater,\n placement: 'dropdown',\n type: 'saveForLater',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.Flag,\n placement: 'dropdown',\n type: 'flag',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.Mute,\n placement: 'dropdown',\n type: 'mute',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.Delete,\n placement: 'dropdown',\n type: 'delete',\n },\n {\n Component: DefaultMessageActionComponents.dropdown.BlockUser,\n placement: 'dropdown',\n type: 'blockUser',\n },\n] as const;\n","import { useMemo } from 'react';\n\nexport const useSplitActionSet = <\n T extends\n | { placement: 'quick' }\n | { placement: 'dropdown' }\n | { placement: 'quick-dropdown-toggle' },\n>(\n actionSet: T[],\n) =>\n useMemo(() => {\n const quickActionSet: Extract<T, { placement: 'quick' }>[] = [];\n const dropdownActionSet: Extract<T, { placement: 'dropdown' }>[] = [];\n let quickDropdownToggleAction:\n | Extract<T, { placement: 'quick-dropdown-toggle' }>\n | undefined;\n\n for (const action of actionSet) {\n if (action.placement === 'quick')\n quickActionSet.push(action as (typeof quickActionSet)[number]);\n if (action.placement === 'dropdown')\n dropdownActionSet.push(action as (typeof dropdownActionSet)[number]);\n if (action.placement === 'quick-dropdown-toggle') {\n quickDropdownToggleAction ??= action as Extract<\n T,\n { placement: 'quick-dropdown-toggle' }\n >;\n }\n }\n\n return { dropdownActionSet, quickActionSet, quickDropdownToggleAction } as const;\n }, [actionSet]);\n","import clsx from 'clsx';\nimport React, { type ComponentPropsWithRef, useState } from 'react';\n\nimport {\n useComponentContext,\n useMessageContext,\n useTranslationContext,\n} from '../../context';\nimport {\n ContextMenu,\n type ContextMenuItemProps,\n useDialogIsOpen,\n useDialogOnNearestManager,\n} from '../Dialog';\nimport { useBaseMessageActionSetFilter } from './hooks';\nimport { defaultMessageActionSet } from './MessageActions.defaults';\nimport { type MESSAGE_ACTIONS } from '../Message';\nimport { ReactionSelector } from '../Reactions';\nimport { useSplitActionSet } from '../Chat/hooks/useSplitActionSet';\n\ntype BaseMessageActionSetItem = {\n type: keyof typeof MESSAGE_ACTIONS | (string & {});\n};\n\nexport type QuickMessageActionSetItem = BaseMessageActionSetItem & {\n Component: React.ComponentType;\n placement: 'quick';\n};\n\nexport type DropdownMessageActionSetItem = BaseMessageActionSetItem & {\n Component: React.ComponentType<ContextMenuItemProps>;\n placement: 'dropdown';\n};\n\nexport type QuickDropdownToggleActionSetItem = {\n Component: React.ComponentType<ComponentPropsWithRef<'button'>>;\n placement: 'quick-dropdown-toggle';\n};\n\nexport type MessageActionSetItem =\n | QuickMessageActionSetItem\n | DropdownMessageActionSetItem\n | QuickDropdownToggleActionSetItem;\n\nexport type MessageActionsProps = {\n disableBaseMessageActionSetFilter?: boolean;\n messageActionSet?: MessageActionSetItem[];\n};\n\ninterface MessageActionsInterface {\n (props: MessageActionsProps): React.ReactNode;\n getDialogId: (_: { messageId: string }) => string;\n displayName: string;\n}\n\n/**\n * A new actions component to replace current `MessageOptions` component.\n * Exports from `stream-chat-react/experimental` __MIGHT__ change - use with caution\n * and follow release notes in case you notice unexpected behavior.\n */\nexport const MessageActions: MessageActionsInterface = ({\n disableBaseMessageActionSetFilter = false,\n messageActionSet = defaultMessageActionSet,\n}) => {\n const { isMyMessage, message, threadList } = useMessageContext();\n const { ContextMenu: ContextMenuComponent = ContextMenu } = useComponentContext();\n const { t } = useTranslationContext();\n const [actionsBoxButtonElement, setActionsBoxButtonElement] =\n useState<HTMLButtonElement | null>(null);\n\n const filteredMessageActionSet = useBaseMessageActionSetFilter(\n messageActionSet,\n disableBaseMessageActionSetFilter,\n );\n\n const { dropdownActionSet, quickActionSet, quickDropdownToggleAction } =\n useSplitActionSet(filteredMessageActionSet);\n\n const messageActionsDialogId = MessageActions.getDialogId({ messageId: message.id });\n const reactionSelectorDialogId = ReactionSelector.getDialogId({\n messageId: message.id,\n threadList,\n });\n const dropdownReactionSelectorDialogId = `${reactionSelectorDialogId}-dropdown`;\n const { dialog, dialogManager } = useDialogOnNearestManager({\n id: messageActionsDialogId,\n });\n const messageActionsDialogIsOpen = useDialogIsOpen(\n messageActionsDialogId,\n dialogManager?.id,\n );\n const reactionSelectorDialogIsOpen = useDialogIsOpen(\n reactionSelectorDialogId,\n dialogManager?.id,\n );\n const dropdownReactionSelectorDialogIsOpen = useDialogIsOpen(\n dropdownReactionSelectorDialogId,\n dialogManager?.id,\n );\n\n // do not render anything if total action count is zero\n if (dropdownActionSet.length + quickActionSet.length === 0) {\n return null;\n }\n\n return (\n <div\n className={clsx('str-chat__message-options', {\n 'str-chat__message-options--active':\n messageActionsDialogIsOpen ||\n reactionSelectorDialogIsOpen ||\n dropdownReactionSelectorDialogIsOpen,\n })}\n >\n {quickDropdownToggleAction && dropdownActionSet.length > 0 && (\n <>\n <quickDropdownToggleAction.Component ref={setActionsBoxButtonElement} />\n\n <ContextMenuComponent\n aria-label={t('aria/Message Actions')}\n backLabel={t('Back')}\n className={clsx('str-chat__message-actions-box', {\n 'str-chat__message-actions-box--hidden':\n dropdownReactionSelectorDialogIsOpen,\n 'str-chat__message-actions-box--open': messageActionsDialogIsOpen,\n })}\n dialogManagerId={dialogManager?.id}\n id={messageActionsDialogId}\n onClose={dialog?.close}\n placement={isMyMessage() ? 'top-end' : 'top-start'}\n referenceElement={actionsBoxButtonElement}\n tabIndex={-1}\n trapFocus\n >\n {dropdownActionSet.map(({ Component, type }) => (\n <Component key={type} />\n ))}\n </ContextMenuComponent>\n </>\n )}\n {quickActionSet.map(({ Component: QuickActionComponent, type }) => (\n <QuickActionComponent key={type} />\n ))}\n </div>\n );\n};\n\nMessageActions.getDialogId = ({ messageId }) => `message-actions-${messageId}`;\n\nMessageActions.displayName = 'MessageActions';\n","import React, { useMemo, useState } from 'react';\nimport clsx from 'clsx';\nimport { MessageBouncePrompt as DefaultMessageBouncePrompt } from '../MessageBounce';\nimport { MessageDeletedBubble as DefaultMessageDeletedBubble } from './MessageDeletedBubble';\nimport { MessageBlocked as DefaultMessageBlocked } from './MessageBlocked';\nimport { MessageActions as DefaultMessageActions } from '../MessageActions';\nimport { MessageRepliesCountButton as DefaultMessageRepliesCountButton } from './MessageRepliesCountButton';\nimport { MessageStatus as DefaultMessageStatus } from './MessageStatus';\nimport { MessageText } from './MessageText';\nimport { MessageEditedIndicator as DefaultMessageEditedIndicator } from './MessageEditedIndicator';\nimport { MessageTimestamp as DefaultMessageTimestamp } from './MessageTimestamp';\nimport { StreamedMessageText as DefaultStreamedMessageText } from './StreamedMessageText';\nimport { isDateSeparatorMessage } from '../MessageList';\nimport { MessageAlsoSentInChannelIndicator as DefaultMessageAlsoSentInChannelIndicator } from './MessageAlsoSentInChannelIndicator';\nimport { ReminderNotification as DefaultReminderNotification } from './ReminderNotification';\nimport { MessageTranslationIndicator as DefaultMessageTranslationIndicator } from './MessageTranslationIndicator';\nimport { useMessageReminder } from './hooks';\nimport {\n areMessageUIPropsEqual,\n countEmojis,\n isMessageBlocked,\n isMessageBounced,\n isMessageDeleted,\n isMessageEdited,\n isMessageErrorRetryable,\n messageHasAttachments,\n messageHasGiphyAttachment,\n messageHasQuotedMessage,\n messageHasReactions,\n messageHasSingleAttachment,\n messageTextHasEmojisOnly,\n} from './utils';\n\nimport { Avatar as DefaultAvatar } from '../Avatar';\nimport { Attachment as DefaultAttachment } from '../Attachment';\nimport { Poll } from '../Poll';\nimport { MessageReactions as DefaultMessageReactions } from '../Reactions';\nimport { MessageBounceModal } from '../MessageBounce/MessageBounceModal';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport type { MessageContextValue } from '../../context/MessageContext';\nimport { useMessageContext } from '../../context/MessageContext';\n\nimport {\n useChannelStateContext,\n useChatContext,\n useTranslationContext,\n} from '../../context';\n\nimport type { MessageUIComponentProps } from './types';\nimport { PinIndicator as DefaultPinIndicator } from './PinIndicator';\nimport { QuotedMessage as DefaultQuotedMessage } from './QuotedMessage';\nimport { MessageBubble } from './MessageBubble';\nimport { ErrorBadge } from '../Badge';\nimport { extractDisplayInfo as defaultExtractDisplayInfo } from '../Avatar/utils';\n\ntype MessageUIWithContextProps = MessageContextValue;\n\nconst MessageUIWithContext = ({\n endOfGroup,\n firstOfGroup,\n groupedByUser,\n handleAction,\n handleOpenThread,\n highlighted,\n isMessageAIGenerated,\n isMyMessage,\n message,\n onUserClick,\n onUserHover,\n renderText,\n showAvatar = 'incoming',\n threadList,\n}: MessageUIWithContextProps) => {\n const { channel } = useChannelStateContext();\n const { client } = useChatContext();\n const { t } = useTranslationContext('MessageUI');\n const [isBounceDialogOpen, setIsBounceDialogOpen] = useState(false);\n const reminder = useMessageReminder(message.id);\n\n const {\n Attachment = DefaultAttachment,\n Avatar = DefaultAvatar,\n extractDisplayInfo = defaultExtractDisplayInfo,\n MessageActions = DefaultMessageActions,\n MessageAlsoSentInChannelIndicator = DefaultMessageAlsoSentInChannelIndicator,\n MessageBlocked = DefaultMessageBlocked,\n MessageBouncePrompt = DefaultMessageBouncePrompt,\n MessageDeleted,\n MessageDeletedBubble = DefaultMessageDeletedBubble,\n MessageEditedIndicator = DefaultMessageEditedIndicator,\n MessageReactions = DefaultMessageReactions,\n MessageRepliesCountButton = DefaultMessageRepliesCountButton,\n MessageStatus = DefaultMessageStatus,\n MessageTimestamp = DefaultMessageTimestamp,\n MessageTranslationIndicator = DefaultMessageTranslationIndicator,\n PinIndicator = DefaultPinIndicator,\n QuotedMessage = DefaultQuotedMessage,\n ReminderNotification = DefaultReminderNotification,\n StreamedMessageText = DefaultStreamedMessageText,\n } = useComponentContext('MessageUI');\n\n const isAIGenerated = useMemo(\n () => isMessageAIGenerated?.(message),\n [isMessageAIGenerated, message],\n );\n const isDeleted = isMessageDeleted(message);\n\n const finalAttachments = useMemo(\n () =>\n !message.shared_location && !message.attachments\n ? []\n : !message.shared_location\n ? message.attachments\n : [message.shared_location, ...(message.attachments ?? [])],\n [message],\n );\n\n if (isDateSeparatorMessage(message)) {\n return null;\n }\n\n if (MessageDeleted && isDeleted) {\n return <MessageDeleted message={message} />;\n }\n\n if (isMessageBlocked(message)) {\n return <MessageBlocked />;\n }\n\n const poll = message.poll_id && client.polls.fromState(message.poll_id);\n\n const memberCount = Object.keys(channel?.state?.members ?? {}).length;\n const hasAttachment = !isDeleted && messageHasAttachments(message);\n const hasSingleAttachment = !isDeleted && messageHasSingleAttachment(message);\n const hasGiphyAttachment = !isDeleted && messageHasGiphyAttachment(message);\n const hasReactions = !isDeleted && messageHasReactions(message);\n const hasQuotedMessage = !isDeleted && messageHasQuotedMessage(message);\n const textHasEmojisOnly = !isDeleted && messageTextHasEmojisOnly(message);\n\n const allowRetry = isMessageErrorRetryable(message);\n const isBounced = isMessageBounced(message);\n const isEdited = isMessageEdited(message) && !isAIGenerated;\n\n const showMetadata = !groupedByUser || endOfGroup;\n const showReplyCountButton = !threadList && !!message.reply_count;\n\n const rootClassName = clsx(\n 'str-chat__message',\n `str-chat__message--${message.type}`,\n `str-chat__message--${message.status}`,\n {\n 'str-chat__message--has-attachment': hasAttachment,\n 'str-chat__message--has-giphy-attachment': hasGiphyAttachment,\n 'str-chat__message--has-no-text': !message.text,\n 'str-chat__message--has-quoted-message': hasQuotedMessage,\n 'str-chat__message--has-single-attachment': hasSingleAttachment,\n 'str-chat__message--has-text': !!message.text,\n 'str-chat__message--highlighted': highlighted,\n 'str-chat__message--is-emoji-only': textHasEmojisOnly,\n [`str-chat__message--is-emoji-only-count-${countEmojis(message.text)}`]:\n textHasEmojisOnly,\n 'str-chat__message--me': isMyMessage(),\n 'str-chat__message--other': !isMyMessage(),\n 'str-chat__message--pinned': message.pinned,\n 'str-chat__message--with-avatar': (() => {\n if (!message.user) return false;\n if (showAvatar === 'incoming') return !isMyMessage();\n if (showAvatar === 'outgoing') return isMyMessage();\n return showAvatar;\n })(),\n 'str-chat__message--with-reactions': hasReactions,\n 'str-chat__message-send-can-be-retried':\n message?.status === 'failed' && message?.error?.status !== 403,\n 'str-chat__message-with-thread-link': showReplyCountButton,\n 'str-chat__virtual-message__wrapper--end': endOfGroup,\n 'str-chat__virtual-message__wrapper--first': firstOfGroup,\n 'str-chat__virtual-message__wrapper--group': groupedByUser,\n },\n );\n\n let handleClick: (() => void) | undefined;\n\n if (isBounced) {\n handleClick = () => setIsBounceDialogOpen(true);\n }\n\n const isMessageInnerInteractive = !!handleClick;\n const messageInnerAriaLabel = isMessageInnerInteractive\n ? t('aria/Review bounced message')\n : undefined;\n\n const handleMessageInnerKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (!handleClick || (event.key !== 'Enter' && event.key !== ' ')) return;\n\n event.preventDefault();\n handleClick();\n };\n\n return (\n <>\n {isBounceDialogOpen && (\n <MessageBounceModal\n MessageBouncePrompt={MessageBouncePrompt}\n onClose={() => setIsBounceDialogOpen(false)}\n open={isBounceDialogOpen}\n />\n )}\n <div className={rootClassName} key={message.id}>\n {message.pinned && <PinIndicator message={message} />}\n {message.show_in_channel && <MessageAlsoSentInChannelIndicator />}\n {!!reminder && <ReminderNotification reminder={reminder} />}\n <MessageTranslationIndicator message={message} />\n {message.user && (\n <Avatar\n {...extractDisplayInfo({ user: message.user ?? undefined })}\n className='str-chat__avatar--with-border'\n onClick={onUserClick}\n onMouseOver={onUserHover}\n size='md'\n />\n )}\n <div\n aria-label={messageInnerAriaLabel}\n className={clsx('str-chat__message-inner', {\n 'str-chat__message-inner--error': allowRetry || isBounced,\n })}\n data-testid='message-inner'\n onClick={handleClick}\n onKeyDown={isMessageInnerInteractive ? handleMessageInnerKeyDown : undefined}\n role={isMessageInnerInteractive ? 'button' : undefined}\n tabIndex={isMessageInnerInteractive ? 0 : undefined}\n >\n {!isDeleted && <MessageActions />}\n {showReplyCountButton && (\n <MessageRepliesCountButton\n onClick={handleOpenThread}\n reply_count={message.reply_count}\n thread_participants={message.thread_participants}\n />\n )}\n {isDeleted ? (\n <MessageDeletedBubble />\n ) : (\n <>\n <MessageBubble>\n {poll && <Poll poll={poll} />}\n {message.quoted_message && <QuotedMessage />}\n {finalAttachments?.length ? (\n <Attachment\n actionHandler={handleAction}\n attachments={finalAttachments}\n />\n ) : null}\n {isAIGenerated ? (\n <StreamedMessageText message={message} renderText={renderText} />\n ) : (\n <MessageText message={message} renderText={renderText} />\n )}\n </MessageBubble>\n <div className='str-chat__message-reactions-host'>\n {hasReactions && <MessageReactions reverse />}\n </div>\n <div className='str-chat__message-error-indicator'>\n <ErrorBadge />\n </div>\n </>\n )}\n </div>\n {showMetadata && (\n <div className='str-chat__message-metadata'>\n <MessageStatus />\n {!isMyMessage() && !!message.user && memberCount > 2 && (\n <span className='str-chat__message-metadata__name'>\n {message.user.name || message.user.id}\n </span>\n )}\n <MessageTimestamp customClass='str-chat__message-metadata__timestamp' />\n {!isDeleted && isEdited && <MessageEditedIndicator />}\n </div>\n )}\n </div>\n </>\n );\n};\n\nconst MemoizedMessageUI = React.memo(\n MessageUIWithContext,\n areMessageUIPropsEqual,\n) as typeof MessageUIWithContext;\n\n/**\n * The default UI component that renders a message and receives functionality and logic from the MessageContext.\n */\nexport const MessageUI = (props: MessageUIComponentProps) => {\n const messageContext = useMessageContext('MessageUI');\n\n return <MemoizedMessageUI {...messageContext} {...props} />;\n};\n","import React, { useCallback, useMemo } from 'react';\n\nimport {\n useActionHandler,\n useDeleteHandler,\n useFlagHandler,\n useMarkUnreadHandler,\n useMentionsHandler,\n useMuteHandler,\n useOpenThreadHandler,\n usePinHandler,\n useReactionHandler,\n useReactionsFetcher,\n useRetryHandler,\n useUserHandler,\n useUserRole,\n} from './hooks';\nimport { areMessagePropsEqual, getMessageActions, MESSAGE_ACTIONS } from './utils';\n\nimport type { MessageContextValue } from '../../context';\nimport {\n MessageProvider,\n useChannelStateContext,\n useChatContext,\n useComponentContext,\n useMessageTranslationViewContext,\n} from '../../context';\n\nimport { MessageUI as DefaultMessageUI } from './MessageUI';\n\nimport type { MessageProps } from './types';\n\ntype MessagePropsToOmit =\n | 'onMentionsClick'\n | 'onMentionsHover'\n | 'openThread'\n | 'retrySendMessage';\n\ntype MessageContextPropsToPick =\n | 'handleAction'\n | 'handleDelete'\n | 'handleFetchReactions'\n | 'handleFlag'\n | 'handleMarkUnread'\n | 'handleMute'\n | 'handleOpenThread'\n | 'handlePin'\n | 'handleReaction'\n | 'handleRetry'\n | 'mutes'\n | 'onMentionsClickMessage'\n | 'onMentionsHoverMessage'\n | 'reactionDetailsSort'\n | 'sortReactions';\n\ntype MessageWithContextProps = Omit<MessageProps, MessagePropsToOmit> &\n Pick<MessageContextValue, MessageContextPropsToPick> & {\n canPin: boolean;\n userRoles: ReturnType<typeof useUserRole>;\n };\n\nconst MessageWithContext = (props: MessageWithContextProps) => {\n const {\n canPin,\n Message: propMessage,\n message,\n messageActions = Object.keys(MESSAGE_ACTIONS),\n onUserClick: propOnUserClick,\n onUserHover: propOnUserHover,\n userRoles,\n } = props;\n\n const { client, isMessageAIGenerated } = useChatContext('Message');\n const { channelConfig, read } = useChannelStateContext('Message');\n const {\n Message: contextMessage = DefaultMessageUI,\n // TODO: remove this passthrough once we drop Message from the ComponentContext\n MessageUI: contextMessageUI = contextMessage,\n } = useComponentContext('Message');\n const { getTranslationView, setTranslationView: setTranslationViewInContext } =\n useMessageTranslationViewContext();\n\n const translationView = getTranslationView(message.id, !!message.i18n);\n const setTranslationView = useCallback(\n (view: 'original' | 'translated') => setTranslationViewInContext(message.id, view),\n [message.id, setTranslationViewInContext],\n );\n\n const actionsEnabled = message.type === 'regular' && message.status === 'received';\n const MessageUIComponent = propMessage ?? contextMessageUI;\n\n const { onUserClick, onUserHover } = useUserHandler(message, {\n onUserClickHandler: propOnUserClick,\n onUserHoverHandler: propOnUserHover,\n });\n\n const {\n canDelete,\n canEdit,\n canFlag,\n canMarkUnread,\n canMute,\n canQuote,\n canReact,\n canReply,\n isMyMessage,\n } = userRoles;\n\n const messageIsUnread = useMemo(\n () =>\n !!(\n !isMyMessage &&\n client.user?.id &&\n read &&\n (!read[client.user.id] ||\n (message?.created_at &&\n new Date(message.created_at).getTime() >\n read[client.user.id].last_read.getTime()))\n ),\n [client, isMyMessage, message.created_at, read],\n );\n\n const messageActionsHandler = useCallback(\n () =>\n getMessageActions(\n messageActions,\n {\n canDelete,\n canEdit,\n canFlag,\n canMarkUnread,\n canMute,\n canPin,\n canQuote,\n canReact,\n canReply,\n },\n channelConfig,\n ),\n\n [\n messageActions,\n canDelete,\n canEdit,\n canFlag,\n canMarkUnread,\n canMute,\n canPin,\n canQuote,\n canReact,\n canReply,\n channelConfig,\n ],\n );\n\n const {\n canPin: canPinPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n messageActions: messageActionsPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n onUserClick: onUserClickPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n onUserHover: onUserHoverPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n userRoles: userRolesPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n ...rest\n } = props;\n\n const messageContextValue: MessageContextValue = {\n ...rest,\n actionsEnabled,\n getMessageActions: messageActionsHandler,\n isMessageAIGenerated,\n isMyMessage: () => isMyMessage,\n messageIsUnread,\n onUserClick,\n onUserHover,\n setTranslationView,\n translationView,\n };\n\n return (\n <MessageProvider value={messageContextValue}>\n <MessageUIComponent />\n </MessageProvider>\n );\n};\n\nconst MemoizedMessage = React.memo(\n MessageWithContext,\n areMessagePropsEqual,\n) as typeof MessageWithContext;\n\n/**\n * The Message component is a context provider which implements all the logic required for rendering\n * an individual message. The actual UI of the message is delegated via the Message prop on Channel.\n */\nexport const Message = (props: MessageProps) => {\n const {\n closeReactionSelectorOnClick,\n disableQuotedMessages,\n message,\n onMentionsClick: propOnMentionsClick,\n onMentionsHover: propOnMentionsHover,\n openThread: propOpenThread,\n reactionDetailsSort,\n retrySendMessage: propRetrySendMessage,\n sortReactions,\n } = props;\n\n const { highlightedMessageId, mutes } = useChannelStateContext('Message');\n\n const handleAction = useActionHandler(message);\n const handleOpenThread = useOpenThreadHandler(message, propOpenThread);\n const handleReaction = useReactionHandler(message);\n const handleRetry = useRetryHandler(propRetrySendMessage);\n const userRoles = useUserRole(message, disableQuotedMessages);\n\n const handleFetchReactions = useReactionsFetcher(message);\n\n const handleDelete = useDeleteHandler(message);\n\n const handleFlag = useFlagHandler(message);\n\n const handleMarkUnread = useMarkUnreadHandler(message);\n\n const handleMute = useMuteHandler(message);\n\n const { onMentionsClick, onMentionsHover } = useMentionsHandler(message, {\n onMentionsClick: propOnMentionsClick,\n onMentionsHover: propOnMentionsHover,\n });\n\n const { canPin, handlePin } = usePinHandler(message);\n\n const highlighted = highlightedMessageId === message.id;\n\n return (\n <MemoizedMessage\n additionalMessageComposerProps={props.additionalMessageComposerProps}\n autoscrollToBottom={props.autoscrollToBottom}\n canPin={canPin}\n closeReactionSelectorOnClick={closeReactionSelectorOnClick}\n deliveredTo={props.deliveredTo}\n disableQuotedMessages={props.disableQuotedMessages}\n formatDate={props.formatDate}\n groupStyles={props.groupStyles}\n handleAction={handleAction}\n handleDelete={handleDelete}\n handleFetchReactions={handleFetchReactions}\n handleFlag={handleFlag}\n handleMarkUnread={handleMarkUnread}\n handleMute={handleMute}\n handleOpenThread={handleOpenThread}\n handlePin={handlePin}\n handleReaction={handleReaction}\n handleRetry={handleRetry}\n highlighted={highlighted}\n initialMessage={props.initialMessage}\n lastOwnMessage={props.lastOwnMessage}\n lastReceivedId={props.lastReceivedId}\n message={message}\n Message={props.Message}\n messageActions={props.messageActions}\n messageListRect={props.messageListRect}\n mutes={mutes}\n onMentionsClickMessage={onMentionsClick}\n onMentionsHoverMessage={onMentionsHover}\n onUserClick={props.onUserClick}\n onUserHover={props.onUserHover}\n reactionDetailsSort={reactionDetailsSort}\n readBy={props.readBy}\n renderText={props.renderText}\n returnAllReadData={props.returnAllReadData}\n sortReactions={sortReactions}\n threadList={props.threadList}\n unsafeHTML={props.unsafeHTML}\n userRoles={userRoles}\n />\n );\n};\n","import React from 'react';\n\nimport { Message } from '../Message/Message';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type GiphyPreviewMessageProps = {\n message: LocalMessage;\n};\n\nexport const GiphyPreviewMessage = (props: GiphyPreviewMessageProps) => {\n const { message } = props;\n\n return (\n <div className='giphy-preview-message'>\n <Message message={message} />\n </div>\n );\n};\n","import { useMemo } from 'react';\n\nimport type { GroupStyle, ProcessMessagesParams, RenderedMessage } from '../../utils';\nimport { getGroupStyles, insertIntro, processMessages } from '../../utils';\n\nimport { useChatContext } from '../../../../context/ChatContext';\nimport { useComponentContext } from '../../../../context/ComponentContext';\n\nimport type { Channel, LocalMessage } from 'stream-chat';\n\nexport const useEnrichedMessages = (args: {\n channel: Channel;\n disableDateSeparator: boolean;\n hideDeletedMessages: boolean;\n hideNewMessageSeparator: boolean;\n messages: LocalMessage[];\n noGroupByUser: boolean;\n groupStyles?: (\n message: RenderedMessage,\n previousMessage: RenderedMessage,\n nextMessage: RenderedMessage,\n noGroupByUser: boolean,\n maxTimeBetweenGroupedMessages?: number,\n ) => GroupStyle;\n headerPosition?: number;\n maxTimeBetweenGroupedMessages?: number;\n reviewProcessedMessage?: ProcessMessagesParams['reviewProcessedMessage'];\n}) => {\n const {\n channel,\n disableDateSeparator,\n groupStyles,\n headerPosition,\n hideDeletedMessages,\n hideNewMessageSeparator,\n maxTimeBetweenGroupedMessages,\n messages,\n noGroupByUser,\n reviewProcessedMessage,\n } = args;\n\n const { client } = useChatContext('useEnrichedMessages');\n const { HeaderComponent } = useComponentContext('useEnrichedMessages');\n\n const lastRead = useMemo(() => channel.lastRead?.(), [channel]);\n\n const enableDateSeparator = !disableDateSeparator;\n\n let messagesWithDates =\n !enableDateSeparator && !hideDeletedMessages && hideNewMessageSeparator\n ? messages\n : processMessages({\n enableDateSeparator,\n hideDeletedMessages,\n hideNewMessageSeparator,\n lastRead,\n messages,\n reviewProcessedMessage,\n userId: client.userID || '',\n });\n\n if (HeaderComponent) {\n messagesWithDates = insertIntro(messagesWithDates, headerPosition);\n }\n\n const groupStylesFn = groupStyles || getGroupStyles;\n const messageGroupStyles = useMemo(\n () =>\n messagesWithDates.reduce<Record<string, GroupStyle>>((acc, message, i) => {\n const style = groupStylesFn(\n message,\n messagesWithDates[i - 1],\n messagesWithDates[i + 1],\n noGroupByUser,\n maxTimeBetweenGroupedMessages,\n );\n if (style) acc[message.id] = style;\n return acc;\n }, {}),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [maxTimeBetweenGroupedMessages, messagesWithDates, noGroupByUser],\n );\n\n return { messageGroupStyles, messages: messagesWithDates };\n};\n","import { useCallback, useEffect, useState } from 'react';\nimport throttle from 'lodash.throttle';\n\nimport type { RenderedMessage } from '../../utils';\n\nconst DATE_SEPARATOR_SELECTOR =\n '.str-chat__date-separator:not(.str-chat__date-separator--floating)';\nconst THROTTLE_MS = 100;\n\nexport type UseFloatingDateSeparatorMessageListParams = {\n disableDateSeparator: boolean;\n listElement: HTMLDivElement | null;\n processedMessages: RenderedMessage[];\n};\n\nexport type UseFloatingDateSeparatorMessageListResult = {\n floatingDate: Date | null;\n showFloatingDate: boolean;\n};\n\n/**\n * For non-virtualized MessageList: keeps the floating date synced with the\n * separator currently pinned to the top boundary of the list viewport.\n */\nexport const useFloatingDateSeparatorMessageList = ({\n disableDateSeparator,\n listElement,\n processedMessages,\n}: UseFloatingDateSeparatorMessageListParams): UseFloatingDateSeparatorMessageListResult => {\n const [state, setState] = useState<{ date: Date | null; visible: boolean }>({\n date: null,\n visible: false,\n });\n\n const update = useCallback(() => {\n if (disableDateSeparator || !listElement || processedMessages.length === 0) {\n setState({ date: null, visible: false });\n return;\n }\n\n const separators = listElement.querySelectorAll<HTMLElement>(DATE_SEPARATOR_SELECTOR);\n if (separators.length === 0) {\n setState({ date: null, visible: false });\n return;\n }\n\n const containerRect = listElement.getBoundingClientRect();\n let bestDate: Date | null = null;\n let bestTop = -Infinity;\n\n for (const el of separators) {\n const rect = el.getBoundingClientRect();\n const dataDate = el.getAttribute('data-date');\n if (!dataDate) continue;\n\n const isAtOrAboveTopBoundary = rect.top <= containerRect.top;\n\n if (isAtOrAboveTopBoundary && rect.top > bestTop) {\n bestTop = rect.top;\n const d = new Date(dataDate);\n if (!isNaN(d.getTime())) bestDate = d;\n }\n }\n\n setState({\n date: bestDate,\n visible: bestDate !== null,\n });\n }, [disableDateSeparator, listElement, processedMessages]);\n\n useEffect(() => {\n if (!listElement) return;\n\n const throttled = throttle(update, THROTTLE_MS);\n\n throttled();\n listElement.addEventListener('scroll', throttled);\n\n if (typeof ResizeObserver === 'undefined') {\n return () => {\n listElement.removeEventListener('scroll', throttled);\n throttled.cancel();\n };\n }\n\n const resizeObserver = new ResizeObserver(throttled);\n resizeObserver.observe(listElement);\n\n return () => {\n listElement.removeEventListener('scroll', throttled);\n resizeObserver.disconnect();\n throttled.cancel();\n };\n }, [listElement, update]);\n\n return {\n floatingDate: state.date,\n showFloatingDate: state.visible,\n };\n};\n","import { useMemo } from 'react';\nimport type { Channel, LocalMessage, UserResponse } from 'stream-chat';\n\ntype UseLastReadDataParams = {\n channel: Channel;\n messages: LocalMessage[];\n returnAllReadData: boolean;\n lastOwnMessage?: LocalMessage;\n};\n\nexport const useLastReadData = (props: UseLastReadDataParams) => {\n const { channel, lastOwnMessage, messages, returnAllReadData } = props;\n\n return useMemo(() => {\n if (returnAllReadData) {\n return messages.reduce(\n (acc, msg) => {\n acc[msg.id] = channel.messageReceiptsTracker.readersForMessage({\n msgId: msg.id,\n timestampMs: msg.created_at.getTime(),\n });\n return acc;\n },\n {} as Record<string, UserResponse[]>,\n );\n }\n\n if (!lastOwnMessage) return {};\n return {\n [lastOwnMessage.id]: channel.messageReceiptsTracker.readersForMessage({\n msgId: lastOwnMessage.id,\n timestampMs: lastOwnMessage.created_at.getTime(),\n }),\n };\n }, [channel, lastOwnMessage, messages, returnAllReadData]);\n};\n","import { useCallback, useEffect, useState } from 'react';\nimport type { Channel, LocalMessage, UserResponse } from 'stream-chat';\n\ntype UseLastDeliveredDataParams = {\n channel: Channel;\n messages: LocalMessage[];\n returnAllReadData: boolean;\n lastOwnMessage?: LocalMessage;\n};\n\nexport const useLastDeliveredData = (\n props: UseLastDeliveredDataParams,\n): Record<string, UserResponse[]> => {\n const { channel, lastOwnMessage, messages, returnAllReadData } = props;\n\n const calculateForAll = useCallback(\n () =>\n messages.reduce(\n (acc, msg) => {\n acc[msg.id] = channel.messageReceiptsTracker.deliveredForMessage({\n msgId: msg.id,\n timestampMs: msg.created_at.getTime(),\n });\n return acc;\n },\n {} as Record<string, UserResponse[]>,\n ),\n [channel, messages],\n );\n\n const calculateForLastOwn = useCallback(() => {\n if (!lastOwnMessage) return {};\n return {\n [lastOwnMessage.id]: channel.messageReceiptsTracker.deliveredForMessage({\n msgId: lastOwnMessage.id,\n timestampMs: lastOwnMessage.created_at.getTime(),\n }),\n };\n }, [channel, lastOwnMessage]);\n\n const [deliveredTo, setDeliveredTo] = useState<Record<string, UserResponse[]>>(\n returnAllReadData ? calculateForAll : calculateForLastOwn,\n );\n\n useEffect(() => {\n if (!returnAllReadData) return;\n setDeliveredTo(calculateForAll);\n return channel.on('message.delivered', () => setDeliveredTo(calculateForAll))\n .unsubscribe;\n }, [channel, calculateForAll, returnAllReadData]);\n\n useEffect(() => {\n if (returnAllReadData) return;\n else setDeliveredTo(calculateForLastOwn);\n return channel.on('message.delivered', () => setDeliveredTo(calculateForLastOwn))\n .unsubscribe;\n }, [channel, calculateForLastOwn, returnAllReadData]);\n\n return deliveredTo;\n};\n","import type React from 'react';\nimport { useMemo } from 'react';\n\nimport { useLastReadData } from '../useLastReadData';\nimport type { GroupStyle, RenderedMessage } from '../../utils';\nimport { getLastReceived } from '../../utils';\n\nimport { useChatContext } from '../../../../context/ChatContext';\nimport { useComponentContext } from '../../../../context/ComponentContext';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { ChannelUnreadUiState } from '../../../../types/types';\nimport type { MessageRenderer, SharedMessageProps } from '../../renderMessages';\nimport { useChannelStateContext } from '../../../../context';\nimport { useLastDeliveredData } from '../useLastDeliveredData';\n\ntype UseMessageListElementsProps = {\n messages: LocalMessage[];\n enrichedMessages: RenderedMessage[];\n internalMessageProps: SharedMessageProps;\n messageGroupStyles: Record<string, GroupStyle>;\n renderMessages: MessageRenderer;\n returnAllReadData: boolean;\n threadList: boolean;\n channelUnreadUiState?: ChannelUnreadUiState;\n lastOwnMessage?: LocalMessage;\n};\n\nexport const useMessageListElements = (props: UseMessageListElementsProps) => {\n const {\n channelUnreadUiState,\n enrichedMessages,\n internalMessageProps,\n lastOwnMessage,\n messageGroupStyles,\n messages,\n renderMessages,\n returnAllReadData,\n threadList,\n } = props;\n\n const { customClasses } = useChatContext('useMessageListElements');\n const { channel } = useChannelStateContext();\n const components = useComponentContext('useMessageListElements');\n\n // get the readData, but only for messages submitted by the user themselves\n const readData = useLastReadData({\n channel,\n lastOwnMessage,\n messages,\n returnAllReadData,\n });\n\n const ownMessagesDeliveredToOthers = useLastDeliveredData({\n channel,\n lastOwnMessage,\n messages,\n returnAllReadData,\n });\n\n const lastReceivedMessageId = useMemo(\n () => getLastReceived(enrichedMessages),\n [enrichedMessages],\n );\n\n const elements: React.ReactNode[] = useMemo(\n () =>\n renderMessages({\n channelUnreadUiState,\n components,\n customClasses,\n lastOwnMessage,\n lastReceivedMessageId,\n messageGroupStyles,\n messages: enrichedMessages,\n ownMessagesDeliveredToOthers,\n readData,\n sharedMessageProps: { ...internalMessageProps, returnAllReadData, threadList },\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n enrichedMessages,\n internalMessageProps,\n lastOwnMessage,\n lastReceivedMessageId,\n messageGroupStyles,\n channelUnreadUiState,\n readData,\n renderMessages,\n returnAllReadData,\n threadList,\n ],\n );\n\n return elements;\n};\n","import { useLayoutEffect, useRef } from 'react';\n\nimport { useChatContext } from '../../../../context/ChatContext';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type ContainerMeasures = {\n offsetHeight: number;\n scrollHeight: number;\n scrollTop: number;\n};\n\nexport type UseMessageListScrollManagerParams = {\n captureAnchor: () => { id: string; offsetTop: number } | null;\n disableScrollManagement?: boolean;\n justReachedLatestMessageSet?: boolean;\n loadMoreScrollThreshold: number;\n loadingMore?: boolean;\n messages: LocalMessage[];\n onScrollBy: (scrollBy: number) => void;\n onScrollToTop: () => void;\n restoreAnchor: (anchor: { id: string; offsetTop: number }) => void;\n scrollContainerMeasures: () => ContainerMeasures;\n scrolledUpThreshold: number;\n scrollToBottom: () => void;\n showNewMessages: () => void;\n};\n\n// Tracks how the current older-page pagination cycle should restore the viewport\n// once messages are prepended. The mode is chosen when loading starts and cleared\n// after the prepend has been handled.\n//\n// Modes:\n// - `idle`: there is no active older-page restoration strategy\n// - `stick-to-top`: pagination started from the absolute top, so keep the newly\n// loaded page pinned to the top of the container\n// - `preserve-anchor`: pagination started near the top but not at the absolute\n// top, so restore the captured anchor message to its previous viewport offset\ntype OlderPaginationState =\n | { anchor: null; mode: 'idle' }\n | { anchor: null; mode: 'stick-to-top' }\n | { anchor: { id: string; offsetTop: number }; mode: 'preserve-anchor' };\n\n// An \"anchor\" is the currently visible message row we want to keep visually pinned\n// to the same spot in the viewport while older messages are inserted above it.\n// It stores:\n// - `id`: which rendered message row should stay stable\n// - `offsetTop`: how far that row sits from the top edge of the scroll container\n//\n// After a prepend, the DOM shifts downward. Restoring the anchor means finding the\n// same message row again and correcting scrollTop until it returns to that offset.\n\n// When all previous messages appear at the start of the new array, the growth\n// happened at the bottom of the list.\nconst messageIdsMatchAsPrefix = (\n prevMessages: LocalMessage[],\n newMessages: LocalMessage[],\n) => prevMessages.every((message, index) => message.id === newMessages[index]?.id);\n\n// When all previous messages appear at the end of the new array, the growth\n// happened at the top of the list.\nconst messageIdsMatchAsSuffix = (\n prevMessages: LocalMessage[],\n newMessages: LocalMessage[],\n) =>\n prevMessages.every(\n (message, index) =>\n message.id === newMessages[newMessages.length - prevMessages.length + index]?.id,\n );\n\n/**\n * Coordinates scroll-position preservation when the rendered message array changes.\n *\n * The hook distinguishes three broad cases:\n * 1. Older-page pagination prepends messages at the top of the list.\n * This path either sticks to the top of the new page or restores a captured\n * message anchor, depending on where the user was when pagination started.\n * 2. Newer messages append to the bottom of the list.\n * This path preserves normal chat behavior by auto-scrolling only when the\n * user was already near the bottom or the appended message is the user's own.\n * 3. Disjunct/overlapping page switches.\n * These intentionally bypass prepend heuristics because the old and new arrays\n * are not comparable as a single contiguous list.\n */\nexport function useMessageListScrollManager(params: UseMessageListScrollManagerParams) {\n const {\n captureAnchor,\n disableScrollManagement = false,\n justReachedLatestMessageSet = false,\n loadingMore = false,\n loadMoreScrollThreshold,\n onScrollBy,\n onScrollToTop,\n restoreAnchor,\n scrollContainerMeasures,\n scrolledUpThreshold,\n scrollToBottom,\n showNewMessages,\n } = params;\n\n const { client } = useChatContext('useMessageListScrollManager');\n\n const measures = useRef<ContainerMeasures>({\n offsetHeight: 0,\n scrollHeight: 0,\n scrollTop: 0,\n });\n const messages = useRef<LocalMessage[]>(undefined);\n const olderPaginationState = useRef<OlderPaginationState>({\n anchor: null,\n mode: 'idle',\n });\n const previousLoadingMoreRef = useRef(loadingMore);\n const scrollTop = useRef(0);\n\n useLayoutEffect(() => {\n if (disableScrollManagement) {\n // Even while management is disabled we still refresh the cached list shape,\n // so the next enabled render compares against the most recent DOM state.\n messages.current = params.messages;\n measures.current = scrollContainerMeasures();\n previousLoadingMoreRef.current = loadingMore;\n return;\n }\n\n const prevMeasures = measures.current;\n const prevMessages = messages.current;\n const newMessages = params.messages;\n const lastNewMessage = newMessages[newMessages.length - 1] || {};\n const lastPrevMessage = prevMessages?.[prevMessages.length - 1];\n const newMeasures = scrollContainerMeasures();\n const startedLoadingOlder = loadingMore && !previousLoadingMoreRef.current;\n const finishedLoadingOlder = !loadingMore && previousLoadingMoreRef.current;\n\n if (startedLoadingOlder) {\n // Read the live DOM scroll position instead of the cached ref so we get\n // the correct value even when scrollToBottom() has been called but the\n // async scroll event hasn't updated the ref yet (common on initial mount).\n const liveMeasures = scrollContainerMeasures();\n const hasOverflow = liveMeasures.scrollHeight > liveMeasures.offsetHeight;\n const liveScrollTop = liveMeasures.scrollTop;\n\n // Older-page pagination uses one of three modes:\n // - `stick-to-top`: user hit the absolute top and wants to keep reading upward\n // - `preserve-anchor`: user was only near the top, so keep the same message in view\n // - `idle`: no restoration needed for this load cycle\n //\n // When the container doesn't overflow yet (e.g. content hasn't reached its\n // final height due to font loading) the scroll position is meaningless, so\n // default to idle to avoid a false stick-to-top that would jump the list.\n if (!hasOverflow) {\n olderPaginationState.current = {\n anchor: null,\n mode: 'idle',\n };\n } else if (liveScrollTop <= 1) {\n olderPaginationState.current = {\n anchor: null,\n mode: 'stick-to-top',\n };\n } else if (liveScrollTop < loadMoreScrollThreshold) {\n const capturedAnchor = captureAnchor();\n if (capturedAnchor) {\n olderPaginationState.current = {\n anchor: capturedAnchor,\n mode: 'preserve-anchor',\n };\n } else {\n olderPaginationState.current = {\n anchor: null,\n mode: 'idle',\n };\n }\n } else {\n olderPaginationState.current = {\n anchor: null,\n mode: 'idle',\n };\n }\n }\n\n // Evaluate bottom proximity from the previous render, before any new content\n // changes the list height and invalidates the prior bottom distance.\n const wasAtBottom =\n prevMeasures.scrollHeight - prevMeasures.offsetHeight - scrollTop.current <\n scrolledUpThreshold;\n\n if (typeof prevMessages !== 'undefined') {\n if (prevMessages.length < newMessages.length) {\n const messagesAddedToTop = messageIdsMatchAsSuffix(prevMessages, newMessages);\n const messagesAddedToBottom = messageIdsMatchAsPrefix(prevMessages, newMessages);\n\n // A clean prepend means older messages were inserted ahead of the current\n // viewport. Restore the viewport according to the mode chosen when loading\n // started, then clear the mode for the next pagination cycle.\n if (messagesAddedToTop) {\n const preservedAnchor =\n olderPaginationState.current.mode === 'preserve-anchor' &&\n olderPaginationState.current.anchor &&\n (finishedLoadingOlder || loadingMore)\n ? olderPaginationState.current.anchor\n : null;\n\n // When pagination was triggered from absolute top, keep the newly\n // loaded page pinned to top instead of restoring the old viewport.\n if (olderPaginationState.current.mode === 'stick-to-top') {\n onScrollToTop();\n } else if (preservedAnchor) {\n restoreAnchor(preservedAnchor);\n } else if (scrollTop.current < loadMoreScrollThreshold) {\n // Fallback for prepends when there is no stable DOM anchor to restore.\n // This is less accurate than anchor restoration, but still avoids a full\n // jump by compensating for the inserted page height.\n const listHeightDelta = newMeasures.scrollHeight - prevMeasures.scrollHeight;\n onScrollBy(listHeightDelta);\n }\n\n olderPaginationState.current = {\n anchor: null,\n mode: 'idle',\n };\n }\n // A clean append means the list grew downward. Preserve the usual chat\n // semantics: auto-scroll only for self-sent messages or when the user was\n // already close enough to bottom.\n else if (messagesAddedToBottom) {\n if (justReachedLatestMessageSet) {\n // Merging into the latest page is handled by dedicated logic higher up.\n // Returning here avoids undoing that behavior with a normal append scroll.\n messages.current = newMessages;\n measures.current = newMeasures;\n previousLoadingMoreRef.current = loadingMore;\n return;\n }\n\n const lastMessageIsFromCurrentUser = lastNewMessage.user?.id === client.userID;\n\n if (lastMessageIsFromCurrentUser || wasAtBottom) {\n scrollToBottom();\n } else {\n showNewMessages();\n }\n } else {\n // If the new page is neither a pure prepend nor a pure append, treat it as\n // a disjunct/overlapping page switch and avoid applying prepend heuristics.\n olderPaginationState.current = {\n anchor: null,\n mode: 'idle',\n };\n }\n }\n // message list length didn't change, but check if last message had reaction/reply update\n else {\n const hasNewReactions =\n lastPrevMessage?.latest_reactions?.length !==\n lastNewMessage.latest_reactions?.length;\n const hasNewReplies = lastPrevMessage?.reply_count !== lastNewMessage.reply_count;\n\n if ((hasNewReactions || hasNewReplies) && wasAtBottom) {\n scrollToBottom();\n }\n\n if (finishedLoadingOlder) {\n // Clear any older-page mode when the request ends without increasing the\n // rendered list size, so the next pagination cycle starts from a clean slate.\n olderPaginationState.current = {\n anchor: null,\n mode: 'idle',\n };\n }\n }\n }\n\n messages.current = newMessages;\n measures.current = newMeasures;\n previousLoadingMoreRef.current = loadingMore;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n captureAnchor,\n disableScrollManagement,\n justReachedLatestMessageSet,\n loadingMore,\n measures,\n messages,\n params.messages,\n restoreAnchor,\n scrollContainerMeasures,\n ]);\n\n return (\n scrollTopValue: number,\n getLatestAnchor: (() => { id: string; offsetTop: number } | null) | null = null,\n ) => {\n scrollTop.current = scrollTopValue;\n\n if (\n loadingMore &&\n getLatestAnchor &&\n olderPaginationState.current.mode === 'preserve-anchor'\n ) {\n // Keep the anchor fresh while the request is in flight so restoration matches\n // the latest viewport position if the user keeps scrolling before data arrives.\n // The getter keeps normal scroll events cheap by avoiding DOM anchor capture\n // unless anchor preservation is actually active.\n const latestAnchor = getLatestAnchor();\n if (!latestAnchor) return;\n\n olderPaginationState.current = {\n anchor: latestAnchor,\n mode: 'preserve-anchor',\n };\n }\n };\n}\n","import type React from 'react';\nimport { useCallback, useLayoutEffect, useRef, useState } from 'react';\n\nimport { useMessageListScrollManager } from './useMessageListScrollManager';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type UseScrollLocationLogicParams = {\n /** Disables automatic scroll-to-bottom updates after message changes. */\n disableAutoScrollToBottom?: boolean;\n /** Disables scroll-management adjustments (anchor restore, append/prepend handling). */\n disableScrollManagement?: boolean;\n /** True when there are newer messages to load beyond the currently rendered page. */\n hasMoreNewer: boolean;\n /** Scrollable message-list container element. */\n listElement: HTMLDivElement | null;\n /** Threshold used to detect older-page pagination proximity near the top. */\n loadMoreScrollThreshold: number;\n /** Indicates whether older-page pagination is currently in progress. */\n loadingMore?: boolean;\n /** Hard-disable all autoscroll behavior. */\n suppressAutoscroll: boolean;\n /** Current rendered message set used for scroll reconciliation. */\n messages?: LocalMessage[];\n /** Distance from bottom (px) considered as \"near bottom\". */\n scrolledUpThreshold?: number;\n};\n\n/**\n * Centralized scroll-position logic for MessageList.\n *\n * Responsibilities:\n * - Keep viewport stable during prepend/append pagination updates.\n * - Track whether the list is near bottom and expose that state to UI.\n * - Auto-scroll to bottom when appropriate while respecting suppression flags.\n * - Perform a short hydration settle pass so freshly loaded lists land at bottom.\n */\nexport const useScrollLocationLogic = (params: UseScrollLocationLogicParams) => {\n const {\n disableAutoScrollToBottom = false,\n disableScrollManagement = false,\n hasMoreNewer,\n listElement,\n loadingMore = false,\n loadMoreScrollThreshold,\n messages = [],\n scrolledUpThreshold = 200,\n suppressAutoscroll,\n } = params;\n\n const [hasNewMessages, setHasNewMessages] = useState(false);\n const [wrapperRect, setWrapperRect] = useState<DOMRect>();\n const previousHasMoreNewerRef = useRef(hasMoreNewer);\n const justReachedLatestMessageSet = previousHasMoreNewerRef.current && !hasMoreNewer;\n const skipNextAutoScrollRef = useRef(false);\n const isRestoringOlderAnchorRef = useRef(false);\n\n const [isMessageListScrolledToBottom, setIsMessageListScrolledToBottom] =\n useState(true);\n const closeToBottom = useRef(false);\n const closeToTop = useRef(false);\n const previousScrollTopRef = useRef(0);\n const previousMessagesLengthRef = useRef(messages.length);\n const previousDisableAutoScrollToBottomRef = useRef(disableAutoScrollToBottom);\n const previousDisableAutoScrollSettleRef = useRef(disableAutoScrollToBottom);\n const anchorRestoreCleanupRef = useRef<(() => void) | null>(null);\n\n const captureAnchor = useCallback(() => {\n if (!listElement) return null;\n\n const listRect = listElement.getBoundingClientRect();\n const listTop = listRect.top;\n const listBottom = listRect.bottom;\n const listCenter = listTop + listRect.height / 2;\n // Older-page pagination should track the top edge, while the generic\n // “keep this viewport stable” case works better from the center.\n const preferTopEdgeAnchor =\n loadingMore || listElement.scrollTop < loadMoreScrollThreshold;\n const messageElements = Array.from(\n listElement.querySelectorAll<HTMLElement>('[data-message-id]'),\n );\n const messageAnchors = messageElements.map((element) => {\n const rect = element.getBoundingClientRect();\n return {\n center: rect.top + rect.height / 2,\n element,\n offsetTop: rect.top - listTop,\n rect,\n };\n });\n\n const visibleMessageAnchors = messageAnchors.filter(\n ({ rect }) => rect.bottom > listTop && rect.top < listBottom,\n );\n\n const topEdgeAnchor = visibleMessageAnchors.reduce<\n (typeof visibleMessageAnchors)[number] | null\n >((closest, candidate) => {\n if (!closest || candidate.rect.top < closest.rect.top) {\n return candidate;\n }\n\n return closest;\n }, null);\n\n const centerAnchor =\n visibleMessageAnchors.find(\n ({ rect }) => rect.top <= listCenter && rect.bottom >= listCenter,\n ) ??\n visibleMessageAnchors.reduce<(typeof visibleMessageAnchors)[number] | null>(\n (closest, candidate) => {\n if (!closest) return candidate;\n\n const distance = Math.abs(candidate.center - listCenter);\n const closestDistance = Math.abs(closest.center - listCenter);\n\n return distance < closestDistance ? candidate : closest;\n },\n null,\n );\n\n const anchor =\n (preferTopEdgeAnchor ? topEdgeAnchor : centerAnchor) ?? messageAnchors[0];\n\n if (!anchor?.element.dataset.messageId) return null;\n\n return {\n id: anchor.element.dataset.messageId,\n offsetTop: anchor.offsetTop,\n };\n }, [listElement, loadMoreScrollThreshold, loadingMore]);\n\n const restoreAnchor = useCallback(\n (anchor: { id: string; offsetTop: number }) => {\n if (!listElement) return;\n\n anchorRestoreCleanupRef.current?.();\n\n let cancelled = false;\n let stableFrameCount = 0;\n let frameQueued = false;\n let resizeObserver: ResizeObserver | undefined;\n // eslint-disable-next-line prefer-const\n let settleTimeoutId: ReturnType<typeof setTimeout> | undefined;\n let animationFrameId: number | undefined;\n\n isRestoringOlderAnchorRef.current = true;\n\n const applyAnchor = () => {\n if (cancelled) return true;\n\n const anchorElement = listElement.querySelector<HTMLElement>(\n `[data-message-id='${anchor.id}']`,\n );\n if (!anchorElement) return true;\n\n const listTop = listElement.getBoundingClientRect().top;\n const nextOffsetTop = anchorElement.getBoundingClientRect().top - listTop;\n const offsetDelta = nextOffsetTop - anchor.offsetTop;\n\n if (Math.abs(offsetDelta) > 1) {\n listElement.scrollBy({ top: offsetDelta });\n return false;\n }\n\n return true;\n };\n\n const cleanup = () => {\n cancelled = true;\n frameQueued = false;\n isRestoringOlderAnchorRef.current = false;\n if (typeof animationFrameId !== 'undefined') {\n window.cancelAnimationFrame(animationFrameId);\n }\n if (settleTimeoutId) {\n clearTimeout(settleTimeoutId);\n }\n resizeObserver?.disconnect();\n };\n\n // Keep correcting against the same anchor until the DOM stops shifting.\n const queueNextFrame = () => {\n if (cancelled || frameQueued) return;\n frameQueued = true;\n animationFrameId = window.requestAnimationFrame(() => {\n frameQueued = false;\n const isStable = applyAnchor();\n stableFrameCount = isStable ? stableFrameCount + 1 : 0;\n\n if (stableFrameCount >= 2) {\n cleanup();\n return;\n }\n\n queueNextFrame();\n });\n };\n\n stableFrameCount = applyAnchor() ? 1 : 0;\n queueNextFrame();\n\n // Late media/layout updates can still move the anchor after the first\n // correction, so restart the settle check when the list resizes.\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => {\n stableFrameCount = 0;\n queueNextFrame();\n });\n resizeObserver.observe(listElement);\n }\n\n settleTimeoutId = setTimeout(() => {\n cleanup();\n }, 1200);\n\n anchorRestoreCleanupRef.current = cleanup;\n },\n [listElement],\n );\n\n useLayoutEffect(\n () => () => {\n anchorRestoreCleanupRef.current?.();\n },\n [],\n );\n\n const scrollToBottom = useCallback(\n (options?: ScrollToOptions) => {\n if (\n !listElement?.scrollTo ||\n hasMoreNewer ||\n isRestoringOlderAnchorRef.current ||\n justReachedLatestMessageSet ||\n suppressAutoscroll\n ) {\n return;\n }\n\n listElement.scrollTo({\n behavior: options?.behavior,\n top: listElement.scrollHeight,\n });\n setHasNewMessages(false);\n },\n [hasMoreNewer, justReachedLatestMessageSet, listElement, suppressAutoscroll],\n );\n\n /**\n * Keeps wrapper geometry up to date and handles the \"reached latest merged set\"\n * path where existing viewport position must be preserved.\n */\n useLayoutEffect(() => {\n const disableAutoScrollJustReleased =\n previousDisableAutoScrollToBottomRef.current && !disableAutoScrollToBottom;\n previousDisableAutoScrollToBottomRef.current = disableAutoScrollToBottom;\n\n // Re-enabling auto-scroll should not immediately force a jump to bottom.\n // This avoids snap-back after temporary suppression (e.g. jump-to-message).\n if (disableAutoScrollJustReleased) {\n return;\n }\n\n if (listElement) {\n setWrapperRect(listElement.getBoundingClientRect());\n }\n\n if (listElement && justReachedLatestMessageSet) {\n listElement.scrollTop = previousScrollTopRef.current;\n skipNextAutoScrollRef.current = true;\n return;\n }\n\n if (skipNextAutoScrollRef.current) {\n skipNextAutoScrollRef.current = false;\n return;\n }\n\n if (listElement && !disableAutoScrollToBottom && !isRestoringOlderAnchorRef.current) {\n scrollToBottom();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [disableAutoScrollToBottom, justReachedLatestMessageSet, listElement, hasMoreNewer]);\n\n /**\n * Short post-render bottom settle. This is intentionally small (immediate + 2 retries)\n * to catch late layout updates without keeping the list in a prolonged lock loop.\n */\n useLayoutEffect(() => {\n const disableAutoScrollJustReleased =\n previousDisableAutoScrollSettleRef.current && !disableAutoScrollToBottom;\n previousDisableAutoScrollSettleRef.current = disableAutoScrollToBottom;\n\n // Skip one settle cycle when auto-scroll suppression is released.\n // Without this guard, a jump-to-message flow can scroll to the target and then\n // get pulled back down by the delayed \"keep pinned to bottom\" retries\n // (80/260/420/900/1700ms), which looks like a snap-back to the latest message.\n // Letting this transition frame pass preserves the jump destination.\n if (disableAutoScrollJustReleased) {\n return;\n }\n\n if (\n !listElement ||\n disableAutoScrollToBottom ||\n hasMoreNewer ||\n suppressAutoscroll ||\n justReachedLatestMessageSet ||\n isRestoringOlderAnchorRef.current\n ) {\n return;\n }\n\n const initialDistanceToBottom =\n listElement.scrollHeight - (listElement.scrollTop + listElement.clientHeight);\n const messagesHydrated =\n previousMessagesLengthRef.current === 0 && messages.length > 0;\n\n if (initialDistanceToBottom > scrolledUpThreshold && !messagesHydrated) {\n return;\n }\n\n let keepPinnedToBottom = true;\n\n const maybeScrollToBottom = () => {\n if (keepPinnedToBottom) {\n scrollToBottom();\n }\n };\n\n maybeScrollToBottom();\n const settleDelays = [80, messagesHydrated ? 260 : 420, 900, 1700];\n const settleTimeoutIds = settleDelays.map((delay) =>\n setTimeout(maybeScrollToBottom, delay),\n );\n\n const stopKeepingPinnedToBottom = () => {\n keepPinnedToBottom = false;\n };\n\n // Any direct user interaction with the scroller disables the temporary\n // initial-load pin, so manual scrolling is never force-overridden.\n listElement.addEventListener('pointerdown', stopKeepingPinnedToBottom, {\n passive: true,\n });\n listElement.addEventListener('touchstart', stopKeepingPinnedToBottom, {\n passive: true,\n });\n listElement.addEventListener('wheel', stopKeepingPinnedToBottom, {\n passive: true,\n });\n listElement.addEventListener('keydown', stopKeepingPinnedToBottom);\n\n const pinWindowTimeoutId = setTimeout(() => {\n stopKeepingPinnedToBottom();\n }, 2200);\n\n return () => {\n settleTimeoutIds.forEach(clearTimeout);\n clearTimeout(pinWindowTimeoutId);\n listElement.removeEventListener('pointerdown', stopKeepingPinnedToBottom);\n listElement.removeEventListener('touchstart', stopKeepingPinnedToBottom);\n listElement.removeEventListener('wheel', stopKeepingPinnedToBottom);\n listElement.removeEventListener('keydown', stopKeepingPinnedToBottom);\n };\n }, [\n disableAutoScrollToBottom,\n hasMoreNewer,\n justReachedLatestMessageSet,\n listElement,\n messages.length,\n scrollToBottom,\n scrolledUpThreshold,\n suppressAutoscroll,\n ]);\n\n const updateScrollTop = useMessageListScrollManager({\n captureAnchor,\n disableScrollManagement: disableScrollManagement || isRestoringOlderAnchorRef.current,\n justReachedLatestMessageSet,\n loadingMore,\n loadMoreScrollThreshold,\n messages,\n onScrollBy: (scrollBy) => {\n listElement?.scrollBy({ top: scrollBy });\n },\n onScrollToTop: () => {\n if (!listElement) return;\n listElement.scrollTop = 0;\n },\n restoreAnchor,\n\n scrollContainerMeasures: () => ({\n offsetHeight: listElement?.offsetHeight || 0,\n scrollHeight: listElement?.scrollHeight || 0,\n scrollTop: listElement?.scrollTop || 0,\n }),\n scrolledUpThreshold,\n scrollToBottom,\n showNewMessages: () => setHasNewMessages(true),\n });\n\n useLayoutEffect(() => {\n previousHasMoreNewerRef.current = hasMoreNewer;\n }, [hasMoreNewer]);\n\n useLayoutEffect(() => {\n previousMessagesLengthRef.current = messages.length;\n }, [messages.length]);\n\n /**\n * Updates cached scroll metrics and bottom/top proximity state used by\n * notifications, autoscroll decisions, and paginator behavior.\n */\n const onScroll = useCallback(\n (event: React.UIEvent<HTMLDivElement>) => {\n const element = event.target as HTMLDivElement;\n const scrollTop = element.scrollTop;\n previousScrollTopRef.current = scrollTop;\n\n updateScrollTop(scrollTop, captureAnchor);\n\n const offsetHeight = element.offsetHeight;\n const scrollHeight = element.scrollHeight;\n const distanceToBottom = scrollHeight - (scrollTop + offsetHeight);\n const bottomEnterThreshold = Math.max(Math.floor(scrolledUpThreshold * 0.6), 24);\n\n const prevCloseToBottom = closeToBottom.current;\n closeToBottom.current = prevCloseToBottom\n ? distanceToBottom < scrolledUpThreshold\n : distanceToBottom < bottomEnterThreshold;\n closeToTop.current = scrollTop < scrolledUpThreshold;\n\n if (closeToBottom.current) {\n setHasNewMessages(false);\n }\n if (prevCloseToBottom && !closeToBottom.current) {\n setIsMessageListScrolledToBottom(false);\n } else if (!prevCloseToBottom && closeToBottom.current) {\n setIsMessageListScrolledToBottom(true);\n }\n },\n [captureAnchor, updateScrollTop, closeToTop, closeToBottom, scrolledUpThreshold],\n );\n\n return {\n hasNewMessages,\n isMessageListScrolledToBottom,\n onScroll,\n scrollToBottom,\n wrapperRect,\n };\n};\n","import React from 'react';\nimport type { PropsWithChildrenOnly } from '../../types/types';\n\nexport const MESSAGE_LIST_MAIN_PANEL_CLASS =\n 'str-chat__main-panel-inner str-chat__message-list-main-panel' as const;\n\nexport const MessageListMainPanel = ({ children }: PropsWithChildrenOnly) => (\n <div className={MESSAGE_LIST_MAIN_PANEL_CLASS}>{children}</div>\n);\n","import React from 'react';\nimport {\n useChannelActionContext,\n useComponentContextIcons,\n useTranslationContext,\n} from '../../context';\nimport { Button } from '../Button';\n\nexport const UNREAD_MESSAGE_SEPARATOR_CLASS = 'str-chat__unread-messages-separator';\n\nexport type UnreadMessagesSeparatorProps = {\n /**\n * Configuration parameter to determine, whether the unread count is to be shown on the component. Enabled by default.\n */\n showCount?: boolean;\n /**\n * The count of unread messages to be displayed if enabled.\n */\n unreadCount?: number;\n};\n\nexport const UnreadMessagesSeparator = ({\n showCount = true,\n unreadCount,\n}: UnreadMessagesSeparatorProps) => {\n const { IconXmark } = useComponentContextIcons();\n\n const { t } = useTranslationContext('UnreadMessagesSeparator');\n const { markRead } = useChannelActionContext();\n return (\n <div\n className={UNREAD_MESSAGE_SEPARATOR_CLASS}\n data-testid='unread-messages-separator'\n >\n <div className={'str-chat__unread-messages-separator__text'}>\n {unreadCount && showCount\n ? t('{{count}} unread', { count: unreadCount })\n : t('Unread messages')}\n </div>\n <Button\n appearance='ghost'\n aria-label={t('aria/Mark messages as read')}\n circular\n onClick={() => markRead()}\n size='sm'\n variant='secondary'\n >\n <IconXmark />\n </Button>\n </div>\n );\n};\n","import { useChannelStateContext } from '../../../../context';\nimport { useEffect, useRef, useState } from 'react';\nimport { MESSAGE_LIST_MAIN_PANEL_CLASS } from '../../MessageListMainPanel';\nimport { UNREAD_MESSAGE_SEPARATOR_CLASS } from '../../UnreadMessagesSeparator';\n\nconst targetScrolledAboveVisibleContainerArea = (\n element: Element,\n container?: Element,\n) => {\n const { bottom: targetBottom } = element.getBoundingClientRect();\n const containerTop = container?.getBoundingClientRect().top ?? 0;\n return targetBottom < containerTop;\n};\n\nconst targetScrolledBelowVisibleContainerArea = (\n element: Element,\n container: Element,\n) => {\n const { top: targetTop } = element.getBoundingClientRect();\n const { bottom: containerBottom } = container.getBoundingClientRect();\n return targetTop > containerBottom;\n};\n\nexport type UseUnreadMessagesNotificationParams = {\n /** Scroll container (the element with overflow that actually scrolls). When provided, used as IntersectionObserver root and for initial visibility. */\n listElement: HTMLDivElement | null;\n isMessageListScrolledToBottom: boolean;\n showAlways: boolean;\n unreadCount?: number;\n};\n\nexport const useUnreadMessagesNotification = ({\n isMessageListScrolledToBottom,\n listElement,\n showAlways,\n unreadCount,\n}: UseUnreadMessagesNotificationParams) => {\n const { messages } = useChannelStateContext('UnreadMessagesNotification');\n const [show, setShow] = useState(false);\n const isScrolledAboveTargetTop = useRef(false);\n const intersectionObserverIsSupported = typeof IntersectionObserver !== 'undefined';\n\n useEffect(() => {\n if (!(unreadCount && intersectionObserverIsSupported)) {\n setShow(false);\n return;\n }\n\n const scrollRoot = listElement ?? null;\n if (!scrollRoot) {\n const [msgListPanel] = document.getElementsByClassName(\n MESSAGE_LIST_MAIN_PANEL_CLASS,\n );\n if (!msgListPanel) return;\n const [observedTarget] = document.getElementsByClassName(\n UNREAD_MESSAGE_SEPARATOR_CLASS,\n );\n if (!observedTarget) {\n setShow(true);\n }\n return;\n }\n\n const [observedTarget] = document.getElementsByClassName(\n UNREAD_MESSAGE_SEPARATOR_CLASS,\n );\n if (!observedTarget) {\n setShow(true);\n return;\n }\n\n const scrolledBelowSeparator = targetScrolledAboveVisibleContainerArea(\n observedTarget,\n scrollRoot,\n );\n const scrolledAboveSeparator = targetScrolledBelowVisibleContainerArea(\n observedTarget,\n scrollRoot,\n );\n\n setShow(\n showAlways\n ? scrolledBelowSeparator || scrolledAboveSeparator\n : scrolledBelowSeparator,\n );\n\n const observer = new IntersectionObserver(\n (elements) => {\n if (!elements.length) return;\n const entry = elements[0];\n const { boundingClientRect, isIntersecting, rootBounds } = entry;\n if (isIntersecting) {\n setShow(false);\n return;\n }\n const rootTop = rootBounds?.top ?? 0;\n const separatorIsAboveContainerTop = boundingClientRect.bottom < rootTop;\n setShow(showAlways || separatorIsAboveContainerTop);\n isScrolledAboveTargetTop.current = separatorIsAboveContainerTop;\n },\n { root: scrollRoot },\n );\n observer.observe(observedTarget);\n\n return () => {\n observer.disconnect();\n };\n }, [\n intersectionObserverIsSupported,\n listElement,\n isMessageListScrolledToBottom,\n messages,\n showAlways,\n unreadCount,\n ]);\n\n useEffect(() => {\n /**\n * Handle situation when scrollToBottom is called from another component when the msg list is scrolled above the observed target (unread separator).\n * The intersection observer is not triggered when Element.scrollTo() is called. So we end up in a situation when we are scrolled to the bottom\n * and at the same time scrolled above the observed target.\n */\n\n if (\n unreadCount &&\n isMessageListScrolledToBottom &&\n isScrolledAboveTargetTop.current\n ) {\n setShow(true);\n isScrolledAboveTargetTop.current = false;\n }\n }, [isMessageListScrolledToBottom, unreadCount]);\n\n return { show: show && intersectionObserverIsSupported };\n};\n","import { useEffect } from 'react';\nimport {\n useChannelActionContext,\n useChannelStateContext,\n useChatContext,\n} from '../../../context';\nimport type { Channel, Event, LocalMessage, MessageResponse } from 'stream-chat';\nimport { getChannelConfig } from '../../../utils/getChannelConfig';\n\nconst hasReadLastMessage = (channel: Channel, userId: string) => {\n const latestMessageIdInChannel = channel.state.latestMessages.slice(-1)[0]?.id;\n const lastReadMessageIdServer = channel.state.read[userId]?.last_read_message_id;\n return latestMessageIdInChannel === lastReadMessageIdServer;\n};\n\ntype UseMarkReadParams = {\n isMessageListScrolledToBottom: boolean;\n messageListIsThread: boolean;\n wasMarkedUnread?: boolean;\n};\n\n/**\n * Takes care of marking a channel read. The channel is read only if all the following applies:\n * 1. the message list is not rendered in a thread\n * 2. the message list is scrolled to the bottom\n * 3. the channel was not marked unread by the user\n * @param isMessageListScrolledToBottom\n * @param messageListIsThread\n * @param wasChannelMarkedUnread\n */\nexport const useMarkRead = ({\n isMessageListScrolledToBottom,\n messageListIsThread,\n wasMarkedUnread,\n}: UseMarkReadParams) => {\n const { client } = useChatContext('useMarkRead');\n const { markRead, setChannelUnreadUiState } = useChannelActionContext('useMarkRead');\n const { channel } = useChannelStateContext('useMarkRead');\n\n useEffect(() => {\n const unreadNotificationSupported =\n getChannelConfig(channel)?.read_events || client.options.isLocalUnreadCountEnabled;\n\n if (!unreadNotificationSupported) return;\n\n const shouldMarkRead = () =>\n !document.hidden &&\n !wasMarkedUnread &&\n !messageListIsThread &&\n isMessageListScrolledToBottom &&\n client.user?.id &&\n !hasReadLastMessage(channel, client.user.id);\n\n const onVisibilityChange = () => {\n if (shouldMarkRead()) markRead();\n };\n\n const handleMessageNew = (event: Event) => {\n const mainChannelUpdated =\n !event.message?.parent_id || event.message?.show_in_channel;\n\n // Thread replies that are not shown in the channel must not affect the\n // main channel's unread UI state (count / notification).\n if (!mainChannelUpdated) return;\n\n if (!isMessageListScrolledToBottom || wasMarkedUnread || document.hidden) {\n setChannelUnreadUiState((prev) => {\n const previousUnreadCount = prev?.unread_messages ?? 0;\n const previousLastMessage = getPreviousLastMessage(\n channel.state.messages,\n event.message,\n );\n return {\n ...(prev || {}),\n last_read:\n prev?.last_read ??\n (previousUnreadCount === 0 && previousLastMessage?.created_at\n ? new Date(previousLastMessage.created_at)\n : new Date(0)), // not having information about the last read message means the whole channel is unread,\n unread_messages: previousUnreadCount + 1,\n };\n });\n } else if (shouldMarkRead()) {\n markRead();\n }\n };\n\n channel.on('message.new', handleMessageNew);\n document.addEventListener('visibilitychange', onVisibilityChange);\n\n if (shouldMarkRead()) {\n markRead();\n }\n\n return () => {\n channel.off('message.new', handleMessageNew);\n document.removeEventListener('visibilitychange', onVisibilityChange);\n };\n }, [\n channel,\n client,\n isMessageListScrolledToBottom,\n markRead,\n messageListIsThread,\n setChannelUnreadUiState,\n wasMarkedUnread,\n ]);\n};\n\nfunction getPreviousLastMessage(messages: LocalMessage[], newMessage?: MessageResponse) {\n if (!newMessage) return;\n let previousLastMessage;\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (!msg?.id) break;\n if (msg.id !== newMessage.id) {\n previousLastMessage = msg;\n break;\n }\n }\n return previousLastMessage;\n}\n","import React from 'react';\n\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\n\nexport type NewMessageNotificationProps = {\n /** Pre-computed label text (passed to custom override) */\n label?: string;\n /** Controls the notification display */\n showNotification?: boolean;\n /** Number of new messages since user scrolled up (optional; when provided shows \"{{count}} new messages\") */\n newMessageCount?: number;\n};\n\nconst UnMemoizedNewMessageNotification = (props: NewMessageNotificationProps) => {\n const { newMessageCount = 0, showNotification } = props;\n\n const { t } = useTranslationContext();\n\n const { NewMessageNotification: CustomNewMessageNotification } = useComponentContext();\n\n if (!showNotification) return null;\n\n const label =\n newMessageCount > 0\n ? t('{{count}} new messages', { count: newMessageCount })\n : t('New Messages!');\n\n if (CustomNewMessageNotification) {\n return <CustomNewMessageNotification {...props} label={label} />;\n }\n\n return (\n <div className='str-chat__new-message-notification'>\n <div\n aria-atomic='true'\n aria-live='polite'\n className='str-chat__message-notification__label'\n data-testid='message-notification'\n role='status'\n >\n {label}\n </div>\n </div>\n );\n};\n\nexport const NewMessageNotification = React.memo(\n UnMemoizedNewMessageNotification,\n) as typeof UnMemoizedNewMessageNotification;\n","import React from 'react';\nimport {\n useChannelActionContext,\n useComponentContextIcons,\n useTranslationContext,\n} from '../../context';\nimport { Button } from '../Button';\nimport clsx from 'clsx';\n\nexport type UnreadMessagesNotificationProps = {\n /**\n * Configuration parameter to determine the message page size, when jumping to the first unread message.\n */\n queryMessageLimit?: number;\n /**\n * Configuration parameter to determine, whether the unread count is to be shown on the component. Enabled by default.\n */\n showCount?: boolean;\n /**\n * The count of unread messages to be displayed if enabled.\n */\n unreadCount?: number;\n};\n\nexport const UnreadMessagesNotification = ({\n queryMessageLimit,\n showCount = true,\n unreadCount,\n}: UnreadMessagesNotificationProps) => {\n const { IconArrowUp, IconXmark } = useComponentContextIcons();\n\n const { jumpToFirstUnreadMessage, markRead } = useChannelActionContext();\n const { t } = useTranslationContext('UnreadMessagesNotification');\n\n return (\n <div\n className={clsx('str-chat__unread-messages-notification', {\n 'str-chat__unread-messages-notification--with-count': unreadCount && showCount,\n })}\n data-testid='unread-messages-notification'\n >\n <Button\n appearance='outline'\n onClick={() => jumpToFirstUnreadMessage(queryMessageLimit)}\n variant='secondary'\n >\n <IconArrowUp />\n {unreadCount && showCount\n ? t('{{count}} unread', { count: unreadCount })\n : t('Unread messages')}\n </Button>\n <Button\n appearance='outline'\n aria-label={t('aria/Mark messages as read')}\n onClick={() => markRead()}\n variant='secondary'\n >\n <IconXmark />\n </Button>\n </div>\n );\n};\n","import type { PropsWithChildren } from 'react';\nimport React, { useEffect, useRef, useState } from 'react';\nimport type { PaginatorProps } from '../../types/types';\nimport { DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD } from '../../constants/limits';\n\n/**\n * Prevents Chrome hangups\n * See: https://stackoverflow.com/questions/47524205/random-high-content-download-time-in-chrome/47684257#47684257\n */\nconst mousewheelListener = (event: Event) => {\n if (event instanceof WheelEvent && event.deltaY === 1) {\n event.preventDefault();\n }\n};\n\nexport type InfiniteScrollProps = PaginatorProps & {\n className?: string;\n element?: React.ElementType;\n /** Element to be rendered at the top of the thread message list. By default, Message and ThreadStart components */\n head?: React.ReactNode;\n initialLoad?: boolean;\n isLoading?: boolean;\n listenToScroll?: (offset: number, reverseOffset: number, threshold: number) => void;\n loader?: React.ReactNode;\n useCapture?: boolean;\n};\n\n/**\n * This component serves a single purpose - load more items on scroll inside the MessageList component\n * It is not a general purpose infinite scroll controller, because:\n * 1. It is re-rendered whenever queryInProgress, hasNext, hasPrev changes. This can lead to scrollListener to have stale data.\n * 2. It pretends to invoke scrollListener on resize event even though this event is emitted only on window resize. It should\n * rather use ResizeObserver. But then again, it ResizeObserver would invoke a stale version of scrollListener.\n *\n * In general, the infinite scroll controller should not aim for checking the loading state and whether there is more data to load.\n * That should be controlled by the loading function.\n */\nexport const InfiniteScroll = (props: PropsWithChildren<InfiniteScrollProps>) => {\n const {\n children,\n element: Component = 'div',\n hasNextPage,\n hasPreviousPage,\n head,\n initialLoad = true,\n isLoading,\n listenToScroll,\n loader,\n loadNextPage,\n loadPreviousPage,\n threshold = DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD,\n useCapture = false,\n ...elementProps\n } = props;\n\n const [scrollComponent, setScrollComponent] = useState<HTMLElement | null>(null);\n const previousOffset = useRef<number | undefined>(undefined);\n const previousReverseOffset = useRef<number | undefined>(undefined);\n\n const scrollListenerRef = useRef<() => void>(undefined);\n scrollListenerRef.current = () => {\n const element = scrollComponent;\n\n if (!element || element.offsetParent === null) {\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const parentElement = element.parentElement!;\n\n const offset =\n element.scrollHeight - parentElement.scrollTop - parentElement.clientHeight;\n const reverseOffset = parentElement.scrollTop;\n\n if (listenToScroll) {\n listenToScroll(offset, reverseOffset, threshold);\n }\n\n if (isLoading) return;\n\n if (\n previousOffset.current === offset &&\n previousReverseOffset.current === reverseOffset\n )\n return;\n previousOffset.current = offset;\n previousReverseOffset.current = reverseOffset;\n\n // FIXME: this triggers loadMore call when a user types messages in thread and the scroll container expands\n if (\n reverseOffset < Number(threshold) &&\n typeof loadPreviousPage === 'function' &&\n hasPreviousPage\n ) {\n loadPreviousPage();\n }\n\n if (offset < Number(threshold) && typeof loadNextPage === 'function' && hasNextPage) {\n loadNextPage();\n }\n };\n\n useEffect(() => {\n const scrollElement = scrollComponent?.parentNode;\n\n if (!scrollElement) return;\n\n const scrollListener = () => scrollListenerRef.current?.();\n\n scrollElement.addEventListener('scroll', scrollListener, useCapture);\n scrollElement.addEventListener('resize', scrollListener, useCapture);\n\n // Defer the initial proximity check so that any pending scroll-to-bottom\n // from useLayoutEffect (e.g. the MessageList settle pass) has been applied\n // to the DOM before we evaluate whether more pages should be loaded.\n // Without this, scrollTop is still 0 on mount which falsely triggers\n // loadPreviousPage and breaks the initial scroll position.\n const rafId = requestAnimationFrame(() => {\n scrollListener();\n });\n\n return () => {\n cancelAnimationFrame(rafId);\n scrollElement.removeEventListener('scroll', scrollListener, useCapture);\n scrollElement.removeEventListener('resize', scrollListener, useCapture);\n };\n }, [initialLoad, scrollComponent, useCapture]);\n\n useEffect(() => {\n const scrollElement = scrollComponent?.parentNode;\n\n if (!scrollElement) return;\n\n scrollElement.addEventListener('wheel', mousewheelListener, { passive: false });\n\n return () => {\n scrollElement.removeEventListener('wheel', mousewheelListener, useCapture);\n };\n }, [scrollComponent, useCapture]);\n\n return (\n <Component {...elementProps} ref={setScrollComponent}>\n {head}\n {loader}\n {children}\n </Component>\n );\n};\n","import React, { useEffect, useMemo } from 'react';\nimport clsx from 'clsx';\n\nimport { AvatarStack as DefaultAvatarStack } from '../Avatar';\nimport { TypingIndicatorDots } from './TypingIndicatorDots';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { useChatContext } from '../../context/ChatContext';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useTypingContext } from '../../context/TypingContext';\nimport { useThreadContext } from '../Threads';\nimport { VisuallyHidden } from '../VisuallyHidden';\n\nimport { useDebouncedTypingActive } from './hooks/useDebouncedTypingActive';\nimport { getTypingStatusMessage } from './utils/getTypingStatusMessage';\nimport { useComponentContext } from '../../context';\nimport { extractDisplayInfo as defaultExtractDisplayInfo } from '../Avatar/utils';\n\nexport type TypingIndicatorProps = {\n /** When false, the indicator is not rendered (e.g. when list is not scrolled to bottom). Omit or true to show when typing. */\n isMessageListScrolledToBottom?: boolean;\n scrollToBottom: () => void;\n /** Whether the typing indicator is in a thread */\n threadList?: boolean;\n};\n\n/**\n * TypingIndicator shows avatars of users currently typing and a bubble with animated dots.\n * Renders only for other participants (never the current user), only when scrolled to latest message if isMessageListScrolledToBottom is provided.\n * It must be a child of Channel component.\n */\nconst UnMemoizedTypingIndicator = (props: TypingIndicatorProps) => {\n const { isMessageListScrolledToBottom = true, scrollToBottom, threadList } = props;\n\n const {\n AvatarStack = DefaultAvatarStack,\n extractDisplayInfo = defaultExtractDisplayInfo,\n } = useComponentContext();\n const { channelConfig, thread } = useChannelStateContext('TypingIndicator');\n const threadInstance = useThreadContext();\n const parentId = threadInstance?.id ?? thread?.id;\n const { client } = useChatContext('TypingIndicator');\n const { t } = useTranslationContext();\n const { typing = {} } = useTypingContext('TypingIndicator');\n\n const typingInChannel = !threadList\n ? Object.values(typing).filter(\n ({ parent_id, user }) => user?.id !== client.user?.id && !parent_id,\n )\n : [];\n\n const typingInThread = threadList\n ? Object.values(typing).filter(\n ({ parent_id, user }) => user?.id !== client.user?.id && parent_id === parentId,\n )\n : [];\n\n const typingUsers = threadList ? typingInThread : typingInChannel;\n const { displayUsers } = useDebouncedTypingActive(typingUsers);\n const showIndicator = displayUsers.length > 0;\n const typingAnnouncement = useMemo(\n () => getTypingStatusMessage(displayUsers, t),\n [displayUsers, t],\n );\n\n const displayInfo = useMemo(\n () => displayUsers.map(extractDisplayInfo),\n [displayUsers, extractDisplayInfo],\n );\n\n useEffect(() => {\n if (showIndicator && isMessageListScrolledToBottom) scrollToBottom();\n }, [scrollToBottom, isMessageListScrolledToBottom, showIndicator]);\n\n if (channelConfig?.typing_events === false) {\n return null;\n }\n\n if (!showIndicator || !isMessageListScrolledToBottom) {\n return null;\n }\n\n return (\n <div\n className={clsx(\n 'str-chat__typing-indicator',\n 'str-chat__typing-indicator--with-transition',\n {\n 'str-chat__typing-indicator--typing': showIndicator,\n },\n )}\n data-testid='typing-indicator'\n >\n {displayInfo.length > 0 && (\n <div aria-hidden='true'>\n <AvatarStack badgeSize='md' displayInfo={displayInfo} size='md' />\n </div>\n )}\n <div aria-hidden='true' className='str-chat__typing-indicator__bubble'>\n <div className='str-chat__typing-indicator__dots'>\n <TypingIndicatorDots />\n </div>\n </div>\n <VisuallyHidden>\n <span\n aria-atomic='true'\n aria-live='polite'\n data-testid='typing-indicator-status'\n role='status'\n >\n {typingAnnouncement}\n </span>\n </VisuallyHidden>\n </div>\n );\n};\n\nexport const TypingIndicator = React.memo(\n UnMemoizedTypingIndicator,\n) as typeof UnMemoizedTypingIndicator;\n","import { useCallback, useState } from 'react';\n\nimport type { RenderedMessage } from '../../utils';\nimport { isDateSeparatorMessage, isIntroMessage } from '../../utils';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type UseFloatingDateSeparatorParams = {\n disableDateSeparator: boolean;\n processedMessages: RenderedMessage[];\n};\n\nexport type UseFloatingDateSeparatorResult = {\n floatingDate: Date | null;\n onItemsRendered: (rendered: RenderedMessage[]) => void;\n showFloatingDate: boolean;\n};\n\n/**\n * Returns the date to show in the floating date separator based on currently visible messages.\n * When the first visible item is a message (not a date separator), we've scrolled past its\n * date separator — find that separator's date.\n */\nfunction getFloatingDateForFirstMessage(\n firstMessage: RenderedMessage,\n processedMessages: RenderedMessage[],\n firstMessageIndex: number,\n): Date | null {\n if (isIntroMessage(firstMessage)) return null;\n\n // Walk backwards to find the last date separator before this message\n for (let i = firstMessageIndex - 1; i >= 0; i -= 1) {\n const item = processedMessages[i];\n if (isDateSeparatorMessage(item)) {\n return item.date;\n }\n }\n\n // No preceding date separator; use message's created_at\n const msg = firstMessage as LocalMessage;\n const created = msg.created_at;\n if (created) {\n const d = new Date(created);\n return isNaN(d.getTime()) ? null : d;\n }\n return null;\n}\n\nfunction getFloatingDateForFirstItem(\n firstItem: RenderedMessage,\n processedMessages: RenderedMessage[],\n firstItemIndex: number,\n): Date | null {\n if (isDateSeparatorMessage(firstItem)) return firstItem.date;\n\n return getFloatingDateForFirstMessage(firstItem, processedMessages, firstItemIndex);\n}\n\n/**\n * Controls the floating date separator as a sticky \"current section\" label.\n * It follows the date separator represented by the first visible item.\n */\nconst HIDDEN_STATE = { date: null, visible: false } as const;\n\nexport const useFloatingDateSeparator = ({\n disableDateSeparator,\n processedMessages,\n}: UseFloatingDateSeparatorParams): UseFloatingDateSeparatorResult => {\n const [state, setState] = useState<{\n date: Date | null;\n visible: boolean;\n }>(HIDDEN_STATE);\n\n const onItemsRendered = useCallback(\n (rendered: RenderedMessage[]) => {\n if (disableDateSeparator || processedMessages.length === 0) {\n setState(HIDDEN_STATE);\n return;\n }\n\n const valid = rendered.filter((m): m is RenderedMessage => m != null);\n if (valid.length === 0) {\n setState(HIDDEN_STATE);\n return;\n }\n\n const first = valid[0];\n const firstIndex = processedMessages.findIndex((m) => m.id === first.id);\n const date =\n firstIndex >= 0\n ? getFloatingDateForFirstItem(first, processedMessages, firstIndex)\n : null;\n\n const visible = date !== null;\n setState((prev) => {\n const prevTime = prev.date?.getTime() ?? null;\n const nextTime = date?.getTime() ?? null;\n if (prev.visible === visible && prevTime === nextTime) return prev;\n return { date, visible };\n });\n },\n [disableDateSeparator, processedMessages],\n );\n\n return {\n floatingDate: state.date,\n onItemsRendered,\n showFloatingDate: !!state.date && state.visible,\n };\n};\n","import { useEffect, useState } from 'react';\n\nimport { useChatContext } from '../../../../context/ChatContext';\n\nimport type { EventHandler, LocalMessage } from 'stream-chat';\n\nexport const useGiphyPreview = (separateGiphyPreview: boolean) => {\n const [giphyPreviewMessage, setGiphyPreviewMessage] = useState<LocalMessage>();\n\n const { client } = useChatContext('useGiphyPreview');\n\n useEffect(() => {\n if (!separateGiphyPreview) return;\n const handleEvent: EventHandler = (event) => {\n const { message, user } = event;\n\n if (message?.command === 'giphy' && user?.id === client.userID) {\n setGiphyPreviewMessage(undefined);\n }\n };\n\n client.on('message.new', handleEvent);\n return () => client.off('message.new', handleEvent);\n }, [client, separateGiphyPreview]);\n\n return {\n giphyPreviewMessage,\n setGiphyPreviewMessage: separateGiphyPreview ? setGiphyPreviewMessage : undefined,\n };\n};\n","import { useEffect, useRef, useState } from 'react';\nimport type { LocalMessage } from 'stream-chat';\n\ntype UseMessageSetKeyParams = {\n messages?: LocalMessage[];\n};\n\nexport const useMessageSetKey = ({ messages }: UseMessageSetKeyParams) => {\n /**\n * Logic to update the key of the virtuoso component when the list jumps to a new location.\n */\n const [messageSetKey, setMessageSetKey] = useState(+new Date());\n const firstMessageId = useRef<string | undefined>(undefined);\n\n useEffect(() => {\n const continuousSet = messages?.find(\n (message) => message.id === firstMessageId.current,\n );\n if (!continuousSet) {\n setMessageSetKey(+new Date());\n }\n firstMessageId.current = messages?.[0]?.id;\n }, [messages]);\n\n return {\n messageSetKey,\n };\n};\n","import { useEffect, useRef, useState } from 'react';\nimport type { LocalMessage } from 'stream-chat';\nimport type { RenderedMessage } from '../../utils';\n\nexport function useNewMessageNotification(\n messages: RenderedMessage[],\n currentUserId: string | undefined,\n hasMoreNewer?: boolean,\n) {\n const [newMessagesNotification, setNewMessagesNotification] = useState(false);\n const [isMessageListScrolledToBottom, setIsMessageListScrolledToBottom] =\n useState(true);\n /**\n * use the flag to avoid the initial \"new messages\" quick blink\n */\n const didMount = useRef(false);\n\n const lastMessageId = useRef('');\n const atBottom = useRef(false);\n\n useEffect(() => {\n if (hasMoreNewer) {\n setNewMessagesNotification(true);\n return;\n }\n /* handle scrolling behavior for new messages */\n if (!messages?.length) return;\n\n const lastMessage = messages[messages.length - 1];\n const prevMessageId = lastMessageId.current;\n lastMessageId.current = lastMessage.id || ''; // update last message id\n\n /* do nothing if new messages are loaded from top(loadMore) */\n if (lastMessage.id === prevMessageId) return;\n\n /* if list is already at the bottom return, followOutput will do the job */\n if (atBottom.current) return;\n\n /* if the new message belongs to current user scroll to bottom */\n if ((lastMessage as LocalMessage).user?.id !== currentUserId && didMount.current) {\n /* otherwise just show newMessage notification */\n setNewMessagesNotification(true);\n }\n didMount.current = true;\n }, [currentUserId, messages, hasMoreNewer]);\n\n return {\n atBottom,\n isMessageListScrolledToBottom,\n newMessagesNotification,\n setIsMessageListScrolledToBottom,\n setNewMessagesNotification,\n };\n}\n","import { useMemo, useRef } from 'react';\nimport type { RenderedMessage } from '../../utils';\nimport { isLocalMessage } from '../../utils';\n\nconst STATUSES_EXCLUDED_FROM_PREPEND = {\n failed: true,\n sending: true,\n} as const as Record<string, boolean>;\n\nexport function usePrependedMessagesCount(\n messages: RenderedMessage[],\n hasDateSeparator: boolean,\n) {\n const firstRealMessageIndex = hasDateSeparator ? 1 : 0;\n const firstMessageOnFirstLoadedPage = useRef<RenderedMessage>(undefined);\n const previousFirstMessageOnFirstLoadedPage = useRef<RenderedMessage>(undefined);\n const previousNumItemsPrepended = useRef(0);\n\n const numItemsPrepended = useMemo(() => {\n if (!messages || !messages.length) {\n previousNumItemsPrepended.current = 0;\n return 0;\n }\n\n const currentFirstMessage = messages?.[firstRealMessageIndex];\n\n const noNewMessages =\n currentFirstMessage?.id === previousFirstMessageOnFirstLoadedPage.current?.id;\n\n // This is possible only, when sending messages very quickly (basically single char messages submitted like a crazy) in empty channel (first page)\n // Optimistic UI update, when sending messages, can lead to a situation, when\n // the order of the messages changes for a moment. This can happen, when a user\n // sends multiple messages withing few milliseconds. E.g. we send a message A\n // then message B. At first we have message array with both messages of status \"sending\"\n // then response for message A is received with a new - later - created_at timestamp\n // this leads to rearrangement of 1.B (\"sending\"), 2.A (\"received\"). Still firstMessageOnFirstLoadedPage.current\n // points to message A, but now this message has index 1 => previousNumItemsPrepended.current === 1\n // That in turn leads to incorrect index calculation in VirtualizedMessageList trying to access a message\n // at non-existent index. Therefore, we ignore messages of status \"sending\" / \"failed\" in order they are\n // not considered as prepended messages.\n const currentFirstMessageStatus = isLocalMessage(currentFirstMessage)\n ? currentFirstMessage.status\n : undefined;\n const firstMsgMovedAfterMessagesInExcludedStatus = !!(\n currentFirstMessageStatus &&\n STATUSES_EXCLUDED_FROM_PREPEND[currentFirstMessageStatus]\n );\n\n if (noNewMessages || firstMsgMovedAfterMessagesInExcludedStatus) {\n return previousNumItemsPrepended.current;\n }\n\n if (!firstMessageOnFirstLoadedPage.current) {\n firstMessageOnFirstLoadedPage.current = currentFirstMessage;\n }\n previousFirstMessageOnFirstLoadedPage.current = currentFirstMessage;\n // if new messages were prepended, find out how many\n // start with this number because there cannot be fewer prepended items than before\n for (\n let prependedMessageCount = previousNumItemsPrepended.current;\n prependedMessageCount < messages.length;\n prependedMessageCount += 1\n ) {\n const messageIsFirstOnFirstLoadedPage =\n messages[prependedMessageCount].id === firstMessageOnFirstLoadedPage.current?.id;\n\n if (messageIsFirstOnFirstLoadedPage) {\n previousNumItemsPrepended.current = prependedMessageCount - firstRealMessageIndex;\n return previousNumItemsPrepended.current;\n }\n }\n\n // if no match has found, we have jumped - reset the prepended item count.\n firstMessageOnFirstLoadedPage.current = currentFirstMessage;\n previousNumItemsPrepended.current = 0;\n return 0;\n // TODO: there's a bug here, the messages prop is the same array instance (something mutates it)\n // that's why the second dependency is necessary\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [firstRealMessageIndex, messages, messages?.length]);\n\n return numItemsPrepended;\n}\n","import { useEffect, useRef, useState } from 'react';\nimport type { RenderedMessage } from '../../utils';\n\ntype UseScrollToBottomOnNewMessageParams = {\n scrollToBottom: () => void;\n messages?: RenderedMessage[];\n /** When `true`, the list will scroll to the latest message when the window regains focus */\n scrollToLatestMessageOnFocus?: boolean;\n};\n\nexport const useScrollToBottomOnNewMessage = ({\n messages,\n scrollToBottom,\n scrollToLatestMessageOnFocus,\n}: UseScrollToBottomOnNewMessageParams) => {\n const [newMessagesReceivedInBackground, setNewMessagesReceivedInBackground] =\n useState(false);\n\n const scrollToBottomIfConfigured = useRef<(e: Event) => void>(undefined);\n\n scrollToBottomIfConfigured.current = (event: Event) => {\n if (\n !scrollToLatestMessageOnFocus ||\n !newMessagesReceivedInBackground ||\n event.target !== window\n ) {\n return;\n }\n\n setTimeout(scrollToBottom, 100);\n };\n\n useEffect(() => {\n setNewMessagesReceivedInBackground(true);\n }, [messages]);\n\n useEffect(() => {\n const handleFocus = (event: Event) => {\n scrollToBottomIfConfigured.current?.(event);\n };\n\n const handleBlur = () => {\n setNewMessagesReceivedInBackground(false);\n };\n\n if (typeof window !== 'undefined') {\n window.addEventListener('focus', handleFocus);\n window.addEventListener('blur', handleBlur);\n }\n\n return () => {\n window.removeEventListener('focus', handleFocus);\n window.removeEventListener('blur', handleBlur);\n };\n }, []);\n};\n","import { useEffect, useRef } from 'react';\nimport type { RenderedMessage } from '../../utils';\nimport type { LocalMessage } from 'stream-chat';\n\nexport function useShouldForceScrollToBottom(\n messages: RenderedMessage[],\n currentUserId?: string,\n) {\n const lastFocusedOwnMessage = useRef('');\n const initialFocusRegistered = useRef(false);\n\n function recheckForNewOwnMessage() {\n if (messages && messages.length > 0) {\n const lastMessage = messages[messages.length - 1];\n\n if (\n (lastMessage as LocalMessage).user?.id === currentUserId &&\n lastFocusedOwnMessage.current !== lastMessage.id\n ) {\n lastFocusedOwnMessage.current = lastMessage.id;\n return true;\n }\n }\n return false;\n }\n\n useEffect(() => {\n if (messages && messages.length && !initialFocusRegistered.current) {\n initialFocusRegistered.current = true;\n recheckForNewOwnMessage();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [messages, messages?.length]);\n\n return recheckForNewOwnMessage;\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport type { RenderedMessage } from '../../utils';\nimport type { LocalMessage } from 'stream-chat';\n\nexport type UseUnreadMessagesNotificationParams = {\n showAlways: boolean;\n unreadCount: number;\n lastRead?: Date | null;\n};\n\n/**\n * Controls the logic when an `UnreadMessagesNotification` component should be shown.\n * In virtualized message list there is no notion of being scrolled below or above `UnreadMessagesSeparator`.\n * Therefore, the `UnreadMessagesNotification` component is rendered based on timestamps.\n * If the there are unread messages in the channel and the `VirtualizedMessageList` renders\n * messages created later than the last read message in the channel, then the\n * `UnreadMessagesNotification` component is rendered. This is an approximate equivalent to being\n * scrolled below the `UnreadMessagesNotification` component.\n * @param lastRead\n * @param showAlways\n * @param unreadCount\n */\nexport const useUnreadMessagesNotificationVirtualized = ({\n lastRead,\n showAlways,\n unreadCount,\n}: UseUnreadMessagesNotificationParams) => {\n const [show, setShow] = useState(false);\n\n const toggleShowUnreadMessagesNotification = useCallback(\n (renderedMessages: RenderedMessage[]) => {\n if (!unreadCount) return;\n const firstRenderedMessage = renderedMessages[0];\n const lastRenderedMessage = renderedMessages.slice(-1)[0];\n if (!(firstRenderedMessage && lastRenderedMessage)) return;\n\n const firstRenderedMessageTime = new Date(\n (firstRenderedMessage as LocalMessage).created_at ?? 0,\n ).getTime();\n const lastRenderedMessageTime = new Date(\n (lastRenderedMessage as LocalMessage).created_at ?? 0,\n ).getTime();\n const lastReadTime = new Date(lastRead ?? 0).getTime();\n\n const scrolledBelowSeparator =\n !!lastReadTime && firstRenderedMessageTime > lastReadTime;\n const scrolledAboveSeparator =\n !!lastReadTime && lastRenderedMessageTime < lastReadTime;\n\n setShow(\n showAlways\n ? scrolledBelowSeparator || scrolledAboveSeparator\n : scrolledBelowSeparator,\n );\n },\n [lastRead, showAlways, unreadCount],\n );\n\n useEffect(() => {\n if (!unreadCount) setShow(false);\n }, [unreadCount]);\n\n return { show, toggleShowUnreadMessagesNotification };\n};\n","import React, { useLayoutEffect } from 'react';\nimport type { RefObject } from 'react';\n\nimport { DateSeparator as DefaultDateSeparator } from '../DateSeparator';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useFloatingDateSeparatorMessageList } from './hooks/MessageList';\nimport { useFloatingDateSeparator } from './hooks/VirtualizedMessageList';\nimport type { RenderedMessage } from './utils';\n\ntype BaseProps = {\n disableDateSeparator: boolean;\n processedMessages: RenderedMessage[];\n};\n\nexport type FloatingDateSeparatorProps = BaseProps &\n (\n | {\n /** For VirtualizedMessageList: ref the parent calls with visible items */\n itemsRenderedRef: RefObject<((rendered: RenderedMessage[]) => void) | null>;\n }\n | {\n /** For MessageList: scroll container to query DOM for date separators */\n listElement: HTMLDivElement | null;\n }\n );\n\n/**\n * Renders a floating date separator when the user has scrolled past the in-flow date.\n * State is internal so MessageList/VirtualizedMessageList do not re-render when it changes.\n * Use itemsRenderedRef for Virtuoso, listElement for non-virtualized MessageList.\n */\nexport const FloatingDateSeparator = (props: FloatingDateSeparatorProps) => {\n const { DateSeparator = DefaultDateSeparator } = useComponentContext(\n 'FloatingDateSeparator',\n );\n const { disableDateSeparator, processedMessages } = props;\n\n const listElement = 'listElement' in props ? props.listElement : null;\n const useDomMode = listElement != null;\n\n const virtuosoResult = useFloatingDateSeparator({\n disableDateSeparator,\n processedMessages,\n });\n const domResult = useFloatingDateSeparatorMessageList({\n disableDateSeparator,\n listElement,\n processedMessages,\n });\n\n const floatingDate = useDomMode ? domResult.floatingDate : virtuosoResult.floatingDate;\n const showFloatingDate = useDomMode\n ? domResult.showFloatingDate\n : virtuosoResult.showFloatingDate;\n\n const itemsRenderedRef = 'itemsRenderedRef' in props ? props.itemsRenderedRef : null;\n useLayoutEffect(() => {\n if (!itemsRenderedRef) return;\n itemsRenderedRef.current = virtuosoResult.onItemsRendered;\n return () => {\n itemsRenderedRef.current = null;\n };\n }, [itemsRenderedRef, virtuosoResult.onItemsRendered]);\n\n if (!showFloatingDate || !floatingDate || !DateSeparator) return null;\n\n return <DateSeparator date={floatingDate} floating />;\n};\n","import React from 'react';\n\nimport type { Event, LocalMessage } from 'stream-chat';\nimport type { TimestampFormatterOptions } from '../../i18n/types';\n\nexport type EventComponentProps = TimestampFormatterOptions & {\n message: LocalMessage & {\n event?: Event;\n };\n unsafeHTML?: boolean;\n};\n\n/**\n * Component to display system and channel event messages\n */\nconst UnMemoizedEventComponent = (props: EventComponentProps) => {\n const { message, unsafeHTML = false } = props;\n const { type } = message;\n\n if (type !== 'system') return null;\n\n return (\n <div className='str-chat__message--system' data-testid='message-system'>\n <div className='str-chat__message--system__text'>\n {unsafeHTML ? (\n <div\n dangerouslySetInnerHTML={{ __html: message.html || '' }}\n data-unsafe-inner-html\n />\n ) : (\n <span>{message.text}</span>\n )}\n </div>\n </div>\n );\n};\n\nexport const EventComponent = React.memo(\n UnMemoizedEventComponent,\n) as typeof UnMemoizedEventComponent;\n","import type { ReactNode } from 'react';\nimport React, { Fragment } from 'react';\nimport type { GroupStyle, RenderedMessage } from './utils';\nimport { getIsFirstUnreadMessage, isDateSeparatorMessage, isIntroMessage } from './utils';\nimport type { MessageProps } from '../Message';\nimport { Message } from '../Message';\nimport { DateSeparator as DefaultDateSeparator } from '../DateSeparator';\nimport { EventComponent as DefaultMessageSystem } from '../EventComponent';\nimport { UnreadMessagesSeparator as DefaultUnreadMessagesSeparator } from './UnreadMessagesSeparator';\nimport type { LocalMessage, UserResponse } from 'stream-chat';\nimport type { ComponentContextValue, CustomClasses } from '../../context';\nimport type { ChannelUnreadUiState } from '../../types';\n\nexport interface RenderMessagesOptions {\n components: ComponentContextValue;\n lastReceivedMessageId: string | null;\n messageGroupStyles: Record<string, GroupStyle>;\n messages: Array<RenderedMessage>;\n ownMessagesDeliveredToOthers: Record<string, UserResponse[]>;\n /**\n * Object mapping message IDs of own messages to the users who read those messages.\n */\n readData: Record<string, Array<UserResponse>>;\n /**\n * Props forwarded to the Message component.\n */\n sharedMessageProps: SharedMessageProps;\n /** Latest own message in currently displayed message set. */\n lastOwnMessage?: LocalMessage;\n /**\n * Current user's channel read state used to render components reflecting unread state.\n * It does not reflect the back-end state if a channel is marked read on mount.\n * This is in order to keep the unread UI when an unread channel is open.\n */\n channelUnreadUiState?: ChannelUnreadUiState;\n customClasses?: CustomClasses;\n}\n\nexport type SharedMessageProps = Omit<MessageProps, MessagePropsToOmit>;\n\nexport type MessageRenderer = (options: RenderMessagesOptions) => Array<ReactNode>;\n\ntype MessagePropsToOmit =\n | 'channel'\n | 'deliveredTo'\n | 'groupStyles'\n | 'initialMessage'\n | 'lastReceivedId'\n | 'message'\n | 'readBy';\n\nexport function defaultRenderMessages({\n channelUnreadUiState,\n components,\n customClasses,\n lastOwnMessage,\n lastReceivedMessageId: lastReceivedId,\n messageGroupStyles,\n messages,\n ownMessagesDeliveredToOthers,\n readData,\n sharedMessageProps: messageProps,\n}: RenderMessagesOptions) {\n const {\n DateSeparator = DefaultDateSeparator,\n HeaderComponent,\n MessageListItem = 'li',\n MessageSystem = DefaultMessageSystem,\n UnreadMessagesSeparator = DefaultUnreadMessagesSeparator,\n } = components;\n\n const renderedMessages = [];\n let firstMessage;\n let previousMessage = undefined;\n for (let index = 0; index < messages.length; index++) {\n const message = messages[index];\n if (isDateSeparatorMessage(message)) {\n renderedMessages.push(\n <MessageListItem data-index={index} key={`${message.date.toISOString()}-i`}>\n <DateSeparator\n date={message.date}\n formatDate={messageProps.formatDate}\n unread={message.unread}\n />\n </MessageListItem>,\n );\n } else if (isIntroMessage(message)) {\n if (HeaderComponent) {\n renderedMessages.push(\n <MessageListItem data-index={index} key='intro'>\n <HeaderComponent />\n </MessageListItem>,\n );\n }\n } else if (message.type === 'system') {\n renderedMessages.push(\n <MessageListItem\n data-index={index}\n data-message-id={message.id}\n key={message.id || message.created_at.toISOString()}\n >\n <MessageSystem message={message} unsafeHTML={messageProps.unsafeHTML} />\n </MessageListItem>,\n );\n } else {\n if (!firstMessage) {\n firstMessage = message;\n }\n const groupStyles: GroupStyle = messageGroupStyles[message.id] || '';\n const messageClass =\n customClasses?.message || `str-chat__li str-chat__li--${groupStyles}`;\n\n const isFirstUnreadMessage = getIsFirstUnreadMessage({\n firstUnreadMessageId: channelUnreadUiState?.first_unread_message_id,\n isFirstMessage: !!firstMessage?.id && firstMessage.id === message.id,\n lastReadDate: channelUnreadUiState?.last_read,\n lastReadMessageId: channelUnreadUiState?.last_read_message_id,\n message,\n previousMessage,\n unreadMessageCount: channelUnreadUiState?.unread_messages,\n });\n\n renderedMessages.push(\n <Fragment key={message.id || message.created_at.toISOString()}>\n {isFirstUnreadMessage && UnreadMessagesSeparator && (\n <MessageListItem className='str-chat__li str-chat__unread-messages-separator-wrapper'>\n <UnreadMessagesSeparator\n unreadCount={channelUnreadUiState?.unread_messages}\n />\n </MessageListItem>\n )}\n <MessageListItem\n className={messageClass}\n data-index={index}\n data-message-id={message.id}\n data-testid={messageClass}\n >\n <Message\n deliveredTo={ownMessagesDeliveredToOthers[message.id] || []}\n groupStyles={[groupStyles]} /* TODO: convert to simple string */\n lastOwnMessage={lastOwnMessage}\n lastReceivedId={lastReceivedId}\n message={message}\n readBy={readData[message.id] || []}\n {...messageProps}\n />\n </MessageListItem>\n </Fragment>,\n );\n previousMessage = message;\n }\n }\n return renderedMessages;\n}\n","// last own message should be tracked in the low-level client\nexport const findReverse = <T>(\n items: T[],\n matches: (items: T) => boolean,\n): T | undefined => {\n for (let i = items.length - 1; i >= 0; i -= 1) {\n if (matches(items[i])) {\n return items[i];\n }\n }\n\n return undefined;\n};\n","import { useMemo } from 'react';\nimport { findReverse } from '../../../utils/findReverse';\nimport type { LocalMessage } from 'stream-chat';\n\n// fixme: we should be able to retrieve last own message quickly from the LLC. Should be done when refactoring the LLC Channel state to reactive.\nexport const useLastOwnMessage = ({\n messages,\n ownUserId,\n}: {\n messages?: LocalMessage[];\n ownUserId?: string;\n}) =>\n useMemo(\n () =>\n messages && findReverse(messages, (msg) => (msg.user && msg.user.id) === ownUserId),\n [messages, ownUserId],\n );\n","import { useSyncExternalStore } from 'use-sync-external-store/shim';\n\nconst REDUCED_MOTION_MEDIA_QUERY = '(prefers-reduced-motion: reduce)';\n\nconst getReducedMotionSnapshot = () => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n return false;\n }\n\n return window.matchMedia(REDUCED_MOTION_MEDIA_QUERY).matches;\n};\n\nconst subscribeToReducedMotion = (onStoreChange: () => void) => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n return () => undefined;\n }\n\n const mediaQueryList = window.matchMedia(REDUCED_MOTION_MEDIA_QUERY);\n const handleChange = () => onStoreChange();\n\n if (typeof mediaQueryList.addEventListener === 'function') {\n mediaQueryList.addEventListener('change', handleChange);\n return () => mediaQueryList.removeEventListener('change', handleChange);\n }\n\n mediaQueryList.addListener(handleChange);\n return () => mediaQueryList.removeListener(handleChange);\n};\n\nexport const useReducedMotionPreference = () =>\n useSyncExternalStore(subscribeToReducedMotion, getReducedMotionSnapshot, () => false);\n","import React, { useEffect, useState } from 'react';\n\nimport {\n useChannelStateContext,\n useChatContext,\n useComponentContextIcons,\n useTranslationContext,\n} from '../../context';\n\nimport type { Event } from 'stream-chat';\nimport { Badge } from '../Badge';\nimport { Button } from '../Button';\n\nexport type ScrollToLatestMessageButtonProps = {\n /** When true, user has jumped to an older message set and newer messages can be loaded */\n isNotAtLatestMessageSet?: boolean;\n isMessageListScrolledToBottom?: boolean;\n onClick: React.MouseEventHandler;\n threadList?: boolean;\n};\n\nconst UnMemoizedScrollToLatestMessageButton = (\n props: ScrollToLatestMessageButtonProps,\n) => {\n const {\n isMessageListScrolledToBottom,\n isNotAtLatestMessageSet = false,\n onClick,\n threadList,\n } = props;\n\n const { channel: activeChannel, client } = useChatContext();\n const { thread } = useChannelStateContext();\n const { t } = useTranslationContext();\n const { IconArrowDown } = useComponentContextIcons();\n const [countUnread, setCountUnread] = useState(activeChannel?.countUnread() || 0);\n const [replyCount, setReplyCount] = useState(thread?.reply_count || 0);\n const observedEvent = threadList ? 'message.updated' : 'message.new';\n\n useEffect(() => {\n const handleEvent = (event: Event) => {\n const newMessageInAnotherChannel = event.cid !== activeChannel?.cid;\n const newMessageIsMine = event.user?.id === client.user?.id;\n\n const isThreadOpen = !!thread;\n const newMessageIsReply = !!event.message?.parent_id;\n const dontIncreaseMainListCounterOnNewReply =\n isThreadOpen && !threadList && newMessageIsReply;\n\n if (\n isMessageListScrolledToBottom ||\n newMessageInAnotherChannel ||\n newMessageIsMine ||\n dontIncreaseMainListCounterOnNewReply\n ) {\n return;\n }\n\n if (event.type === 'message.new') {\n // cannot rely on channel.countUnread because active channel is automatically marked read\n setCountUnread((prev) => prev + 1);\n } else if (event.message?.id === thread?.id) {\n const newReplyCount = event.message?.reply_count || 0;\n setCountUnread(() => newReplyCount - replyCount);\n }\n };\n client.on(observedEvent, handleEvent);\n\n return () => {\n client.off(observedEvent, handleEvent);\n };\n }, [\n activeChannel,\n client,\n isMessageListScrolledToBottom,\n observedEvent,\n replyCount,\n thread,\n threadList,\n ]);\n\n useEffect(() => {\n if (isMessageListScrolledToBottom) {\n setCountUnread(0);\n setReplyCount(thread?.reply_count || 0);\n }\n }, [isMessageListScrolledToBottom, thread]);\n\n if (isMessageListScrolledToBottom && !isNotAtLatestMessageSet) return null;\n\n return (\n <div className='str-chat__jump-to-latest-message'>\n <Button\n appearance='ghost'\n aria-label={t('aria/Jump to latest message')}\n aria-live='polite'\n circular\n className='str-chat__jump-to-latest-message__button'\n data-testid='scroll-to-latest-message-button'\n onClick={onClick}\n size='md'\n variant='secondary'\n >\n <IconArrowDown />\n </Button>\n {countUnread > 0 && (\n <Badge\n className='str-chat__jump-to-latest__unread-count'\n data-testid='unread-message-notification-counter'\n size='md'\n variant='primary'\n >\n {countUnread}\n </Badge>\n )}\n </div>\n );\n};\n\nexport const ScrollToLatestMessageButton = React.memo(\n UnMemoizedScrollToLatestMessageButton,\n) as typeof UnMemoizedScrollToLatestMessageButton;\n","import clsx from 'clsx';\nimport React from 'react';\n\nimport {\n useEnrichedMessages,\n useMessageListElements,\n useScrollLocationLogic,\n useUnreadMessagesNotification,\n} from './hooks/MessageList';\nimport { useMarkRead } from './hooks/useMarkRead';\nimport { NewMessageNotification as DefaultNewMessageNotification } from './NewMessageNotification';\nimport { UnreadMessagesNotification as DefaultUnreadMessagesNotification } from './UnreadMessagesNotification';\n\nimport type { ChannelActionContextValue } from '../../context/ChannelActionContext';\nimport { useChannelActionContext } from '../../context/ChannelActionContext';\nimport type { ChannelStateContextValue } from '../../context/ChannelStateContext';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { DialogManagerProvider } from '../../context';\nimport { useChatContext } from '../../context/ChatContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { MessageListContextProvider } from '../../context/MessageListContext';\nimport { MessageTranslationViewProvider } from '../../context/MessageTranslationViewContext';\nimport { EmptyStateIndicator as DefaultEmptyStateIndicator } from '../EmptyStateIndicator';\nimport type { InfiniteScrollProps } from '../InfiniteScrollPaginator/InfiniteScroll';\nimport { InfiniteScroll } from '../InfiniteScrollPaginator/InfiniteScroll';\nimport { LoadingIndicator as DefaultLoadingIndicator } from '../Loading';\nimport { MESSAGE_ACTIONS } from '../Message/utils';\nimport { TypingIndicator as DefaultTypingIndicator } from '../TypingIndicator';\nimport { MessageListMainPanel as DefaultMessageListMainPanel } from './MessageListMainPanel';\n\nimport { FloatingDateSeparator } from './FloatingDateSeparator';\nimport type { MessageRenderer } from './renderMessages';\nimport { defaultRenderMessages } from './renderMessages';\nimport { useStableId } from '../UtilityComponents/useStableId';\n\nimport type { LocalMessage } from 'stream-chat';\nimport type { GroupStyle, ProcessMessagesParams, RenderedMessage } from './utils';\nimport type { MessageProps } from '../Message/types';\n\nimport {\n DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD,\n DEFAULT_NEXT_CHANNEL_PAGE_SIZE,\n} from '../../constants/limits';\nimport { useLastOwnMessage } from './hooks/useLastOwnMessage';\nimport { useReducedMotionPreference } from './hooks/useReducedMotionPreference';\nimport { ScrollToLatestMessageButton as DefaultScrollToLatestMessageButton } from './ScrollToLatestMessageButton';\nimport {\n NotificationList as DefaultNotificationList,\n useNotificationTarget,\n} from '../Notifications';\nimport { useIncomingMessageAnnouncements } from '../Accessibility';\n\ntype MessageListWithContextProps = Omit<\n ChannelStateContextValue,\n 'members' | 'mutes' | 'watchers'\n> &\n MessageListProps;\n\ntype JumpToLatestPhase = 'idle' | 'waiting-for-render' | 'animating';\ntype HighlightedJumpPhase = 'idle' | 'waiting-for-render' | 'animating';\n\nconst getMessageSetSignature = (messages: LocalMessage[]) =>\n `${messages.length}:${messages[0]?.id || ''}:${messages[messages.length - 1]?.id || ''}`;\n\nconst getMessageTimestamp = (message?: LocalMessage) =>\n message?.created_at?.getTime?.() ?? null;\n\nconst MessageListWithContext = (props: MessageListWithContextProps) => {\n const {\n channel,\n channelUnreadUiState,\n disableDateSeparator = false,\n groupStyles,\n hasMoreNewer = false,\n headerPosition,\n hideDeletedMessages = false,\n hideNewMessageSeparator = false,\n highlightedMessageId,\n internalInfiniteScrollProps: {\n threshold: loadMoreScrollThreshold = DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD,\n ...restInternalInfiniteScrollProps\n } = {},\n jumpToLatestMessage = () => Promise.resolve(),\n loadMore: loadMoreCallback,\n loadMoreNewer: loadMoreNewerCallback,\n maxTimeBetweenGroupedMessages,\n messageActions = Object.keys(MESSAGE_ACTIONS),\n messageLimit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE,\n messages = [],\n noGroupByUser = false,\n reactionDetailsSort,\n renderMessages = defaultRenderMessages,\n returnAllReadData = false,\n reviewProcessedMessage,\n showUnreadNotificationAlways,\n sortReactions,\n suppressAutoscroll,\n thread,\n threadList = false,\n unsafeHTML = false,\n } = props;\n\n const [listElement, setListElement] = React.useState<HTMLDivElement | null>(null);\n const [jumpToLatestPhase, setJumpToLatestPhase] =\n React.useState<JumpToLatestPhase>('idle');\n const [highlightedJumpPhase, setHighlightedJumpPhase] =\n React.useState<HighlightedJumpPhase>('idle');\n const [jumpSourceMessageSetSignature, setJumpSourceMessageSetSignature] =\n React.useState<string | null>(null);\n const previousHasMoreNewerRef = React.useRef(hasMoreNewer);\n const previousMessageSetSignatureRef = React.useRef('');\n const previousMessageSetBoundsRef = React.useRef<{\n firstTimestamp: number | null;\n lastTimestamp: number | null;\n }>({\n firstTimestamp: null,\n lastTimestamp: null,\n });\n\n const { customClasses } = useChatContext('MessageList');\n const prefersReducedMotion = useReducedMotionPreference();\n const scrollBehavior = prefersReducedMotion ? 'auto' : 'smooth';\n\n const {\n EmptyStateIndicator = DefaultEmptyStateIndicator,\n LoadingIndicator = DefaultLoadingIndicator,\n MessageListMainPanel = DefaultMessageListMainPanel,\n MessageListWrapper = 'ul',\n NewMessageNotification = DefaultNewMessageNotification,\n NotificationList = DefaultNotificationList,\n ScrollToLatestMessageButton = DefaultScrollToLatestMessageButton,\n TypingIndicator = DefaultTypingIndicator,\n UnreadMessagesNotification = DefaultUnreadMessagesNotification,\n } = useComponentContext();\n\n const notificationTarget = useNotificationTarget();\n const messageSetSignature = React.useMemo(\n () => getMessageSetSignature(messages),\n [messages],\n );\n const messageSetBounds = React.useMemo(\n () => ({\n firstTimestamp: getMessageTimestamp(messages[0]),\n lastTimestamp: getMessageTimestamp(messages[messages.length - 1]),\n }),\n [messages],\n );\n const isJumpingToLatest = jumpToLatestPhase !== 'idle';\n const isHighlightedJumpRequested = !!highlightedMessageId;\n // Highlighted jumps temporarily disable prepend pagination so a target\n // message rendered near the top does not immediately load the previous page.\n const isJumpingToHighlightedMessage = highlightedJumpPhase !== 'idle';\n const justReachedLatestMergedSet = previousHasMoreNewerRef.current && !hasMoreNewer;\n\n const {\n hasNewMessages,\n isMessageListScrolledToBottom,\n onScroll,\n scrollToBottom,\n wrapperRect,\n } = useScrollLocationLogic({\n disableAutoScrollToBottom:\n isJumpingToLatest || isHighlightedJumpRequested || justReachedLatestMergedSet,\n disableScrollManagement: isJumpingToLatest || isJumpingToHighlightedMessage,\n hasMoreNewer,\n listElement,\n loadingMore: props.loadingMore,\n loadMoreScrollThreshold,\n messages, // todo: is it correct to base the scroll logic on an array that does not contain date separators or intro?\n scrolledUpThreshold: props.scrolledUpThreshold,\n suppressAutoscroll,\n });\n const isTypingIndicatorScrolledToBottom =\n isMessageListScrolledToBottom &&\n !isJumpingToLatest &&\n !isJumpingToHighlightedMessage &&\n !justReachedLatestMergedSet;\n\n const { show: showUnreadMessagesNotification } = useUnreadMessagesNotification({\n isMessageListScrolledToBottom,\n listElement,\n showAlways: !!showUnreadNotificationAlways,\n unreadCount: channelUnreadUiState?.unread_messages,\n });\n\n useMarkRead({\n isMessageListScrolledToBottom: isTypingIndicatorScrolledToBottom,\n messageListIsThread: threadList,\n wasMarkedUnread: !!channelUnreadUiState?.first_unread_message_id,\n });\n\n const { messageGroupStyles, messages: enrichedMessages } = useEnrichedMessages({\n channel,\n disableDateSeparator,\n groupStyles,\n headerPosition,\n hideDeletedMessages,\n hideNewMessageSeparator,\n maxTimeBetweenGroupedMessages,\n messages,\n noGroupByUser,\n reviewProcessedMessage,\n });\n\n const lastOwnMessage = useLastOwnMessage({\n messages,\n ownUserId: channel.getClient().user?.id,\n });\n\n const elements = useMessageListElements({\n channelUnreadUiState,\n enrichedMessages,\n internalMessageProps: {\n additionalMessageComposerProps: props.additionalMessageComposerProps,\n closeReactionSelectorOnClick: props.closeReactionSelectorOnClick,\n disableQuotedMessages: props.disableQuotedMessages,\n formatDate: props.formatDate,\n Message: props.Message,\n messageActions,\n messageListRect: wrapperRect,\n onMentionsClick: props.onMentionsClick,\n onMentionsHover: props.onMentionsHover,\n onUserClick: props.onUserClick,\n onUserHover: props.onUserHover,\n openThread: props.openThread,\n reactionDetailsSort,\n renderText: props.renderText,\n retrySendMessage: props.retrySendMessage,\n showAvatar: props.showAvatar,\n sortReactions,\n unsafeHTML,\n },\n lastOwnMessage,\n messageGroupStyles,\n messages,\n renderMessages,\n returnAllReadData,\n threadList,\n });\n\n useIncomingMessageAnnouncements({\n activeThreadId: thread?.id,\n channel,\n ownUserId: channel.getClient().user?.id,\n threadList,\n });\n\n const messageListClass = customClasses?.messageList || 'str-chat__message-list';\n\n const loadMore = React.useCallback(() => {\n if (loadMoreCallback) {\n loadMoreCallback(messageLimit);\n }\n }, [loadMoreCallback, messageLimit]);\n\n const loadMoreNewer = React.useCallback(() => {\n if (loadMoreNewerCallback) {\n loadMoreNewerCallback(messageLimit);\n }\n }, [loadMoreNewerCallback, messageLimit]);\n\n const scrollToBottomFromNotification = React.useCallback(async () => {\n if (hasMoreNewer) {\n setJumpSourceMessageSetSignature(messageSetSignature);\n setJumpToLatestPhase('waiting-for-render');\n try {\n await jumpToLatestMessage();\n } catch (error) {\n setJumpSourceMessageSetSignature(null);\n setJumpToLatestPhase('idle');\n throw error;\n }\n return;\n }\n\n scrollToBottom({ behavior: scrollBehavior });\n }, [\n scrollBehavior,\n hasMoreNewer,\n jumpToLatestMessage,\n messageSetSignature,\n scrollToBottom,\n ]);\n\n React.useLayoutEffect(() => {\n if (\n jumpToLatestPhase !== 'waiting-for-render' ||\n hasMoreNewer ||\n !listElement?.scrollTo ||\n messageSetSignature === jumpSourceMessageSetSignature\n ) {\n return;\n }\n\n listElement.scrollTo({ top: 0 });\n\n const animationFrameId = requestAnimationFrame(() => {\n setJumpToLatestPhase('animating');\n listElement.scrollTo({\n behavior: scrollBehavior,\n top: listElement.scrollHeight,\n });\n });\n\n return () => cancelAnimationFrame(animationFrameId);\n }, [\n scrollBehavior,\n hasMoreNewer,\n jumpSourceMessageSetSignature,\n jumpToLatestPhase,\n listElement,\n messageSetSignature,\n ]);\n\n React.useLayoutEffect(() => {\n if (jumpToLatestPhase !== 'animating' || !listElement?.scrollTo) {\n return;\n }\n\n const finalize = () => {\n listElement.scrollTo({ top: listElement.scrollHeight });\n setJumpSourceMessageSetSignature(null);\n setJumpToLatestPhase('idle');\n };\n\n const settleTimeoutId = setTimeout(finalize, 500);\n\n return () => {\n clearTimeout(settleTimeoutId);\n };\n }, [jumpToLatestPhase, listElement]);\n\n React.useLayoutEffect(() => {\n if (!highlightedMessageId) {\n setHighlightedJumpPhase('idle');\n return;\n }\n\n const element = listElement?.querySelector(\n `[data-message-id='${highlightedMessageId}']`,\n );\n if (!element) {\n setHighlightedJumpPhase('waiting-for-render');\n return;\n }\n\n const messageSetChanged =\n previousMessageSetSignatureRef.current !== messageSetSignature;\n setHighlightedJumpPhase(messageSetChanged ? 'animating' : 'idle');\n let settleTimeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const animationFrameId = requestAnimationFrame(() => {\n element.scrollIntoView({\n behavior: scrollBehavior,\n block: 'center',\n });\n\n if (!messageSetChanged || !listElement?.scrollTo) {\n setHighlightedJumpPhase('idle');\n return;\n }\n\n settleTimeoutId = setTimeout(() => {\n const elementRect = element.getBoundingClientRect();\n const listRect = listElement.getBoundingClientRect();\n const targetTop =\n listElement.scrollTop +\n (elementRect.top - listRect.top) -\n (listElement.clientHeight - elementRect.height) / 2;\n\n listElement.scrollTo({ top: Math.max(targetTop, 0) });\n setHighlightedJumpPhase('idle');\n }, 500);\n });\n\n return () => {\n cancelAnimationFrame(animationFrameId);\n if (settleTimeoutId) {\n clearTimeout(settleTimeoutId);\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scrollBehavior, highlightedMessageId, messageSetSignature]);\n\n React.useEffect(() => {\n previousHasMoreNewerRef.current = hasMoreNewer;\n }, [hasMoreNewer]);\n\n React.useEffect(() => {\n previousMessageSetSignatureRef.current = messageSetSignature;\n previousMessageSetBoundsRef.current = messageSetBounds;\n }, [messageSetBounds, messageSetSignature]);\n\n const id = useStableId();\n\n const showEmptyStateIndicator = elements.length === 0 && !threadList;\n const dialogManagerId = threadList\n ? `message-list-dialog-manager-thread-${id}`\n : `message-list-dialog-manager-${id}`;\n\n return (\n <MessageListContextProvider\n value={{\n listElement,\n processedMessages: enrichedMessages,\n scrollToBottom,\n }}\n >\n <MessageTranslationViewProvider>\n <MessageListMainPanel>\n <DialogManagerProvider id={dialogManagerId}>\n {!threadList && showUnreadMessagesNotification && (\n <UnreadMessagesNotification\n unreadCount={channelUnreadUiState?.unread_messages}\n />\n )}\n <FloatingDateSeparator\n disableDateSeparator={disableDateSeparator}\n listElement={listElement}\n processedMessages={enrichedMessages}\n />\n <div\n className={clsx(messageListClass, customClasses?.threadList)}\n onScroll={onScroll}\n ref={setListElement}\n tabIndex={0}\n >\n {showEmptyStateIndicator ? (\n <EmptyStateIndicator listType={threadList ? 'thread' : 'message'} />\n ) : (\n <InfiniteScroll\n className='str-chat__message-list-scroll'\n data-testid='reverse-infinite-scroll'\n hasNextPage={props.hasMoreNewer}\n hasPreviousPage={isJumpingToHighlightedMessage ? false : props.hasMore}\n head={props.head}\n isLoading={Boolean(\n props.loadingMore || props.loadingMoreForJumpToChannelMessage,\n )}\n loader={\n <div className='str-chat__list__loading' key='loading-indicator'>\n {(props.loadingMore ||\n props.loadingMoreForJumpToChannelMessage) && <LoadingIndicator />}\n </div>\n }\n loadNextPage={loadMoreNewer}\n loadPreviousPage={\n isJumpingToHighlightedMessage ? () => undefined : loadMore\n }\n threshold={loadMoreScrollThreshold}\n {...restInternalInfiniteScrollProps}\n >\n <MessageListWrapper className='str-chat__ul'>\n {elements}\n </MessageListWrapper>\n <TypingIndicator\n isMessageListScrolledToBottom={isTypingIndicatorScrolledToBottom}\n scrollToBottom={scrollToBottom}\n threadList={threadList}\n />\n\n <div key='bottom' />\n </InfiniteScroll>\n )}\n </div>\n <NewMessageNotification\n newMessageCount={channelUnreadUiState?.unread_messages}\n showNotification={hasNewMessages || hasMoreNewer}\n />\n <ScrollToLatestMessageButton\n isMessageListScrolledToBottom={isMessageListScrolledToBottom}\n isNotAtLatestMessageSet={hasMoreNewer}\n onClick={scrollToBottomFromNotification}\n threadList={threadList}\n />\n </DialogManagerProvider>\n <NotificationList panel={notificationTarget} />\n </MessageListMainPanel>\n </MessageTranslationViewProvider>\n </MessageListContextProvider>\n );\n};\n\ntype PropsDrilledToMessage =\n | 'additionalMessageComposerProps'\n | 'closeReactionSelectorOnClick'\n | 'disableQuotedMessages'\n | 'formatDate'\n | 'Message'\n | 'messageActions'\n | 'onMentionsClick'\n | 'onMentionsHover'\n | 'onUserClick'\n | 'onUserHover'\n | 'openThread'\n | 'reactionDetailsSort'\n | 'renderText'\n | 'retrySendMessage'\n | 'showAvatar'\n | 'sortReactions'\n | 'unsafeHTML';\n\nexport type MessageListProps = Partial<Pick<MessageProps, PropsDrilledToMessage>> & {\n /** Disables the injection of date separator components in MessageList, defaults to `false` */\n disableDateSeparator?: boolean;\n /** Callback function to set group styles for each message */\n groupStyles?: (\n message: RenderedMessage,\n previousMessage: RenderedMessage,\n nextMessage: RenderedMessage,\n noGroupByUser: boolean,\n maxTimeBetweenGroupedMessages?: number,\n ) => GroupStyle;\n /** Whether the list has more items to load */\n hasMore?: boolean;\n /** Element to be rendered at the top of the thread message list. By default, these are the Message and ThreadStart components */\n head?: React.ReactElement;\n /** Position to render HeaderComponent */\n headerPosition?: number;\n /** Hides the MessageDeleted components from the list, defaults to `false` */\n hideDeletedMessages?: boolean;\n /** Hides the DateSeparator component when new messages are received in a channel that's watched but not active, defaults to false */\n hideNewMessageSeparator?: boolean;\n /** Overrides the default props passed to [InfiniteScroll](https://github.com/GetStream/stream-chat-react/blob/master/src/components/InfiniteScrollPaginator/InfiniteScroll.tsx) */\n internalInfiniteScrollProps?: Partial<InfiniteScrollProps>;\n /** Function called when latest messages should be loaded, after the list has jumped at an earlier message set */\n jumpToLatestMessage?: () => Promise<void>;\n /** Whether or not the list is currently loading more items */\n loadingMore?: boolean;\n /** Whether or not the list is currently jumping to a highlighted message */\n loadingMoreForJumpToChannelMessage?: boolean;\n /** Whether or not the list is currently loading newer items */\n loadingMoreNewer?: boolean;\n /** Function called when more messages are to be loaded, defaults to function stored in [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/) */\n loadMore?: ChannelActionContextValue['loadMore'] | (() => Promise<void>);\n /** Function called when newer messages are to be loaded, defaults to function stored in [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/) */\n loadMoreNewer?: ChannelActionContextValue['loadMoreNewer'] | (() => Promise<void>);\n /** Maximum time in milliseconds that should occur between messages to still consider them grouped together */\n maxTimeBetweenGroupedMessages?: number;\n /** The limit to use when paginating messages */\n messageLimit?: number;\n /** The messages to render in the list, defaults to messages stored in [ChannelStateContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_state_context/) */\n messages?: LocalMessage[];\n /** If true, turns off message UI grouping by user */\n noGroupByUser?: boolean;\n /** Overrides the way MessageList renders messages */\n renderMessages?: MessageRenderer;\n /** If true, `readBy` data supplied to the `Message` components will include all user read states per sent message */\n returnAllReadData?: boolean;\n /**\n * Allows to review changes introduced to messages array on per message basis (e.g. date separator injection before a message).\n * The array returned from the function is appended to the array of messages that are later rendered into React elements in the `MessageList`.\n */\n reviewProcessedMessage?: ProcessMessagesParams['reviewProcessedMessage'];\n /**\n * The pixel threshold under which the message list is considered to be so near to the bottom,\n * so that if a new message is delivered, the list will be scrolled to the absolute bottom.\n * Defaults to 200px\n */\n scrolledUpThreshold?: number;\n /**\n * The floating notification informing about unread messages will be shown when the\n * UnreadMessagesSeparator is not visible. The default is false, that means the notification\n * is shown only when viewing unread messages.\n */\n showUnreadNotificationAlways?: boolean;\n /** If true, indicates the message list is a thread */\n threadList?: boolean; // todo: refactor needed - message list should have a state in which among others it would be optionally flagged as thread\n};\n\n/**\n * The MessageList component renders a list of Messages.\n * It is a consumer of the following contexts:\n * - [ChannelStateContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_state_context/)\n * - [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/)\n * - [ComponentContext](https://getstream.io/chat/docs/sdk/react/contexts/component_context/)\n * - [TypingContext](https://getstream.io/chat/docs/sdk/react/contexts/typing_context/)\n */\nexport const MessageList = (props: MessageListProps) => {\n const { jumpToLatestMessage, loadMore, loadMoreNewer } =\n useChannelActionContext('MessageList');\n\n const {\n members: membersPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n mutes: mutesPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n watchers: watchersPropToNotPass, // eslint-disable-line @typescript-eslint/no-unused-vars\n ...restChannelStateContext\n } = useChannelStateContext('MessageList');\n\n return (\n <MessageListWithContext\n jumpToLatestMessage={jumpToLatestMessage}\n loadMore={loadMore}\n loadMoreNewer={loadMoreNewer}\n {...restChannelStateContext}\n {...props}\n />\n );\n};\n","import clsx from 'clsx';\nimport throttle from 'lodash.throttle';\nimport React from 'react';\nimport type { ItemProps, ListItem } from 'react-virtuoso';\n\nimport { EmptyStateIndicator as DefaultEmptyStateIndicator } from '../EmptyStateIndicator';\nimport { LoadingIndicator as DefaultLoadingIndicator } from '../Loading';\nimport { Message } from '../Message';\n\nimport { useComponentContext } from '../../context';\nimport type { GroupStyle, RenderedMessage } from './utils';\nimport { getIsFirstUnreadMessage, isDateSeparatorMessage, isIntroMessage } from './utils';\nimport type { VirtuosoContext } from './VirtualizedMessageList';\nimport type { UnknownType } from '../../types/types';\n\nconst PREPEND_OFFSET = 10 ** 7;\n\nexport function calculateItemIndex(virtuosoIndex: number, numItemsPrepended: number) {\n return virtuosoIndex + numItemsPrepended - PREPEND_OFFSET;\n}\n\nexport function calculateFirstItemIndex(numItemsPrepended: number) {\n return PREPEND_OFFSET - numItemsPrepended;\n}\n\nexport const makeItemsRenderedHandler = (\n renderedItemsActions: Array<(msg: RenderedMessage[]) => void>,\n processedMessages: RenderedMessage[],\n) =>\n throttle((items: ListItem<UnknownType>[]) => {\n const renderedMessages = items\n .map((item) => {\n if (!item.originalIndex) return undefined;\n return processedMessages[calculateItemIndex(item.originalIndex, PREPEND_OFFSET)];\n })\n .filter((msg) => !!msg);\n renderedItemsActions.forEach((action) =>\n action(renderedMessages as RenderedMessage[]),\n );\n }, 200);\n\ntype CommonVirtuosoComponentProps = {\n context?: VirtuosoContext;\n};\n// using 'display: inline-block'\n// traps CSS margins of the item elements, preventing incorrect item measurements\nexport const Item = ({ context, ...props }: ItemProps & CommonVirtuosoComponentProps) => {\n if (!context) return <></>;\n\n const message =\n context.processedMessages[\n calculateItemIndex(props['data-item-index'], context.numItemsPrepended)\n ];\n const groupStyles: GroupStyle = context.messageGroupStyles[message.id];\n\n return (\n <div\n {...props}\n className={\n context?.customClasses?.virtualMessage ||\n clsx('str-chat__virtual-list-message-wrapper str-chat__li', {\n [`str-chat__li--${groupStyles}`]: groupStyles,\n })\n }\n />\n );\n};\nexport const Header = ({ context }: CommonVirtuosoComponentProps) => {\n const { LoadingIndicator = DefaultLoadingIndicator } = useComponentContext(\n 'VirtualizedMessageListHeader',\n );\n\n return (\n <>\n {context?.head}\n {context?.loadingMore && LoadingIndicator && (\n <div className='str-chat__virtual-list__loading'>\n <LoadingIndicator />\n </div>\n )}\n </>\n );\n};\nexport const EmptyPlaceholder = ({ context }: CommonVirtuosoComponentProps) => {\n const { EmptyStateIndicator = DefaultEmptyStateIndicator } = useComponentContext(\n 'VirtualizedMessageList',\n );\n // prevent showing that there are no messages if there actually are messages (for some reason virtuoso decides to render empty placeholder first, even though it has the totalCount prop > 0)\n if (\n typeof context?.processedMessages !== 'undefined' &&\n context.processedMessages.length > 0\n )\n return null;\n\n return (\n <>\n {EmptyStateIndicator && (\n <EmptyStateIndicator listType={context?.threadList ? 'thread' : 'message'} />\n )}\n </>\n );\n};\n\nexport const messageRenderer = (\n virtuosoIndex: number,\n _data: UnknownType,\n virtuosoContext: VirtuosoContext,\n) => {\n const {\n additionalMessageComposerProps,\n closeReactionSelectorOnClick,\n customMessageRenderer,\n DateSeparator,\n firstUnreadMessageId,\n formatDate,\n lastOwnMessage,\n lastReadDate,\n lastReadMessageId,\n lastReceivedMessageId,\n Message: MessageUIComponent,\n messageActions,\n messageGroupStyles,\n MessageSystem,\n numItemsPrepended,\n openThread,\n ownMessagesDeliveredToOthers,\n ownMessagesReadByOthers,\n processedMessages: messageList,\n reactionDetailsSort,\n renderText,\n returnAllReadData,\n showAvatar,\n sortReactions,\n threadList,\n unreadMessageCount = 0,\n UnreadMessagesSeparator,\n virtuosoRef,\n } = virtuosoContext;\n\n const streamMessageIndex = calculateItemIndex(virtuosoIndex, numItemsPrepended);\n\n if (customMessageRenderer) {\n return customMessageRenderer(messageList, streamMessageIndex);\n }\n\n const message = messageList[streamMessageIndex];\n\n if (!message || isIntroMessage(message)) return <div style={{ height: '1px' }}></div>; // returning null or zero height breaks the virtuoso\n\n if (isDateSeparatorMessage(message)) {\n return DateSeparator ? (\n <DateSeparator date={message.date} unread={message.unread} />\n ) : null;\n }\n\n if (message.type === 'system') {\n return MessageSystem ? <MessageSystem message={message} /> : null;\n }\n\n const isFirstUnreadMessage = getIsFirstUnreadMessage({\n firstUnreadMessageId,\n isFirstMessage: streamMessageIndex === 0,\n lastReadDate,\n lastReadMessageId,\n message,\n previousMessage: streamMessageIndex ? messageList[streamMessageIndex - 1] : undefined,\n unreadMessageCount,\n });\n\n return (\n <>\n {isFirstUnreadMessage && (\n <div className='str-chat__unread-messages-separator-wrapper'>\n <UnreadMessagesSeparator unreadCount={unreadMessageCount} />\n </div>\n )}\n <Message\n additionalMessageComposerProps={additionalMessageComposerProps}\n autoscrollToBottom={virtuosoRef.current?.autoscrollToBottom}\n closeReactionSelectorOnClick={closeReactionSelectorOnClick}\n deliveredTo={ownMessagesDeliveredToOthers[message.id] || []}\n formatDate={formatDate}\n groupStyles={[messageGroupStyles[message.id] ?? '']}\n lastOwnMessage={lastOwnMessage}\n lastReceivedId={lastReceivedMessageId}\n message={message}\n Message={MessageUIComponent}\n messageActions={messageActions}\n openThread={openThread}\n reactionDetailsSort={reactionDetailsSort}\n readBy={ownMessagesReadByOthers[message.id] || []}\n renderText={renderText}\n returnAllReadData={returnAllReadData}\n showAvatar={showAvatar}\n sortReactions={sortReactions}\n threadList={threadList}\n />\n </>\n );\n};\n","import type { RefObject } from 'react';\nimport React, { useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport { FloatingDateSeparator } from './FloatingDateSeparator';\nimport type {\n ComputeItemKey,\n ScrollSeekConfiguration,\n ScrollSeekPlaceholderProps,\n VirtuosoHandle,\n VirtuosoProps,\n} from 'react-virtuoso';\nimport { Virtuoso } from 'react-virtuoso';\n\nimport { GiphyPreviewMessage as DefaultGiphyPreviewMessage } from './GiphyPreviewMessage';\nimport { useLastReadData } from './hooks';\nimport {\n useGiphyPreview,\n useMessageSetKey,\n useNewMessageNotification,\n usePrependedMessagesCount,\n useScrollToBottomOnNewMessage,\n useShouldForceScrollToBottom,\n useUnreadMessagesNotificationVirtualized,\n} from './hooks/VirtualizedMessageList';\nimport { useMarkRead } from './hooks/useMarkRead';\nimport { NewMessageNotification as DefaultNewMessageNotification } from './NewMessageNotification';\nimport { MessageListMainPanel as DefaultMessageListMainPanel } from './MessageListMainPanel';\nimport type { GroupStyle, ProcessMessagesParams, RenderedMessage } from './utils';\nimport { getGroupStyles, getLastReceived, processMessages } from './utils';\nimport type { MessageProps, MessageUIComponentProps } from '../Message';\nimport { MessageUI } from '../Message';\nimport { UnreadMessagesNotification as DefaultUnreadMessagesNotification } from './UnreadMessagesNotification';\nimport {\n calculateFirstItemIndex,\n calculateItemIndex,\n EmptyPlaceholder,\n Header,\n Item,\n makeItemsRenderedHandler,\n messageRenderer,\n} from './VirtualizedMessageListComponents';\n\nimport {\n ScrollToLatestMessageButton as DefaultScrollToLatestMessageButton,\n UnreadMessagesSeparator as DefaultUnreadMessagesSeparator,\n} from '../MessageList';\nimport { DateSeparator as DefaultDateSeparator } from '../DateSeparator';\nimport { EventComponent as DefaultMessageSystem } from '../EventComponent';\nimport {\n NotificationList as DefaultNotificationList,\n useNotificationTarget,\n} from '../Notifications';\n\nimport { DialogManagerProvider } from '../../context';\nimport type { ChannelActionContextValue } from '../../context/ChannelActionContext';\nimport { useChannelActionContext } from '../../context/ChannelActionContext';\nimport type {\n ChannelNotifications,\n ChannelStateContextValue,\n} from '../../context/ChannelStateContext';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport type { ChatContextValue } from '../../context/ChatContext';\nimport { useChatContext } from '../../context/ChatContext';\nimport type { ComponentContextValue } from '../../context/ComponentContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { MessageTranslationViewProvider } from '../../context/MessageTranslationViewContext';\nimport { VirtualizedMessageListContextProvider } from '../../context/VirtualizedMessageListContext';\n\nimport type {\n Channel,\n LocalMessage,\n ChannelState as StreamChannelState,\n UserResponse,\n} from 'stream-chat';\nimport type { UnknownType } from '../../types/types';\nimport { DEFAULT_NEXT_CHANNEL_PAGE_SIZE } from '../../constants/limits';\nimport { useStableId } from '../UtilityComponents/useStableId';\nimport { useLastDeliveredData } from './hooks/useLastDeliveredData';\nimport { useLastOwnMessage } from './hooks/useLastOwnMessage';\nimport { useReducedMotionPreference } from './hooks/useReducedMotionPreference';\nimport { useIncomingMessageAnnouncements } from '../Accessibility';\n\ntype PropsDrilledToMessage =\n | 'additionalMessageComposerProps'\n | 'formatDate'\n | 'messageActions'\n | 'openThread'\n | 'reactionDetailsSort'\n | 'renderText'\n | 'showAvatar'\n | 'sortReactions';\n\ntype VirtualizedMessageListPropsForContext =\n | PropsDrilledToMessage\n | 'closeReactionSelectorOnClick'\n | 'customMessageRenderer'\n | 'head'\n | 'loadingMore'\n | 'Message'\n | 'returnAllReadData'\n | 'shouldGroupByUser'\n | 'threadList';\n\n/**\n * Context object provided to some Virtuoso props that are functions (components rendered by Virtuoso and other functions)\n */\nexport type VirtuosoContext = Required<\n Pick<\n ComponentContextValue,\n 'DateSeparator' | 'MessageSystem' | 'UnreadMessagesSeparator'\n >\n> &\n Pick<VirtualizedMessageListProps, VirtualizedMessageListPropsForContext> &\n Pick<ChatContextValue, 'customClasses'> & {\n /** Latest received message id in the current channel */\n lastReceivedMessageId: string | null | undefined;\n /** Object mapping between the message ID and a string representing the position in the group of a sequence of messages posted by the same user. */\n messageGroupStyles: Record<string, GroupStyle>;\n /** Number of messages prepended before the first page of messages. This is needed to calculate the virtual position in the virtual list. */\n numItemsPrepended: number;\n /** Mapping of message ID of own messages to the array of users, who were delivered the given message */\n ownMessagesDeliveredToOthers: Record<string, UserResponse[]>;\n /** Mapping of message ID of own messages to the array of users, who read the given message */\n ownMessagesReadByOthers: Record<string, UserResponse[]>;\n /** The original message list enriched with date separators, omitted deleted messages or giphy previews. */\n processedMessages: RenderedMessage[];\n /** Instance of VirtuosoHandle object providing the API to navigate in the virtualized list by various scroll actions. */\n virtuosoRef: RefObject<VirtuosoHandle | null>;\n /** Latest own message in currently displayed message set. */\n lastOwnMessage?: LocalMessage;\n /** Message id which was marked as unread. ALl the messages following this message are considered unrea. */\n firstUnreadMessageId?: string;\n lastReadDate?: Date;\n /**\n * The ID of the last message considered read by the current user in the current channel.\n * All the messages following this message are considered unread.\n */\n lastReadMessageId?: string;\n /** The number of unread messages in the current channel. */\n unreadMessageCount?: number;\n };\n\ntype VirtualizedMessageListWithContextProps = VirtualizedMessageListProps & {\n channel: Channel;\n hasMore: boolean;\n hasMoreNewer: boolean;\n jumpToLatestMessage: () => Promise<void>;\n loadingMore: boolean;\n loadingMoreNewer: boolean;\n notifications: ChannelNotifications;\n read?: StreamChannelState['read'];\n thread?: ChannelStateContextValue['thread'];\n};\n\nfunction captureResizeObserverExceededError(e: ErrorEvent) {\n if (\n e.message === 'ResizeObserver loop completed with undelivered notifications.' ||\n e.message === 'ResizeObserver loop limit exceeded'\n ) {\n e.stopImmediatePropagation();\n }\n}\n\nfunction useCaptureResizeObserverExceededError() {\n useEffect(() => {\n window.addEventListener('error', captureResizeObserverExceededError);\n return () => {\n window.removeEventListener('error', captureResizeObserverExceededError);\n };\n }, []);\n}\n\nfunction fractionalItemSize(element: HTMLElement) {\n return element.getBoundingClientRect().height;\n}\n\nfunction findMessageIndex(messages: RenderedMessage[], id: string) {\n return messages.findIndex((message) => message.id === id);\n}\n\nfunction calculateInitialTopMostItemIndex(\n messages: RenderedMessage[],\n highlightedMessageId: string | undefined,\n) {\n if (highlightedMessageId) {\n const index = findMessageIndex(messages, highlightedMessageId);\n if (index !== -1) {\n return { align: 'center', index } as const;\n }\n }\n return messages.length - 1;\n}\n\nconst VirtualizedMessageListWithContext = (\n props: VirtualizedMessageListWithContextProps,\n) => {\n const {\n additionalMessageComposerProps,\n additionalVirtuosoProps = {},\n channel,\n channelUnreadUiState,\n closeReactionSelectorOnClick,\n customMessageRenderer,\n defaultItemHeight,\n disableDateSeparator = true,\n formatDate,\n groupStyles,\n hasMoreNewer,\n head,\n hideDeletedMessages = false,\n hideNewMessageSeparator = false,\n highlightedMessageId,\n jumpToLatestMessage,\n loadingMore,\n loadMore,\n loadMoreNewer,\n maxTimeBetweenGroupedMessages,\n Message: MessageUIComponentFromProps,\n messageActions,\n messageLimit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE,\n messages,\n openThread,\n // TODO: refactor to scrollSeekPlaceHolderConfiguration and components.ScrollSeekPlaceholder, like the Virtuoso Component\n overscan = 0,\n reactionDetailsSort,\n renderText,\n returnAllReadData = false,\n reviewProcessedMessage,\n scrollSeekPlaceHolder,\n scrollToLatestMessageOnFocus = false,\n separateGiphyPreview = false,\n shouldGroupByUser = false,\n showAvatar,\n showUnreadNotificationAlways,\n sortReactions,\n stickToBottomScrollBehavior = 'smooth',\n suppressAutoscroll,\n thread,\n threadList,\n } = props;\n\n const { components: virtuosoComponentsFromProps, ...overridingVirtuosoProps } =\n additionalVirtuosoProps;\n\n // Stops errors generated from react-virtuoso to bubble up\n // to Sentry or other tracking tools.\n useCaptureResizeObserverExceededError();\n\n const {\n DateSeparator = DefaultDateSeparator,\n GiphyPreviewMessage = DefaultGiphyPreviewMessage,\n MessageListMainPanel = DefaultMessageListMainPanel,\n MessageSystem = DefaultMessageSystem,\n NewMessageNotification = DefaultNewMessageNotification,\n NotificationList = DefaultNotificationList,\n ScrollToLatestMessageButton = DefaultScrollToLatestMessageButton,\n TypingIndicator,\n UnreadMessagesNotification = DefaultUnreadMessagesNotification,\n UnreadMessagesSeparator = DefaultUnreadMessagesSeparator,\n VirtualMessage: MessageUIComponentFromContext = MessageUI,\n } = useComponentContext('VirtualizedMessageList');\n const MessageUIComponent = MessageUIComponentFromProps || MessageUIComponentFromContext;\n\n const { client, customClasses } = useChatContext('VirtualizedMessageList');\n const prefersReducedMotion = useReducedMotionPreference();\n const effectiveStickToBottomScrollBehavior = prefersReducedMotion\n ? 'auto'\n : stickToBottomScrollBehavior;\n const notificationTarget = useNotificationTarget();\n\n const virtuoso = useRef<VirtuosoHandle>(null);\n\n const lastRead = useMemo(() => channel.lastRead?.(), [channel]);\n\n const { show: showUnreadMessagesNotification, toggleShowUnreadMessagesNotification } =\n useUnreadMessagesNotificationVirtualized({\n lastRead: channelUnreadUiState?.last_read,\n showAlways: !!showUnreadNotificationAlways,\n unreadCount: channelUnreadUiState?.unread_messages ?? 0,\n });\n\n const { giphyPreviewMessage, setGiphyPreviewMessage } =\n useGiphyPreview(separateGiphyPreview);\n\n const processedMessages = useMemo(() => {\n if (typeof messages === 'undefined') {\n return [];\n }\n\n if (\n disableDateSeparator &&\n !hideDeletedMessages &&\n hideNewMessageSeparator &&\n !separateGiphyPreview\n ) {\n return messages;\n }\n\n return processMessages({\n enableDateSeparator: !disableDateSeparator,\n hideDeletedMessages,\n hideNewMessageSeparator,\n lastRead,\n messages,\n reviewProcessedMessage,\n setGiphyPreviewMessage,\n userId: client.userID || '',\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n disableDateSeparator,\n hideDeletedMessages,\n hideNewMessageSeparator,\n lastRead,\n messages,\n messages?.length,\n client.userID,\n ]);\n\n /**\n * This indirection via a ref is needed because Virtuoso’s itemsRendered is set at render time,\n * while FloatingDateSeparator lives in a child component that may run its hooks in a different order.\n * Using a ref lets the parent provide the callback to Virtuoso while the child keeps ownership\n * of the actual handler implementation.\n */\n const floatingDateItemsRenderedRef = useRef<\n ((rendered: RenderedMessage[]) => void) | null\n >(null);\n\n const lastOwnMessage = useLastOwnMessage({ messages, ownUserId: client.user?.id });\n\n // get the mapping of own messages to array of users who read them\n const ownMessagesReadByOthers = useLastReadData({\n channel,\n lastOwnMessage,\n messages: messages || [],\n returnAllReadData,\n });\n\n const ownMessagesDeliveredToOthers = useLastDeliveredData({\n channel,\n lastOwnMessage,\n messages: messages || [],\n returnAllReadData,\n });\n\n const lastReceivedMessageId = useMemo(\n () => getLastReceived(processedMessages),\n [processedMessages],\n );\n\n const groupStylesFn = groupStyles || getGroupStyles;\n const messageGroupStyles = useMemo(\n () =>\n processedMessages.reduce<Record<string, GroupStyle>>((acc, message, i) => {\n const style = groupStylesFn(\n message,\n processedMessages[i - 1],\n processedMessages[i + 1],\n !shouldGroupByUser,\n maxTimeBetweenGroupedMessages,\n );\n if (style && message.id) acc[message.id] = style;\n return acc;\n }, {}),\n // processedMessages were incorrectly rebuilt with a new object identity at some point, hence the .length usage\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n maxTimeBetweenGroupedMessages,\n processedMessages.length,\n shouldGroupByUser,\n groupStylesFn,\n ],\n );\n\n const {\n atBottom,\n isMessageListScrolledToBottom,\n newMessagesNotification,\n setIsMessageListScrolledToBottom,\n setNewMessagesNotification,\n } = useNewMessageNotification(processedMessages, client.userID, hasMoreNewer);\n\n useMarkRead({\n isMessageListScrolledToBottom,\n messageListIsThread: !!threadList,\n wasMarkedUnread: !!channelUnreadUiState?.first_unread_message_id,\n });\n\n const scrollToBottom = useCallback(async () => {\n if (hasMoreNewer) {\n await jumpToLatestMessage();\n return;\n }\n\n if (virtuoso.current) {\n virtuoso.current.scrollToIndex(processedMessages.length - 1);\n }\n\n setNewMessagesNotification(false);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n virtuoso,\n processedMessages,\n setNewMessagesNotification,\n // processedMessages were incorrectly rebuilt with a new object identity at some point, hence the .length usage\n processedMessages.length,\n hasMoreNewer,\n jumpToLatestMessage,\n ]);\n\n useScrollToBottomOnNewMessage({\n messages,\n scrollToBottom,\n scrollToLatestMessageOnFocus,\n });\n\n const numItemsPrepended = usePrependedMessagesCount(\n processedMessages,\n !disableDateSeparator,\n );\n\n const { messageSetKey } = useMessageSetKey({ messages });\n\n const shouldForceScrollToBottom = useShouldForceScrollToBottom(\n processedMessages,\n client.userID,\n );\n\n useIncomingMessageAnnouncements({\n activeThreadId: thread?.id,\n channel,\n ownUserId: client.userID,\n threadList,\n });\n\n const handleItemsRendered = useMemo(\n () =>\n makeItemsRenderedHandler(\n [\n toggleShowUnreadMessagesNotification,\n (rendered) => floatingDateItemsRenderedRef.current?.(rendered),\n ],\n processedMessages,\n ),\n [processedMessages, toggleShowUnreadMessagesNotification],\n );\n const followOutput = (isAtBottom: boolean) => {\n if (hasMoreNewer || suppressAutoscroll) {\n return false;\n }\n\n if (shouldForceScrollToBottom()) {\n return isAtBottom ? effectiveStickToBottomScrollBehavior : 'auto';\n }\n // a message from another user has been received - don't scroll to bottom unless already there\n return isAtBottom ? effectiveStickToBottomScrollBehavior : false;\n };\n\n const computeItemKey = useCallback<ComputeItemKey<UnknownType, VirtuosoContext>>(\n (index, _, { numItemsPrepended, processedMessages }) =>\n processedMessages[calculateItemIndex(index, numItemsPrepended)].id,\n [],\n );\n\n const atBottomStateChange = (isAtBottom: boolean) => {\n atBottom.current = isAtBottom;\n setIsMessageListScrolledToBottom(isAtBottom);\n\n if (isAtBottom) {\n loadMoreNewer?.(messageLimit);\n setNewMessagesNotification?.(false);\n }\n };\n const atTopStateChange = (isAtTop: boolean) => {\n if (isAtTop) {\n loadMore?.(messageLimit);\n }\n };\n\n useEffect(() => {\n let scrollTimeout: ReturnType<typeof setTimeout>;\n if (highlightedMessageId) {\n const index = findMessageIndex(processedMessages, highlightedMessageId);\n if (index !== -1) {\n scrollTimeout = setTimeout(() => {\n virtuoso.current?.scrollToIndex({ align: 'center', index });\n }, 0);\n }\n }\n return () => {\n clearTimeout(scrollTimeout);\n };\n }, [highlightedMessageId, processedMessages]);\n\n const id = useStableId();\n\n if (!processedMessages) return null;\n\n const dialogManagerId = threadList\n ? `virtualized-message-list-dialog-manager-thread-${id}`\n : `virtualized-message-list-dialog-manager-${id}`;\n\n return (\n <VirtualizedMessageListContextProvider value={{ scrollToBottom }}>\n <MessageTranslationViewProvider>\n <MessageListMainPanel>\n <DialogManagerProvider id={dialogManagerId}>\n {!threadList && showUnreadMessagesNotification && (\n <UnreadMessagesNotification\n unreadCount={channelUnreadUiState?.unread_messages}\n />\n )}\n <div\n className={\n customClasses?.virtualizedMessageList || 'str-chat__virtual-list'\n }\n >\n <FloatingDateSeparator\n disableDateSeparator={disableDateSeparator}\n itemsRenderedRef={floatingDateItemsRenderedRef}\n processedMessages={processedMessages}\n />\n <Virtuoso<UnknownType, VirtuosoContext>\n atBottomStateChange={atBottomStateChange}\n atBottomThreshold={100}\n atTopStateChange={atTopStateChange}\n atTopThreshold={100}\n className='str-chat__message-list-scroll'\n components={{\n EmptyPlaceholder,\n Header,\n Item,\n ...(TypingIndicator && {\n Footer: () =>\n isMessageListScrolledToBottom ? (\n <TypingIndicator\n isMessageListScrolledToBottom={isMessageListScrolledToBottom}\n scrollToBottom={scrollToBottom}\n threadList={threadList}\n />\n ) : null,\n }),\n ...virtuosoComponentsFromProps,\n }}\n computeItemKey={computeItemKey}\n context={{\n additionalMessageComposerProps,\n closeReactionSelectorOnClick,\n customClasses,\n customMessageRenderer,\n DateSeparator,\n firstUnreadMessageId: channelUnreadUiState?.first_unread_message_id,\n formatDate,\n head,\n lastOwnMessage,\n lastReadDate: channelUnreadUiState?.last_read,\n lastReadMessageId: channelUnreadUiState?.last_read_message_id,\n lastReceivedMessageId,\n loadingMore,\n Message: MessageUIComponent,\n messageActions,\n messageGroupStyles,\n MessageSystem,\n numItemsPrepended,\n openThread,\n ownMessagesDeliveredToOthers,\n ownMessagesReadByOthers,\n processedMessages,\n reactionDetailsSort,\n renderText,\n returnAllReadData,\n shouldGroupByUser,\n showAvatar,\n sortReactions,\n threadList,\n unreadMessageCount: channelUnreadUiState?.unread_messages,\n UnreadMessagesSeparator,\n virtuosoRef: virtuoso,\n }}\n firstItemIndex={calculateFirstItemIndex(numItemsPrepended)}\n followOutput={followOutput}\n increaseViewportBy={{ bottom: 200, top: 0 }}\n initialTopMostItemIndex={calculateInitialTopMostItemIndex(\n processedMessages,\n highlightedMessageId,\n )}\n itemContent={messageRenderer}\n itemSize={fractionalItemSize}\n itemsRendered={handleItemsRendered}\n key={messageSetKey}\n overscan={overscan}\n ref={virtuoso}\n style={{ overflowX: 'hidden' }}\n totalCount={processedMessages.length}\n {...overridingVirtuosoProps}\n {...(scrollSeekPlaceHolder ? { scrollSeek: scrollSeekPlaceHolder } : {})}\n {...(defaultItemHeight ? { defaultItemHeight } : {})}\n />\n <NewMessageNotification\n newMessageCount={channelUnreadUiState?.unread_messages}\n showNotification={newMessagesNotification || hasMoreNewer}\n />\n <ScrollToLatestMessageButton\n isMessageListScrolledToBottom={isMessageListScrolledToBottom}\n isNotAtLatestMessageSet={hasMoreNewer}\n onClick={scrollToBottom}\n threadList={threadList}\n />\n </div>\n </DialogManagerProvider>\n <NotificationList panel={notificationTarget} />\n </MessageListMainPanel>\n {giphyPreviewMessage && <GiphyPreviewMessage message={giphyPreviewMessage} />}\n </MessageTranslationViewProvider>\n </VirtualizedMessageListContextProvider>\n );\n};\n\nexport type VirtualizedMessageListProps = Partial<\n Pick<MessageProps, PropsDrilledToMessage>\n> & {\n /** Additional props to be passed the underlying [`react-virtuoso` virtualized list dependency](https://virtuoso.dev/virtuoso-api-reference/) */\n additionalVirtuosoProps?: VirtuosoProps<UnknownType, VirtuosoContext>;\n channelUnreadUiState?: ChannelStateContextValue['channelUnreadUiState'];\n /** If true, picking a reaction from the `ReactionSelector` component will close the selector */\n closeReactionSelectorOnClick?: boolean;\n /** Custom render function, if passed, certain UI props are ignored */\n customMessageRenderer?: (\n messageList: RenderedMessage[],\n index: number,\n ) => React.ReactElement;\n /** @deprecated Use additionalVirtuosoProps.defaultItemHeight instead. Will be removed with next major release - `v11.0.0`.\n * If set, the default item height is used for the calculation of the total list height. Use if you expect messages with a lot of height variance\n * */\n defaultItemHeight?: number;\n /** Disables the injection of date separator components in MessageList, defaults to `true` */\n disableDateSeparator?: boolean;\n /** Callback function to set group styles for each message */\n groupStyles?: (\n message: RenderedMessage,\n previousMessage: RenderedMessage,\n nextMessage: RenderedMessage,\n noGroupByUser: boolean,\n maxTimeBetweenGroupedMessages?: number,\n ) => GroupStyle;\n /** Whether or not the list has more items to load */\n hasMore?: boolean;\n /** Whether or not the list has newer items to load */\n hasMoreNewer?: boolean;\n /**\n * @deprecated Use additionalVirtuosoProps.components.Header to override default component rendered above the list ove messages.\n * Element to be rendered at the top of the thread message list. By default, these are the Message and ThreadStart components\n */\n head?: React.ReactElement;\n /** Hides the `MessageDeleted` components from the list, defaults to `false` */\n hideDeletedMessages?: boolean;\n /** Hides the `DateSeparator` component when new messages are received in a channel that's watched but not active, defaults to false */\n hideNewMessageSeparator?: boolean;\n /** The id of the message to highlight and center */\n highlightedMessageId?: string;\n /** Whether or not the list is currently loading more items */\n loadingMore?: boolean;\n /** Whether or not the list is currently loading newer items */\n loadingMoreNewer?: boolean;\n /** Function called when more messages are to be loaded, defaults to function stored in [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/) */\n loadMore?: ChannelActionContextValue['loadMore'] | (() => Promise<void>);\n /** Function called when new messages are to be loaded, defaults to function stored in [ChannelActionContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_action_context/) */\n loadMoreNewer?: ChannelActionContextValue['loadMore'] | (() => Promise<void>);\n /** Maximum time in milliseconds that should occur between messages to still consider them grouped together */\n maxTimeBetweenGroupedMessages?: number;\n /** Custom UI component to display a message, defaults to and accepts same props as [MessageUI](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message/MessageUI.tsx) */\n Message?: React.ComponentType<MessageUIComponentProps>;\n /** The limit to use when paginating messages */\n messageLimit?: number;\n /** Optional prop to override the messages available from [ChannelStateContext](https://getstream.io/chat/docs/sdk/react/contexts/channel_state_context/) */\n messages?: LocalMessage[];\n /**\n * @deprecated Use additionalVirtuosoProps.overscan instead. Will be removed with next major release - `v11.0.0`.\n * The amount of extra content the list should render in addition to what's necessary to fill in the viewport\n */\n overscan?: number;\n /** Keep track of read receipts for each message sent by the user. When disabled, only the last own message delivery / read status is rendered. */\n returnAllReadData?: boolean;\n /**\n * Allows to review changes introduced to messages array on per message basis (e.g. date separator injected before a message).\n * The array returned from the function is appended to the array of messages that are later rendered into React elements in the `VirtualizedMessageList`.\n */\n reviewProcessedMessage?: ProcessMessagesParams['reviewProcessedMessage'];\n /**\n * @deprecated Pass additionalVirtuosoProps.scrollSeekConfiguration and specify the placeholder in additionalVirtuosoProps.components.ScrollSeekPlaceholder instead. Will be removed with next major release - `v11.0.0`.\n * Performance improvement by showing placeholders if user scrolls fast through list.\n * it can be used like this:\n * ```\n * {\n * enter: (velocity) => Math.abs(velocity) > 120,\n * exit: (velocity) => Math.abs(velocity) < 40,\n * change: () => null,\n * placeholder: ({index, height})=> <div style={{height: height + \"px\"}}>{index}</div>,\n * }\n * ```\n */\n scrollSeekPlaceHolder?: ScrollSeekConfiguration & {\n placeholder: React.ComponentType<ScrollSeekPlaceholderProps>;\n };\n /** When `true`, the list will scroll to the latest message when the window regains focus */\n scrollToLatestMessageOnFocus?: boolean;\n /** If true, the Giphy preview will render as a separate component above the `MessageComposer`, rather than inline with the other messages in the list */\n separateGiphyPreview?: boolean;\n /** If true, group messages belonging to the same user, otherwise show each message individually */\n shouldGroupByUser?: boolean;\n /**\n * The floating notification informing about unread messages will be shown when the\n * UnreadMessagesSeparator is not visible. The default is false, that means the notification\n * is shown only when viewing unread messages.\n */\n showUnreadNotificationAlways?: boolean;\n /** The scrollTo behavior when new messages appear. Use `\"smooth\"` for regular chat channels, and `\"auto\"` (which results in instant scroll to bottom) if you expect high throughput. Reduced-motion users are always treated as `\"auto\"`. */\n stickToBottomScrollBehavior?: 'smooth' | 'auto';\n /** stops the list from autoscrolling when new messages are loaded */\n suppressAutoscroll?: boolean;\n /** If true, indicates the message list is a thread */\n threadList?: boolean;\n};\n\n/**\n * The VirtualizedMessageList component renders a list of messages in a virtualized list.\n * It is a consumer of the React contexts set in [Channel](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Channel/Channel.tsx).\n */\nexport function VirtualizedMessageList(props: VirtualizedMessageListProps) {\n const { jumpToLatestMessage, loadMore, loadMoreNewer } = useChannelActionContext(\n 'VirtualizedMessageList',\n );\n const {\n channel,\n channelUnreadUiState,\n hasMore,\n hasMoreNewer,\n highlightedMessageId,\n loadingMore,\n loadingMoreNewer,\n messages: contextMessages,\n notifications,\n read,\n suppressAutoscroll,\n thread,\n } = useChannelStateContext('VirtualizedMessageList');\n\n const messages = props.messages || contextMessages;\n\n return (\n <VirtualizedMessageListWithContext\n channel={channel}\n channelUnreadUiState={props.channelUnreadUiState ?? channelUnreadUiState}\n hasMore={!!hasMore}\n hasMoreNewer={!!hasMoreNewer}\n highlightedMessageId={highlightedMessageId}\n jumpToLatestMessage={jumpToLatestMessage}\n loadingMore={!!loadingMore}\n loadingMoreNewer={!!loadingMoreNewer}\n loadMore={loadMore}\n loadMoreNewer={loadMoreNewer}\n messages={messages}\n notifications={notifications}\n read={read}\n suppressAutoscroll={suppressAutoscroll}\n thread={thread}\n {...props}\n />\n );\n}\n","// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt#getting_whole_characters\nexport const getWholeChar = (str: string, i: number) => {\n const code = str.charCodeAt(i);\n\n if (Number.isNaN(code)) return '';\n\n if (code < 0xd800 || code > 0xdfff) return str.charAt(i);\n\n if (0xd800 <= code && code <= 0xdbff) {\n if (str.length <= i + 1) {\n throw 'High surrogate without following low surrogate';\n }\n\n const next = str.charCodeAt(i + 1);\n\n if (0xdc00 > next || next > 0xdfff) {\n throw 'High surrogate without following low surrogate';\n }\n\n return str.charAt(i) + str.charAt(i + 1);\n }\n\n if (i === 0) {\n throw 'Low surrogate without preceding high surrogate';\n }\n\n const prev = str.charCodeAt(i - 1);\n\n if (0xd800 > prev || prev > 0xdbff) {\n throw 'Low surrogate without preceding high surrogate';\n }\n\n return '';\n};\n","import { useEffect, useRef } from 'react';\nimport type { RefObject } from 'react';\n\nimport { useStableCallback } from '../../../utils/useStableCallback';\n\nconst DEFAULT_INIT: MutationObserverInit = { childList: true, subtree: true };\nconst NOOP = () => undefined;\n\nexport type UseMutationObserverOptions = {\n /** When `false`, the observer is not connected (and `onDisconnect` runs if it was). Default `true`. */\n enabled?: boolean;\n /** `MutationObserver` init, read when (re)connecting. Default `{ childList: true, subtree: true }`. */\n init?: MutationObserverInit;\n /** Runs when observation stops — target/`enabled` change or unmount. Use to clean up side effects\n * started in `onMutation` (e.g. cancel a pending announcement). */\n onDisconnect?: () => void;\n /** Also invoke `onMutation` once right after connecting, to react to the current DOM. Default `true`. */\n runOnConnect?: boolean;\n};\n\n/**\n * Runs `onMutation` whenever the observed subtree of `ref` changes (and, by default, once on\n * connect). A thin, generic wrapper around `MutationObserver`: toggle with `enabled`, react to the\n * initial state with `runOnConnect`, and clean up side effects via `onDisconnect`. The latest\n * `onMutation`/`onDisconnect` are always used without reconnecting the observer.\n *\n * Note: like any `useEffect`-based hook, it (re)connects on `enabled` change or remount — not on a\n * silent `ref.current` swap. Drive remounts with a `key` or toggle `enabled` if the target changes.\n */\nexport const useMutationObserver = (\n ref: RefObject<HTMLElement | null>,\n onMutation: () => void,\n {\n enabled = true,\n init = DEFAULT_INIT,\n onDisconnect,\n runOnConnect = true,\n }: UseMutationObserverOptions = {},\n) => {\n // Stable identities that always call the latest callback, so updating either does not reconnect\n // the observer.\n const handleMutation = useStableCallback(onMutation);\n const handleDisconnect = useStableCallback(onDisconnect ?? NOOP);\n // `init` is read only when (re)connecting; keep it off the effect deps so a fresh object literal\n // each render does not reconnect.\n const initRef = useRef(init);\n initRef.current = init;\n\n useEffect(() => {\n const target = ref.current;\n if (!enabled || !target) return;\n\n if (runOnConnect) handleMutation();\n\n // `MutationObserver` is available in every browser the SDK targets (and this runs only in an\n // effect, never during SSR), but degrade gracefully if it is missing — e.g. a non-DOM test\n // environment: react to the initial state and still run the disconnect cleanup, just without\n // observing further changes.\n if (typeof MutationObserver === 'undefined') return handleDisconnect;\n\n const observer = new MutationObserver(() => handleMutation());\n observer.observe(target, initRef.current);\n\n return () => {\n observer.disconnect();\n handleDisconnect();\n };\n }, [enabled, handleDisconnect, handleMutation, ref, runOnConnect]);\n};\n","import { useRef } from 'react';\nimport type { RefObject } from 'react';\nimport type { SearchSource } from 'stream-chat';\n\nimport { useInteractionAnnouncements } from '../../Accessibility';\nimport { useMutationObserver } from '../../UtilityComponents/hooks/useMutationObserver';\n\nconst OPTION_SELECTOR = '[role=\"option\"]';\n\n/**\n * Announces how many items are listed in the search results — and, when the list is fully loaded,\n * folds the \"all results loaded\" end-of-list status into that SAME announcement.\n *\n * The count is taken from the rendered options (`[role=\"option\"]`) in `containerRef`, observed with\n * {@link useMutationObserver} — so it is source-agnostic (works across channels/messages/users and\n * any custom result component) and reflects exactly what the user sees. Delivery goes through the\n * shared {@link useInteractionAnnouncements} registry (`search.resultCount`), which debounces the\n * value so it lands once results settle (after the screen reader's typing echo) instead of on every\n * change.\n *\n * `allResultsLoaded` is derived (when the announcement fires) from the active sources' latest state:\n * true only when every active source has no next page and is not loading. Carrying it in the count\n * message — rather than as a separate live-region announcement — keeps the end-of-list status from\n * competing with (and superseding) the count.\n *\n * The observer fires on every subtree mutation, but the announcement is made only when the\n * `count`/`allResultsLoaded` SIGNATURE changes — so an in-place action (e.g. muting a channel in a\n * result, which re-renders the row without changing the count) does not re-announce. It also bails\n * while inactive: gated on `active` (an in-progress search with a query) so it never fires during\n * presearch, and the pending (debounced) count is cancelled — and the signature reset — when search\n * is exited, so a stale count is not spoken after the results are gone.\n */\nexport const useAnnounceSearchResultCount = (\n containerRef: RefObject<HTMLElement | null>,\n active: boolean,\n activeSources: SearchSource[] = [],\n) => {\n const { announceInteraction, cancelInteraction } = useInteractionAnnouncements();\n const lastSignatureRef = useRef<string | null>(null);\n\n useMutationObserver(\n containerRef,\n () => {\n if (!active) return;\n const count = containerRef.current?.querySelectorAll(OPTION_SELECTOR).length ?? 0;\n const allResultsLoaded =\n activeSources.length > 0 &&\n activeSources.every((source) => {\n const { hasNext, isLoading } = source.state.getLatestValue();\n return !hasNext && !isLoading;\n });\n\n // Announce only when the meaningful state changes, not on every re-render of a result row.\n const signature = `${count}|${allResultsLoaded}`;\n if (signature === lastSignatureRef.current) return;\n lastSignatureRef.current = signature;\n\n announceInteraction('search.resultCount', { allResultsLoaded, count });\n },\n {\n enabled: active,\n onDisconnect: () => {\n lastSignatureRef.current = null;\n cancelInteraction('search.resultCount');\n },\n },\n );\n};\n","import { useEffect, useState } from 'react';\nimport type { SearchController, SearchControllerState, SearchSource } from 'stream-chat';\n\nimport { useStateStore } from '../../../store';\n\nconst searchControllerStateSelector = (value: SearchControllerState) => ({\n sources: value.sources,\n});\n\nexport type UseSearchQueriesInProgressParams = {\n searchController: SearchController;\n};\n\nexport const useSearchQueriesInProgress = (searchController: SearchController) => {\n const [queriesInProgress, setQueriesInProgress] = useState<string[]>([]);\n const { sources } = useStateStore(\n searchController.state,\n searchControllerStateSelector,\n );\n\n useEffect(() => {\n const subscriptions = sources.map((source: SearchSource) =>\n source.state.subscribeWithSelector(\n (value) => ({ isLoading: value.isLoading }),\n ({ isLoading }) => {\n setQueriesInProgress((prev) => {\n if (isLoading) return prev.concat(source.type);\n return prev.filter((type) => type !== source.type);\n });\n },\n ),\n );\n\n return () => {\n subscriptions.forEach((unsubscribe) => unsubscribe());\n };\n }, [sources]);\n return queriesInProgress;\n};\n","import type { KeyboardEvent as ReactKeyboardEvent, RefObject } from 'react';\n\nimport { getNextRovingFocusIndex } from '../a11yUtils';\n\nconst DEFAULT_OPTION_SELECTOR = '[role=\"option\"]';\nconst VERTICAL_KEYS = ['ArrowUp', 'ArrowDown', 'Home', 'End'];\n\n/** State handed to a {@link ListboxKeyHandler} when its key is pressed inside the container. */\nexport type ListboxNavigationContext = {\n /** The focused element — guaranteed to be inside the container. */\n active: HTMLElement;\n /** The listbox container element. */\n container: HTMLElement;\n /** The current option elements (live). */\n getOptions: () => HTMLElement[];\n /** Whether {@link ListboxNavigationContext.active} is itself an option. */\n onOption: boolean;\n};\n\n/**\n * Handler for a non-roving key. Return `true` if it handled the key — the hook then\n * `preventDefault()`s and `stopPropagation()`s so nothing else acts on it. Return nothing to let the\n * key fall through (default behaviour preserved).\n */\nexport type ListboxKeyHandler = (context: ListboxNavigationContext) => boolean | void;\n\nexport type ListboxKeyboardNavigationConfig = {\n /**\n * Where the roving (vertical) keys are active:\n * - `'option'` (default): only when focus is already on an option — a plain listbox.\n * - `'container'`: anywhere inside the container, so focus can enter the list from a preceding\n * control (e.g. a filter tag); when not on an option, Down/Home land on the first, Up/End on the\n * last.\n */\n enterScope?: 'container' | 'option';\n /**\n * Extra keys to handle, beyond the built-in roving. Mapped by `event.key` to a handler that\n * receives the current {@link ListboxNavigationContext} and decides what to do. The hook does not\n * prescribe any particular keys (e.g. ArrowRight to reach a row's actions) — compose what you need,\n * optionally with {@link createRowActionKeyHandlers}. Roving keys (Up/Down/Home/End) are reserved.\n */\n keyHandlers?: Record<string, ListboxKeyHandler>;\n /** Selector for the navigable options. Default `[role=\"option\"]`. */\n optionSelector?: string;\n /**\n * Maps the focused element to the option that vertical roving (Up/Down/Home/End) should move\n * relative to. Use with `enterScope: 'container'` so those keys work while focus is on something\n * inside an option's row (e.g. its action buttons) and step to the next/previous option from that\n * row, rather than jumping to the first/last. Return `null` to fall back to that default.\n */\n resolveActiveOption?: (active: HTMLElement) => HTMLElement | null;\n};\n\n/**\n * Keyboard navigation for a list of options (the channel list, the search results, …). Returns an\n * `onKeyDown` to spread onto the container plus `getOptions` for callers that need the current\n * options (e.g. load-more focus management):\n * - **ArrowUp/ArrowDown/Home/End** rove the options (scope set by `enterScope`).\n * - any other key listed in `keyHandlers` is delegated to its handler.\n *\n * For keys, it handles it `stopPropagation()`s, so it stays authoritative — nothing downstream (a\n * parent handler, or the browser/AT \"jump to first/last focusable\" fallback) can move focus to a\n * non-option. Stateless — safe to call on every render; the handlers read the DOM live.\n */\nexport const useListboxKeyboardNavigation = (\n containerRef: RefObject<HTMLElement | null>,\n {\n enterScope = 'option',\n keyHandlers,\n optionSelector = DEFAULT_OPTION_SELECTOR,\n resolveActiveOption,\n }: ListboxKeyboardNavigationConfig = {},\n) => {\n const getOptions = () =>\n Array.from(containerRef.current?.querySelectorAll<HTMLElement>(optionSelector) ?? []);\n\n const onKeyDown = (event: ReactKeyboardEvent<HTMLElement>) => {\n const container = containerRef.current;\n const active = document.activeElement;\n if (!container || !(active instanceof HTMLElement) || !container.contains(active)) {\n return;\n }\n\n const onOption = active.matches(optionSelector);\n\n if (VERTICAL_KEYS.includes(event.key)) {\n if (enterScope === 'option' && !onOption) return;\n const options = getOptions();\n // The option the move is relative to: the focused option itself, or — when focus is on\n // something inside an option's row (e.g. an action button) — the option that row maps to.\n const current = onOption ? active : (resolveActiveOption?.(active) ?? null);\n const nextIndex = getNextRovingFocusIndex({\n activeIndex: current ? options.indexOf(current) : -1,\n itemCount: options.length,\n key: event.key,\n });\n if (nextIndex === null) return;\n event.preventDefault();\n event.stopPropagation();\n options[nextIndex]?.focus();\n return;\n }\n\n const handled = keyHandlers?.[event.key]?.({\n active,\n container,\n getOptions,\n onOption,\n });\n if (handled) {\n event.preventDefault();\n event.stopPropagation();\n }\n };\n\n return { getOptions, onKeyDown };\n};\n\n/**\n * Composable {@link ListboxKeyHandler}s for the \"each option sits in a row alongside one or more\n * action targets\" pattern (e.g. a channel row + its actions/menu buttons). The option and its\n * actions form one **horizontal cyclic group** in DOM order: from the option **ArrowRight** enters\n * the actions; **ArrowLeft/ArrowRight** move between the actions; stepping off either end returns to\n * the option (so the actions need not be in the Tab order). Rows with no actions (a lone option)\n * leave the keys unhandled. Pass the result as (part of) `keyHandlers`.\n */\nexport const createRowActionKeyHandlers = ({\n actionSelector,\n optionSelector = DEFAULT_OPTION_SELECTOR,\n rowSelector,\n}: {\n actionSelector: string;\n optionSelector?: string;\n rowSelector: string;\n}): Record<string, ListboxKeyHandler> => {\n const rove =\n (step: -1 | 1): ListboxKeyHandler =>\n ({ active }) => {\n const row = active.closest(rowSelector);\n if (!row) return;\n // The option + its action targets, in document order, as one cyclic group.\n const items = Array.from(\n row.querySelectorAll<HTMLElement>(`${optionSelector}, ${actionSelector}`),\n );\n if (items.length < 2) return; // a lone option — nothing to move between\n const index = items.indexOf(active);\n if (index === -1) return;\n items[(index + step + items.length) % items.length].focus();\n return true;\n };\n\n return { ArrowLeft: rove(-1), ArrowRight: rove(1) };\n};\n","import type { RefObject } from 'react';\n\nimport {\n createRowActionKeyHandlers,\n useListboxKeyboardNavigation,\n} from '../../../a11y/hooks/useListboxKeyboardNavigation';\n\n// Channel/message results render a `ChannelListItem` (same markup as the channel list), so they\n// carry a row container and action buttons. User results do not, so the horizontal keys no-op there.\nconst OPTION_SELECTOR = '[role=\"option\"]';\nconst ROW_SELECTOR = '.str-chat__channel-list-item-container';\nconst ACTION_BUTTON_SELECTOR = '.str-chat__channel-list-item__action-buttons button';\n\n/**\n * Keyboard navigation for the search results list (see {@link useListboxKeyboardNavigation}):\n * - **ArrowUp/ArrowDown/Home/End** rove the result options — from anywhere in the container, so the\n * user can enter the list from the preceding filter tags (`enterScope: 'container'`) and so they\n * keep working while focus is on a result's action button (moving relative to that result).\n * - **ArrowRight/ArrowLeft** move between a channel/message result and its actions button and back;\n * user results have no actions, so the horizontal keys do nothing for them.\n */\nexport const useSearchResultsKeyboardNavigation = (\n containerRef: RefObject<HTMLElement | null>,\n) => {\n const { onKeyDown } = useListboxKeyboardNavigation(containerRef, {\n enterScope: 'container',\n keyHandlers: createRowActionKeyHandlers({\n actionSelector: ACTION_BUTTON_SELECTOR,\n rowSelector: ROW_SELECTOR,\n }),\n resolveActiveOption: (active) =>\n active.closest(ROW_SELECTOR)?.querySelector<HTMLElement>(OPTION_SELECTOR) ?? null,\n });\n\n return { onKeyDown };\n};\n","import type { KeyboardEvent as ReactKeyboardEvent, RefObject } from 'react';\nimport { useCallback, useRef } from 'react';\n\nimport { getNextRovingFocusIndex } from '../a11yUtils';\n\nconst DEFAULT_OPTION_SELECTOR = '[role=\"option\"]';\n// After scrolling an off-window row into view, the row may not be in the DOM on the very next tick\n// (a virtual list's \"rendered\" callback can fire a frame before the row paints). Retry focusing it\n// across a few animation frames before giving up.\nconst MAX_FOCUS_ATTEMPTS_AFTER_SCROLL = 5;\n\n// Escape a value for use inside a quoted attribute selector (`[attr=\"value\"]`).\nconst escapeAttributeValue = (value: string) => value.replace(/([\"\\\\])/g, '\\\\$1');\n\nexport type VirtualizedListboxKeyboardNavigationParams<T> = {\n /** Stable id for an item; must equal the value the item's option carries in `itemIdAttribute`. */\n getItemId: (item: T) => string;\n /**\n * The attribute every option carries its id in (e.g. `'data-thread-id'`). Used both to read the id\n * off the focused element and to locate the target option in the DOM.\n */\n itemIdAttribute: string;\n /** The full, unvirtualized list — NOT just the rendered window. Roving indexes into this. */\n items: T[];\n /** Selector for the focusable option elements. Default `[role=\"option\"]`. */\n optionSelector?: string;\n /**\n * Bring the item at `index` into the rendered window, then invoke `onRendered` once it should be in\n * the DOM. For a virtualized list wrap the list's imperative scroll (e.g. Virtuoso's\n * `scrollIntoView({ index, done: onRendered })`); for a non-virtualized list just call\n * `onRendered()`.\n */\n scrollIndexIntoView: (index: number, onRendered: () => void) => void;\n /** Ref to the scrollable listbox container whose subtree holds the rendered options. */\n scrollerRef: RefObject<HTMLElement | null>;\n};\n\n/**\n * Vertical roving-focus keyboard navigation (ArrowUp/Down/Home/End) for a **virtualized** listbox,\n * where only a window of `role=\"option\"` rows exists in the DOM at a time.\n *\n * A DOM-query-and-`.focus()` approach (see {@link useListboxKeyboardNavigation}) can't work here: it\n * would only ever see the rendered window, so it would cycle within those rows and never scroll the\n * rest of the list into view. This hook instead indexes into the **full** `items` array, focuses the\n * target row if it is already rendered, and otherwise asks the list to scroll it into existence\n * (`scrollIndexIntoView`) and focuses it once painted (retrying across a few frames).\n *\n * Returns an `onKeyDown` to spread onto the scroll container (the `role=\"listbox\"` element). The\n * caller wires `scrollerRef` to that same element and provides `scrollIndexIntoView`. Stateless — the\n * active row is read live from `document.activeElement` on each key.\n */\nexport const useVirtualizedListboxKeyboardNavigation = <T>({\n getItemId,\n itemIdAttribute,\n items,\n optionSelector = DEFAULT_OPTION_SELECTOR,\n scrollerRef,\n scrollIndexIntoView,\n}: VirtualizedListboxKeyboardNavigationParams<T>) => {\n // Each roving key press bumps this. A deferred (post-scroll) focus chain captures the id at\n // schedule time and bails once it is superseded, so a slower older scroll can't steal focus back\n // to an outdated row after the user has pressed another key.\n const latestFocusRequestRef = useRef(0);\n\n // Focus the option for `items[index]` if it is currently in the DOM. Returns whether it was found.\n const focusOptionAt = useCallback(\n (index: number) => {\n const item = items[index];\n if (!item) return false;\n const option = scrollerRef.current?.querySelector<HTMLElement>(\n `${optionSelector}[${itemIdAttribute}=\"${escapeAttributeValue(getItemId(item))}\"]`,\n );\n if (!option) return false;\n option.focus();\n return true;\n },\n [getItemId, itemIdAttribute, items, optionSelector, scrollerRef],\n );\n\n const focusOptionAfterRender = useCallback(\n (\n index: number,\n requestId: number,\n attemptsLeft = MAX_FOCUS_ATTEMPTS_AFTER_SCROLL,\n ) => {\n // A newer key press superseded this chain — stop so it can't steal focus back.\n if (requestId !== latestFocusRequestRef.current) return;\n if (focusOptionAt(index) || attemptsLeft <= 0) return;\n requestAnimationFrame(() =>\n focusOptionAfterRender(index, requestId, attemptsLeft - 1),\n );\n },\n [focusOptionAt],\n );\n\n const onKeyDown = useCallback(\n (event: ReactKeyboardEvent<HTMLElement>) => {\n const active = document.activeElement;\n const activeId =\n active instanceof HTMLElement\n ? (active\n .closest<HTMLElement>(`[${itemIdAttribute}]`)\n ?.getAttribute(itemIdAttribute) ?? undefined)\n : undefined;\n const activeIndex =\n activeId != null ? items.findIndex((item) => getItemId(item) === activeId) : -1;\n const nextIndex = getNextRovingFocusIndex({\n activeIndex,\n itemCount: items.length,\n key: event.key,\n });\n if (nextIndex === null) return; // not a roving key — leave it alone\n\n event.preventDefault();\n event.stopPropagation();\n // Supersede any still-pending off-window focus chain from a previous key press.\n const requestId = ++latestFocusRequestRef.current;\n // Within the rendered window: focus right away (no scroll lag; native focus brings it fully\n // into view if it sat in the overscan). Otherwise scroll the row into existence, then focus it\n // once the list has painted it.\n if (focusOptionAt(nextIndex)) return;\n scrollIndexIntoView(nextIndex, () => focusOptionAfterRender(nextIndex, requestId));\n },\n [\n focusOptionAfterRender,\n focusOptionAt,\n getItemId,\n itemIdAttribute,\n items,\n scrollIndexIntoView,\n ],\n );\n\n return { onKeyDown };\n};\n","import { useEffect } from 'react';\n\nimport { useChatContext } from '../../../context/ChatContext';\n\nexport const useConnectionRecoveredListener = (forceUpdate?: () => void) => {\n const { client } = useChatContext('useConnectionRecoveredListener');\n\n useEffect(() => {\n const handleEvent = () => {\n if (forceUpdate) {\n forceUpdate();\n }\n };\n\n client.on('connection.recovered', handleEvent);\n\n return () => {\n client.off('connection.recovered', handleEvent);\n };\n }, [client, forceUpdate]);\n};\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport uniqBy from 'lodash.uniqby';\n\nimport type {\n APIErrorResponse,\n Channel,\n ChannelFilters,\n ChannelOptions,\n ChannelSort,\n ErrorFromResponse,\n ParsedPredefinedFilterResponse,\n StreamChat,\n} from 'stream-chat';\n\nimport { useChatContext } from '../../../context/ChatContext';\nimport { useTranslationContext } from '../../../context/TranslationContext';\nimport { useNotificationApi } from '../../Notifications';\n\nimport type { ChannelsQueryState } from '../../Chat/hooks/useChannelsQueryState';\n\nconst RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS = 5000;\nconst MIN_RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS = 2000;\n\ntype AllowedQueryType = Extract<\n ChannelsQueryState['queryInProgress'],\n 'reload' | 'load-more'\n>;\n\nexport type CustomQueryChannelParams = {\n currentChannels: Array<Channel>;\n queryType: AllowedQueryType;\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>;\n setHasNextPage: React.Dispatch<React.SetStateAction<boolean>>;\n};\n\nexport type CustomQueryChannelsFn = (params: CustomQueryChannelParams) => Promise<void>;\n\n/**\n * Filters and sort effectively used by the channel list. When `options.predefined_filter`\n * is set, these reflect the backend-resolved values from `predefined_filter` response\n * metadata; otherwise they fall back to the caller-supplied `filters`/`sort`.\n */\nexport type EffectiveQueryParams = {\n filters: ChannelFilters;\n sort: ChannelSort;\n};\n\n/**\n * The `predefined_filter` response carries sort as\n * `[{ field, direction }]`. `ChannelSort` expects `[{ field: direction }]`.\n */\nconst mapPredefinedFilterSortToChannelSort = (\n sort: NonNullable<ParsedPredefinedFilterResponse['sort']>,\n): ChannelSort =>\n sort.map(({ direction = 1, field }) => ({\n [field]: direction,\n })) as ChannelSort;\n\nexport const usePaginatedChannels = (\n client: StreamChat,\n filters: ChannelFilters,\n sort: ChannelSort,\n options: ChannelOptions,\n activeChannelHandler: (\n channels: Array<Channel>,\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n effectiveQueryParams: EffectiveQueryParams,\n ) => void,\n recoveryThrottleIntervalMs: number = RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS,\n customQueryChannels?: CustomQueryChannelsFn,\n) => {\n const { addNotification } = useNotificationApi();\n const {\n channelsQueryState: { error, setError, setQueryInProgress },\n } = useChatContext('usePaginatedChannels');\n const { t } = useTranslationContext();\n const [channels, setChannels] = useState<Array<Channel>>([]);\n const [hasNextPage, setHasNextPage] = useState(true);\n // Backend-resolved filter/sort from `predefined_filter` response metadata.\n // Used to override the caller `filters`/`sort` for local WS-driven list\n // mutation decisions (archiving, pinning) when a predefined filter is in\n // use. Stays `undefined` for non-predefined queries.\n const [responseFilters, setResponseFilters] = useState<ChannelFilters | undefined>(\n undefined,\n );\n const [responseSort, setResponseSort] = useState<ChannelSort | undefined>(undefined);\n const lastRecoveryTimestamp = useRef<number | undefined>(undefined);\n\n const recoveryThrottleInterval =\n recoveryThrottleIntervalMs < MIN_RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS\n ? MIN_RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS\n : (recoveryThrottleIntervalMs ?? RECOVER_LOADED_CHANNELS_THROTTLE_INTERVAL_IN_MS);\n // memoize props\n const filterString = useMemo(() => JSON.stringify(filters), [filters]);\n const sortString = useMemo(() => JSON.stringify(sort), [sort]);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const queryChannels = async (queryType = 'load-more') => {\n setError(null);\n const offset = queryType === 'reload' ? 0 : channels.length;\n const isFirstPage = offset === 0;\n\n if (queryType === 'reload') {\n setChannels([]);\n }\n setQueryInProgress(queryType as AllowedQueryType);\n\n try {\n if (customQueryChannels) {\n await customQueryChannels({\n currentChannels: channels,\n queryType: queryType as AllowedQueryType,\n setChannels,\n setHasNextPage,\n });\n // `customQueryChannels` bypasses the SDK response so any previously\n // resolved predefined-filter metadata is no longer trustworthy.\n setResponseFilters(undefined);\n setResponseSort(undefined);\n } else {\n const newOptions = {\n offset,\n ...options,\n };\n\n const channelQueryResponse = await client.queryChannels(\n filters,\n sort || {},\n newOptions,\n { withResponse: true },\n );\n\n const newChannels =\n queryType === 'reload'\n ? channelQueryResponse.channels\n : uniqBy([...channels, ...channelQueryResponse.channels], 'cid');\n\n setChannels(newChannels);\n setHasNextPage(channelQueryResponse.channels.length >= (newOptions.limit ?? 1));\n\n // Pull backend-resolved filter/sort from `predefined_filter` metadata so\n // WS-driven list mutations use the effective semantics. Always reset\n // first; non-predefined queries do not return this metadata and keeping\n // stale values would silently change list behavior.\n const predefinedFilter = channelQueryResponse.predefined_filter;\n const nextResponseFilters = predefinedFilter\n ? (predefinedFilter.filter as ChannelFilters)\n : undefined;\n const nextResponseSort = predefinedFilter?.sort\n ? mapPredefinedFilterSortToChannelSort(predefinedFilter.sort)\n : undefined;\n\n setResponseFilters(nextResponseFilters);\n setResponseSort(nextResponseSort);\n\n // Set active channel only on load of first page\n if (!offset && activeChannelHandler) {\n activeChannelHandler(newChannels, setChannels, {\n filters: nextResponseFilters ?? filters,\n sort: nextResponseSort ?? sort,\n });\n }\n }\n } catch (error) {\n console.warn(error);\n addNotification({\n emitter: 'ChannelList',\n error: error instanceof Error ? error : undefined,\n message: isFirstPage\n ? t('Failed to load channels')\n : t('Failed to load more channels'),\n severity: 'error',\n targetPanels: ['channel-list'],\n type: isFirstPage\n ? 'api:channel-list:load:failed'\n : 'api:channel-list:load-more:failed',\n });\n\n if (isFirstPage) {\n setError(error as ErrorFromResponse<APIErrorResponse>);\n }\n }\n\n setQueryInProgress(null);\n };\n\n const throttleRecover = useCallback(() => {\n const now = Date.now();\n const isFirstRecovery = !lastRecoveryTimestamp.current;\n const timeElapsedSinceLastRecoveryMs = lastRecoveryTimestamp.current\n ? now - lastRecoveryTimestamp.current\n : 0;\n\n if (\n !isFirstRecovery &&\n timeElapsedSinceLastRecoveryMs < recoveryThrottleInterval &&\n !error\n ) {\n return;\n }\n\n lastRecoveryTimestamp.current = now;\n queryChannels('reload');\n }, [error, queryChannels, recoveryThrottleInterval]);\n\n const loadNextPage = () => queryChannels();\n\n useEffect(() => {\n if (client.recoverStateOnReconnect) return;\n const { unsubscribe } = client.on('connection.recovered', throttleRecover);\n\n return () => {\n unsubscribe();\n };\n }, [client, throttleRecover]);\n\n useEffect(() => {\n queryChannels('reload');\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [filterString, sortString]);\n\n // Effective filters/sort: response-derived values take precedence over\n // caller-supplied props when a predefined filter is in use. Falls back to\n // the caller props for non-predefined queries and during the initial load\n // before the first response.\n const effectiveFilters = responseFilters ?? filters;\n const effectiveSort = responseSort ?? sort;\n\n return {\n channels,\n effectiveFilters,\n effectiveSort,\n hasNextPage,\n loadNextPage,\n setChannels,\n };\n};\n","import type { Channel, ChannelSort, ChannelSortBase } from 'stream-chat';\n\nimport type { ChannelListProps } from './ChannelList';\n\n/**\n * Expects channel array sorted by `{ pinned_at: -1 }`.\n *\n * TODO: add support for the `{ pinned_at: 1 }`\n */\nexport function findLastPinnedChannelIndex({ channels }: { channels: Channel[] }) {\n let lastPinnedChannelIndex: number | null = null;\n\n for (const channel of channels) {\n if (!isChannelPinned(channel)) break;\n\n if (typeof lastPinnedChannelIndex === 'number') {\n lastPinnedChannelIndex++;\n } else {\n lastPinnedChannelIndex = 0;\n }\n }\n\n return lastPinnedChannelIndex;\n}\n\ntype MoveChannelUpwardsParams = {\n channels: Array<Channel>;\n channelToMove: Channel;\n sort: ChannelSort;\n /**\n * If the index of the channel within `channels` list which is being moved upwards\n * (`channelToMove`) is known, you can supply it to skip extra calculation.\n */\n channelToMoveIndexWithinChannels?: number;\n};\n\nexport const moveChannelUpwards = ({\n channels,\n channelToMove,\n channelToMoveIndexWithinChannels,\n sort,\n}: MoveChannelUpwardsParams) => {\n // get index of channel to move up\n const targetChannelIndex =\n channelToMoveIndexWithinChannels ??\n channels.findIndex((channel) => channel.cid === channelToMove.cid);\n\n const targetChannelExistsWithinList = targetChannelIndex >= 0;\n const targetChannelAlreadyAtTheTop = targetChannelIndex === 0;\n\n // pinned channels should not move within the list based on recent activity, channels which\n // receive messages and are not pinned should move upwards but only under the last pinned channel\n // in the list\n const considerPinnedChannels = shouldConsiderPinnedChannels(sort);\n const isTargetChannelPinned = isChannelPinned(channelToMove);\n\n if (targetChannelAlreadyAtTheTop || (considerPinnedChannels && isTargetChannelPinned)) {\n return channels;\n }\n\n const newChannels = [...channels];\n\n // target channel index is known, remove it from the list\n if (targetChannelExistsWithinList) {\n newChannels.splice(targetChannelIndex, 1);\n }\n\n // as position of pinned channels has to stay unchanged, we need to\n // find last pinned channel in the list to move the target channel after\n let lastPinnedChannelIndex: number | null = null;\n if (considerPinnedChannels) {\n lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels });\n }\n\n // re-insert it at the new place (to specific index if pinned channels are considered)\n newChannels.splice(\n typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0,\n 0,\n channelToMove,\n );\n\n return newChannels;\n};\n\n/**\n * Returns `true` only if object with `pinned_at` property is first within the `sort` array\n * or if `pinned_at` key of the `sort` object gets picked first when using `for...in` looping mechanism\n * and value of the `pinned_at` is either `1` or `-1`.\n */\nexport const shouldConsiderPinnedChannels = (sort: ChannelListProps['sort']) => {\n const value = extractSortValue({ atIndex: 0, sort, targetKey: 'pinned_at' });\n\n if (typeof value !== 'number') return false;\n\n return Math.abs(value) === 1;\n};\n\nexport const extractSortValue = ({\n atIndex,\n sort,\n targetKey,\n}: {\n atIndex: number;\n targetKey: keyof ChannelSortBase;\n sort?: ChannelListProps['sort'];\n}) => {\n if (!sort) return null;\n let option: null | ChannelSortBase = null;\n\n if (Array.isArray(sort)) {\n option = sort[atIndex] ?? null;\n } else {\n let index = 0;\n for (const key in sort) {\n if (index !== atIndex) {\n index++;\n continue;\n }\n\n if (key !== targetKey) {\n return null;\n }\n\n option = sort;\n\n break;\n }\n }\n\n return option?.[targetKey] ?? null;\n};\n\n/**\n * Returns `true` only if `archived` property is of type `boolean` within `filters` object.\n */\nexport const shouldConsiderArchivedChannels = (filters: ChannelListProps['filters']) => {\n if (!filters) return false;\n\n return typeof filters.archived === 'boolean';\n};\n\n/**\n * Returns `true` only if `pinned_at` property is of type `string` within `membership` object.\n */\nexport const isChannelPinned = (channel: Channel) => {\n if (!channel) return false;\n\n const membership = channel.state.membership;\n\n return typeof membership.pinned_at === 'string';\n};\n\n/**\n * Returns `true` only if `archived_at` property is of type `string` within `membership` object.\n */\nexport const isChannelArchived = (channel: Channel) => {\n if (!channel) return false;\n\n const membership = channel.state.membership;\n\n return typeof membership.archived_at === 'string';\n};\n","import { useCallback, useEffect, useMemo, useRef } from 'react';\nimport type { Channel, Event } from 'stream-chat';\nimport type { Dispatch, SetStateAction } from 'react';\n\nimport {\n extractSortValue,\n findLastPinnedChannelIndex,\n isChannelArchived,\n isChannelPinned,\n moveChannelUpwards,\n shouldConsiderArchivedChannels,\n shouldConsiderPinnedChannels,\n} from '../utils';\nimport { useChatContext } from '../../../context';\nimport { getChannel } from '../../../utils';\nimport type { ChannelListProps } from '../ChannelList';\n\ntype SetChannels = Dispatch<SetStateAction<Channel[]>>;\n\ntype BaseParameters = {\n event: Event;\n setChannels: SetChannels;\n};\n\ntype RepeatedParameters = {\n customHandler?: (\n setChannels: BaseParameters['setChannels'],\n event: BaseParameters['event'],\n ) => void;\n};\n\ntype HandleMessageNewParameters = BaseParameters &\n RepeatedParameters & {\n allowNewMessagesFromUnfilteredChannels: boolean;\n lockChannelOrder: boolean;\n } & Required<Pick<ChannelListProps, 'filters' | 'sort'>>;\n\ntype HandleNotificationMessageNewParameters = BaseParameters &\n RepeatedParameters & {\n allowNewMessagesFromUnfilteredChannels: boolean;\n lockChannelOrder: boolean;\n } & Required<Pick<ChannelListProps, 'filters' | 'sort'>>;\n\ntype HandleNotificationRemovedFromChannelParameters = BaseParameters & RepeatedParameters;\n\ntype HandleNotificationAddedToChannelParameters = BaseParameters &\n RepeatedParameters & {\n allowNewMessagesFromUnfilteredChannels: boolean;\n lockChannelOrder: boolean;\n } & Required<Pick<ChannelListProps, 'sort'>>;\n\ntype HandleChannelVisibleParameters = BaseParameters &\n RepeatedParameters &\n Required<Pick<ChannelListProps, 'sort' | 'filters'>>;\n\ntype HandleMemberUpdatedParameters = BaseParameters & {\n lockChannelOrder: boolean;\n} & Required<Pick<ChannelListProps, 'sort' | 'filters'>>;\n\ntype HandleChannelDeletedParameters = BaseParameters & RepeatedParameters;\n\ntype HandleChannelHiddenParameters = BaseParameters & RepeatedParameters;\n\ntype HandleChannelTruncatedParameters = BaseParameters & RepeatedParameters;\n\ntype HandleChannelUpdatedParameters = BaseParameters & RepeatedParameters;\n\ntype HandleUserPresenceChangedParameters = BaseParameters;\n\nconst shared = ({\n customHandler,\n event,\n setChannels,\n}: BaseParameters & RepeatedParameters) => {\n if (typeof customHandler === 'function') {\n return customHandler(setChannels, event);\n }\n\n setChannels((channels) => {\n const channelIndex = channels.findIndex((channel) => channel.cid === event.cid);\n\n if (channelIndex < 0) return channels;\n\n channels.splice(channelIndex, 1);\n\n return [...channels];\n });\n};\n\nexport const useChannelListShapeDefaults = () => {\n const { client } = useChatContext();\n\n const handleMessageNew = useCallback(\n ({\n allowNewMessagesFromUnfilteredChannels,\n customHandler,\n event,\n filters,\n lockChannelOrder,\n setChannels,\n sort,\n }: HandleMessageNewParameters) => {\n if (typeof customHandler === 'function') {\n return customHandler(setChannels, event);\n }\n\n const channelType = event.channel_type;\n const channelId = event.channel_id;\n\n if (!channelType || !channelId) return;\n\n setChannels((currentChannels) => {\n const targetChannel = client.channel(channelType, channelId);\n const targetChannelIndex = currentChannels.indexOf(targetChannel);\n const targetChannelExistsWithinList = targetChannelIndex >= 0;\n\n const isTargetChannelPinned = isChannelPinned(targetChannel);\n const isTargetChannelArchived = isChannelArchived(targetChannel);\n\n const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n const considerPinnedChannels = shouldConsiderPinnedChannels(sort);\n\n if (\n // filter is defined, target channel is archived and filter option is set to false\n (considerArchivedChannels && isTargetChannelArchived && !filters.archived) ||\n // filter is defined, target channel isn't archived and filter option is set to true\n (considerArchivedChannels && !isTargetChannelArchived && filters.archived) ||\n // sort option is defined, target channel is pinned\n (considerPinnedChannels && isTargetChannelPinned) ||\n // list order is locked\n lockChannelOrder ||\n // target channel is not within the loaded list and loading from cache is disallowed\n (!targetChannelExistsWithinList && !allowNewMessagesFromUnfilteredChannels)\n ) {\n return currentChannels;\n }\n\n return moveChannelUpwards({\n channels: currentChannels,\n channelToMove: targetChannel,\n channelToMoveIndexWithinChannels: targetChannelIndex,\n sort,\n });\n });\n },\n [client],\n );\n\n const handleNotificationMessageNew = useCallback(\n async ({\n allowNewMessagesFromUnfilteredChannels,\n customHandler,\n event,\n filters,\n setChannels,\n sort,\n }: HandleNotificationMessageNewParameters) => {\n if (typeof customHandler === 'function') {\n return customHandler(setChannels, event);\n }\n\n if (!event.channel) {\n return;\n }\n\n // Bail out before querying the channel: if new messages from unfiltered\n // channels are not allowed, this handler would discard the result anyway.\n // Querying first issued a `channel.watch()` (queryChannel) for every\n // `notification.message_new`, which could exhaust the rate limit when many\n // such events arrive at once (#2441).\n if (!allowNewMessagesFromUnfilteredChannels) {\n return;\n }\n\n const channel = await getChannel({\n client,\n id: event.channel.id,\n type: event.channel.type,\n });\n\n const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n if (isChannelArchived(channel) && considerArchivedChannels && !filters.archived) {\n return;\n }\n\n setChannels((channels) =>\n moveChannelUpwards({\n channels,\n channelToMove: channel,\n sort,\n }),\n );\n },\n [client],\n );\n\n const handleNotificationAddedToChannel = useCallback(\n async ({\n allowNewMessagesFromUnfilteredChannels,\n customHandler,\n event,\n setChannels,\n sort,\n }: HandleNotificationAddedToChannelParameters) => {\n if (typeof customHandler === 'function') {\n return customHandler(setChannels, event);\n }\n\n if (!event.channel || !allowNewMessagesFromUnfilteredChannels) {\n return;\n }\n\n const channel = await getChannel({\n client,\n id: event.channel.id,\n members: event.channel.members?.reduce<string[]>(\n (newMembers, { user, user_id }) => {\n const userId = user_id || user?.id;\n\n if (userId) newMembers.push(userId);\n\n return newMembers;\n },\n [],\n ),\n type: event.channel.type,\n });\n\n // membership has been reset (target channel shouldn't be pinned nor archived)\n setChannels((channels) =>\n moveChannelUpwards({\n channels,\n channelToMove: channel,\n sort,\n }),\n );\n },\n [client],\n );\n\n const handleNotificationRemovedFromChannel = useCallback(\n ({\n customHandler,\n event,\n setChannels,\n }: HandleNotificationRemovedFromChannelParameters) => {\n if (typeof customHandler === 'function') {\n return customHandler(setChannels, event);\n }\n\n setChannels((channels) =>\n channels.filter((channel) => channel.cid !== event.channel?.cid),\n );\n },\n [],\n );\n\n const handleMemberUpdated = useCallback(\n ({\n event,\n filters,\n lockChannelOrder,\n setChannels,\n sort,\n }: HandleMemberUpdatedParameters) => {\n if (\n !event.member?.user ||\n event.member.user.id !== client.userID ||\n !event.channel_type\n ) {\n return;\n }\n\n const channelType = event.channel_type;\n const channelId = event.channel_id;\n\n const considerPinnedChannels = shouldConsiderPinnedChannels(sort);\n const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n\n // `pinned_at` nor `archived` properties are set or channel list order is locked, return early\n if ((!considerPinnedChannels && !considerArchivedChannels) || lockChannelOrder) {\n return;\n }\n\n const pinnedAtSort = extractSortValue({ atIndex: 0, sort, targetKey: 'pinned_at' });\n\n setChannels((currentChannels) => {\n const targetChannel = client.channel(channelType, channelId);\n // assumes that channel instances are not changing\n const targetChannelIndex = currentChannels.indexOf(targetChannel);\n const targetChannelExistsWithinList = targetChannelIndex >= 0;\n\n const isTargetChannelArchived = isChannelArchived(targetChannel);\n const isTargetChannelPinned = isChannelPinned(targetChannel);\n\n const newChannels = [...currentChannels];\n\n if (targetChannelExistsWithinList) {\n newChannels.splice(targetChannelIndex, 1);\n }\n\n // handle archiving (remove channel)\n if (\n (considerArchivedChannels && isTargetChannelArchived && !filters.archived) ||\n (considerArchivedChannels && !isTargetChannelArchived && filters.archived)\n ) {\n return newChannels;\n }\n\n let lastPinnedChannelIndex: number | null = null;\n\n // calculate last pinned channel index only if `pinned_at` sort is set to\n // ascending order or if it's in descending order while the pin is being removed, otherwise\n // we move to the top (index 0)\n if (pinnedAtSort === 1 || (pinnedAtSort === -1 && !isTargetChannelPinned)) {\n lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels });\n }\n\n const newTargetChannelIndex =\n typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0;\n\n newChannels.splice(newTargetChannelIndex, 0, targetChannel);\n\n return newChannels;\n });\n },\n [client],\n );\n\n const handleChannelDeleted = useCallback(\n (p: HandleChannelDeletedParameters) => shared(p),\n [],\n );\n\n const handleChannelHidden = useCallback(\n (p: HandleChannelHiddenParameters) => shared(p),\n [],\n );\n\n const handleChannelVisible = useCallback(\n async ({\n customHandler,\n event,\n filters,\n setChannels,\n sort,\n }: HandleChannelVisibleParameters) => {\n if (typeof customHandler === 'function') {\n return customHandler(setChannels, event);\n }\n\n if (!event.channel_id && !event.channel_type) {\n return;\n }\n\n const channel = await getChannel({\n client,\n id: event.channel_id,\n type: event.channel_type,\n });\n\n const considerArchivedChannels = shouldConsiderArchivedChannels(filters);\n if (isChannelArchived(channel) && considerArchivedChannels && !filters.archived) {\n return;\n }\n\n setChannels((channels) =>\n moveChannelUpwards({\n channels,\n channelToMove: channel,\n sort,\n }),\n );\n },\n [client],\n );\n\n const handleChannelTruncated = useCallback(\n ({ customHandler, event, setChannels }: HandleChannelTruncatedParameters) => {\n if (typeof customHandler === 'function') {\n return customHandler(setChannels, event);\n }\n\n // TODO: not sure whether this is needed\n setChannels((channels) => [...channels]);\n // if (forceUpdate) {\n // forceUpdate();\n // }\n },\n [],\n );\n\n const handleChannelUpdated = useCallback(\n ({ customHandler, event, setChannels }: HandleChannelUpdatedParameters) => {\n if (typeof customHandler === 'function') {\n return customHandler(setChannels, event);\n }\n\n setChannels((channels) => {\n const channelIndex = channels.findIndex(\n (channel) => channel.cid === event.channel?.cid,\n );\n\n if (channelIndex > -1 && event.channel) {\n const newChannels = channels;\n newChannels[channelIndex].data = {\n ...event.channel,\n hidden: event.channel?.hidden ?? newChannels[channelIndex].data?.hidden,\n own_capabilities:\n event.channel?.own_capabilities ??\n newChannels[channelIndex].data?.own_capabilities,\n };\n\n return [...newChannels];\n }\n\n return channels;\n });\n\n // if (forceUpdate) {\n // forceUpdate();\n // }\n },\n [],\n );\n\n const handleUserPresenceChanged = useCallback(\n ({ event, setChannels }: HandleUserPresenceChangedParameters) => {\n setChannels((channels) => {\n const newChannels = channels.map((channel) => {\n if (!event.user?.id || !channel.state.members[event.user.id]) {\n return channel;\n }\n\n // FIXME: oh no...\n const newChannel = channel;\n newChannel.state.members[event.user.id].user = event.user;\n\n return newChannel;\n });\n\n return newChannels;\n });\n },\n [],\n );\n\n return useMemo(\n () => ({\n handleChannelDeleted,\n handleChannelHidden,\n handleChannelTruncated,\n handleChannelUpdated,\n handleChannelVisible,\n handleMemberUpdated,\n handleMessageNew,\n handleNotificationAddedToChannel,\n handleNotificationMessageNew,\n handleNotificationRemovedFromChannel,\n handleUserPresenceChanged,\n }),\n [\n handleChannelDeleted,\n handleChannelHidden,\n handleChannelTruncated,\n handleChannelUpdated,\n handleChannelVisible,\n handleMemberUpdated,\n handleMessageNew,\n handleNotificationAddedToChannel,\n handleNotificationMessageNew,\n handleNotificationRemovedFromChannel,\n handleUserPresenceChanged,\n ],\n );\n};\n\ntype UseDefaultHandleChannelListShapeParameters = Required<\n Pick<\n ChannelListProps,\n 'allowNewMessagesFromUnfilteredChannels' | 'lockChannelOrder' | 'filters' | 'sort'\n >\n> &\n Pick<\n ChannelListProps,\n | 'onAddedToChannel'\n | 'onChannelDeleted'\n | 'onChannelHidden'\n | 'onChannelTruncated'\n | 'onChannelUpdated'\n | 'onChannelVisible'\n | 'onMessageNew'\n | 'onMessageNewHandler'\n | 'onRemovedFromChannel'\n > & {\n setChannels: SetChannels;\n customHandleChannelListShape?: (data: {\n defaults: ReturnType<typeof useChannelListShapeDefaults>;\n event: Event;\n setChannels: SetChannels;\n }) => void;\n };\n\nexport const usePrepareShapeHandlers = ({\n allowNewMessagesFromUnfilteredChannels,\n customHandleChannelListShape,\n filters,\n lockChannelOrder,\n onAddedToChannel,\n onChannelDeleted,\n onChannelHidden,\n onChannelTruncated,\n onChannelUpdated,\n onChannelVisible,\n onMessageNew,\n onMessageNewHandler,\n onRemovedFromChannel,\n setChannels,\n sort,\n}: UseDefaultHandleChannelListShapeParameters) => {\n const defaults = useChannelListShapeDefaults();\n\n const defaultHandleChannelListShapeRef = useRef<(e: Event) => void>(undefined);\n\n const customHandleChannelListShapeRef = useRef<(e: Event) => void>(undefined);\n\n customHandleChannelListShapeRef.current = (event: Event) => {\n customHandleChannelListShape?.({ defaults, event, setChannels });\n };\n\n defaultHandleChannelListShapeRef.current = (event: Event) => {\n switch (event.type) {\n case 'message.new':\n defaults.handleMessageNew({\n allowNewMessagesFromUnfilteredChannels,\n customHandler: onMessageNewHandler,\n event,\n filters,\n lockChannelOrder,\n setChannels,\n sort,\n });\n break;\n case 'notification.message_new':\n defaults.handleNotificationMessageNew({\n allowNewMessagesFromUnfilteredChannels,\n customHandler: onMessageNew,\n event,\n filters,\n lockChannelOrder,\n setChannels,\n sort,\n });\n break;\n case 'notification.added_to_channel':\n defaults.handleNotificationAddedToChannel({\n allowNewMessagesFromUnfilteredChannels,\n customHandler: onAddedToChannel,\n event,\n lockChannelOrder,\n setChannels,\n sort,\n });\n break;\n case 'notification.removed_from_channel':\n defaults.handleNotificationRemovedFromChannel({\n customHandler: onRemovedFromChannel,\n event,\n setChannels,\n });\n break;\n case 'channel.deleted':\n defaults.handleChannelDeleted({\n customHandler: onChannelDeleted,\n event,\n setChannels,\n });\n break;\n case 'channel.hidden':\n defaults.handleChannelHidden({\n customHandler: onChannelHidden,\n event,\n setChannels,\n });\n break;\n case 'channel.visible':\n defaults.handleChannelVisible({\n customHandler: onChannelVisible,\n event,\n filters,\n setChannels,\n sort,\n });\n break;\n case 'channel.truncated':\n defaults.handleChannelTruncated({\n customHandler: onChannelTruncated,\n event,\n setChannels,\n });\n break;\n case 'channel.updated':\n defaults.handleChannelUpdated({\n customHandler: onChannelUpdated,\n event,\n setChannels,\n });\n break;\n case 'user.presence.changed':\n defaults.handleUserPresenceChanged({ event, setChannels });\n break;\n case 'member.updated':\n defaults.handleMemberUpdated({\n event,\n filters,\n lockChannelOrder,\n setChannels,\n sort,\n });\n break;\n default:\n break;\n }\n };\n\n const defaultFn = useCallback((e: Event) => {\n defaultHandleChannelListShapeRef.current?.(e);\n }, []);\n\n const customFn = useMemo(() => {\n if (!customHandleChannelListShape) return null;\n return (e: Event) => {\n customHandleChannelListShapeRef.current?.(e);\n };\n }, [customHandleChannelListShape]);\n\n return {\n customHandler: customFn,\n defaultHandler: defaultFn,\n };\n};\n\nexport const useChannelListShape = (handler: (e: Event) => void) => {\n const { client } = useChatContext();\n\n useEffect(() => {\n const subscription = client.on('all', handler);\n\n return subscription.unsubscribe;\n }, [client, handler]);\n};\n","import { useEffect, useRef } from 'react';\nimport type { MouseEvent as ReactMouseEvent, RefObject } from 'react';\n\nimport {\n createRowActionKeyHandlers,\n useListboxKeyboardNavigation,\n} from '../../../a11y/hooks/useListboxKeyboardNavigation';\n\nconst OPTION_SELECTOR = '[role=\"option\"]';\nconst ROW_SELECTOR = '.str-chat__channel-list-item-container';\nconst ACTION_BUTTON_SELECTOR = '.str-chat__channel-list-item__action-buttons button';\nconst LOAD_MORE_SELECTOR = '[data-testid=\"load-more-button\"]';\n// Roving covers the channel rows AND the Load more button, so Down from the last channel lands on\n// it (and Up/End/Home behave). The load-more \"focus the first new item\" logic below still counts\n// channel rows only, so the button being a roving target does not skew the page-boundary index.\nconst NAVIGABLE_SELECTOR = `${OPTION_SELECTOR}, ${LOAD_MORE_SELECTOR}`;\n\n// Upper bound for how long a pending \"focus the first item of the next page\" request stays armed\n// after the Load more button is pressed. If the new page hasn't rendered within this window we drop\n// the request, so an unrelated later list change (e.g. a channel arriving over the WebSocket) can't\n// trigger a stray focus move.\nconst LOAD_MORE_FOCUS_TIMEOUT_MS = 4000;\n\n/**\n * Keyboard navigation for the channel list (`role=\"listbox\"`). Returns handlers to spread onto the\n * listbox element:\n * - **ArrowUp/ArrowDown/Home/End** move focus between the channel rows (`role=\"option\"`) and the\n * **Load more** button (the last roving target when present).\n * - **ArrowRight** moves focus from a row to its actions button (the menu is then navigable with\n * Up/Down via the ContextMenu's own roving focus).\n * - **ArrowLeft** moves focus from a row's actions back to the row.\n * - When **Load more** is activated, focus moves to the **first item of the newly loaded page** once\n * it renders.\n */\nexport const useChannelListKeyboardNavigation = (\n listboxRef: RefObject<HTMLElement | null>,\n) => {\n // Shared roving (channels + Load more) + ArrowRight→actions / ArrowLeft→row. `enterScope:\n // 'container'` + `resolveActiveOption` make Up/Down/Home/End work even while focus is on a row's\n // action button — moving to the next/previous channel relative to that row.\n const { onKeyDown } = useListboxKeyboardNavigation(listboxRef, {\n enterScope: 'container',\n keyHandlers: createRowActionKeyHandlers({\n actionSelector: ACTION_BUTTON_SELECTOR,\n rowSelector: ROW_SELECTOR,\n }),\n optionSelector: NAVIGABLE_SELECTOR,\n resolveActiveOption: (active) =>\n active.closest(ROW_SELECTOR)?.querySelector<HTMLElement>(OPTION_SELECTOR) ?? null,\n });\n\n // Channel rows only (excludes the Load more button) — used to find the first item of the next page.\n const getChannelOptions = () =>\n Array.from(listboxRef.current?.querySelectorAll<HTMLElement>(OPTION_SELECTOR) ?? []);\n\n // A pending \"focus the first item of the next page\" request. Rather than keying off the raw row\n // COUNT (which a WebSocket-driven insert/reorder during the load window could satisfy with an\n // unrelated row), we snapshot the pre-load rows: `boundary` is the last pre-load option (the new\n // page is appended after it) and `preLoad` is the set of all pre-load option nodes (so a genuinely\n // new row can be told apart from a reordered existing one). Rows are keyed by cid, so React keeps\n // their DOM nodes stable across re-renders, making these references reliable identities.\n const pendingFocusRef = useRef<{\n boundary: HTMLElement | null;\n preLoad: Set<HTMLElement>;\n } | null>(null);\n const pendingTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearPendingFocus = () => {\n pendingFocusRef.current = null;\n if (pendingTimeoutRef.current) {\n clearTimeout(pendingTimeoutRef.current);\n pendingTimeoutRef.current = null;\n }\n };\n\n // Activating Load more (by mouse or keyboard, which both dispatch a click) arms the focus move.\n const onClickCapture = (event: ReactMouseEvent<HTMLElement>) => {\n const target = event.target;\n if (!(target instanceof Element) || !target.closest(LOAD_MORE_SELECTOR)) return;\n const options = getChannelOptions();\n pendingFocusRef.current = {\n boundary: options[options.length - 1] ?? null,\n preLoad: new Set(options),\n };\n if (pendingTimeoutRef.current) clearTimeout(pendingTimeoutRef.current);\n pendingTimeoutRef.current = setTimeout(clearPendingFocus, LOAD_MORE_FOCUS_TIMEOUT_MS);\n };\n\n // After the newly loaded page renders, focus its first item. Runs after every commit; cheap no-op\n // unless a focus move is pending. We look for the first option that is BOTH after the pre-load\n // boundary AND was not present before load — so an unrelated row arriving over the WebSocket (which\n // sorts above the boundary, and/or is not \"after\" it) does not trigger a stray focus move.\n useEffect(() => {\n const pending = pendingFocusRef.current;\n if (!pending) return;\n const options = getChannelOptions();\n // Empty list when Load more was pressed: the whole list is the new page — focus its first row.\n if (!pending.boundary) {\n if (options.length > 0) {\n options[0].focus();\n clearPendingFocus();\n }\n return;\n }\n const boundaryIndex = options.indexOf(pending.boundary);\n // Boundary row was removed (e.g. the user left that channel) — drop the request rather than\n // guessing where the page starts.\n if (boundaryIndex === -1) {\n clearPendingFocus();\n return;\n }\n const firstNewOption = options\n .slice(boundaryIndex + 1)\n .find((option) => !pending.preLoad.has(option));\n // Nothing new after the boundary yet: keep waiting (within the timeout) for the page to render.\n if (!firstNewOption) return;\n firstNewOption.focus();\n clearPendingFocus();\n });\n\n useEffect(() => () => clearPendingFocus(), []);\n\n return { onClickCapture, onKeyDown };\n};\n","import React, { useRef } from 'react';\nimport type { PropsWithChildren } from 'react';\nimport type { APIErrorResponse, Channel, ErrorFromResponse } from 'stream-chat';\n\nimport { LoadingChannels } from '../Loading/LoadingChannels';\nimport { NullComponent } from '../UtilityComponents';\nimport { useChannelListKeyboardNavigation } from './hooks/useChannelListKeyboardNavigation';\nimport { useComponentContext, useTranslationContext } from '../../context';\n\nexport type ChannelListUIProps = {\n /** Whether the channel query request returned an errored response */\n error: ErrorFromResponse<APIErrorResponse> | null;\n /** The channels currently loaded in the list, only defined if `sendChannelsToList` on `ChannelList` is true */\n loadedChannels?: Channel[];\n /** Whether the channels are currently loading */\n loading?: boolean;\n /** Local state hook that resets the currently loaded channels */\n setChannels?: React.Dispatch<React.SetStateAction<Channel[]>>;\n};\n\n/**\n * A preview list of channels, allowing you to select the channel you want to open\n */\nexport const ChannelListUI = (props: PropsWithChildren<ChannelListUIProps>) => {\n const { children, error = null, loading = false } = props;\n const { LoadingErrorIndicator = NullComponent, LoadingIndicator = LoadingChannels } =\n useComponentContext('ChannelListUI');\n const { t } = useTranslationContext('ChannelListUI');\n\n const listboxRef = useRef<HTMLDivElement>(null);\n const { onClickCapture, onKeyDown } = useChannelListKeyboardNavigation(listboxRef);\n\n if (error) {\n return <LoadingErrorIndicator error={error} />;\n }\n\n return (\n <div className='str-chat__channel-list-inner'>\n <div\n aria-label={t('aria/Channel list')}\n className='str-chat__channel-list-inner__main'\n onClickCapture={onClickCapture}\n onKeyDown={onKeyDown}\n ref={listboxRef}\n role='listbox'\n >\n {loading ? <LoadingIndicator /> : children}\n </div>\n </div>\n );\n};\n","import React, { createContext, useContext } from 'react';\nimport type { PropsWithChildren } from 'react';\nimport type { SearchController } from 'stream-chat';\nimport type { SearchProps } from './Search';\n\nexport type SearchContextValue = {\n /** Instance of the search controller that handles the data management */\n searchController: SearchController;\n /** Reference to the container element of the search component */\n containerRef: React.RefObject<HTMLDivElement | null>;\n /** Reference to the container element of the filter buttons */\n filterButtonsContainerRef: React.RefObject<HTMLDivElement | null>;\n} & Pick<SearchProps, 'disabled' | 'inputProps' | 'placeholder'> &\n Required<Pick<SearchProps, 'exitSearchOnInputBlur' | 'directMessagingChannelType'>>;\n\nexport const SearchContext = createContext<SearchContextValue | undefined>(undefined);\n\n/**\n * Context provider for components rendered within the `Search` component\n */\nexport const SearchContextProvider = ({\n children,\n value,\n}: PropsWithChildren<{\n value: SearchContextValue;\n}>) => (\n <SearchContext.Provider value={value as unknown as SearchContextValue}>\n {children}\n </SearchContext.Provider>\n);\n\nexport const useSearchContext = () => {\n const contextValue = useContext(SearchContext);\n return contextValue as unknown as SearchContextValue;\n};\n","import clsx from 'clsx';\nimport React, { useEffect, useRef, useState } from 'react';\n\nimport { useSearchContext } from '../SearchContext';\nimport { useSearchQueriesInProgress } from '../hooks';\nimport { useInteractionAnnouncements } from '../../Accessibility';\nimport { useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport { Button, IconSearch, IconXCircle } from '../../../components';\n\nimport type { SearchControllerState } from 'stream-chat';\n\nconst searchControllerStateSelector = (nextValue: SearchControllerState) => ({\n isActive: nextValue.isActive,\n searchQuery: nextValue.searchQuery,\n});\n\nexport const SearchBar = () => {\n const { t } = useTranslationContext();\n const { announceInteraction } = useInteractionAnnouncements();\n const {\n containerRef,\n disabled,\n exitSearchOnInputBlur,\n inputProps,\n placeholder,\n searchController,\n } = useSearchContext();\n const queriesInProgress = useSearchQueriesInProgress(searchController);\n\n const [input, setInput] = useState<HTMLInputElement | null>(null);\n // Was the most recent pointerdown inside the search widget? Used to disambiguate a blur with a\n // null `relatedTarget`: browsers report `null` both when focus genuinely leaves the widget AND\n // when the user presses a non-focusable descendant (the search icon, wrapper padding). Only the\n // former should collapse search.\n const pointerDownInsideRef = useRef(false);\n const { isActive, searchQuery } = useStateStore(\n searchController.state,\n searchControllerStateSelector,\n );\n\n useEffect(() => {\n const handlePointerDown = (event: PointerEvent) => {\n pointerDownInsideRef.current = !!containerRef.current?.contains(\n event.target as Node | null,\n );\n };\n // Capture so it runs before the input's blur, regardless of where the press landed.\n document.addEventListener('pointerdown', handlePointerDown, true);\n return () => {\n document.removeEventListener('pointerdown', handlePointerDown, true);\n };\n }, [containerRef]);\n\n useEffect(() => {\n if (!input) return;\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n searchController.exit();\n // Keep focus on the search input (it no longer re-activates search on focus), so the user\n // can keep navigating from a known place rather than having focus drop to the body.\n input.focus();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [searchController, input]);\n\n return (\n <div className='str-chat__search-bar' data-testid='search-bar' role='search'>\n <div\n className={clsx('str-chat__search-bar__input-wrapper', {\n 'str-chat__search-bar__input-wrapper--active': isActive,\n })}\n >\n <IconSearch />\n <input\n {...inputProps}\n aria-label={t('Search')}\n className={clsx('str-chat__search-bar__input', inputProps?.className)}\n data-testid='search-input'\n disabled={disabled}\n onBlur={({ relatedTarget }) => {\n // Exit search only when focus leaves the search widget entirely. Moving focus to a\n // control inside it — the results list, the source filter buttons, the clear button,\n // or the Cancel/exit button — is not \"leaving search\", so it must not collapse it (the\n // Cancel button exits via its own activation, per WCAG 3.2.1). This matches the\n // documented contract (\"clear on every click outside the search\") independent of\n // whether the input currently holds a query — an empty input is not activated, so the\n // previous value check only ever suppressed the exit while a query was present.\n if (!exitSearchOnInputBlur) return;\n const focusMovedInside = !!containerRef.current?.contains(relatedTarget);\n // A null relatedTarget also occurs when a non-focusable element inside the widget is\n // pressed; the preceding pointerdown tells us it was an in-widget interaction, which\n // must not collapse search.\n const pressedInside = relatedTarget === null && pointerDownInsideRef.current;\n pointerDownInsideRef.current = false;\n if (!focusMovedInside && !pressedInside) {\n searchController.exit();\n }\n }}\n onChange={(event: React.ChangeEvent<HTMLInputElement>) => {\n // Activate search on user input — NOT on focus (WCAG 3.2.1: focusing a control must not\n // change context). `search()` runs against the active sources, so activation has to\n // happen here; `activate()` is idempotent once already active.\n if (event.target.value) {\n searchController.activate();\n searchController.search(event.target.value);\n } else {\n searchController.clear();\n }\n }}\n placeholder={placeholder ?? t('Search')}\n ref={setInput}\n type='text'\n value={searchQuery}\n />\n {searchQuery && (\n <Button\n appearance='ghost'\n aria-label={t('aria/Clear search')}\n circular\n className='str-chat__search-bar__clear-button'\n data-testid='clear-input-button'\n disabled={queriesInProgress.length > 0} // prevent user from clearing the input while query is in progress and avoid out-of-sync UX\n onClick={() => {\n searchController.clear();\n input?.focus();\n announceInteraction('search.cleared');\n }}\n size='xs'\n variant='secondary'\n >\n <IconXCircle />\n </Button>\n )}\n </div>\n {isActive && (\n <Button\n appearance='ghost'\n aria-label={t('aria/Exit search')}\n className='str-chat__search-bar__exit-search-button'\n data-testid='search-bar-button'\n onClick={() => {\n searchController.exit();\n // Return focus to the search input so navigation can continue from there (focusing it\n // no longer re-activates search — see RW19).\n input?.focus();\n }}\n size='sm'\n variant='secondary'\n >\n {t('Cancel')}\n </Button>\n )}\n </div>\n );\n};\n","import React, { useCallback, useMemo } from 'react';\nimport uniqBy from 'lodash.uniqby';\nimport type { ComponentType } from 'react';\nimport type { Channel, MessageResponse, User } from 'stream-chat';\n\nimport { useSearchContext } from '../SearchContext';\nimport { Avatar as DefaultAvatar } from '../../../components/Avatar';\nimport { extractDisplayInfo as defaultExtractDisplayInfo } from '../../../components/Avatar/utils';\nimport { ChannelListItem } from '../../../components/ChannelListItem';\nimport {\n useChannelListContext,\n useChatContext,\n useComponentContext,\n useTranslationContext,\n} from '../../../context';\nimport { DEFAULT_JUMP_TO_PAGE_SIZE } from '../../../constants/limits';\nimport { Timestamp } from '../../../components/Message/Timestamp';\n\nexport type ChannelSearchResultItemProps = {\n item: Channel;\n};\n\nexport const ChannelSearchResultItem = ({ item }: ChannelSearchResultItemProps) => {\n const { setActiveChannel } = useChatContext();\n const { setChannels } = useChannelListContext();\n\n const onSelect = useCallback(() => {\n setActiveChannel(item);\n setChannels?.((channels) => uniqBy([item, ...channels], 'cid'));\n }, [item, setActiveChannel, setChannels]);\n\n return (\n <ChannelListItem\n channel={item}\n className='str-chat__search-result'\n onSelect={onSelect}\n />\n );\n};\n\nexport type ChannelByMessageSearchResultItemProps = {\n item: MessageResponse;\n};\n\nexport const MessageSearchResultItem = ({\n item,\n}: ChannelByMessageSearchResultItemProps) => {\n const {\n channel: activeChannel,\n client,\n searchController,\n setActiveChannel,\n } = useChatContext();\n const { setChannels } = useChannelListContext();\n\n const channel = useMemo(() => {\n const { channel: channelData } = item;\n const type = channelData?.type ?? 'unknown';\n const id = channelData?.id ?? 'unknown';\n return client.channel(type, id);\n }, [client, item]);\n\n const onSelect = useCallback(async () => {\n if (!channel) return;\n await channel.state.loadMessageIntoState(\n item.id,\n undefined,\n DEFAULT_JUMP_TO_PAGE_SIZE,\n );\n // FIXME: message focus should be handled by yet non-existent msg list controller in client packaged\n searchController._internalState.partialNext({ focusedMessage: item });\n setActiveChannel(channel);\n setChannels?.((channels) => uniqBy([channel, ...channels], 'cid'));\n }, [channel, item, searchController, setActiveChannel, setChannels]);\n\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const getLatestMessagePreview = useCallback(() => item.text!, [item]);\n\n if (!channel) return null;\n\n return (\n <ChannelListItem\n active={\n channel.cid === activeChannel?.cid &&\n item.id === searchController._internalState.getLatestValue().focusedMessage?.id\n }\n channel={channel}\n className='str-chat__search-result'\n getLatestMessagePreview={getLatestMessagePreview}\n onSelect={onSelect}\n />\n );\n};\n\nexport type UserSearchResultItemProps = {\n item: User;\n};\n\nexport const UserSearchResultItem = ({ item }: UserSearchResultItemProps) => {\n const { client, setActiveChannel } = useChatContext();\n const { setChannels } = useChannelListContext();\n const { directMessagingChannelType } = useSearchContext();\n const { t } = useTranslationContext();\n const { Avatar = DefaultAvatar, extractDisplayInfo = defaultExtractDisplayInfo } =\n useComponentContext();\n\n const onClick = useCallback(() => {\n const newChannel = client.channel(directMessagingChannelType, {\n members: [client.userID as string, item.id],\n });\n newChannel.watch();\n setActiveChannel(newChannel);\n setChannels?.((channels) => uniqBy([newChannel, ...channels], 'cid'));\n }, [client, item, setActiveChannel, setChannels, directMessagingChannelType]);\n\n return (\n <div className='str-chat__search-result-container'>\n <button\n aria-label={t('aria/Select User Channel: {{ name }}', {\n name: item.name || '',\n })}\n className='str-chat__search-result str-chat__search-result--user'\n data-testid='search-result-user'\n onClick={onClick}\n role='option'\n >\n <Avatar\n {...extractDisplayInfo({ user: item })}\n isOnline={item.online}\n size='xl'\n />\n <div className='str-chat__search-result-data'>\n <div className='str-chat__search-result__display-name'>\n {item.name || item.username || item.id}\n </div>\n <Timestamp\n customClass='str-chat__search-result__last-active-timestamp'\n timestamp={item.last_active}\n />\n </div>\n </button>\n </div>\n );\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type SearchResultItemComponents = Record<string, ComponentType<{ item: any }>>;\n\nexport const DefaultSearchResultItems: SearchResultItemComponents = {\n channels: ChannelSearchResultItem,\n messages: MessageSearchResultItem,\n users: UserSearchResultItem,\n};\n","import type { PropsWithChildren } from 'react';\nimport React, { createContext, useContext } from 'react';\nimport type { SearchSource } from 'stream-chat';\n\nexport type SearchSourceResultsContextValue = {\n searchSource: SearchSource;\n};\n\nexport const SearchSourceResultsContext = createContext<\n SearchSourceResultsContextValue | undefined\n>(undefined);\n\n/**\n * Context provider for components rendered within the `SearchSourceResults`\n */\nexport const SearchSourceResultsContextProvider = ({\n children,\n value,\n}: PropsWithChildren<{\n value: SearchSourceResultsContextValue;\n}>) => (\n <SearchSourceResultsContext.Provider\n value={value as unknown as SearchSourceResultsContextValue}\n >\n {children}\n </SearchSourceResultsContext.Provider>\n);\n\nexport const useSearchSourceResultsContext = () => {\n const contextValue = useContext(SearchSourceResultsContext);\n return contextValue as unknown as SearchSourceResultsContextValue;\n};\n","import React from 'react';\nimport { useTranslationContext } from '../../../context';\nimport { useSearchSourceResultsContext } from '../SearchSourceResultsContext';\n\nexport const SearchSourceResultsLoadingIndicator = () => {\n const { t } = useTranslationContext();\n const { searchSource } = useSearchSourceResultsContext();\n return (\n <div\n className='str-chat__search-source-results__loading-indicator'\n data-testid='search-loading-indicator'\n >\n {t('Searching for {{ searchSourceType }}...', {\n searchSourceType: searchSource.type,\n })}\n </div>\n );\n};\n","import React from 'react';\nimport type { SearchSourceState } from 'stream-chat';\n\nimport { SearchSourceResultsLoadingIndicator as DefaultSearchSourceResultsLoadingIndicator } from './SearchSourceResultsLoadingIndicator';\nimport { useSearchSourceResultsContext } from '../SearchSourceResultsContext';\nimport { useComponentContext, useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nconst searchSourceStateSelector = (value: SearchSourceState) => ({\n hasNext: value.hasNext,\n isLoading: value.isLoading,\n});\n\nexport const SearchSourceResultListFooter = () => {\n const { t } = useTranslationContext();\n const {\n SearchSourceResultsLoadingIndicator = DefaultSearchSourceResultsLoadingIndicator,\n } = useComponentContext();\n const { searchSource } = useSearchSourceResultsContext();\n const { hasNext, isLoading } = useStateStore(\n searchSource.state,\n searchSourceStateSelector,\n );\n\n // The \"all results loaded\" end-of-list status is announced (combined with the result count) by\n // `useAnnounceSearchResultCount`; here it is visual only.\n return (\n <div\n className='str-chat__search-source-result-list__footer'\n data-testid='search-footer'\n >\n {isLoading ? (\n <SearchSourceResultsLoadingIndicator />\n ) : !hasNext ? (\n // Hidden from assistive tech: the end-of-list status is announced (combined with the result\n // count) by `useAnnounceSearchResultCount`, so the text is not read as a navigable result.\n <div aria-hidden='true' className='str-chat__search-source-results---empty'>\n {t('All results loaded')}\n </div>\n ) : null}\n </div>\n );\n};\n","import React from 'react';\nimport type { ComponentType } from 'react';\nimport type { SearchSourceState, SearchSourceType } from 'stream-chat';\n\nimport { DefaultSearchResultItems } from './SearchResultItem';\nimport { SearchSourceResultListFooter as DefaultSearchSourceResultListFooter } from './SearchSourceResultListFooter';\nimport { useSearchSourceResultsContext } from '../SearchSourceResultsContext';\nimport { InfiniteScrollPaginator } from '../../../components/InfiniteScrollPaginator/InfiniteScrollPaginator';\nimport { useComponentContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport type { SearchResultItemComponents } from './SearchResultItem';\n\nconst searchSourceStateSelector = (nextValue: SearchSourceState) => ({\n items: nextValue.items,\n});\n\nexport type SearchSourceResultListProps = {\n loadMoreDebounceMs?: number;\n loadMoreThresholdPx?: number;\n SearchResultItems?: SearchResultItemComponents;\n};\n\nexport const SearchSourceResultList = ({\n loadMoreDebounceMs = 100,\n loadMoreThresholdPx = 80,\n SearchResultItems = DefaultSearchResultItems,\n}: SearchSourceResultListProps) => {\n const { SearchSourceResultListFooter = DefaultSearchSourceResultListFooter } =\n useComponentContext();\n\n const { searchSource } = useSearchSourceResultsContext();\n const { items } = useStateStore(searchSource.state, searchSourceStateSelector);\n\n const SearchResultItem = SearchResultItems[\n searchSource.type as SearchSourceType\n ] as ComponentType<{ item: unknown }>;\n\n if (!SearchResultItem) return null;\n\n return (\n <div\n className='str-chat__search-source-result-list'\n data-testid='search-source-result-list'\n >\n <InfiniteScrollPaginator\n loadNextDebounceMs={loadMoreDebounceMs}\n loadNextOnScrollToBottom={searchSource.search}\n threshold={loadMoreThresholdPx}\n >\n {items?.map((item, i) => (\n <SearchResultItem\n item={item}\n key={`source-search-result-${searchSource.type}-${i}`}\n />\n ))}\n <SearchSourceResultListFooter />\n </InfiniteScrollPaginator>\n </div>\n );\n};\n","import React from 'react';\nimport { useTranslationContext } from '../../../context';\n\nexport const SearchSourceResultsEmpty = () => {\n const { t } = useTranslationContext();\n return (\n <div className='str-chat__search-source-results-empty'>{t('No results found')}</div>\n );\n};\n","export const SearchSourceResultsHeader = () => null;\n","import React from 'react';\nimport type { SearchSource, SearchSourceState } from 'stream-chat';\n\nimport { SearchSourceResultList as DefaultSearchSourceResultList } from './SearchSourceResultList';\nimport { SearchSourceResultsEmpty as DefaultSearchSourceResultsEmpty } from './SearchSourceResultsEmpty';\nimport { SearchSourceResultsHeader as DefaultSearchSourceResultsHeader } from './SearchSourceResultsHeader';\nimport { SearchSourceResultsContextProvider } from '../SearchSourceResultsContext';\nimport { useComponentContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nconst searchSourceStateSelector = (nextValue: SearchSourceState) => ({\n isLoading: nextValue.isLoading,\n items: nextValue.items,\n});\n\nexport type SearchSourceResultsProps = { searchSource: SearchSource };\n\nexport const SearchSourceResults = ({ searchSource }: SearchSourceResultsProps) => {\n const {\n SearchSourceResultList = DefaultSearchSourceResultList,\n SearchSourceResultsEmpty = DefaultSearchSourceResultsEmpty,\n SearchSourceResultsHeader = DefaultSearchSourceResultsHeader,\n } = useComponentContext();\n const { isLoading, items } = useStateStore(\n searchSource.state,\n searchSourceStateSelector,\n );\n\n if (!items && !isLoading) return null;\n\n return (\n <SearchSourceResultsContextProvider value={{ searchSource }}>\n <div\n className='str-chat__search-source-results'\n data-testid='search-source-results'\n >\n <SearchSourceResultsHeader />\n {items?.length || isLoading ? (\n <SearchSourceResultList />\n ) : (\n <SearchSourceResultsEmpty />\n )}\n </div>\n </SearchSourceResultsContextProvider>\n );\n};\n","import clsx from 'clsx';\nimport React, { useMemo } from 'react';\nimport type { SearchSource, SearchSourceState } from 'stream-chat';\n\nimport { useSearchContext } from '../SearchContext';\nimport { useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\nimport { Button } from '../../../components';\n\nconst searchSourceStateSelector = (nextValue: SearchSourceState) => ({\n isActive: nextValue.isActive,\n});\n\ntype SearchSourceFilterButtonProps = {\n source: SearchSource;\n};\n\nconst SearchSourceFilterButton = ({ source }: SearchSourceFilterButtonProps) => {\n const { t } = useTranslationContext();\n const { searchController } = useSearchContext();\n const { isActive } = useStateStore(source.state, searchSourceStateSelector);\n const label = `search-results-header-filter-source-button-label--${source.type}`;\n\n const knownLabels = useMemo<Record<string, string>>(\n () => ({\n 'search-results-header-filter-source-button-label--channels': t(\n 'search-results-header-filter-source-button-label--channels',\n ),\n 'search-results-header-filter-source-button-label--messages': t(\n 'search-results-header-filter-source-button-label--messages',\n ),\n 'search-results-header-filter-source-button-label--users': t(\n 'search-results-header-filter-source-button-label--users',\n ),\n }),\n [t],\n );\n\n const buttonContent = knownLabels[label] ?? t(label);\n return (\n <Button\n appearance='outline'\n aria-label={t('aria/Search results header filter button for: {{ source }}', {\n source: buttonContent,\n })}\n aria-pressed={isActive}\n className={clsx('str-chat__search-results-header__filter-source-button', {\n 'str-chat__search-results-header__filter-source-button--active': isActive,\n })}\n key={label}\n onClick={() => {\n if (source.isActive) {\n searchController.deactivateSource(source.type);\n } else {\n searchController.activateSource(source.type);\n if (searchController.searchQuery && !source.items?.length)\n source.search(searchController.searchQuery);\n }\n }}\n size='xs'\n variant='secondary'\n >\n {buttonContent}\n </Button>\n );\n};\n\nexport const SearchResultsHeader = () => {\n const { filterButtonsContainerRef, searchController } = useSearchContext();\n\n // render nothing if there's only one source (can't change filters)\n if (searchController.sources.length < 2) return null;\n\n return (\n <div className='str-chat__search-results-header' data-testid='search-results-header'>\n <div\n className='str-chat__search-results-header__filter-source-buttons'\n data-testid='filter-source-buttons'\n ref={filterButtonsContainerRef}\n >\n {searchController.sources.map((source) => (\n <SearchSourceFilterButton key={source.type} source={source} />\n ))}\n </div>\n </div>\n );\n};\n","import React from 'react';\n\nimport { useTranslationContext } from '../../../context';\n\nimport type { SearchSource } from 'stream-chat';\n\nexport type SearchResultsPresearchProps = {\n activeSources: SearchSource[];\n};\n\nexport const SearchResultsPresearch = () => {\n const { t } = useTranslationContext();\n return (\n <div className='str-chat__search-results-presearch'>\n {t('Start typing to search')}\n </div>\n );\n};\n","import React, { useRef } from 'react';\nimport type { SearchControllerState } from 'stream-chat';\n\nimport { SearchSourceResults as DefaultSourceSearchResults } from './SearchSourceResults';\nimport { SearchResultsHeader as DefaultSearchResultsHeader } from './SearchResultsHeader';\nimport { SearchResultsPresearch as DefaultSearchResultsPresearch } from './SearchResultsPresearch';\nimport { useSearchContext } from '../SearchContext';\nimport {\n useAnnounceSearchResultCount,\n useSearchResultsKeyboardNavigation,\n} from '../hooks';\nimport { useComponentContext, useTranslationContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nconst searchControllerStateSelector = (nextValue: SearchControllerState) => ({\n activeSources: nextValue.sources.filter((s) => s.isActive),\n isActive: nextValue.isActive,\n searchQuery: nextValue.searchQuery,\n});\n\nexport const SearchResults = () => {\n const { t } = useTranslationContext('ResultsContainer');\n const {\n SearchResultsHeader = DefaultSearchResultsHeader,\n SearchResultsPresearch = DefaultSearchResultsPresearch,\n SearchSourceResults = DefaultSourceSearchResults,\n } = useComponentContext();\n const { searchController } = useSearchContext();\n const { activeSources, isActive, searchQuery } = useStateStore(\n searchController.state,\n searchControllerStateSelector,\n );\n\n const resultsRef = useRef<HTMLDivElement | null>(null);\n const { onKeyDown } = useSearchResultsKeyboardNavigation(resultsRef);\n // Announce the number of listed results once the list settles (only while a query is in progress,\n // not during presearch); the end-of-list status rides along in that same announcement.\n useAnnounceSearchResultCount(resultsRef, isActive && !!searchQuery, activeSources);\n\n return !isActive ? null : (\n <div\n aria-label={t('aria/Search results')}\n className='str-chat__search-results'\n onKeyDown={onKeyDown}\n ref={resultsRef}\n >\n <SearchResultsHeader />\n {!searchQuery ? (\n <SearchResultsPresearch activeSources={activeSources} />\n ) : (\n activeSources.map((source) => (\n <SearchSourceResults key={source.type} searchSource={source} />\n ))\n )}\n </div>\n );\n};\n","import clsx from 'clsx';\nimport React, { useRef } from 'react';\nimport type { SearchControllerState } from 'stream-chat';\n\nimport { SearchBar as DefaultSearchBar } from './SearchBar/SearchBar';\nimport { SearchResults as DefaultSearchResults } from './SearchResults/SearchResults';\nimport { SearchContextProvider } from './SearchContext';\nimport { useChatContext, useComponentContext } from '../../context';\nimport { useStateStore } from '../../store';\n\ntype SearchControllerStateSelectorReturnValue = {\n isActive: boolean;\n};\n\nconst searchControllerStateSelector = (\n nextValue: SearchControllerState,\n): SearchControllerStateSelectorReturnValue => ({ isActive: nextValue.isActive });\n\nexport type SearchProps = {\n /** The type of channel to create on user result select, defaults to `messaging` */\n directMessagingChannelType?: string;\n /** Sets the input element into disabled state */\n disabled?: boolean;\n /** Clear the search state/results on every click outside the search input, defaults to `false` */\n exitSearchOnInputBlur?: boolean;\n /**\n * Extra props spread onto the search `<input>` element — e.g. to opt the field out of password\n * managers (`data-1p-ignore`, `data-lpignore`, `autoComplete: 'off'`) or add `name`/`aria-*`\n * attributes. The component's own controlled props (`value`, `onChange`, `onBlur`, `type`, `id`,\n * `disabled`, `ref`) take precedence and cannot be overridden; `className` is merged.\n */\n inputProps?: React.ComponentPropsWithoutRef<'input'>;\n /** Custom placeholder text to be displayed in the search input */\n placeholder?: string;\n};\n\nexport const Search = ({\n directMessagingChannelType = 'messaging',\n disabled,\n exitSearchOnInputBlur = false,\n inputProps,\n placeholder,\n}: SearchProps) => {\n const { SearchBar = DefaultSearchBar, SearchResults = DefaultSearchResults } =\n useComponentContext();\n const containerRef = useRef<HTMLDivElement | null>(null);\n const filterButtonsContainerRef = useRef<HTMLDivElement | null>(null);\n\n const { searchController } = useChatContext();\n\n const { isActive } = useStateStore<\n SearchControllerState,\n SearchControllerStateSelectorReturnValue\n >(searchController.state, searchControllerStateSelector);\n\n return (\n <SearchContextProvider\n value={{\n containerRef,\n directMessagingChannelType,\n disabled,\n exitSearchOnInputBlur,\n filterButtonsContainerRef,\n inputProps,\n placeholder,\n searchController,\n }}\n >\n <div\n className={clsx('str-chat__search', {\n 'str-chat__search--active': isActive,\n })}\n data-testid='search'\n ref={containerRef}\n >\n <SearchBar />\n <SearchResults />\n </div>\n </SearchContextProvider>\n );\n};\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\nimport { LoadingIndicator } from '../Loading';\nimport { useTranslationContext } from '../../context';\nimport { Button } from '../Button';\n\nexport type LoadMoreButtonProps = {\n /** onClick handler load more button. Pagination logic should be executed in this handler. */\n onClick: React.MouseEventHandler<HTMLButtonElement>;\n /** indicates whether a loading request is in progress */\n isLoading?: boolean;\n};\n\nconst UnMemoizedLoadMoreButton = ({\n children,\n isLoading,\n onClick,\n}: PropsWithChildren<LoadMoreButtonProps>) => {\n const { t } = useTranslationContext('UnMemoizedLoadMoreButton');\n\n const childrenOrDefaultString = children ?? t('Load more');\n\n return (\n <div className='str-chat__load-more-button'>\n <Button\n appearance='ghost'\n aria-label={t('Load more')}\n data-testid='load-more-button'\n disabled={isLoading}\n onClick={onClick}\n size='sm'\n variant='secondary'\n >\n {isLoading ? <LoadingIndicator /> : childrenOrDefaultString}\n </Button>\n </div>\n );\n};\n\nexport const LoadMoreButton = React.memo(\n UnMemoizedLoadMoreButton,\n) as typeof UnMemoizedLoadMoreButton;\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\n\nimport type { LoadMoreButtonProps } from './LoadMoreButton';\nimport { LoadMoreButton as DefaultLoadMoreButton } from './LoadMoreButton';\nimport type { PaginatorProps } from '../../types/types';\n\nexport type LoadMorePaginatorProps = PaginatorProps & {\n /** A UI button component that handles pagination logic */\n LoadMoreButton?: React.ComponentType<LoadMoreButtonProps>;\n /** indicates if the `LoadMoreButton` should be displayed at the top of the list of channels instead of the bottom of the list (the default) */\n reverse?: boolean;\n};\n\nexport const UnMemoizedLoadMorePaginator = (\n props: PropsWithChildren<LoadMorePaginatorProps>,\n) => {\n const {\n children,\n hasNextPage,\n isLoading,\n LoadMoreButton = DefaultLoadMoreButton,\n loadNextPage,\n reverse,\n } = props;\n\n return (\n <>\n {!reverse && children}\n {hasNextPage && <LoadMoreButton isLoading={isLoading} onClick={loadNextPage} />}\n {reverse && children}\n </>\n );\n};\n\nexport const LoadMorePaginator = React.memo(\n UnMemoizedLoadMorePaginator,\n) as typeof UnMemoizedLoadMorePaginator;\n","import React from 'react';\nimport {\n useChatContext,\n useComponentContext,\n useTranslationContext,\n} from '../../context';\n\nexport const ChannelListHeader = () => {\n const { t } = useTranslationContext();\n const { channel } = useChatContext();\n const { HeaderEndContent } = useComponentContext();\n return (\n <div className='str-chat__channel-list__header'>\n <div className='str-chat__channel-list__header__title'>{t('Chats')}</div>\n {channel && HeaderEndContent && <HeaderEndContent />}\n </div>\n );\n};\n","import type { ReactNode } from 'react';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\nimport clsx from 'clsx';\nimport type {\n Channel,\n ChannelFilters,\n ChannelOptions,\n ChannelSort,\n Event,\n SearchControllerState,\n} from 'stream-chat';\n\nimport { useConnectionRecoveredListener } from './hooks/useConnectionRecoveredListener';\nimport type {\n CustomQueryChannelsFn,\n EffectiveQueryParams,\n} from './hooks/usePaginatedChannels';\nimport { usePaginatedChannels } from './hooks/usePaginatedChannels';\nimport {\n useChannelListShape,\n usePrepareShapeHandlers,\n} from './hooks/useChannelListShape';\nimport { useStateStore } from '../../store';\nimport { ChannelListUI as DefaultChannelListUI } from './ChannelListUI';\nimport { ChannelListItem } from '../ChannelListItem/ChannelListItem';\nimport { Search as DefaultSearch } from '../Search';\nimport type { EmptyStateIndicatorProps } from '../EmptyStateIndicator';\nimport { EmptyStateIndicator as DefaultEmptyStateIndicator } from '../EmptyStateIndicator';\nimport type { LoadMorePaginatorProps } from '../LoadMore/LoadMorePaginator';\nimport { LoadMorePaginator } from '../LoadMore/LoadMorePaginator';\nimport { NotificationList as DefaultNotificationList } from '../Notifications';\nimport type { ChatContextValue } from '../../context';\nimport {\n ChannelListContextProvider,\n DialogManagerProvider,\n useChatContext,\n useComponentContext,\n} from '../../context';\nimport { moveChannelUpwards } from './utils';\nimport type { TranslationContextValue } from '../../context/TranslationContext';\nimport type { PaginatorProps } from '../../types/types';\nimport { ChannelListHeader as DefaultChannelListHeader } from './ChannelListHeader';\nimport { useStableId } from '../UtilityComponents/useStableId';\n\nconst DEFAULT_FILTERS = {};\nconst DEFAULT_OPTIONS = {};\nconst DEFAULT_SORT = {};\n\nconst searchControllerStateSelector = (nextValue: SearchControllerState) => ({\n searchIsActive: nextValue.isActive,\n});\n\nexport type ChannelListProps = {\n /**\n * When the client receives `message.new`, `notification.message_new`, and `notification.added_to_channel` events, we automatically\n * push that channel to the top of the list. If the channel doesn't currently exist in the list, we grab the channel from\n * `client.activeChannels` and push it to the top of the list. You can disable this behavior by setting this prop\n * to false, which will prevent channels not in the list from incrementing the list. The default is true.\n */\n allowNewMessagesFromUnfilteredChannels?: boolean;\n /** Optional function to filter channels prior to loading in the DOM. Do not use any complex or async logic that would delay the loading of the ChannelList. We recommend using a pure function with array methods like filter/sort/reduce. */\n channelRenderFilterFn?: (channels: Array<Channel>) => Array<Channel>;\n // FIXME: how is this even legal (WHY IS IT STRING?!)\n /** Set a channel (with this ID) to active and manually move it to the top of the list */\n customActiveChannel?: string;\n /** Custom function that handles the channel pagination. Has to build query filters, sort and options and query and append channels to the current channels state and update the hasNext pagination flag after each query. */\n customQueryChannels?: CustomQueryChannelsFn;\n /** Custom UI component for rendering an empty list, defaults to and accepts same props as: [EmptyStateIndicator](https://github.com/GetStream/stream-chat-react/blob/master/src/components/EmptyStateIndicator/EmptyStateIndicator.tsx) */\n EmptyStateIndicator?: React.ComponentType<EmptyStateIndicatorProps>;\n /** An object containing channel query filters */\n filters?: ChannelFilters;\n /** Custom function that generates the message preview in ChannelPreview component */\n getLatestMessagePreview?: (\n channel: Channel,\n t: TranslationContextValue['t'],\n userLanguage: TranslationContextValue['userLanguage'],\n isMessageAIGenerated?: ChatContextValue['isMessageAIGenerated'],\n ) => ReactNode;\n /** When true, channels won't dynamically sort by most recent message */\n lockChannelOrder?: boolean;\n /** Function to override the default behavior when a user is added to a channel, corresponds to [notification.added\\_to\\_channel](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n onAddedToChannel?: (\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n event: Event,\n ) => void;\n /** Function to override the default behavior when a channel is deleted, corresponds to [channel.deleted](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n onChannelDeleted?: (\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n event: Event,\n ) => void;\n /** Function to override the default behavior when a channel is hidden, corresponds to [channel.hidden](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n onChannelHidden?: (\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n event: Event,\n ) => void;\n /** Function to override the default behavior when a channel is truncated, corresponds to [channel.truncated](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n onChannelTruncated?: (\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n event: Event,\n ) => void;\n /** Function to override the default behavior when a channel is updated, corresponds to [channel.updated](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n onChannelUpdated?: (\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n event: Event,\n ) => void;\n /** Function to override the default channel visible behavior, corresponds to [channel.visible](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n onChannelVisible?: (\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n event: Event,\n ) => void;\n /** Function to override the default behavior when a message is received on a channel not being watched, corresponds to [notification.message\\_new](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n onMessageNew?: (\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n event: Event,\n ) => void;\n /** Function to override the default behavior when a message is received on a channel being watched, handles [message.new](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n onMessageNewHandler?: (\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n event: Event,\n ) => void;\n /** Function to override the default behavior when a user gets removed from a channel, corresponds to [notification.removed\\_from\\_channel](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) event */\n onRemovedFromChannel?: (\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n event: Event,\n ) => void;\n /** An object containing channel query options */\n options?: ChannelOptions;\n /** Custom UI component to handle channel pagination logic, defaults to and accepts same props as: [LoadMorePaginator](https://github.com/GetStream/stream-chat-react/blob/master/src/components/LoadMore/LoadMorePaginator.tsx) */\n Paginator?: React.ComponentType<PaginatorProps | LoadMorePaginatorProps>;\n /**\n * Custom interval during which the recovery channel list queries will be prevented.\n * This is to avoid firing unnecessary queries during internet connection fluctuation.\n * Recovery channel query is triggered upon `connection.recovered` and leads to complete channel list reload with pagination offset 0.\n * The minimum throttle interval is 2000ms. The default throttle interval is 5000ms.\n */\n recoveryThrottleIntervalMs?: number;\n /** Function to override the default behavior when rendering channels, so this function is called instead of rendering the Preview directly */\n renderChannels?: (\n channels: Channel[],\n channelPreview: (item: Channel) => React.ReactNode,\n ) => React.ReactNode;\n /** If true, sends the list's currently loaded channels to the `List` component as the `loadedChannels` prop */\n sendChannelsToList?: boolean;\n /** Last channel will be set as active channel if true, defaults to true */\n setActiveChannelOnMount?: boolean;\n /** Whether or not to load the list with a search component, defaults to false */\n showChannelSearch?: boolean;\n /** An object containing channel query sort parameters */\n sort?: ChannelSort;\n /** An object containing query parameters for fetching channel watchers */\n watchers?: { limit?: number; offset?: number };\n};\n\nconst UnMemoizedChannelList = (props: ChannelListProps) => {\n const {\n allowNewMessagesFromUnfilteredChannels = true,\n channelRenderFilterFn,\n customActiveChannel,\n customQueryChannels,\n EmptyStateIndicator = DefaultEmptyStateIndicator,\n filters = {},\n getLatestMessagePreview,\n lockChannelOrder = false,\n onAddedToChannel,\n onChannelDeleted,\n onChannelHidden,\n onChannelTruncated,\n onChannelUpdated,\n onChannelVisible,\n onMessageNew,\n onMessageNewHandler,\n onRemovedFromChannel,\n options,\n Paginator = LoadMorePaginator,\n recoveryThrottleIntervalMs,\n renderChannels,\n sendChannelsToList = false,\n setActiveChannelOnMount = true,\n showChannelSearch = false,\n sort = DEFAULT_SORT,\n watchers = {},\n } = props;\n\n const stableId = useStableId();\n\n const {\n channel,\n channelsQueryState,\n client,\n customClasses,\n searchController,\n setActiveChannel,\n theme,\n useImageFlagEmojisOnWindows,\n } = useChatContext('ChannelList');\n const {\n ChannelListHeader = DefaultChannelListHeader,\n ChannelListUI = DefaultChannelListUI,\n NotificationList = DefaultNotificationList,\n Search = DefaultSearch,\n } = useComponentContext();\n\n const channelListRef = useRef<HTMLDivElement | null>(null);\n const [channelUpdateCount, setChannelUpdateCount] = useState(0);\n\n // Indicator relevant when Search component that relies on SearchController is used\n const { searchIsActive } = useStateStore(\n searchController.state,\n searchControllerStateSelector,\n );\n /**\n * Set a channel with id {customActiveChannel} as active and move it to the top of the list.\n * If customActiveChannel prop is absent, then set the first channel in list as active channel.\n */\n const activeChannelHandler = async (\n channels: Array<Channel>,\n setChannels: React.Dispatch<React.SetStateAction<Array<Channel>>>,\n effectiveQueryParams: EffectiveQueryParams,\n ) => {\n if (!channels.length) {\n return;\n }\n\n if (customActiveChannel) {\n // FIXME: this is wrong...\n let customActiveChannelObject = channels.find(\n (chan) => chan.id === customActiveChannel,\n );\n\n if (!customActiveChannelObject) {\n [customActiveChannelObject] = await client.queryChannels({\n id: customActiveChannel,\n });\n }\n\n if (customActiveChannelObject) {\n setActiveChannel(customActiveChannelObject, watchers);\n\n const newChannels = moveChannelUpwards({\n channels,\n channelToMove: customActiveChannelObject,\n sort: effectiveQueryParams.sort,\n });\n\n setChannels(newChannels);\n return;\n }\n }\n\n if (setActiveChannelOnMount) {\n setActiveChannel(channels[0], watchers);\n }\n };\n\n /**\n * For some events, inner properties on the channel will update but the shallow comparison will not\n * force a re-render. Incrementing this dummy variable ensures the channel previews update.\n */\n const forceUpdate = useCallback(() => setChannelUpdateCount((count) => count + 1), []);\n\n const {\n channels,\n effectiveFilters,\n effectiveSort,\n hasNextPage,\n loadNextPage,\n setChannels,\n } = usePaginatedChannels(\n client,\n filters || DEFAULT_FILTERS,\n sort || DEFAULT_SORT,\n options || DEFAULT_OPTIONS,\n activeChannelHandler,\n recoveryThrottleIntervalMs,\n customQueryChannels,\n );\n\n const loadedChannels = channelRenderFilterFn\n ? channelRenderFilterFn(channels)\n : channels;\n\n const { customHandler, defaultHandler } = usePrepareShapeHandlers({\n allowNewMessagesFromUnfilteredChannels,\n // `effectiveFilters`/`effectiveSort` reflect the backend-resolved\n // `predefined_filter` metadata when `options.predefined_filter` is in use.\n // For non-predefined queries they fall back to the caller-supplied\n // `filters`/`sort` props so behavior is unchanged.\n filters: effectiveFilters,\n lockChannelOrder,\n onAddedToChannel,\n onChannelDeleted,\n onChannelHidden,\n onChannelTruncated,\n onChannelUpdated,\n onChannelVisible,\n onMessageNew,\n onMessageNewHandler,\n onRemovedFromChannel,\n setChannels,\n sort: effectiveSort,\n // TODO: implement\n // customHandleChannelListShape\n });\n\n useChannelListShape(customHandler ?? defaultHandler);\n\n // TODO: maybe move this too\n useConnectionRecoveredListener(forceUpdate);\n\n useEffect(() => {\n const handleEvent = (event: Event) => {\n if (event.cid === channel?.cid) {\n setActiveChannel();\n }\n };\n\n client.on('channel.deleted', handleEvent);\n client.on('channel.hidden', handleEvent);\n\n return () => {\n client.off('channel.deleted', handleEvent);\n client.off('channel.hidden', handleEvent);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [channel?.cid]);\n\n const renderChannel = (item: Channel) => {\n const previewProps = {\n activeChannel: channel,\n channel: item,\n // forces the update of preview component on channel update\n channelUpdateCount,\n getLatestMessagePreview,\n setActiveChannel,\n watchers,\n };\n\n return <ChannelListItem key={item.cid} {...previewProps} />;\n };\n\n const baseClass = 'str-chat__channel-list';\n const className = clsx(\n customClasses?.chat ?? 'str-chat',\n theme,\n customClasses?.channelList ?? `${baseClass}`,\n {\n 'str-chat--windows-flags':\n useImageFlagEmojisOnWindows && navigator.userAgent.match(/Win/),\n },\n );\n\n const showChannelList = !searchIsActive;\n return (\n <ChannelListContextProvider\n value={{ channels, hasNextPage, loadNextPage, setChannels }}\n >\n <div className={className} ref={channelListRef}>\n <DialogManagerProvider id={`channel-list-dialog-manager-${stableId}`}>\n <ChannelListHeader />\n {showChannelSearch && <Search />}\n {showChannelList && (\n <ChannelListUI\n error={channelsQueryState.error}\n loadedChannels={sendChannelsToList ? loadedChannels : undefined}\n loading={\n !!channelsQueryState.queryInProgress &&\n ['reload', 'uninitialized'].includes(channelsQueryState.queryInProgress)\n }\n setChannels={setChannels}\n >\n {!loadedChannels?.length ? (\n <EmptyStateIndicator listType='channel' />\n ) : (\n <Paginator\n hasNextPage={hasNextPage}\n isLoading={channelsQueryState.queryInProgress === 'load-more'}\n loadNextPage={loadNextPage}\n >\n {renderChannels\n ? renderChannels(loadedChannels, renderChannel)\n : loadedChannels.map((channel) => renderChannel(channel))}\n </Paginator>\n )}\n </ChannelListUI>\n )}\n <NotificationList panel='channel-list' />\n </DialogManagerProvider>\n </div>\n </ChannelListContextProvider>\n );\n};\n\n/**\n * Renders a preview list of Channels, allowing you to select the Channel you want to open\n */\nexport const ChannelList = React.memo(\n UnMemoizedChannelList,\n) as typeof UnMemoizedChannelList;\n","import type { Channel, ChannelMemberResponse, EventTypes } from 'stream-chat';\nimport { useSelectedChannelState } from './useSelectedChannelState';\n\nconst selector = (c: Channel) => c.state.members;\nconst keys: EventTypes[] = [\n 'member.updated',\n 'member.added',\n 'member.removed',\n 'user.banned',\n 'user.unbanned',\n 'user.deleted',\n 'user.presence.changed',\n];\n\nexport function useChannelMembersState(\n channel: Channel,\n): Record<string, ChannelMemberResponse>;\nexport function useChannelMembersState(\n channel?: Channel | undefined,\n): Record<string, ChannelMemberResponse> | undefined;\nexport function useChannelMembersState(channel?: Channel) {\n return useSelectedChannelState({ channel, selector, stateChangeEventKeys: keys });\n}\n","import {\n type ComponentPropsWithoutRef,\n type ComponentPropsWithRef,\n forwardRef,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport {\n useChatContext,\n useComponentContextIcons,\n useTranslationContext,\n} from '../../context';\nimport { useChannelMembershipState, useChannelMembersState } from '../ChannelList';\nimport { useChannelListItemContext } from './ChannelListItem';\nimport { Button } from '../Button';\nimport { useIsChannelMuted } from './hooks/useIsChannelMuted';\nimport {\n ContextMenuButton,\n useContextMenuContext,\n useDialogIsOpen,\n useDialogOnNearestManager,\n} from '../Dialog';\nimport { useNotificationApi } from '../Notifications';\nimport { ChannelListItemActionButtons } from './ChannelListItemActionButtons';\n\ntype ChannelActionBehavior = {\n /** Toggle state for actions that have one (mute/archive/pin); omit for one-shot actions (leave). */\n 'aria-pressed'?: boolean;\n title: string;\n toggle: () => Promise<void>;\n};\n\n// Core mute/unmute action — performs the API call and reports the result. No UI state: the placement\n// wrappers below own the busy/disabled affordance and the menu-close behavior.\nconst useMuteAction = (): ChannelActionBehavior => {\n const { addNotification } = useNotificationApi();\n const { channel } = useChannelListItemContext();\n const { t } = useTranslationContext();\n const { muted: isMuted } = useIsChannelMuted(channel);\n\n const toggle = async () => {\n try {\n if (isMuted) {\n await channel.unmute();\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n message: t('Channel unmuted'),\n severity: 'success',\n type: 'api:channel:unmute:success',\n });\n } else {\n await channel.mute();\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n message: t('Channel muted'),\n severity: 'success',\n type: 'api:channel:mute:success',\n });\n }\n } catch (error) {\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n error: error instanceof Error ? error : new Error('An unknown error occurred'),\n message: t('Failed to update channel mute status'),\n severity: 'error',\n type: 'api:channel:mute:failed',\n });\n }\n };\n\n return { 'aria-pressed': isMuted, title: isMuted ? t('Unmute') : t('Mute'), toggle };\n};\n\n// Core archive/unarchive action — performs the API call and reports the result.\nconst useArchiveAction = (): ChannelActionBehavior => {\n const { channel } = useChannelListItemContext();\n const { addNotification } = useNotificationApi();\n const membership = useChannelMembershipState(channel);\n const { t } = useTranslationContext();\n\n const toggle = async () => {\n try {\n if (membership.archived_at) {\n await channel.unarchive();\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n message: t('Channel unarchived'),\n severity: 'success',\n type: 'api:channel:unarchive:success',\n });\n } else {\n await channel.archive();\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n message: t('Channel archived'),\n severity: 'success',\n type: 'api:channel:archive:success',\n });\n }\n } catch (error) {\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n error: error instanceof Error ? error : new Error('An unknown error occurred'),\n message: t('Failed to update channel archive status'),\n severity: 'error',\n type: 'api:channel:archive:failed',\n });\n }\n };\n\n return {\n 'aria-pressed': typeof membership.archived_at === 'string',\n title: membership.archived_at ? t('Unarchive') : t('Archive'),\n toggle,\n };\n};\n\n// Quick (hover/focus-revealed) action button. Marks itself busy with `aria-disabled`/`aria-busy` —\n// NOT the native `disabled` attribute, which would blur the button and collapse its hover-revealed\n// row, leaving it un-focusable. Keeps focus and guards against re-activation while in flight.\nconst useQuickActionButtonProps = ({\n 'aria-pressed': ariaPressed,\n title,\n toggle,\n}: ChannelActionBehavior) => {\n // Ref latch flips synchronously in the handler so two clicks in the same tick (before the\n // `setInProgress(true)` rerender commits) can't both call `toggle()` — the `aria-busy`/\n // `aria-disabled` state only guards after the rerender, which is too late for non-idempotent\n // actions (archive/leave/mute).\n const inProgressRef = useRef(false);\n const [inProgress, setInProgress] = useState(false);\n\n return {\n 'aria-busy': inProgress || undefined,\n 'aria-disabled': inProgress || undefined,\n 'aria-pressed': ariaPressed,\n onClick: async (e: React.MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation();\n if (inProgressRef.current) return; // busy: ignore re-activation while in flight\n inProgressRef.current = true;\n try {\n setInProgress(true);\n await toggle();\n } finally {\n inProgressRef.current = false;\n setInProgress(false);\n }\n },\n title,\n } satisfies ComponentPropsWithoutRef<'button'>;\n};\n\n// Dropdown menu item. Standard menu behavior: activating closes the menu (which returns focus to the\n// toggle) and runs the action in the background, reporting via its notification — so the item needs\n// no busy/disabled state, it unmounts with the menu.\n//\n// The action is deferred to after the close commits, on the next animation frame. The open menu is an\n// aria-modal dialog with its OWN `AriaLiveOutlet` (the inert root outlet is ignored by assistive tech\n// while it is open); running the action synchronously can route its notification into that outlet\n// just as it is torn down — so the notification is never spoken. Deferring lets the menu (and its\n// outlet) unmount and focus return to the toggle first, so the notification lands in the root outlet,\n// in a calm window after the focus re-read.\nconst useDropdownActionButtonProps = ({\n 'aria-pressed': ariaPressed,\n title,\n toggle,\n}: ChannelActionBehavior) => {\n const { closeMenu } = useContextMenuContext();\n\n return {\n 'aria-pressed': ariaPressed,\n onClick: (e: React.MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation();\n closeMenu();\n requestAnimationFrame(() => void toggle());\n },\n title,\n } satisfies ComponentPropsWithoutRef<'button'>;\n};\n\n// Core block/unblock action for the other member of a DM.\nconst useBanAction = (): ChannelActionBehavior => {\n const { client } = useChatContext();\n const { addNotification } = useNotificationApi();\n const { t } = useTranslationContext();\n const { channel } = useChannelListItemContext();\n const members = useChannelMembersState(channel);\n const isUserBanned = Object.values(members || {}).some(\n (member) => member.user?.id !== client.userID && member.banned,\n );\n\n const toggle = async () => {\n try {\n const otherUserId = Object.keys(channel.state.members).find(\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n (userId) => userId !== client.userID!,\n );\n if (!otherUserId) return;\n if (isUserBanned) {\n await channel.unbanUser(otherUserId);\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n message: t('User unblocked'),\n severity: 'success',\n type: 'api:user:unban:success',\n });\n } else {\n await channel.banUser(otherUserId, {});\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n message: t('User blocked'),\n severity: 'success',\n type: 'api:user:ban:success',\n });\n }\n } catch (error) {\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n error: error instanceof Error ? error : new Error('An unknown error occurred'),\n message: t('Failed to block user'),\n severity: 'error',\n type: 'api:user:ban:failed',\n });\n }\n };\n\n return {\n 'aria-pressed': isUserBanned,\n title: isUserBanned ? t('Unblock User') : t('Block User'),\n toggle,\n };\n};\n\n// Core leave-channel action (one-shot — not a toggle).\nconst useLeaveAction = (): ChannelActionBehavior => {\n const { t } = useTranslationContext();\n const { channel } = useChannelListItemContext();\n const { client } = useChatContext();\n const { addNotification } = useNotificationApi();\n\n const toggle = async () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n await channel.removeMembers([client.userID!]);\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n message: t('Left channel'),\n severity: 'success',\n type: 'api:channel:leave:success',\n });\n } catch (error) {\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n error: error instanceof Error ? error : new Error('An unknown error occurred'),\n message: t('Failed to leave channel'),\n severity: 'error',\n type: 'api:channel:leave:failed',\n });\n }\n };\n\n return { title: t('Leave Channel'), toggle };\n};\n\n// Core pin/unpin action.\nconst usePinAction = (): ChannelActionBehavior => {\n const { t } = useTranslationContext();\n const { addNotification } = useNotificationApi();\n const { channel } = useChannelListItemContext();\n const membership = useChannelMembershipState(channel);\n\n const toggle = async () => {\n try {\n if (membership.pinned_at) {\n await channel.unpin();\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n message: t('Channel unpinned'),\n severity: 'success',\n type: 'api:channel:unpin:success',\n });\n } else {\n await channel.pin();\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n message: t('Channel pinned'),\n severity: 'success',\n type: 'api:channel:pin:success',\n });\n }\n } catch (error) {\n addNotification({\n context: { channel },\n emitter: ChannelListItemActionButtons.name,\n error: error instanceof Error ? error : new Error('An unknown error occurred'),\n message: t('Failed to update channel pinned status'),\n severity: 'error',\n type: 'api:channel:pin:failed',\n });\n }\n };\n\n return {\n 'aria-pressed': !!membership.pinned_at,\n title: membership.pinned_at ? t('Unpin') : t('Pin'),\n toggle,\n };\n};\n\ntype ChannelActionItem =\n | (({ placement: 'quick' } | { placement: 'dropdown' }) & {\n type: string;\n Component: React.ComponentType;\n })\n | {\n placement: 'quick-dropdown-toggle';\n Component: React.ComponentType<ComponentPropsWithRef<'button'>>;\n };\n\nconst defaultComponents = {\n dropdown: {\n Archive() {\n const behaviorProps = useDropdownActionButtonProps(useArchiveAction());\n const { IconArchive } = useComponentContextIcons();\n\n return (\n <ContextMenuButton\n aria-label={behaviorProps.title}\n data-testid='dropdown-action-archive'\n Icon={IconArchive}\n {...behaviorProps}\n >\n {behaviorProps.title}\n </ContextMenuButton>\n );\n },\n Ban() {\n const behaviorProps = useDropdownActionButtonProps(useBanAction());\n const { IconNoSign } = useComponentContextIcons();\n\n return (\n <ContextMenuButton\n aria-label={behaviorProps.title}\n data-testid='dropdown-action-ban'\n Icon={IconNoSign}\n {...behaviorProps}\n >\n {behaviorProps.title}\n </ContextMenuButton>\n );\n },\n Leave() {\n const behaviorProps = useDropdownActionButtonProps(useLeaveAction());\n const { IconLeave } = useComponentContextIcons();\n\n return (\n <ContextMenuButton\n aria-label={behaviorProps.title}\n data-testid='dropdown-action-leave'\n Icon={IconLeave}\n variant='destructive'\n {...behaviorProps}\n >\n {behaviorProps.title}\n </ContextMenuButton>\n );\n },\n Mute() {\n const behaviorProps = useDropdownActionButtonProps(useMuteAction());\n const { IconMute } = useComponentContextIcons();\n\n return (\n <ContextMenuButton\n aria-label={behaviorProps.title}\n data-testid='dropdown-action-mute'\n Icon={IconMute}\n {...behaviorProps}\n >\n {behaviorProps.title}\n </ContextMenuButton>\n );\n },\n Pin() {\n const behaviorProps = useDropdownActionButtonProps(usePinAction());\n const { IconPin } = useComponentContextIcons();\n\n return (\n <ContextMenuButton\n aria-label={behaviorProps.title}\n data-testid='dropdown-action-pin'\n Icon={IconPin}\n {...behaviorProps}\n >\n {behaviorProps.title}\n </ContextMenuButton>\n );\n },\n },\n quick: {\n Archive() {\n const behaviorProps = useQuickActionButtonProps(useArchiveAction());\n const { IconArchive } = useComponentContextIcons();\n\n return (\n <Button\n appearance='ghost'\n aria-label={behaviorProps.title}\n circular\n data-testid='quick-action-archive'\n size='sm'\n variant='secondary'\n {...behaviorProps}\n >\n <IconArchive />\n </Button>\n );\n },\n Mute() {\n const behaviorProps = useQuickActionButtonProps(useMuteAction());\n const { IconMute } = useComponentContextIcons();\n\n return (\n <Button\n appearance='ghost'\n aria-label={behaviorProps.title}\n circular\n data-testid='quick-action-mute'\n size='sm'\n variant='secondary'\n {...behaviorProps}\n >\n <IconMute />\n </Button>\n );\n },\n },\n QuickDropdownToggle: forwardRef<HTMLButtonElement>((_, ref) => {\n const { channel } = useChannelListItemContext();\n const { t } = useTranslationContext();\n const { IconMore } = useComponentContextIcons();\n\n const dialogId = ChannelListItemActionButtons.getDialogId({\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n channelId: channel.id!,\n });\n const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });\n const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n return (\n <Button\n appearance='ghost'\n aria-expanded={dialogIsOpen}\n aria-label={t('aria/Open Channel Actions Menu')}\n aria-pressed={dialogIsOpen}\n circular\n data-testid='channel-list-item-dropdown-toggle'\n onClick={(e) => {\n e.stopPropagation();\n\n dialog.toggle();\n }}\n ref={ref}\n size='sm'\n variant='secondary'\n >\n <IconMore />\n </Button>\n );\n }),\n};\n\ndefaultComponents.QuickDropdownToggle.displayName = 'QuickDropdownToggle';\n\nexport const defaultChannelActionSet: ChannelActionItem[] = [\n {\n Component: defaultComponents.QuickDropdownToggle,\n placement: 'quick-dropdown-toggle',\n },\n {\n Component: defaultComponents.quick.Mute,\n placement: 'quick',\n type: 'mute',\n },\n {\n Component: defaultComponents.dropdown.Archive,\n placement: 'dropdown',\n type: 'archive',\n },\n {\n Component: defaultComponents.dropdown.Ban,\n placement: 'dropdown',\n type: 'ban',\n },\n {\n Component: defaultComponents.dropdown.Pin,\n placement: 'dropdown',\n type: 'pin',\n },\n {\n Component: defaultComponents.dropdown.Leave,\n placement: 'dropdown',\n type: 'leave',\n },\n];\n\nexport const useBaseChannelActionSetFilter = (channelActionSet: ChannelActionItem[]) => {\n const { channel } = useChannelListItemContext();\n const membership = useChannelMembershipState(channel);\n const memberCount = channel.data?.member_count ?? 0;\n const connectedUserIsMember = typeof membership.user !== 'undefined';\n const isDirectMessageChannel = connectedUserIsMember && memberCount === 2;\n\n const ownCapabilities = channel.data?.own_capabilities;\n\n return useMemo(() => {\n const filtered = channelActionSet.filter((action) => {\n if (action.placement === 'quick-dropdown-toggle') return true;\n\n switch (action.type) {\n case 'archive':\n return connectedUserIsMember;\n case 'mute':\n return ownCapabilities?.includes('mute-channel');\n case 'ban':\n return (\n isDirectMessageChannel && ownCapabilities?.includes('ban-channel-members')\n );\n case 'leave':\n return ownCapabilities?.includes('leave-channel');\n case 'pin':\n return connectedUserIsMember;\n default:\n return true;\n }\n });\n\n return filtered;\n }, [channelActionSet, connectedUserIsMember, ownCapabilities, isDirectMessageChannel]);\n};\n","import React, { type ComponentProps, type ComponentType, type ReactNode } from 'react';\n\nimport clsx from 'clsx';\nimport { ContextMenu, useDialogIsOpen, useDialogOnNearestManager } from '../Dialog';\nimport { useComponentContext, useTranslationContext } from '../../context';\nimport {\n defaultChannelActionSet,\n useBaseChannelActionSetFilter,\n} from './ChannelListItemActionButtons.defaults';\nimport { useSplitActionSet } from '../Chat/hooks/useSplitActionSet';\nimport { useChannelListItemContext } from './ChannelListItem';\n\nexport type ChannelListItemActionButtonsProps = ComponentProps<ComponentType>; // hack to allow empty props\n\ninterface ChannelListItemActionButtonsInterface {\n (props: ChannelListItemActionButtonsProps): ReactNode;\n getDialogId: (_: { channelId: string }) => string;\n displayName: string;\n}\n\nexport const ChannelListItemActionButtons: ChannelListItemActionButtonsInterface = () => {\n const { ContextMenu: ContextMenuComponent = ContextMenu } = useComponentContext();\n const { t } = useTranslationContext();\n const { channel } = useChannelListItemContext();\n const [referenceElement, setReferenceElement] =\n React.useState<HTMLButtonElement | null>(null);\n const [isRestoringFocus, setIsRestoringFocus] = React.useState(false);\n const dialogId = ChannelListItemActionButtons.getDialogId({\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n channelId: channel.id!,\n });\n const { dialog, dialogManager } = useDialogOnNearestManager({ id: dialogId });\n const dialogIsOpen = useDialogIsOpen(dialogId, dialogManager?.id);\n\n const closeContextMenu = React.useCallback(() => {\n setIsRestoringFocus(true);\n dialog?.close();\n\n requestAnimationFrame(() => {\n if (!referenceElement?.isConnected) {\n setIsRestoringFocus(false);\n return;\n }\n\n referenceElement.focus();\n\n requestAnimationFrame(() => {\n if (document.activeElement !== referenceElement) {\n setIsRestoringFocus(false);\n }\n });\n });\n }, [dialog, referenceElement]);\n\n const filteredActionSet = useBaseChannelActionSetFilter(defaultChannelActionSet);\n const { dropdownActionSet, quickActionSet, quickDropdownToggleAction } =\n useSplitActionSet(filteredActionSet);\n\n if (quickActionSet.length + dropdownActionSet.length === 0) {\n // no buttons to render, omit rendering wrapper\n return null;\n }\n\n return (\n <div\n className={clsx('str-chat__channel-list-item__action-buttons', {\n 'str-chat__channel-list-item__action-buttons--active':\n dialogIsOpen || isRestoringFocus,\n })}\n data-testid='channel-list-item-action-buttons'\n onFocusCapture={() => {\n setIsRestoringFocus(false);\n }}\n >\n {quickDropdownToggleAction && dropdownActionSet.length > 0 && (\n <quickDropdownToggleAction.Component ref={setReferenceElement} />\n )}\n {quickActionSet.map(({ Component, type }) => (\n <Component key={type} />\n ))}\n <ContextMenuComponent\n aria-label={t('aria/Channel Actions')}\n className='str-chat__channel-list-item__action-buttons-context-menu'\n data-testid='channel-list-item-context-menu'\n dialogManagerId={dialogManager?.id}\n id={dialog.id}\n onClose={closeContextMenu}\n placement='bottom-start'\n referenceElement={referenceElement}\n tabIndex={-1}\n trapFocus\n >\n {dropdownActionSet.map(({ Component, type }) => (\n <Component key={type} />\n ))}\n </ContextMenuComponent>\n </div>\n );\n};\n\nChannelListItemActionButtons.getDialogId = ({ channelId }) =>\n `channel-action-buttons-${channelId}`;\n\nChannelListItemActionButtons.displayName = 'ChannelListItemActionButtons';\n","import React, { useMemo } from 'react';\nimport type { LocalMessage } from 'stream-chat';\n\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { getDateString, isDate } from '../../i18n/utils';\n\nexport type ChannelListItemTimestampProps = {\n /** The last message in the channel, used to extract the timestamp */\n lastMessage?: LocalMessage;\n};\n\nexport function ChannelListItemTimestamp({ lastMessage }: ChannelListItemTimestampProps) {\n const { t, tDateTimeParser } = useTranslationContext('ChannelListItemTimestamp');\n\n const timestamp = lastMessage?.created_at;\n const normalizedTimestamp =\n timestamp && isDate(timestamp) ? timestamp.toISOString() : undefined;\n\n const when = useMemo(\n () =>\n getDateString({\n messageCreatedAt: normalizedTimestamp,\n t,\n tDateTimeParser,\n timestampTranslationKey: 'timestamp/ChannelPreviewTimestamp',\n }),\n [normalizedTimestamp, t, tDateTimeParser],\n );\n\n if (!when) return null;\n\n return (\n <time\n className='str-chat__channel-list-item-timestamp'\n dateTime={normalizedTimestamp}\n >\n {when}\n </time>\n );\n}\n","import type { TranslationContextValue } from '../context/TranslationContext';\n\n/** Produces one segment of a composed accessible name; return `undefined`/empty to omit it. */\nexport type AccessibleLabelPart<TData> = (data: TData) => string | undefined;\n\n/** Customization for a part-composed accessible name (the channel/thread list-row labels). */\nexport type AccessibleLabelConfig<TData> = {\n /** Full override — return the entire label; ignores `order`/`parts`/`separator`. */\n build?: (data: TData) => string;\n /** Which parts to include, in what order. A part not listed here is never rendered. */\n order?: ReadonlyArray<string>;\n /** Override or add individual part generators; merged over the defaults. */\n parts?: Record<string, AccessibleLabelPart<TData>>;\n /** Joiner between non-empty parts. Defaults to \". \". */\n separator?: string;\n};\n\n/**\n * Composes a single accessible name from named parts: applies `config.build` if present, otherwise\n * merges `config.parts` over `defaultParts`, walks `config.order ?? defaultOrder`, and joins the\n * non-empty segments with `config.separator ?? '. '`. Shared by the channel and thread list-row\n * labels so the assembly logic lives in one place.\n */\nexport const composeAccessibleLabel = <TData>(\n data: TData,\n defaultParts: Record<string, AccessibleLabelPart<TData>>,\n defaultOrder: ReadonlyArray<string>,\n config: AccessibleLabelConfig<TData> = {},\n): string => {\n if (config.build) return config.build(data);\n const parts: Record<string, AccessibleLabelPart<TData>> = {\n ...defaultParts,\n ...config.parts,\n };\n const order = config.order ?? defaultOrder;\n return order\n .map((key) => parts[key]?.(data))\n .filter((value): value is string => !!value)\n .join(config.separator ?? '. ');\n};\n\n// Parts shared verbatim across list-row labels. Typed over the minimal data each needs; function\n// parameter contravariance makes them assignable to the wider channel/thread part types.\ntype WithT = { t: TranslationContextValue['t'] };\n\n/**\n * Announces the active (currently open) row. The active state is announced here (not left to the\n * row's `aria-selected` alone, which is not reliably spoken across screen readers for an option with\n * a custom name); `aria-selected` is kept on the active row for listbox semantics.\n */\nexport const activeLabelPart: AccessibleLabelPart<WithT & { active?: boolean }> = ({\n active,\n t,\n}) => (active ? t('aria/Active') : undefined);\n\n/** Announces the unread count when there is one. */\nexport const unreadCountLabelPart: AccessibleLabelPart<\n WithT & { unreadCount?: number }\n> = ({ t, unreadCount }) =>\n typeof unreadCount === 'number' && unreadCount > 0\n ? t('aria/{{ count }} unread message', { count: unreadCount })\n : undefined;\n","import { useCallback, useEffect, useState } from 'react';\nimport type { Channel, Event, LocalMessage, UserResponse } from 'stream-chat';\n\nimport { useChatContext } from '../../../context';\n\nexport enum MessageDeliveryStatus {\n SENT = 'sent',\n DELIVERED = 'delivered',\n READ = 'read',\n}\n\ntype UseMessageStatusParamsChannelPreviewProps = {\n channel: Channel;\n /** The last message received in a channel */\n lastMessage?: LocalMessage;\n};\n\nexport const useMessageDeliveryStatus = ({\n channel,\n lastMessage,\n}: UseMessageStatusParamsChannelPreviewProps) => {\n const { client } = useChatContext();\n const [messageDeliveryStatus, setMessageDeliveryStatus] = useState<\n MessageDeliveryStatus | undefined\n >();\n\n const isOwnMessage = useCallback(\n (message?: { user?: UserResponse | null }) =>\n client.user && message && message.user?.id === client.user.id,\n [client],\n );\n\n useEffect(() => {\n // empty channel\n if (!lastMessage) {\n setMessageDeliveryStatus(undefined);\n }\n\n const lastMessageIsOwn = isOwnMessage(lastMessage);\n if (!lastMessage?.created_at || !lastMessageIsOwn) return;\n\n const msgRef = {\n msgId: lastMessage.id,\n timestampMs: lastMessage.created_at.getTime(),\n };\n const readersForMessage = channel.messageReceiptsTracker.readersForMessage(msgRef);\n const deliveredForMessage =\n channel.messageReceiptsTracker.deliveredForMessage(msgRef);\n setMessageDeliveryStatus(\n readersForMessage.length > 1 ||\n (readersForMessage.length === 1 && readersForMessage[0].id !== client.user?.id)\n ? MessageDeliveryStatus.READ\n : deliveredForMessage.length > 1 ||\n (deliveredForMessage.length === 1 &&\n deliveredForMessage[0].id !== client.user?.id)\n ? MessageDeliveryStatus.DELIVERED\n : MessageDeliveryStatus.SENT,\n );\n }, [channel, client, isOwnMessage, lastMessage]);\n\n useEffect(() => {\n const handleMessageNew = (event: Event) => {\n // the last message is not mine, so do not show the delivery status\n if (!isOwnMessage(event.message)) {\n return setMessageDeliveryStatus(undefined);\n }\n return setMessageDeliveryStatus(MessageDeliveryStatus.SENT);\n };\n\n channel.on('message.new', handleMessageNew);\n\n return () => {\n channel.off('message.new', handleMessageNew);\n };\n }, [channel, isOwnMessage]);\n\n useEffect(() => {\n if (!isOwnMessage(lastMessage)) return;\n const handleMessageDelivered = (event: Event) => {\n if (\n event.user?.id !== client.user?.id &&\n lastMessage &&\n lastMessage.id === event.last_delivered_message_id\n )\n setMessageDeliveryStatus(MessageDeliveryStatus.DELIVERED);\n };\n\n const handleMarkRead = (event: Event) => {\n if (event.user?.id !== client.user?.id)\n setMessageDeliveryStatus(MessageDeliveryStatus.READ);\n };\n\n channel.on('message.delivered', handleMessageDelivered);\n channel.on('message.read', handleMarkRead);\n channel.on('message.read_locally', handleMarkRead);\n\n return () => {\n channel.off('message.delivered', handleMessageDelivered);\n channel.off('message.read', handleMarkRead);\n channel.off('message.read_locally', handleMarkRead);\n };\n }, [channel, client, isOwnMessage, lastMessage]);\n\n return {\n messageDeliveryStatus,\n };\n};\n","import type { Channel, LocalMessage, StreamChat } from 'stream-chat';\n\nimport type { ChatContextValue } from '../../context';\nimport type { TranslationContextValue } from '../../context/TranslationContext';\nimport {\n type AccessibleLabelConfig,\n type AccessibleLabelPart,\n activeLabelPart,\n composeAccessibleLabel,\n unreadCountLabelPart,\n} from '../../a11y/accessibleLabel';\nimport { getDateString, isDate } from '../../i18n/utils';\nimport { MessageDeliveryStatus } from './hooks/useMessageDeliveryStatus';\nimport { getLatestMessagePreviewText } from './utils';\n\n/**\n * Everything a label part needs. Gathered by `ChannelListItemUI` from its props + contexts and\n * handed to each {@link ChannelListItemLabelPart}.\n */\nexport type ChannelListItemLabelData = {\n /** Whether the row is the active (currently open) channel. */\n active?: boolean;\n /** The channel whose latest message is summarized. */\n channel: Channel;\n /** Client, used to detect whether the latest message is the current user's own. */\n client: StreamChat;\n /** Channel display name. */\n displayTitle?: string;\n isMessageAIGenerated?: ChatContextValue['isMessageAIGenerated'];\n /**\n * The channel's latest message. {@link composeChannelListItemAccessibleLabel} resolves this once\n * (to the last entry of `channel.state.latestMessages` when omitted) and passes the SAME message\n * to every part, so all segments (sender, preview, attachments, time) describe one message.\n */\n latestMessage?: LocalMessage;\n /** Delivery/read status of the latest message when it is the current user's own. */\n messageDeliveryStatus?: MessageDeliveryStatus;\n t: TranslationContextValue['t'];\n tDateTimeParser: TranslationContextValue['tDateTimeParser'];\n /** Unread count for the channel. */\n unreadCount?: number;\n userLanguage?: TranslationContextValue['userLanguage'];\n};\n\n/** Produces one segment of the accessible name; return `undefined`/empty to omit it. */\nexport type ChannelListItemLabelPart = AccessibleLabelPart<ChannelListItemLabelData>;\n\n/**\n * The default, named label parts. Each is independently overridable via\n * {@link ChannelListItemLabelConfig.parts}. The active (currently open) state is announced here (not\n * left to the row's `aria-selected` alone, which is not reliably spoken across screen readers for an\n * option with a custom name); `aria-selected` is kept on the active row for listbox semantics.\n */\nexport const defaultChannelListItemLabelParts = {\n active: activeLabelPart,\n // Announced alongside the last message text: the number of attachments. Link previews are\n // excluded (the linkPreview part announces those). A single attachment with no text is skipped\n // here because the lastMessage part already conveys it as \"Attachment <type>\".\n attachments: ({ latestMessage, t }) => {\n const count =\n latestMessage?.attachments?.filter((attachment) => !attachment.og_scrape_url)\n .length ?? 0;\n if (count === 0 || (count === 1 && !latestMessage?.text)) return undefined;\n return t('aria/{{ count }} attachment', { count });\n },\n deliveryStatus: ({ messageDeliveryStatus, t }) => {\n if (!messageDeliveryStatus) return undefined;\n const statusLabelByStatus: Record<MessageDeliveryStatus, string> = {\n [MessageDeliveryStatus.SENT]: t('aria/Sent'),\n [MessageDeliveryStatus.DELIVERED]: t('aria/Delivered'),\n [MessageDeliveryStatus.READ]: t('aria/Read'),\n };\n return t('aria/Delivery status: {{ deliveryStatus }}', {\n deliveryStatus: statusLabelByStatus[messageDeliveryStatus],\n });\n },\n lastMessage: ({\n channel,\n client,\n isMessageAIGenerated,\n latestMessage,\n t,\n userLanguage,\n }) => {\n const preview = getLatestMessagePreviewText(\n channel,\n t,\n userLanguage,\n isMessageAIGenerated,\n // `latestMessage` is pre-resolved by the composer, so the announced preview describes the same\n // message as the sender/status/time segments.\n latestMessage,\n );\n // Empty channel: announce there are no messages (\"Nothing yet...\").\n if (!latestMessage) return preview;\n const isOwn = !!client.userID && latestMessage.user?.id === client.userID;\n // Use the sender's name (or \"You\" for the current user). When the name is unknown we omit the\n // sender rather than reading out a raw user id.\n const sender = isOwn ? t('You') : latestMessage.user?.name;\n return sender\n ? t('aria/Last message from {{ sender }}: {{ messagePreview }}', {\n messagePreview: preview,\n sender,\n })\n : t('aria/Last message: {{ messagePreview }}', { messagePreview: preview });\n },\n linkPreview: ({ latestMessage, t }) => {\n const link = latestMessage?.attachments?.find(\n (attachment) => attachment.og_scrape_url,\n );\n if (!link) return undefined;\n return link.title\n ? t('aria/Shared a link with title: {{ linkTitle }}', { linkTitle: link.title })\n : t('aria/Shared a link');\n },\n name: ({ displayTitle }) => displayTitle || undefined,\n time: ({ latestMessage, t, tDateTimeParser }) => {\n const createdAt = latestMessage?.created_at;\n if (!createdAt || !isDate(createdAt)) return undefined;\n const when = getDateString({\n messageCreatedAt: createdAt.toISOString(),\n t,\n tDateTimeParser,\n timestampTranslationKey: 'timestamp/ChannelPreviewTimestamp',\n });\n // Prefix the time so it is clearly its own segment (not read as part of the preceding\n // delivery-status segment).\n return when ? t('aria/Last activity: {{ time }}', { time: String(when) }) : undefined;\n },\n unreadCount: unreadCountLabelPart,\n} satisfies Record<string, ChannelListItemLabelPart>;\n\n/** Default order the parts are assembled in (reading order). */\nexport const DEFAULT_CHANNEL_LIST_ITEM_LABEL_ORDER = [\n 'name',\n 'active',\n 'unreadCount',\n 'lastMessage',\n 'attachments',\n 'linkPreview',\n 'deliveryStatus',\n 'time',\n] as const;\n\nexport type ChannelListItemLabelConfig = AccessibleLabelConfig<ChannelListItemLabelData>;\n\n/**\n * Composes a single, coherent accessible name for a channel list row from named parts. The default\n * reading order is name → unread → last message (sender + preview) → delivery status → time.\n *\n * ## Customizing the label\n *\n * The label is generated by `ChannelListItemUI`, which accepts an `accessibleLabelConfig` prop. To\n * customize it, supply your own `ChannelListItemUI` through `ComponentContext` (the same way the\n * component is overridden) and forward the config — no new plumbing:\n *\n * ```tsx\n * const MyChannelPreview = (props) => (\n * <DefaultChannelListItemUI {...props} accessibleLabelConfig={accessibleLabelConfig} />\n * );\n * // <ComponentProvider value={{ ChannelListItemUI: MyChannelPreview }}> … </ComponentProvider>\n * ```\n *\n * ### Adding custom parts (e.g. Pinned, Muted, Frozen)\n *\n * - {@link ChannelListItemLabelConfig.parts} is merged over {@link defaultChannelListItemLabelParts},\n * so a new key is *added* and a same-named key *overrides* the default.\n * - A part returns its segment string, or `undefined`/`''` to be omitted (so e.g. \"Pinned\" is only\n * spoken when actually pinned).\n * - {@link ChannelListItemLabelConfig.order} decides which parts are included AND their sequence —\n * **a part not listed in `order` is never rendered**, even if defined. Spread\n * {@link DEFAULT_CHANNEL_LIST_ITEM_LABEL_ORDER} to keep the defaults and insert your own.\n * - Each part receives {@link ChannelListItemLabelData}. `active`/`unreadCount`/\n * `messageDeliveryStatus` are passed directly and `latestMessage` is pre-resolved by the composer\n * (see its doc); everything else (mute/pin state, `frozen`, member count, custom `channel.data`) is\n * read off `channel`. Parts call `t`, so provide your own i18n keys (or return plain strings) —\n * the SDK does not ship `Pinned`/`Muted`/`Frozen` strings.\n *\n * ```tsx\n * const accessibleLabelConfig: ChannelListItemLabelConfig = {\n * parts: {\n * pinned: ({ channel, t }) => (channel.state.membership?.pinned_at ? t('Pinned') : undefined),\n * muted: ({ channel, t }) => (channel.muteStatus().muted ? t('Muted') : undefined),\n * frozen: ({ channel, t }) => (channel.data?.frozen ? t('Frozen') : undefined),\n * },\n * order: ['name', 'pinned', 'muted', 'frozen', ...DEFAULT_CHANNEL_LIST_ITEM_LABEL_ORDER.slice(1)],\n * };\n * // → \"General. Pinned. Muted. 3 unread messages. Last message from Alice: hi. 2 days ago\"\n * ```\n *\n * For full control, set {@link ChannelListItemLabelConfig.build} (return the entire string), or\n * write a custom `ChannelListItemUI` that calls this function directly — importing\n * {@link defaultChannelListItemLabelParts} to reuse the built-ins.\n */\nexport const composeChannelListItemAccessibleLabel = (\n data: ChannelListItemLabelData,\n config: ChannelListItemLabelConfig = {},\n): string =>\n composeAccessibleLabel(\n // Resolve the latest message ONCE here so every part is handed the same message (sender,\n // preview, attachments, link, time all stay in sync) instead of each re-deriving the channel's\n // latest — which only stayed consistent as long as the duplicated fallbacks matched.\n {\n ...data,\n latestMessage:\n data.latestMessage ??\n data.channel.state.latestMessages[data.channel.state.latestMessages.length - 1],\n },\n defaultChannelListItemLabelParts,\n DEFAULT_CHANNEL_LIST_ITEM_LABEL_ORDER,\n config,\n );\n","import { useMemo } from 'react';\nimport type { Attachment, LocalMessage } from 'stream-chat';\nimport {\n isAudioAttachment,\n isFileAttachment,\n isImageAttachment,\n isScrapedContent,\n isVideoAttachment,\n isVoiceRecordingAttachment,\n} from 'stream-chat';\n\nimport {\n getTranslatedMessageText,\n type TranslationContextValue,\n useChatContext,\n useTranslationContext,\n} from '../../../context';\nimport { isMessageDeleted } from '../../Message/utils';\n\nimport type { MessageDeliveryStatus } from '../../ChannelListItem';\n\nexport type ChannelPreviewMessageType =\n | 'text'\n | 'deleted'\n | 'error'\n | 'empty'\n | 'image'\n | 'giphy'\n | 'video'\n | 'voice'\n | 'file'\n | 'unsupported'\n | 'link'\n | 'location'\n | 'poll';\n\nconst SUPPORTED_VIDEO_FORMATS: string[] = [\n 'video/mp4',\n 'video/ogg',\n 'video/webm',\n 'video/quicktime',\n];\n\n/**\n * Delivery status of the last own message.\n * Determines which delivery status icon to render in the preview.\n *\n * - `sending` — Clock icon\n * - `sent` — Single checkmark icon\n * - `delivered` — Double checkmark icon\n * - `read` — Double checkmark icon (with distinct color)\n */\nexport type ChannelPreviewDeliveryStatus = 'sending' | 'sent' | 'delivered' | 'read';\n\nexport type LatestMessagePreviewData = {\n /**\n * The type of content being previewed.\n * Use this to render the appropriate content-type icon.\n */\n type: ChannelPreviewMessageType;\n /**\n * The preview text to display.\n */\n text: string;\n /**\n * Delivery status of own message.\n * Only present for own messages that are not in error state.\n * Use this to render the delivery status icon (clock, checkmark, double checkmark).\n */\n deliveryStatus?: ChannelPreviewDeliveryStatus;\n /**\n * Sender name prefix.\n * - `\"You\"` (translated) for own messages\n * - Sender's display name for incoming messages in group channels (>2 members)\n * - `undefined` for incoming messages in direct conversations\n */\n senderName?: string;\n};\n\nfunction getAttachmentContentType(attachment: Attachment): ChannelPreviewMessageType {\n if (!attachment) return 'text';\n\n if (attachment.type === 'giphy') return 'giphy';\n if (isScrapedContent(attachment)) return 'link';\n if (isImageAttachment(attachment)) return 'image';\n if (isVideoAttachment(attachment, SUPPORTED_VIDEO_FORMATS)) return 'video';\n if (isVoiceRecordingAttachment(attachment)) return 'voice';\n if (\n isAudioAttachment(attachment) ||\n isFileAttachment(attachment, SUPPORTED_VIDEO_FORMATS)\n ) {\n return 'file';\n }\n\n return 'unsupported';\n}\n\nfunction getAttachmentFallbackText(\n type: ChannelPreviewMessageType,\n count: number,\n t: TranslationContextValue['t'],\n): string {\n switch (type) {\n case 'image':\n return t('imageCount', { count });\n case 'video':\n return t('videoCount', { count });\n case 'voice':\n return t('voiceMessageCount', { count });\n case 'link':\n return t('linkCount', { count });\n case 'file':\n return t('fileCount', { count });\n case 'unsupported':\n return t('Unsupported attachment');\n default:\n return t('fileCount', { count });\n }\n}\n\nexport type UseLatestMessagePreviewParams = {\n /** The channel to generate preview for */\n participantCount?: number;\n /** The latest message in the channel */\n latestMessage?: LocalMessage;\n /**\n * Delivery status from the `useMessageDeliveryStatus` hook.\n * When provided, used to determine the delivery status icon.\n * When omitted, delivery status icons are not shown.\n */\n messageDeliveryStatus?: MessageDeliveryStatus;\n};\n\nexport const useLatestMessagePreview = ({\n latestMessage,\n messageDeliveryStatus,\n participantCount,\n}: UseLatestMessagePreviewParams): LatestMessagePreviewData => {\n const { client } = useChatContext('useLatestMessagePreview');\n const { t, userLanguage } = useTranslationContext('useLatestMessagePreview');\n\n return useMemo(() => {\n if (!latestMessage) {\n return { text: t('Nothing yet...'), type: 'empty' as const };\n }\n\n if (latestMessage.status === 'failed' || latestMessage.type === 'error') {\n return { text: t('Message failed to send'), type: 'error' as const };\n }\n\n const isOwnMessage = latestMessage.user?.id === client.user?.id;\n\n let deliveryStatus: ChannelPreviewDeliveryStatus | undefined;\n if (isOwnMessage) {\n deliveryStatus = messageDeliveryStatus ?? (latestMessage.status as 'sending');\n }\n\n let senderName: string | undefined;\n if (isOwnMessage) {\n senderName = t('You');\n } else if (!isOwnMessage && participantCount !== undefined && participantCount > 2) {\n senderName = latestMessage.user?.name || latestMessage.user?.id;\n }\n\n if (isMessageDeleted(latestMessage)) {\n return {\n deliveryStatus,\n senderName,\n text: t('Message deleted'),\n type: 'deleted' as const,\n };\n }\n\n if (latestMessage.poll) {\n return {\n deliveryStatus,\n senderName,\n text: t('Poll'),\n type: 'poll' as const,\n };\n }\n\n const textContent =\n getTranslatedMessageText({ language: userLanguage, message: latestMessage }) ||\n latestMessage.text;\n\n if (latestMessage.shared_location) {\n return {\n deliveryStatus,\n senderName,\n text: textContent || t('Location'),\n type: 'location' as const,\n };\n }\n\n if (latestMessage.attachments && latestMessage.attachments.length) {\n const attachments = latestMessage.attachments;\n\n let contentType: ChannelPreviewMessageType;\n\n const [firstAttachment] = attachments;\n const firstAttachmentType = getAttachmentContentType(firstAttachment);\n\n if (\n attachments.every(\n (attachment) => getAttachmentContentType(attachment) === firstAttachmentType,\n )\n ) {\n contentType = firstAttachmentType;\n } else {\n contentType = 'file';\n }\n\n let text =\n contentType === 'giphy'\n ? `GIPHY ${firstAttachment.title ?? ''}`.trim()\n : // prioritize message text content if available\n textContent ||\n // then fallback text of the single attachment if only one attachment is present and it's not a voice recording (fallback text is generic for voice recordings, so not useful in the preview)\n (attachments.length === 1 &&\n contentType !== 'voice' &&\n contentType !== 'unsupported'\n ? firstAttachment.fallback || firstAttachment.title\n : '') ||\n // then generic fallback text based on attachment type and count\n getAttachmentFallbackText(contentType, attachments.length, t);\n\n // attach duration for audio/video attachments if available\n if (attachments.length === 1 && typeof firstAttachment.duration === 'number') {\n const minutes = Math.floor(firstAttachment.duration / 60);\n const seconds = Math.ceil(firstAttachment.duration) % 60;\n const durationString = `${minutes}:${seconds.toString().padStart(2, '0')}`;\n text += ` (${durationString})`;\n }\n\n return {\n deliveryStatus,\n senderName,\n text,\n type: contentType,\n };\n }\n\n if (textContent) {\n return {\n deliveryStatus,\n senderName,\n text: textContent,\n type: 'text' as const,\n };\n }\n\n return { text: t('Empty message...'), type: 'empty' as const };\n }, [\n client.user?.id,\n latestMessage,\n messageDeliveryStatus,\n participantCount,\n t,\n userLanguage,\n ]);\n};\n","import React from 'react';\nimport clsx from 'clsx';\nimport {\n type ChannelPreviewDeliveryStatus,\n type ChannelPreviewMessageType,\n useLatestMessagePreview,\n type UseLatestMessagePreviewParams,\n} from './hooks/useLatestMessagePreview';\nimport { useComponentContextIcons } from '../../context';\n\nexport const SummarizedMessagePreview = ({\n latestMessage,\n messageDeliveryStatus,\n participantCount,\n}: UseLatestMessagePreviewParams) => {\n const {\n IconCamera,\n IconCheckmark1Small,\n IconChecks,\n IconClock,\n IconExclamationCircleFill,\n IconFile,\n IconGiphy,\n IconLink,\n IconLocation,\n IconNoSign,\n IconUnsupportedAttachment,\n IconVideo,\n IconVoice,\n } = useComponentContextIcons();\n\n const deliveryStatusIconMap: Record<ChannelPreviewDeliveryStatus, React.ComponentType> =\n {\n delivered: IconChecks,\n read: IconChecks,\n sending: IconClock,\n sent: IconCheckmark1Small,\n };\n\n const contentTypeIconMap: Partial<\n Record<ChannelPreviewMessageType, React.ComponentType>\n > = {\n deleted: IconNoSign,\n error: IconExclamationCircleFill,\n file: IconFile,\n giphy: IconGiphy,\n image: IconCamera,\n link: IconLink,\n location: IconLocation,\n unsupported: IconUnsupportedAttachment,\n video: IconVideo,\n voice: IconVoice,\n };\n\n const { deliveryStatus, senderName, text, type } = useLatestMessagePreview({\n latestMessage,\n messageDeliveryStatus,\n participantCount,\n });\n\n const DeliveryStatusIcon = deliveryStatus\n ? deliveryStatusIconMap[deliveryStatus]\n : undefined;\n const ContentTypeIcon = contentTypeIconMap[type];\n\n return (\n <div\n className={clsx('str-chat__summarized-message-preview', {\n [`str-chat__summarized-message-preview--${type}`]: type,\n })}\n >\n {type !== 'error' && (\n <>\n {DeliveryStatusIcon && (\n <span\n className={clsx('str-chat__summarized-message-preview__delivery-status', {\n [`str-chat__summarized-message-preview__delivery-status--${deliveryStatus}`]:\n deliveryStatus,\n })}\n >\n <DeliveryStatusIcon />\n </span>\n )}\n {senderName && (\n <span className='str-chat__summarized-message-preview__sender'>\n {senderName}:\n </span>\n )}\n </>\n )}\n {ContentTypeIcon && <ContentTypeIcon />}\n <span className='str-chat__summarized-message-preview__text'>{text}</span>\n </div>\n );\n};\n","import React, { useMemo, useRef } from 'react';\nimport clsx from 'clsx';\n\nimport { ChannelListItemActionButtons as DefaultChannelListItemActionButtons } from './ChannelListItemActionButtons';\nimport { ChannelListItemTimestamp } from './ChannelListItemTimestamp';\n\nimport { ChannelAvatar as DefaultChannelAvatar } from '../Avatar';\nimport { Badge } from '../Badge';\nimport { useInteractionAnnouncements } from '../Accessibility';\nimport {\n useChatContext,\n useComponentContext,\n useComponentContextIcons,\n useTranslationContext,\n} from '../../context';\nimport type { ChannelListItemUIProps } from './ChannelListItem';\nimport { composeChannelListItemAccessibleLabel } from './utils.a11y';\nimport { SummarizedMessagePreview } from '../SummarizedMessagePreview';\n\nconst UnMemoizedChannelListItemUI = (props: ChannelListItemUIProps) => {\n const {\n accessibleLabelConfig,\n active,\n channel,\n className: customClassName = '',\n displayImage,\n displayTitle,\n groupChannelDisplayInfo,\n lastMessage,\n messageDeliveryStatus,\n muted,\n onSelect: customOnSelectChannel,\n pinned,\n setActiveChannel,\n unread,\n watchers,\n } = props;\n\n const {\n Avatar = DefaultChannelAvatar,\n ChannelListItemActionButtons = DefaultChannelListItemActionButtons,\n } = useComponentContext();\n const { IconMute, IconPin } = useComponentContextIcons();\n const { client, isMessageAIGenerated } = useChatContext('ChannelListItemUI');\n const { t, tDateTimeParser, userLanguage } = useTranslationContext('ChannelListItemUI');\n const { announceInteraction } = useInteractionAnnouncements();\n\n const channelPreviewButton = useRef<HTMLButtonElement | null>(null);\n\n // Composed accessible name for the row. Built here (the overridable presentation component) so a\n // `ComponentContext`-supplied `ChannelListItemUI` can configure it via `accessibleLabelConfig`.\n const accessibleLabel = useMemo(\n () =>\n composeChannelListItemAccessibleLabel(\n {\n active,\n channel,\n client,\n displayTitle,\n isMessageAIGenerated,\n latestMessage: lastMessage,\n messageDeliveryStatus,\n t,\n tDateTimeParser,\n unreadCount: unread,\n userLanguage,\n },\n accessibleLabelConfig,\n ),\n // `muted`/`pinned` are intentional recompute triggers: the parts read\n // `channel.state` / channel mute & membership state (which ESLint can't see and which do not\n // themselves trigger a re-render), so we key on the state ChannelListItem already tracks.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n accessibleLabelConfig,\n active,\n channel,\n client,\n displayTitle,\n isMessageAIGenerated,\n lastMessage,\n messageDeliveryStatus,\n muted,\n pinned,\n t,\n tDateTimeParser,\n unread,\n userLanguage,\n ],\n );\n\n const avatarName =\n displayTitle || channel.state.messages[channel.state.messages.length - 1]?.user?.id;\n\n const onSelectChannel = (e: React.MouseEvent<HTMLButtonElement>) => {\n if (customOnSelectChannel) {\n customOnSelectChannel(e);\n } else if (setActiveChannel) {\n setActiveChannel(channel, watchers);\n // Confirm the opened channel to assistive tech. Only when actually switching (not re-selecting\n // the open one) and only via the default selection path — a custom `onSelect` owns its own\n // feedback. Debounced in the registry so it lands after the composer's focus announcement.\n if (!active && displayTitle) {\n announceInteraction('channel.opened', { name: displayTitle });\n }\n }\n if (channelPreviewButton?.current) {\n channelPreviewButton.current.blur();\n }\n };\n\n return (\n <div className='str-chat__channel-list-item-container'>\n <button\n aria-label={accessibleLabel}\n // Single-select list: set aria-selected only on the active row. Setting it (false) on every\n // other row makes screen readers announce \"not selected\" on each one — noise.\n aria-selected={active || undefined}\n className={clsx(\n 'str-chat__channel-list-item',\n {\n 'str-chat__channel-list-item--muted': muted,\n 'str-chat__channel-list-item--pinned': pinned,\n 'str-chat__channel-list-item--unread':\n typeof unread === 'number' && unread > 0,\n },\n customClassName,\n )}\n data-testid='channel-list-item-button'\n onClick={onSelectChannel}\n ref={channelPreviewButton}\n role='option'\n >\n <Avatar\n aria-hidden='true'\n displayMembers={groupChannelDisplayInfo?.members}\n imageUrl={displayImage}\n size='xl'\n userName={avatarName}\n />\n <div className='str-chat__channel-list-item-data'>\n <div className='str-chat__channel-list-item-data__first-row'>\n <div className='str-chat__channel-list-item-data__title'>\n <span>{displayTitle || 'N/A'}</span>\n {pinned && <IconPin />}\n {muted && <IconMute />}\n </div>\n <div className='str-chat__channel-list-item-data__timestamp-and-badge'>\n <ChannelListItemTimestamp lastMessage={lastMessage} />\n {typeof unread === 'number' && unread > 0 && (\n <Badge data-testid='unread-badge' size='md' variant='primary'>\n {unread}\n </Badge>\n )}\n </div>\n </div>\n <SummarizedMessagePreview\n latestMessage={lastMessage}\n messageDeliveryStatus={messageDeliveryStatus}\n participantCount={channel.data?.member_count}\n />\n </div>\n </button>\n <ChannelListItemActionButtons />\n </div>\n );\n};\n\n/**\n * Used as preview component for channel item in [ChannelList](#channellist) component.\n * Its best suited for messenger type chat.\n */\nexport const ChannelListItemUI = React.memo(\n UnMemoizedChannelListItemUI,\n) as typeof UnMemoizedChannelListItemUI;\n","import throttle from 'lodash.throttle';\nimport React, { useContext, useEffect, useMemo, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport type { Channel, Event, LocalMessage } from 'stream-chat';\n\nimport { ChannelListItemUI as DefaultChannelListItemUI } from './ChannelListItemUI';\nimport { useIsChannelMuted } from './hooks/useIsChannelMuted';\nimport { useChannelPreviewInfo } from './hooks/useChannelPreviewInfo';\nimport { getLatestMessagePreview as defaultGetLatestMessagePreview } from './utils';\nimport { useTranslationContext } from '../../context/TranslationContext';\nimport { useMessageDeliveryStatus } from './hooks/useMessageDeliveryStatus';\nimport type { MessageDeliveryStatus } from './hooks/useMessageDeliveryStatus';\nimport type { GroupChannelDisplayInfo } from './utils';\nimport type { ChannelListItemLabelConfig } from './utils.a11y';\nimport {\n type ChatContextValue,\n type TranslationContextValue,\n useChatContext,\n useComponentContext,\n} from '../../context';\nimport { useChannelMembershipState } from '../ChannelList';\n\nexport type ChannelListItemUIProps = ChannelListItemProps & {\n /**\n * Configures the row's composed accessible name (part overrides, order, separator, or a full\n * `build`). Supply it from a `ComponentContext`-provided `ChannelListItemUI` to customize the\n * announcement. See `composeChannelListItemAccessibleLabel`.\n */\n accessibleLabelConfig?: ChannelListItemLabelConfig;\n /** Image of Channel to display */\n displayImage?: string;\n /** Title of Channel to display */\n displayTitle?: string;\n /** Title of Channel to display */\n groupChannelDisplayInfo?: GroupChannelDisplayInfo;\n /** The last message received in a channel */\n lastMessage?: LocalMessage;\n /** Latest message preview to display, will be a string or JSX element supporting markdown. */\n latestMessagePreview?: ReactNode;\n /** Status describing whether own message has been delivered or read by another. If the last message is not an own message, then the status is undefined. */\n messageDeliveryStatus?: MessageDeliveryStatus;\n /** Whether the channel is muted by the current user */\n muted?: boolean;\n /** Whether the channel is pinned by the current user */\n pinned?: boolean;\n /** Number of unread Messages */\n unread?: number;\n};\n\nexport type ChannelListItemProps = {\n /** Comes from either the `channelRenderFilterFn` or `usePaginatedChannels` call from [ChannelList](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelList/ChannelList.tsx) */\n channel: Channel;\n /** If the component's channel is the active (selected) Channel */\n active?: boolean;\n /** Current selected channel object */\n activeChannel?: Channel;\n /** Forces the update of preview component on channel update */\n channelUpdateCount?: number;\n /** Custom class for the channel preview root */\n className?: string;\n /** Custom function that generates the message preview in ChannelListItem component */\n getLatestMessagePreview?: (\n channel: Channel,\n t: TranslationContextValue['t'],\n userLanguage: TranslationContextValue['userLanguage'],\n isMessageAIGenerated: ChatContextValue['isMessageAIGenerated'],\n ) => ReactNode;\n key?: string;\n /** Custom ChannelListItem click handler function */\n onSelect?: (event: React.MouseEvent) => void;\n /** Setter for selected Channel */\n setActiveChannel?: ChatContextValue['setActiveChannel'];\n /** Object containing watcher parameters */\n watchers?: { limit?: number; offset?: number };\n};\n\nconst ChannelListItemContext = React.createContext<{ channel: Channel }>({\n channel: null as unknown as Channel,\n});\n\nexport const useChannelListItemContext = () => useContext(ChannelListItemContext);\n\nexport const ChannelListItem = (props: ChannelListItemProps) => {\n const {\n active,\n channel,\n channelUpdateCount,\n getLatestMessagePreview = defaultGetLatestMessagePreview,\n } = props;\n const { ChannelListItemUI = DefaultChannelListItemUI } = useComponentContext();\n const {\n channel: activeChannel,\n client,\n isMessageAIGenerated,\n setActiveChannel,\n } = useChatContext('ChannelPreview');\n const { t, userLanguage } = useTranslationContext('ChannelPreview');\n const { displayImage, displayTitle, groupChannelDisplayInfo } = useChannelPreviewInfo({\n channel,\n });\n const membership = useChannelMembershipState(channel);\n\n const [lastMessage, setLastMessage] = useState<LocalMessage>(\n channel.state.messages[channel.state.messages.length - 1],\n );\n const [latestMessagePreview, setLatestMessagePreview] = useState<ReactNode>(() =>\n getLatestMessagePreview(channel, t, userLanguage, isMessageAIGenerated),\n );\n\n const [unread, setUnread] = useState(0);\n const { messageDeliveryStatus } = useMessageDeliveryStatus({\n channel,\n lastMessage,\n });\n\n const isActive =\n typeof active === 'undefined' ? activeChannel?.cid === channel.cid : active;\n const { muted } = useIsChannelMuted(channel);\n\n useEffect(() => {\n // Channel-scoped read-state events. These are delivered after\n // `Channel._handleChannelEvent` has already updated `channel.state.unreadCount`,\n // so recomputing from `countUnread()` here always sees fresh state.\n const handleChannelReadStateChange = (event: Event) => {\n if (channel.cid !== event.cid) return;\n if (event.user?.id !== client.user?.id) return;\n setUnread(channel.countUnread());\n };\n\n // `notification.mark_read` is a personal event and needs separate handling:\n // `cid` and `user` are both optional on it, and — unlike `message.read` — it has no\n // case in `Channel._handleChannelEvent`, so `channel.state.unreadCount` may still be\n // stale when it arrives. Zero the badge directly instead of recomputing, which keeps\n // the result independent of the `message.read` / `notification.mark_read` arrival order.\n const handleMarkRead = (event: Event) => {\n // a thread was marked read, which does not clear the channel's unread count\n if (event.thread_id) return;\n if (event.user && client.user && event.user.id !== client.user.id) return;\n // a missing `cid` means every channel was marked read\n if (!event.cid) return setUnread(0);\n if (channel.cid !== event.cid) return;\n setUnread(0);\n };\n\n client.on('notification.mark_read', handleMarkRead);\n channel.on('notification.mark_unread', handleChannelReadStateChange);\n channel.on('message.read_locally', handleChannelReadStateChange);\n channel.on('message.read', handleChannelReadStateChange);\n return () => {\n client.off('notification.mark_read', handleMarkRead);\n channel.off('notification.mark_unread', handleChannelReadStateChange);\n channel.off('message.read_locally', handleChannelReadStateChange);\n channel.off('message.read', handleChannelReadStateChange);\n };\n }, [channel, client]);\n\n const refreshUnreadCount = useMemo(\n () =>\n throttle(() => {\n if (muted) {\n setUnread(0);\n } else {\n setUnread(channel.countUnread());\n }\n }, 400),\n [channel, muted],\n );\n\n useEffect(() => {\n refreshUnreadCount();\n setLatestMessagePreview(\n getLatestMessagePreview(channel, t, userLanguage, isMessageAIGenerated),\n );\n\n const handleEvent = (event: Event) => {\n const deletedMessagesInAnotherChannel =\n event.type === 'user.messages.deleted' && event.cid && event.cid !== channel.cid;\n\n if (deletedMessagesInAnotherChannel) return;\n\n setLastMessage(\n channel.state.latestMessages[channel.state.latestMessages.length - 1],\n );\n setLatestMessagePreview(\n getLatestMessagePreview(channel, t, userLanguage, isMessageAIGenerated),\n );\n refreshUnreadCount();\n };\n\n channel.on('message.new', handleEvent);\n channel.on('message.updated', handleEvent);\n channel.on('message.deleted', handleEvent);\n client.on('user.messages.deleted', handleEvent);\n channel.on('message.undeleted', handleEvent);\n channel.on('channel.truncated', handleEvent);\n\n return () => {\n channel.off('message.new', handleEvent);\n channel.off('message.updated', handleEvent);\n channel.off('message.deleted', handleEvent);\n client.off('user.messages.deleted', handleEvent);\n channel.off('message.undeleted', handleEvent);\n channel.off('channel.truncated', handleEvent);\n };\n }, [\n channel,\n client,\n refreshUnreadCount,\n channelUpdateCount,\n getLatestMessagePreview,\n t,\n userLanguage,\n isMessageAIGenerated,\n ]);\n\n const channelPreviewContextValue = useMemo(() => ({ channel }), [channel]);\n\n if (!ChannelListItemUI) return null;\n\n return (\n <ChannelListItemContext.Provider value={channelPreviewContextValue}>\n <ChannelListItemUI\n {...props}\n active={isActive}\n displayImage={displayImage}\n displayTitle={displayTitle}\n groupChannelDisplayInfo={groupChannelDisplayInfo}\n lastMessage={lastMessage}\n latestMessagePreview={latestMessagePreview}\n messageDeliveryStatus={messageDeliveryStatus}\n muted={muted}\n pinned={!!membership.pinned_at}\n setActiveChannel={setActiveChannel}\n unread={unread}\n />\n </ChannelListItemContext.Provider>\n );\n};\n","import type { Channel, LocalMessage, StreamChat } from 'stream-chat';\n\nimport type { ChatContextValue } from '../../../context';\nimport type { TranslationContextValue } from '../../../context/TranslationContext';\nimport {\n type AccessibleLabelConfig,\n type AccessibleLabelPart,\n activeLabelPart,\n composeAccessibleLabel,\n unreadCountLabelPart,\n} from '../../../a11y/accessibleLabel';\nimport { getDateString, isDate } from '../../../i18n/utils';\n\n/**\n * Everything a label part needs. Gathered by `ThreadListItemUI` from the thread state + contexts and\n * handed to each {@link ThreadListItemLabelPart}.\n */\nexport type ThreadListItemLabelData = {\n /** Whether the row is the active (currently open) thread. */\n active?: boolean;\n /** The channel the thread belongs to. */\n channel?: Channel;\n /** Client, used to detect whether a message is the current user's own. */\n client: StreamChat;\n /** The channel's display name (the thread row's title). */\n displayTitle?: string;\n isMessageAIGenerated?: ChatContextValue['isMessageAIGenerated'];\n /** The most recent reply in the thread. */\n latestReply?: LocalMessage;\n /** The message the thread is attached to (its subject); available for custom parts. */\n parentMessage?: LocalMessage;\n /**\n * The parent message's display preview text — the SAME string the visible subtitle shows (from\n * `useLatestMessagePreview`, covering text/attachment/poll/etc.). Used by the default\n * `parentMessage` part so the announcement matches what is shown.\n */\n parentMessagePreview?: string;\n /** The parent message's sender prefix, when the visible preview shows one (e.g. \"You\", a name). */\n parentMessageSender?: string;\n /** Number of participants in the thread. */\n participantCount?: number;\n /** Number of replies in the thread. */\n replyCount?: number;\n t: TranslationContextValue['t'];\n tDateTimeParser: TranslationContextValue['tDateTimeParser'];\n /** The current user's unread reply count for the thread. */\n unreadCount?: number;\n userLanguage?: TranslationContextValue['userLanguage'];\n};\n\n/** Produces one segment of the accessible name; return `undefined`/empty to omit it. */\nexport type ThreadListItemLabelPart = AccessibleLabelPart<ThreadListItemLabelData>;\n\n/**\n * The default, named label parts. Each is independently overridable via\n * {@link ThreadListItemLabelConfig.parts}. The active (currently open) state is announced here (not\n * left to the row's `aria-selected` alone, which is not reliably spoken across screen readers for an\n * option with a custom name); `aria-selected` is kept on the active row for listbox semantics.\n */\nexport const defaultThreadListItemLabelParts = {\n active: activeLabelPart,\n name: ({ displayTitle, t }) =>\n displayTitle\n ? t('aria/Chat: {{ channelName }}', { channelName: displayTitle })\n : undefined,\n // The message the thread is about (shown as the row's subtitle); same preview the subtitle shows.\n parentMessage: ({ parentMessagePreview, parentMessageSender, t }) => {\n if (!parentMessagePreview) return undefined;\n const preview = parentMessageSender\n ? `${parentMessageSender}: ${parentMessagePreview}`\n : parentMessagePreview;\n return t('aria/Thread: {{ messagePreview }}', { messagePreview: preview });\n },\n replyCount: ({ replyCount, t }) =>\n typeof replyCount === 'number' && replyCount > 0\n ? t('replyCount', { count: replyCount })\n : undefined,\n time: ({ latestReply, t, tDateTimeParser }) => {\n const createdAt = latestReply?.created_at;\n if (!createdAt || !isDate(createdAt)) return undefined;\n const when = getDateString({\n messageCreatedAt: createdAt.toISOString(),\n t,\n tDateTimeParser,\n timestampTranslationKey: 'timestamp/ChannelPreviewTimestamp',\n });\n return when ? t('aria/Last activity: {{ time }}', { time: String(when) }) : undefined;\n },\n unreadCount: unreadCountLabelPart,\n} satisfies Record<string, ThreadListItemLabelPart>;\n\n/** Default order the parts are assembled in (reading order). */\nexport const DEFAULT_THREAD_LIST_ITEM_LABEL_ORDER = [\n 'name',\n 'active',\n 'unreadCount',\n 'parentMessage',\n 'replyCount',\n 'time',\n] as const;\n\nexport type ThreadListItemLabelConfig = AccessibleLabelConfig<ThreadListItemLabelData>;\n\n/**\n * Composes a single, coherent accessible name for a thread list row from named parts. The default\n * reading order is name (channel) → active → unread → parent message → reply count → last activity.\n *\n * ## Customizing the label\n *\n * The label is generated by `ThreadListItemUI`, which accepts an `accessibleLabelConfig` prop. To\n * customize it, supply your own `ThreadListItemUI` through `ComponentContext` (the same way the\n * component is overridden) and forward the config — no new plumbing:\n *\n * ```tsx\n * const MyThreadListItemUI = (props) => (\n * <DefaultThreadListItemUI {...props} accessibleLabelConfig={accessibleLabelConfig} />\n * );\n * // <ComponentProvider value={{ ThreadListItemUI: MyThreadListItemUI }}> … </ComponentProvider>\n * ```\n *\n * ### Adding custom parts\n *\n * - {@link ThreadListItemLabelConfig.parts} is merged over {@link defaultThreadListItemLabelParts},\n * so a new key is *added* and a same-named key *overrides* the default.\n * - A part returns its segment string, or `undefined`/`''` to be omitted.\n * - {@link ThreadListItemLabelConfig.order} decides which parts are included AND their sequence —\n * **a part not listed in `order` is never rendered**. Spread\n * {@link DEFAULT_THREAD_LIST_ITEM_LABEL_ORDER} to keep the defaults and insert your own.\n * - Each part receives {@link ThreadListItemLabelData}. Parts call `t`, so provide your own i18n keys\n * (or return plain strings).\n *\n * ```tsx\n * const accessibleLabelConfig: ThreadListItemLabelConfig = {\n * parts: {\n * participants: ({ participantCount, t }) =>\n * participantCount ? t('{{ count }} participants', { count: participantCount }) : undefined,\n * },\n * order: ['name', 'participants', ...DEFAULT_THREAD_LIST_ITEM_LABEL_ORDER.slice(1)],\n * };\n * ```\n *\n * For full control, set {@link ThreadListItemLabelConfig.build} (return the entire string), or write\n * a custom `ThreadListItemUI` that calls this function directly — importing\n * {@link defaultThreadListItemLabelParts} to reuse the built-ins.\n */\nexport const composeThreadListItemAccessibleLabel = (\n data: ThreadListItemLabelData,\n config: ThreadListItemLabelConfig = {},\n): string =>\n composeAccessibleLabel(\n data,\n defaultThreadListItemLabelParts,\n DEFAULT_THREAD_LIST_ITEM_LABEL_ORDER,\n config,\n );\n","import React, { useCallback, useEffect, useMemo } from 'react';\nimport clsx from 'clsx';\n\nimport type { ThreadState } from 'stream-chat';\nimport type { ComponentPropsWithoutRef } from 'react';\n\nimport { Timestamp } from '../../Message/Timestamp';\nimport {\n Avatar,\n type AvatarProps,\n AvatarStack as DefaultAvatarStack,\n} from '../../Avatar';\nimport { useInteractionAnnouncements } from '../../Accessibility';\nimport { useChannelPreviewInfo } from '../../ChannelListItem';\nimport {\n useChatContext,\n useComponentContext,\n useTranslationContext,\n} from '../../../context';\nimport { useThreadsViewContext } from '../../ChatView';\nimport { useThreadListItemContext } from './ThreadListItem';\nimport { useStateStore } from '../../../store';\nimport { Badge } from '../../Badge';\nimport {\n SummarizedMessagePreview,\n useLatestMessagePreview,\n} from '../../SummarizedMessagePreview';\nimport {\n composeThreadListItemAccessibleLabel,\n type ThreadListItemLabelConfig,\n} from './utils.a11y';\nimport { extractDisplayInfo as defaultExtractDisplayInfo } from '../../Avatar/utils';\n\nexport type ThreadListItemUIProps = ComponentPropsWithoutRef<'button'> & {\n /**\n * Configures the row's composed accessible name (the `aria-label`). Override individual parts, the\n * order, the separator, or supply a full `build`. See `composeThreadListItemAccessibleLabel`.\n */\n accessibleLabelConfig?: ThreadListItemLabelConfig;\n resetHighlighting?: () => void;\n};\n\nexport const ThreadListItemUI = ({\n accessibleLabelConfig,\n resetHighlighting,\n ...props\n}: ThreadListItemUIProps) => {\n const { client, isMessageAIGenerated } = useChatContext();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const thread = useThreadListItemContext()!;\n const {\n AvatarStack = DefaultAvatarStack,\n extractDisplayInfo = defaultExtractDisplayInfo,\n } = useComponentContext();\n\n const selector = useCallback(\n (nextValue: ThreadState) => ({\n channel: nextValue.channel,\n deletedAt: nextValue.deletedAt,\n latestReply: nextValue.replies.at(-1),\n ownUnreadMessageCount:\n (client.userID && nextValue.read[client.userID]?.unreadMessageCount) || 0,\n parentMessage: nextValue.parentMessage,\n participants: nextValue.participants,\n replyCount: nextValue.replyCount,\n }),\n [client],\n );\n\n const {\n channel,\n deletedAt,\n latestReply,\n ownUnreadMessageCount,\n parentMessage,\n participants,\n replyCount,\n } = useStateStore(thread.state, selector);\n\n const { displayTitle: channelDisplayTitle } = useChannelPreviewInfo({ channel });\n const { t, tDateTimeParser, userLanguage } = useTranslationContext('ThreadListItemUI');\n const { announceInteraction } = useInteractionAnnouncements();\n\n const { activeThread, setActiveThread } = useThreadsViewContext();\n\n const onSelectThread = useCallback(() => {\n if (activeThread === thread) return;\n setActiveThread(thread);\n // Confirm the opened thread to assistive tech, debounced in the registry so it lands after the\n // thread composer's focus announcement rather than competing with it.\n if (channelDisplayTitle) {\n announceInteraction('thread.opened', { name: channelDisplayTitle });\n }\n }, [activeThread, announceInteraction, channelDisplayTitle, setActiveThread, thread]);\n\n // Reuse the SAME preview the visible subtitle renders (text + sender, all message kinds), so the\n // announced parent message matches what is shown.\n const { senderName: parentMessageSender, text: parentMessagePreview } =\n useLatestMessagePreview({\n latestMessage: parentMessage,\n participantCount: participants?.length,\n });\n\n const accessibleLabel = useMemo(\n () =>\n composeThreadListItemAccessibleLabel(\n {\n active: activeThread === thread,\n channel,\n client,\n displayTitle: channelDisplayTitle,\n isMessageAIGenerated,\n latestReply,\n parentMessage,\n parentMessagePreview: parentMessage ? parentMessagePreview : undefined,\n parentMessageSender: parentMessage ? parentMessageSender : undefined,\n participantCount: participants?.length,\n replyCount,\n t,\n tDateTimeParser,\n unreadCount: ownUnreadMessageCount,\n userLanguage,\n },\n accessibleLabelConfig,\n ),\n [\n accessibleLabelConfig,\n activeThread,\n channel,\n channelDisplayTitle,\n client,\n isMessageAIGenerated,\n latestReply,\n ownUnreadMessageCount,\n parentMessage,\n parentMessagePreview,\n parentMessageSender,\n participants,\n replyCount,\n t,\n tDateTimeParser,\n thread,\n userLanguage,\n ],\n );\n\n const avatarProps: Partial<AvatarProps> | undefined = deletedAt\n ? undefined\n : ({\n imageUrl: latestReply?.user?.image,\n userName: latestReply?.user?.name || latestReply?.user?.id,\n } as const);\n\n const displayInfo = useMemo(() => {\n if (!participants) return [];\n\n return participants.slice(0, 3).map(extractDisplayInfo);\n }, [extractDisplayInfo, participants]);\n\n useEffect(() => {\n if (!resetHighlighting) return;\n\n const reset = resetHighlighting;\n\n const timeout = setTimeout(() => {\n reset();\n }, 2000);\n\n return () => clearTimeout(timeout);\n }, [resetHighlighting]);\n\n return (\n <div className='str-chat__thread-list-item-container'>\n <button\n aria-label={accessibleLabel}\n aria-selected={activeThread === thread}\n className={clsx('str-chat__thread-list-item', {\n 'str-chat__thread-list-item--highlighted':\n typeof resetHighlighting !== 'undefined',\n })}\n data-thread-id={thread.id}\n onClick={onSelectThread}\n role='option'\n {...props}\n >\n <Avatar size='xl' {...avatarProps} />\n <div className='str-chat__thread-list-item__content'>\n <div className='str-chat__thread-list-item__content-leading'>\n <span className='str-chat__thread-list-item__title'>\n {channelDisplayTitle}\n </span>\n <SummarizedMessagePreview\n latestMessage={parentMessage}\n participantCount={participants?.length}\n />\n </div>\n <div className='str-chat__thread-list-item__content-trailing'>\n <div className='str-chat__thread-list-item__reply-information'>\n <AvatarStack displayInfo={displayInfo} size='sm' />\n <span className='str-chat__thread-list-item__reply-count'>\n {t('replyCount', { count: replyCount })}\n </span>\n </div>\n <Timestamp\n customClass='str-chat__thread-list-item__timestamp'\n timestamp={latestReply?.created_at}\n />\n </div>\n </div>\n {ownUnreadMessageCount > 0 && (\n <Badge size='md' variant='primary'>\n {ownUnreadMessageCount}\n </Badge>\n )}\n </button>\n </div>\n );\n};\n","import React, { createContext, useContext } from 'react';\n\nimport type { Thread } from 'stream-chat';\n\nimport { useComponentContext } from '../../../context';\nimport { ThreadListItemUI as DefaultThreadListItemUI } from './ThreadListItemUI';\n\nimport type { ThreadListItemUIProps } from './ThreadListItemUI';\n\nexport type ThreadListItemProps = {\n thread: Thread;\n threadListItemUIProps?: ThreadListItemUIProps;\n};\n\nconst ThreadListItemContext = createContext<Thread | undefined>(undefined);\n\nexport const useThreadListItemContext = () => useContext(ThreadListItemContext);\n\nexport const ThreadListItem = ({\n thread,\n threadListItemUIProps,\n}: ThreadListItemProps) => {\n const { ThreadListItemUI = DefaultThreadListItemUI } = useComponentContext();\n\n return (\n <ThreadListItemContext.Provider value={thread}>\n <ThreadListItemUI {...threadListItemUIProps} />\n </ThreadListItemContext.Provider>\n );\n};\n","import React from 'react';\n\nimport { useComponentContextIcons, useTranslationContext } from '../../../context';\n\nexport const ThreadListEmptyPlaceholder = () => {\n const { IconMessageBubbles } = useComponentContextIcons();\n\n const { t } = useTranslationContext('ThreadListEmptyPlaceholder');\n\n return (\n <div className='str-chat__thread-list-empty-placeholder'>\n <IconMessageBubbles />\n <p>{t('Reply to a message to start a thread')}</p>\n </div>\n );\n};\n","import React from 'react';\nimport clsx from 'clsx';\n\nimport type { ThreadManagerState } from 'stream-chat';\n\nimport {\n useChatContext,\n useComponentContextIcons,\n useTranslationContext,\n} from '../../../context';\nimport { useStateStore } from '../../../store';\nimport { LoadingIndicator } from '../../Loading';\n\nconst selector = (nextValue: ThreadManagerState) => ({\n isLoading: nextValue.pagination.isLoading,\n unseenThreadIds: nextValue.unseenThreadIds,\n});\n\nexport const ThreadListUnseenThreadsBanner = () => {\n const { IconRefresh } = useComponentContextIcons();\n\n const { client } = useChatContext();\n const { t } = useTranslationContext();\n const { isLoading, unseenThreadIds } = useStateStore(client.threads.state, selector);\n\n if (!unseenThreadIds.length) return null;\n\n return (\n <button\n className={clsx('str-chat__unseen-threads-banner', {\n 'str-chat__unseen-threads-banner--loading': isLoading,\n })}\n disabled={isLoading}\n onClick={() => client.threads.reload()}\n >\n {!isLoading && (\n <>\n <IconRefresh />\n <span>\n {t('ThreadListUnseenThreadsBanner/unreadThreads', {\n count: unseenThreadIds.length,\n })}\n </span>\n </>\n )}\n {isLoading && (\n <>\n <LoadingIndicator />\n <span>{t('ThreadListUnseenThreadsBanner/loading')}</span>\n </>\n )}\n </button>\n );\n};\n","import React from 'react';\n\nimport type { ThreadManagerState } from 'stream-chat';\n\nimport { LoadingIndicator as DefaultLoadingIndicator } from '../../Loading';\nimport { useChatContext, useComponentContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nconst selector = (nextValue: ThreadManagerState) => ({\n isLoadingNext: nextValue.pagination.isLoadingNext,\n});\n\nexport const ThreadListLoadingIndicator = () => {\n const { LoadingIndicator = DefaultLoadingIndicator } = useComponentContext();\n const { client } = useChatContext();\n const { isLoadingNext } = useStateStore(client.threads.state, selector);\n\n if (!isLoadingNext) return null;\n\n return (\n <div className='str-chat__thread-list-loading-indicator'>\n <LoadingIndicator />\n </div>\n );\n};\n","import React from 'react';\nimport { useComponentContext, useTranslationContext } from '../../../context';\nimport { useThreadsViewContext } from '../../ChatView';\n\nexport const ThreadListHeader = () => {\n const { t } = useTranslationContext();\n const { HeaderEndContent } = useComponentContext();\n const { activeThread } = useThreadsViewContext();\n return (\n <div className='str-chat__thread-list__header'>\n <div className='str-chat__thread-list__header__title'>{t('Threads')}</div>\n {activeThread && HeaderEndContent && <HeaderEndContent />}\n </div>\n );\n};\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport type { ComputeItemKey, VirtuosoHandle, VirtuosoProps } from 'react-virtuoso';\nimport { Virtuoso } from 'react-virtuoso';\nimport type { Thread, ThreadManager, ThreadManagerState } from 'stream-chat';\n\nimport { useVirtualizedListboxKeyboardNavigation } from '../../../a11y/hooks/useVirtualizedListboxKeyboardNavigation';\nimport { ThreadListItem as DefaultThreadListItem } from './ThreadListItem';\nimport { ThreadListEmptyPlaceholder as DefaultThreadListEmptyPlaceholder } from './ThreadListEmptyPlaceholder';\nimport { ThreadListUnseenThreadsBanner as DefaultThreadListUnseenThreadsBanner } from './ThreadListUnseenThreadsBanner';\nimport { ThreadListLoadingIndicator as DefaultThreadListLoadingIndicator } from './ThreadListLoadingIndicator';\nimport { LoadingChannels } from '../../Loading';\nimport { NotificationList } from '../../Notifications';\nimport {\n useChatContext,\n useComponentContext,\n useTranslationContext,\n} from '../../../context';\nimport { useStateStore } from '../../../store';\nimport { ThreadListHeader } from './ThreadListHeader';\n\nconst selector = (nextValue: ThreadManagerState) => ({\n isLoading: nextValue.pagination.isLoading,\n threads: nextValue.threads,\n});\n\nconst computeItemKey: ComputeItemKey<Thread, unknown> = (_, item) => item.id;\n\ntype ThreadListProps = {\n virtuosoProps?: VirtuosoProps<Thread, unknown>;\n};\n\nexport const useThreadList = () => {\n const { client } = useChatContext();\n\n useEffect(() => {\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'visible') {\n client.threads.activate();\n }\n if (document.visibilityState === 'hidden') {\n client.threads.deactivate();\n }\n };\n\n handleVisibilityChange();\n\n document.addEventListener('visibilitychange', handleVisibilityChange);\n return () => {\n client.threads.deactivate();\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n };\n }, [client]);\n};\n\nconst useThreadHighlighting = (threadManager: ThreadManager) => {\n const [threadsToHighlight, setThreadsToHighlight] = useState<\n Record<string, () => void>\n >({});\n\n useEffect(() => {\n const unsubscribe = threadManager.state.subscribeWithSelector(\n (state) => state.threads,\n (nextThreads, previousThreads) => {\n if (!previousThreads) return;\n\n const resetByThreadId: Record<string, () => void> = {};\n\n for (const thread of nextThreads) {\n if (previousThreads.includes(thread)) continue;\n\n resetByThreadId[thread.id] = () => {\n setThreadsToHighlight((pv) => {\n const copy = { ...pv };\n delete copy[thread.id];\n return copy;\n });\n };\n }\n\n setThreadsToHighlight(resetByThreadId);\n },\n );\n\n return unsubscribe;\n });\n\n return threadsToHighlight;\n};\n\nexport const ThreadList = ({ virtuosoProps }: ThreadListProps) => {\n const { client } = useChatContext();\n const { t } = useTranslationContext('ThreadList');\n const {\n NotificationList: NotificationListFromContext = NotificationList,\n ThreadListEmptyPlaceholder = DefaultThreadListEmptyPlaceholder,\n ThreadListItem = DefaultThreadListItem,\n ThreadListLoadingIndicator = DefaultThreadListLoadingIndicator,\n ThreadListUnseenThreadsBanner = DefaultThreadListUnseenThreadsBanner,\n } = useComponentContext();\n const { isLoading, threads } = useStateStore(client.threads.state, selector);\n\n const resetByThreadId = useThreadHighlighting(client.threads);\n\n // Keyboard roving for the thread list (a `role=\"listbox\"` of `role=\"option\"` rows, no row actions\n // → ArrowUp/Down/Home/End only). The list is virtualized, so only a window of rows exists in the\n // DOM at a time; `useVirtualizedListboxKeyboardNavigation` indexes into the full `threads` array\n // and drives Virtuoso's `scrollIntoView` to bring off-window rows into existence before focusing.\n const virtuosoRef = useRef<VirtuosoHandle>(null);\n const scrollerRef = useRef<HTMLElement | null>(null);\n\n const scrollIndexIntoView = useCallback((index: number, onRendered: () => void) => {\n virtuosoRef.current?.scrollIntoView({ done: onRendered, index });\n }, []);\n\n const { onKeyDown } = useVirtualizedListboxKeyboardNavigation({\n getItemId: (thread) => thread.id,\n itemIdAttribute: 'data-thread-id',\n items: threads,\n scrollerRef,\n scrollIndexIntoView,\n });\n\n useThreadList();\n\n if (isLoading && !threads.length) {\n return (\n <div className='str-chat__thread-list-container'>\n <ThreadListHeader />\n <div className='str-chat__thread-list str-chat__thread-list--loading'>\n <LoadingChannels />\n </div>\n </div>\n );\n }\n\n return (\n <div className='str-chat__thread-list-container'>\n <ThreadListHeader />\n {/* TODO: allow re-load on stale ThreadManager state */}\n <ThreadListUnseenThreadsBanner />\n <Virtuoso\n aria-label={t('aria/Thread list')}\n atBottomStateChange={(atBottom) => atBottom && client.threads.loadNextPage()}\n className='str-chat__thread-list'\n components={{\n EmptyPlaceholder: ThreadListEmptyPlaceholder,\n Footer: ThreadListLoadingIndicator,\n }}\n computeItemKey={computeItemKey}\n data={threads}\n itemContent={(_, thread) => (\n <ThreadListItem\n thread={thread}\n threadListItemUIProps={{\n resetHighlighting: resetByThreadId[thread.id],\n }}\n />\n )}\n onKeyDown={(event) =>\n onKeyDown(event as unknown as React.KeyboardEvent<HTMLElement>)\n }\n ref={virtuosoRef}\n role='listbox'\n scrollerRef={(el) => {\n scrollerRef.current = el instanceof HTMLElement ? el : null;\n }}\n // TODO: handle visibility (for a button that scrolls to the unread thread)\n // itemsRendered={(items) => console.log({ items })}\n {...virtuosoProps}\n />\n <NotificationListFromContext panel='thread-list' />\n </div>\n );\n};\n","import { useCallback } from 'react';\n\nimport type { Notification, NotificationManagerState } from 'stream-chat';\n\nimport { useChatContext } from '../../../context';\nimport { useStateStore } from '../../../store';\n\nimport { hasSystemNotificationTag } from './useNotificationApi';\n\nexport type UseSystemNotificationsFilter = (notification: Notification) => boolean;\n\nexport type UseSystemNotificationsOptions = {\n /**\n * Applied after the built-in filter that keeps only notifications tagged for the system banner.\n */\n filter?: UseSystemNotificationsFilter;\n};\n\n/**\n * Subscribes to `client.notifications` and returns only **system** banner notifications\n * (same subset `NotificationList` excludes from toasts). Optional `filter` narrows further.\n */\nexport const useSystemNotifications = (\n options?: UseSystemNotificationsOptions,\n): Notification[] => {\n const { client } = useChatContext();\n const selector = useCallback(\n (state: NotificationManagerState) => {\n const withSystemTag = state.notifications.filter(hasSystemNotificationTag);\n const notifications = options?.filter\n ? withSystemTag.filter(options.filter)\n : withSystemTag;\n\n return { notifications };\n },\n [options?.filter],\n );\n\n const { notifications } = useStateStore(client.notifications.store, selector);\n\n return notifications;\n};\n","import { useEffect, useRef } from 'react';\nimport type { Notification } from 'stream-chat';\n\nimport { useAnnouncementQueue } from './scheduling';\nimport { useAriaLiveAnnouncer } from './useAriaLiveAnnouncer';\nimport type { AriaLivePriority } from './useAriaLiveAnnouncer';\nimport { useNotifications } from '../Notifications';\nimport { useTranslationContext } from '../../context';\n\nexport type NotificationAnnouncementBuilderParams = {\n defaultMessage: string;\n notification: Notification;\n translatedMessage: string;\n};\n\nexport type NotificationAnnouncementBuilder = (\n params: NotificationAnnouncementBuilderParams,\n) => string;\nexport type NotificationAnnouncementFilter = (notification: Notification) => boolean;\n\nconst getAnnouncementPriority = (notification: Notification): AriaLivePriority =>\n notification.severity === 'error' ? 'assertive' : 'polite';\n\nconst getSeverityLabel = (notification: Notification) => {\n if (!notification.severity) return null;\n return `${notification.severity[0].toUpperCase()}${notification.severity.slice(1)}`;\n};\n\nconst getDefaultAnnouncementMessage = (notification: Notification, message: string) => {\n const severityLabel = getSeverityLabel(notification);\n\n if (severityLabel) {\n return `${severityLabel} notification: ${message}`;\n }\n\n return `Notification: ${message}`;\n};\n\nexport type NotificationAnnouncerProps = {\n buildNotificationAnnouncement?: NotificationAnnouncementBuilder;\n notificationFilter?: NotificationAnnouncementFilter;\n};\n\nconst defaultBuildNotificationAnnouncement: NotificationAnnouncementBuilder = ({\n defaultMessage,\n}) => defaultMessage;\nconst defaultNotificationFilter: NotificationAnnouncementFilter = () => true;\n\n/**\n * Announces app notifications to assistive technology.\n *\n * As of the announcer unification this renders **no live region of its own** — it routes new\n * notifications through the shared {@link useAriaLiveAnnouncer} sink (so they land in the active\n * {@link AriaLiveOutlet}, including inside an open modal) and paces them with\n * {@link useAnnouncementQueue}.\n *\n * ## Required context (contract)\n * `NotificationAnnouncer` **must** be rendered inside an `AriaLiveAnnouncerProvider`. `Chat` mounts\n * that provider (with a root, portalled `AriaLiveOutlet`), so the default component tree already\n * satisfies this and no extra setup is needed.\n *\n * Rendered **without** a provider ancestor it mounts successfully but **announces nothing** —\n * `useAriaLiveAnnouncer()` returns a no-op and logs a `console.warn` (\"… called outside of an\n * AriaLiveAnnouncerProvider\"). This is intentional post-F4: the component no longer carries a\n * fallback live region, so a single announcer owns all output and there are no duplicate/competing\n * regions. If you render it outside `Chat`, wrap it in `AriaLiveAnnouncerProvider` + `AriaLiveOutlet`\n * yourself.\n */\nexport const NotificationAnnouncer = ({\n buildNotificationAnnouncement = defaultBuildNotificationAnnouncement,\n notificationFilter = defaultNotificationFilter,\n}: NotificationAnnouncerProps) => {\n const { t } = useTranslationContext();\n const notifications = useNotifications();\n const announce = useAriaLiveAnnouncer();\n const { enqueue } = useAnnouncementQueue(announce);\n\n const initializedRef = useRef(false);\n const seenNotificationIdsRef = useRef(new Set<string>());\n\n useEffect(() => {\n const visibleNotificationIds = new Set(notifications.map(({ id }) => id));\n\n seenNotificationIdsRef.current.forEach((id) => {\n if (!visibleNotificationIds.has(id)) {\n seenNotificationIdsRef.current.delete(id);\n }\n });\n\n // Do not announce notifications already present on first render.\n if (!initializedRef.current) {\n notifications.forEach(({ id }) => seenNotificationIdsRef.current.add(id));\n initializedRef.current = true;\n return;\n }\n\n notifications.forEach((notification) => {\n if (seenNotificationIdsRef.current.has(notification.id)) return;\n\n seenNotificationIdsRef.current.add(notification.id);\n if (!notificationFilter(notification)) return;\n\n const message = t('translationBuilderTopic/notification', {\n notification,\n value: notification.message,\n });\n\n if (!message) return;\n\n const defaultMessage = getDefaultAnnouncementMessage(notification, message);\n const announcementMessage = buildNotificationAnnouncement({\n defaultMessage,\n notification,\n translatedMessage: message,\n });\n\n if (!announcementMessage) return;\n\n enqueue({\n message: announcementMessage,\n priority: getAnnouncementPriority(notification),\n });\n });\n }, [buildNotificationAnnouncement, enqueue, notificationFilter, notifications, t]);\n\n return null;\n};\n","import { useCallback, useRef } from 'react';\n\nexport type ReserveFocusReturnOptions = {\n /**\n * Explicit element focus should return to. Defaults to the current\n * `document.activeElement` (the natural \"origin\" — e.g. the composer when a\n * transient surface steals focus). Provide this when the desired return target\n * is NOT where focus currently is. A non-focusable value (or `document.body`)\n * reserves nothing.\n */\n target?: HTMLElement | null;\n};\n\nexport type UseFocusReturnResult = {\n /**\n * Capture the element focus should return to. Called with no argument it\n * captures the current `document.activeElement`; pass `{ target }` to override.\n * Options is an object for forward-compatibility (future flags add fields here\n * without changing the call signature).\n */\n reserve: (options?: ReserveFocusReturnOptions) => void;\n /**\n * Move focus back to the reserved element (if it is still connected) and clear\n * the reservation. No-op when nothing was reserved or the element is gone.\n * Focuses synchronously — defer announcements yourself if you need the focus\n * announcement to be spoken first.\n */\n restore: () => void;\n};\n\nconst isFocusableElement = (value: Element | null): value is HTMLElement =>\n value instanceof HTMLElement && typeof value.focus === 'function';\n\n/**\n * Generic focus-restoration primitive: capture-before-steal, restore-on-finish —\n * the pattern dialogs/popovers use. A transient surface (e.g. the Giphy preview)\n * `reserve()`s before it moves focus into itself, then `restore()`s when it\n * completes, returning focus to wherever it was — WITHOUT the surface knowing or\n * naming that element (no coupling to \"the composer\").\n *\n * Single-candidate by design: each consumer holds its own reservation in a ref,\n * so concurrent/nested transient surfaces never clobber each other (each restores\n * its own origin). There is one `document.activeElement` at a time, and these\n * flows are mutually exclusive, so no shared slot/stack/key registry is needed.\n * If a cross-component rendezvous or deep nesting ever appears, a stack (nesting)\n * or coarse typed keys (rendezvous) can be added without changing this API.\n *\n * React 17/18/19 compatible — `useRef`/`useCallback` only.\n */\nexport const useFocusReturn = (): UseFocusReturnResult => {\n const reservedTargetRef = useRef<HTMLElement | null>(null);\n\n const reserve = useCallback((options?: ReserveFocusReturnOptions) => {\n const candidate = options?.target ?? (document.activeElement as Element | null);\n reservedTargetRef.current =\n isFocusableElement(candidate) && candidate !== document.body ? candidate : null;\n }, []);\n\n const restore = useCallback(() => {\n const target = reservedTargetRef.current;\n reservedTargetRef.current = null;\n if (target?.isConnected) target.focus();\n }, []);\n\n return { reserve, restore };\n};\n","import { useCallback, useEffect, useRef } from 'react';\nimport type { Channel, Event, MessageResponse } from 'stream-chat';\n\nimport { useAriaLiveAnnouncer } from '../useAriaLiveAnnouncer';\nimport { useTranslationContext } from '../../../context/TranslationContext';\n\nconst MESSAGE_ANNOUNCEMENT_THROTTLE_MS = 1000;\n\nconst isAnnounceableIncomingMessage = (\n message: MessageResponse,\n ownUserId?: string,\n): boolean => {\n const messageUserId = message.user?.id;\n\n if (!message.id || !messageUserId || messageUserId === ownUserId) {\n return false;\n }\n\n return (\n message.type !== 'deleted' &&\n message.type !== 'ephemeral' &&\n message.type !== 'error' &&\n message.type !== 'system' &&\n message.status !== 'failed' &&\n message.status !== 'sending'\n );\n};\n\nconst getSenderName = (\n message: MessageResponse,\n t: ReturnType<typeof useTranslationContext>['t'],\n) => message.user?.name?.trim() || message.user?.id || t('Anonymous');\n\nexport type UseIncomingMessageAnnouncementsParams = {\n activeThreadId?: string;\n channel?: Channel;\n ownUserId?: string;\n threadList?: boolean;\n};\n\nexport const useIncomingMessageAnnouncements = ({\n activeThreadId,\n channel,\n ownUserId,\n threadList = false,\n}: UseIncomingMessageAnnouncementsParams) => {\n const announce = useAriaLiveAnnouncer();\n const { t } = useTranslationContext('useIncomingMessageAnnouncements');\n const lastAnnouncementTimestampRef = useRef(0);\n const flushTimeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const announcedMessageIdsRef = useRef(new Set<string>());\n const pendingAnnouncementBatchRef = useRef<{\n count: number;\n firstSender: string | null;\n }>({\n count: 0,\n firstSender: null,\n });\n\n const flushPendingAnnouncements = useCallback(() => {\n const pendingAnnouncementBatch = pendingAnnouncementBatchRef.current;\n\n if (pendingAnnouncementBatch.count <= 0) return;\n\n if (pendingAnnouncementBatch.count === 1) {\n announce(\n t('New message from {{user}}', {\n user: pendingAnnouncementBatch.firstSender || t('Anonymous'),\n }),\n );\n } else {\n announce(t('{{count}} new messages', { count: pendingAnnouncementBatch.count }));\n }\n\n pendingAnnouncementBatch.count = 0;\n pendingAnnouncementBatch.firstSender = null;\n lastAnnouncementTimestampRef.current = Date.now();\n }, [announce, t]);\n\n const scheduleFlush = useCallback(() => {\n if (flushTimeoutRef.current) return;\n\n const now = Date.now();\n const elapsedSinceLastAnnouncement = now - lastAnnouncementTimestampRef.current;\n\n if (elapsedSinceLastAnnouncement >= MESSAGE_ANNOUNCEMENT_THROTTLE_MS) {\n flushPendingAnnouncements();\n return;\n }\n\n flushTimeoutRef.current = setTimeout(() => {\n flushTimeoutRef.current = undefined;\n flushPendingAnnouncements();\n }, MESSAGE_ANNOUNCEMENT_THROTTLE_MS - elapsedSinceLastAnnouncement);\n }, [flushPendingAnnouncements]);\n\n useEffect(\n () => () => {\n if (flushTimeoutRef.current) {\n clearTimeout(flushTimeoutRef.current);\n }\n },\n [],\n );\n\n useEffect(() => {\n if (!channel) {\n return;\n }\n\n const handleMessageNew = (event: Event) => {\n const message = event.message;\n if (!message) return;\n\n if (\n (event.cid && event.cid !== channel.cid) ||\n !isAnnounceableIncomingMessage(message, ownUserId)\n ) {\n return;\n }\n\n const isReply = !!message.parent_id;\n const belongsToActiveThread =\n !!activeThreadId && message.parent_id === activeThreadId;\n const shouldAnnounceInThreadList = threadList && belongsToActiveThread;\n const shouldAnnounceInMainList = !threadList && !isReply;\n\n if (!shouldAnnounceInThreadList && !shouldAnnounceInMainList) {\n return;\n }\n\n if (announcedMessageIdsRef.current.has(message.id || '')) {\n return;\n }\n\n if (message.id) {\n if (announcedMessageIdsRef.current.size > 500) {\n announcedMessageIdsRef.current.clear();\n }\n announcedMessageIdsRef.current.add(message.id);\n }\n\n pendingAnnouncementBatchRef.current.count += 1;\n if (!pendingAnnouncementBatchRef.current.firstSender) {\n pendingAnnouncementBatchRef.current.firstSender = getSenderName(message, t);\n }\n\n scheduleFlush();\n };\n\n const subscription = channel.on('message.new', handleMessageNew);\n\n return () => {\n subscription.unsubscribe();\n if (flushTimeoutRef.current) {\n clearTimeout(flushTimeoutRef.current);\n flushTimeoutRef.current = undefined;\n }\n };\n }, [activeThreadId, channel, ownUserId, scheduleFlush, t, threadList]);\n};\n","import React from 'react';\n\nimport { type ChannelAvatarProps, ChannelAvatar as DefaultAvatar } from '../Avatar';\nimport { TypingIndicatorHeader } from '../TypingIndicator/TypingIndicatorHeader';\nimport { useChannelHeaderOnlineStatus } from './hooks/useChannelHeaderOnlineStatus';\nimport { useChannelPreviewInfo } from '../ChannelListItem/hooks/useChannelPreviewInfo';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\nimport { useChatContext } from '../../context/ChatContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { useTypingContext } from '../../context/TypingContext';\n\nconst ChannelHeaderSubtitle = () => {\n const { channelConfig } = useChannelStateContext('ChannelHeaderSubtitle');\n const { client } = useChatContext('ChannelHeaderSubtitle');\n const { typing = {} } = useTypingContext('ChannelHeaderSubtitle');\n const onlineStatusText = useChannelHeaderOnlineStatus();\n const typingInChannel = Object.values(typing).filter(\n ({ parent_id, user }) => user?.id !== client.user?.id && !parent_id,\n );\n const hasTyping = channelConfig?.typing_events !== false && typingInChannel.length > 0;\n\n if (!hasTyping && !onlineStatusText) return null;\n\n return (\n <div className='str-chat__channel-header__data__subtitle'>\n <span\n className='str-chat__subtitle-content-transition'\n key={hasTyping ? 'typing' : 'default'}\n >\n {hasTyping ? <TypingIndicatorHeader /> : onlineStatusText}\n </span>\n </div>\n );\n};\n\nexport type ChannelHeaderProps = {\n /** UI component to display an avatar, defaults to [Avatar](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Avatar/Avatar.tsx) component and accepts the same props as: [ChannelAvatar](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Avatar/ChannelAvatar.tsx) */\n Avatar?: React.ComponentType<ChannelAvatarProps>;\n /** Manually set the image to render, defaults to the Channel image */\n image?: string;\n /** Set title manually */\n title?: string;\n};\n\n/**\n * The ChannelHeader component renders some basic information about a Channel.\n */\nexport const ChannelHeader = (props: ChannelHeaderProps) => {\n const { Avatar = DefaultAvatar, image: overrideImage, title: overrideTitle } = props;\n\n const { channel } = useChannelStateContext();\n const { HeaderStartContent } = useComponentContext();\n const { displayImage, displayTitle, groupChannelDisplayInfo } = useChannelPreviewInfo({\n channel,\n overrideImage,\n overrideTitle,\n });\n\n return (\n <div className='str-chat__channel-header'>\n <div className='str-chat__channel-header__start'>\n {HeaderStartContent && <HeaderStartContent />}\n </div>\n <div className='str-chat__channel-header__data'>\n <div className='str-chat__channel-header__data__title'>{displayTitle}</div>\n <ChannelHeaderSubtitle />\n </div>\n <div className='str-chat__channel-header__end'>\n <Avatar\n className='str-chat__avatar--channel-header'\n displayMembers={groupChannelDisplayInfo?.members}\n imageUrl={displayImage}\n size='lg'\n userName={displayTitle}\n />\n </div>\n </div>\n );\n};\n","import type { ComponentPropsWithoutRef, ReactNode } from 'react';\nimport React, { useEffect, useRef } from 'react';\n\n/**\n * `SkipNavigation` is an opt-in skip links helper for integrators and is not rendered by `Chat`.\n *\n * Intended integration:\n * - Render as the first keyboard-focusable element in your chat layout.\n * - Pass `targetIds` ordered by keyboard priority (for example message composer first).\n * - Each value must be a DOM id (without `#`) so links keep native hash navigation semantics.\n *\n * Activation behavior:\n * - Renders one link per target id.\n * - Keeps native hash-link behavior via `href=\"#{targetId}\"`.\n * - Programmatically moves focus to each target element for reliable keyboard navigation.\n * - If the target is not naturally focusable, temporarily applies `tabindex=\"-1\"` and\n * removes it on blur.\n *\n * The caller can intercept activation by passing `onClick` and calling `event.preventDefault()`.\n *\n * @example\n * ```tsx\n * <SkipNavigation\n * getLinkLabel={(targetId) =>\n * targetId === 'my-message-composer-textarea'\n * ? 'Skip to message composer'\n * : 'Skip to channel messages'\n * }\n * targetIds={['my-message-composer-textarea', 'my-channel-root']}\n * />\n * ```\n */\nexport type SkipNavigationProps = Omit<ComponentPropsWithoutRef<'a'>, 'href'> & {\n /** Optional per-link label generator. Defaults to `Skip to {targetId}`. */\n getLinkLabel?: (targetId: string, index: number) => ReactNode;\n /** Ordered DOM ids of elements that should receive focus when links are activated. */\n targetIds: string[];\n};\n\nconst normalizeTargetId = (targetId: string) =>\n targetId.startsWith('#') ? targetId.slice(1) : targetId;\nconst isActivationKey = (event: React.KeyboardEvent<HTMLAnchorElement>) =>\n event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar';\n\ntype FocusCleanupState = {\n cleanup: () => void;\n hasTemporaryTabIndex: boolean;\n};\n\nconst focusTargetElement = (\n targetId: string,\n focusCleanupRegistry: React.MutableRefObject<Map<HTMLElement, FocusCleanupState>>,\n) => {\n const targetElement = document.getElementById(targetId);\n if (!targetElement) return;\n\n const hasTabIndexAttribute = targetElement.hasAttribute('tabindex');\n if (!hasTabIndexAttribute) {\n targetElement.setAttribute('tabindex', '-1');\n }\n\n targetElement.focus();\n\n if (!hasTabIndexAttribute) {\n const existingFocusCleanup = focusCleanupRegistry.current.get(targetElement);\n if (existingFocusCleanup) {\n existingFocusCleanup.cleanup();\n }\n\n const handleBlur = () => {\n targetElement.removeAttribute('tabindex');\n focusCleanupRegistry.current.delete(targetElement);\n };\n\n targetElement.addEventListener('blur', handleBlur, { once: true });\n\n focusCleanupRegistry.current.set(targetElement, {\n cleanup: () => targetElement.removeEventListener('blur', handleBlur),\n hasTemporaryTabIndex: true,\n });\n }\n};\n\nexport const SkipNavigation = ({\n className,\n getLinkLabel,\n onClick,\n onKeyDown,\n targetIds,\n ...anchorProps\n}: SkipNavigationProps) => {\n const focusCleanupRegistry = useRef<Map<HTMLElement, FocusCleanupState>>(new Map());\n\n useEffect(\n () => () => {\n focusCleanupRegistry.current.forEach(\n ({ cleanup, hasTemporaryTabIndex }, targetElement) => {\n cleanup();\n if (hasTemporaryTabIndex && targetElement.getAttribute('tabindex') === '-1') {\n targetElement.removeAttribute('tabindex');\n }\n },\n );\n\n focusCleanupRegistry.current.clear();\n },\n [],\n );\n\n if (!targetIds.length) return null;\n\n const handleClick = (event: React.MouseEvent<HTMLAnchorElement>, targetId: string) => {\n onClick?.(event);\n if (event.defaultPrevented) return;\n\n event.preventDefault();\n focusTargetElement(targetId, focusCleanupRegistry);\n };\n const handleKeyDown = (\n event: React.KeyboardEvent<HTMLAnchorElement>,\n targetId: string,\n ) => {\n onKeyDown?.(event);\n if (event.defaultPrevented || !isActivationKey(event)) return;\n\n event.preventDefault();\n focusTargetElement(targetId, focusCleanupRegistry);\n };\n\n return (\n <>\n {targetIds.map((targetId, index) => {\n const normalizedTargetId = normalizeTargetId(targetId);\n const linkLabel =\n getLinkLabel?.(normalizedTargetId, index) ?? `Skip to ${normalizedTargetId}`;\n\n return (\n <a\n {...anchorProps}\n className={['str-chat__skip-navigation-link', className]\n .filter(Boolean)\n .join(' ')}\n href={`#${normalizedTargetId}`}\n key={`${normalizedTargetId}-${index}`}\n onClick={(event) => handleClick(event, normalizedTargetId)}\n onKeyDown={(event) => handleKeyDown(event, normalizedTargetId)}\n >\n {linkLabel}\n </a>\n );\n })}\n </>\n );\n};\n","import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport type { TranslationContextValue } from '../../../context/TranslationContext';\nimport type { SupportedTranslations } from '../../../i18n';\nimport {\n defaultDateTimeParser,\n defaultTranslatorFunction,\n isLanguageSupported,\n Streami18n,\n} from '../../../i18n';\n\nimport type {\n AppSettingsAPIResponse,\n Channel,\n Event,\n Mute,\n OwnUserResponse,\n StreamChat,\n} from 'stream-chat';\n\nexport type UseChatParams = {\n client: StreamChat;\n defaultLanguage?: SupportedTranslations;\n i18nInstance?: Streami18n;\n};\n\nexport const useChat = ({\n client,\n defaultLanguage = 'en',\n i18nInstance,\n}: UseChatParams) => {\n const [translators, setTranslators] = useState<TranslationContextValue>({\n t: defaultTranslatorFunction,\n tDateTimeParser: defaultDateTimeParser,\n userLanguage: 'en',\n });\n\n const [channel, setChannel] = useState<Channel>();\n const [mutes, setMutes] = useState<Array<Mute>>([]);\n const [latestMessageDatesByChannels, setLatestMessageDatesByChannels] = useState({});\n\n const clientMutes = (client.user as OwnUserResponse)?.mutes ?? [];\n\n const appSettings = useRef<Promise<AppSettingsAPIResponse> | null>(null);\n\n const getAppSettings = () => {\n if (appSettings.current) {\n return appSettings.current;\n }\n appSettings.current = client.getAppSettings();\n return appSettings.current;\n };\n\n useEffect(() => {\n if (!client) return;\n\n const version = process.env.STREAM_CHAT_REACT_VERSION;\n\n const userAgent = client.getUserAgent();\n if (!userAgent.includes('stream-chat-react')) {\n // result looks like: 'stream-chat-react-2.3.2-stream-chat-javascript-client-browser-2.2.2'\n // the upper-case text between double underscores is replaced with the actual semantic version of the library\n client.setUserAgent(`stream-chat-react-${version}-${userAgent}`);\n }\n\n client.threads.registerSubscriptions();\n client.polls.registerSubscriptions();\n client.reminders.registerSubscriptions();\n client.reminders.initTimers();\n\n return () => {\n client.threads.unregisterSubscriptions();\n client.polls.unregisterSubscriptions();\n client.reminders.unregisterSubscriptions();\n client.reminders.clearTimers();\n };\n }, [client]);\n\n useEffect(() => {\n setMutes(clientMutes);\n\n const handleEvent = (event: Event) => {\n setMutes(event.me?.mutes || []);\n };\n\n client.on('notification.mutes_updated', handleEvent);\n return () => client.off('notification.mutes_updated', handleEvent);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [clientMutes?.length]);\n\n useEffect(() => {\n let userLanguage = client.user?.language;\n\n if (!userLanguage) {\n const browserLanguage = window.navigator.language.slice(0, 2); // just get language code, not country-specific version\n userLanguage = isLanguageSupported(browserLanguage)\n ? browserLanguage\n : defaultLanguage;\n }\n\n const streami18n = i18nInstance || new Streami18n({ language: userLanguage });\n\n streami18n.registerSetLanguageCallback((t) =>\n setTranslators((prevTranslator) => ({ ...prevTranslator, t })),\n );\n\n streami18n.getTranslators().then((translator) => {\n setTranslators({\n ...translator,\n userLanguage: userLanguage || defaultLanguage,\n });\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [i18nInstance]);\n\n const setActiveChannel = useCallback(\n async (\n activeChannel?: Channel,\n watchers: { limit?: number; offset?: number } = {},\n event?: React.BaseSyntheticEvent,\n ) => {\n if (event && event.preventDefault) event.preventDefault();\n\n if (activeChannel && Object.keys(watchers).length) {\n await activeChannel.query({ watch: true, watchers });\n }\n\n setChannel(activeChannel);\n },\n [],\n );\n\n useEffect(() => {\n setLatestMessageDatesByChannels({});\n }, [client.user?.id]);\n\n return {\n channel,\n getAppSettings,\n latestMessageDatesByChannels,\n mutes,\n setActiveChannel,\n translators,\n };\n};\n","import { useEffect, useRef } from 'react';\n\nimport { useChatContext } from '../../../context/ChatContext';\nimport { useTranslationContext } from '../../../context/TranslationContext';\nimport { useNotificationApi } from '../../Notifications/hooks/useNotificationApi';\n\n/**\n * Publishes a persistent system notification while the client is offline and removes it when\n * back online. Must run under `ChatProvider` and `TranslationProvider` (e.g. from a child of `<Chat>`).\n */\nexport const useReportLostConnectionSystemNotification = () => {\n const { t } = useTranslationContext();\n const { client } = useChatContext();\n const { addSystemNotification, removeNotification } = useNotificationApi();\n const connectionLostNotificationIdRef = useRef<string | null>(null);\n\n useEffect(() => {\n if (!t || !client) return;\n\n const dismissConnectionLostNotification = () => {\n if (!connectionLostNotificationIdRef.current) return;\n removeNotification(connectionLostNotificationIdRef.current);\n connectionLostNotificationIdRef.current = null;\n };\n\n const handleConnectionChanged = ({ online }: { online?: boolean }) => {\n if (!online) {\n if (connectionLostNotificationIdRef.current) return;\n\n connectionLostNotificationIdRef.current = addSystemNotification({\n duration: 0,\n emitter: 'Chat',\n message: t('Waiting for network…'),\n severity: 'loading',\n type: 'system:network:connection:lost',\n });\n return;\n }\n\n dismissConnectionLostNotification();\n };\n\n client.on('connection.changed', handleConnectionChanged);\n\n return () => {\n client.off('connection.changed', handleConnectionChanged);\n dismissConnectionLostNotification();\n };\n }, [addSystemNotification, client, removeNotification, t]);\n};\n","import { useMemo } from 'react';\n\nimport type { ChatContextValue } from '../../../context/ChatContext';\n\nexport const useCreateChatContext = (value: ChatContextValue) => {\n const {\n channel,\n channelsQueryState,\n client,\n customClasses,\n getAppSettings,\n isMessageAIGenerated,\n latestMessageDatesByChannels,\n mutes,\n searchController,\n setActiveChannel,\n theme,\n useImageFlagEmojisOnWindows,\n } = value;\n\n const channelCid = channel?.cid;\n const channelsQueryError = channelsQueryState.error;\n const channelsQueryInProgress = channelsQueryState.queryInProgress;\n const clientValues = `${client.clientID}${Object.keys(client.activeChannels).length}${\n Object.keys(client.listeners).length\n }${client.mutedChannels.length}\n ${client.user?.id}`;\n const mutedUsersLength = mutes.length;\n\n const chatContext: ChatContextValue = useMemo(\n () => ({\n channel,\n channelsQueryState,\n client,\n customClasses,\n getAppSettings,\n isMessageAIGenerated,\n latestMessageDatesByChannels,\n mutes,\n searchController,\n setActiveChannel,\n theme,\n useImageFlagEmojisOnWindows,\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n channelCid,\n channelsQueryError,\n channelsQueryInProgress,\n clientValues,\n getAppSettings,\n searchController,\n mutedUsersLength,\n isMessageAIGenerated,\n ],\n );\n\n return chatContext;\n};\n","import type { Dispatch, SetStateAction } from 'react';\nimport { useState } from 'react';\nimport type { APIErrorResponse, ErrorFromResponse } from 'stream-chat';\n\ntype ChannelQueryState =\n | 'uninitialized' // the initial state before the first channels query is triggered\n | 'reload' // the initial channels query (loading the first page) is in progress\n | 'load-more' // loading the next page of channels\n | null; // at least one channels page has been loaded and there is no query in progress at the moment\n\nexport interface ChannelsQueryState {\n error: ErrorFromResponse<APIErrorResponse> | null;\n queryInProgress: ChannelQueryState;\n setError: Dispatch<SetStateAction<ErrorFromResponse<APIErrorResponse> | null>>;\n setQueryInProgress: Dispatch<SetStateAction<ChannelQueryState>>;\n}\n\nexport const useChannelsQueryState = (): ChannelsQueryState => {\n const [error, setError] = useState<ErrorFromResponse<APIErrorResponse> | null>(null);\n const [queryInProgress, setQueryInProgress] =\n useState<ChannelQueryState>('uninitialized');\n\n return {\n error,\n queryInProgress,\n setError,\n setQueryInProgress,\n };\n};\n","import type { PropsWithChildren } from 'react';\nimport React, { useMemo } from 'react';\nimport type { StreamChat } from 'stream-chat';\nimport {\n ChannelSearchSource,\n MessageSearchSource,\n SearchController,\n UserSearchSource,\n} from 'stream-chat';\n\nimport {\n AriaLiveAnnouncerProvider,\n AriaLiveOutlet,\n NotificationAnnouncer as DefaultNotificationAnnouncer,\n} from '../Accessibility';\nimport { useOpenedDialogCount } from '../Dialog';\nimport {\n getNotificationTargetPanels,\n NotificationConfigurationProvider,\n type NotificationDisplayFilter,\n} from '../Notifications';\nimport { useChat } from './hooks/useChat';\nimport { useReportLostConnectionSystemNotification } from './hooks/useReportLostConnectionSystemNotification';\nimport { useCreateChatContext } from './hooks/useCreateChatContext';\nimport { useChannelsQueryState } from './hooks/useChannelsQueryState';\nimport type { CustomClasses } from '../../context/ChatContext';\nimport { ChatProvider } from '../../context/ChatContext';\nimport { useComponentContext } from '../../context/ComponentContext';\nimport { TranslationProvider } from '../../context/TranslationContext';\nimport {\n type MessageContextValue,\n modalDialogManagerId,\n ModalDialogManagerProvider,\n} from '../../context';\nimport type { SupportedTranslations } from '../../i18n/types';\nimport type { Streami18n } from '../../i18n/Streami18n';\n\nconst NetworkConnectionNotificationReporter = () => {\n useReportLostConnectionSystemNotification();\n return null;\n};\n\nconst createDefaultNotificationDisplayFilter =\n (modalManagerHasOpenDialog: boolean): NotificationDisplayFilter =>\n ({ notification, panel }) => {\n const targetPanels = getNotificationTargetPanels(notification);\n\n if (targetPanels.includes('modal')) {\n // While a modal is open, keep modal-tagged notifications inside it (not behind it).\n if (modalManagerHasOpenDialog) return panel === 'modal';\n // The modal that emitted this notification has since closed — a common shape is a dialog that\n // closes optimistically and only then emits a confirmation (e.g. \"Poll sent\"). Its `modal`\n // NotificationList is already unmounted, so without a fallback the notification would be a\n // dead letter (announced by the aria-live announcer, but rendered nowhere). Fall back to its\n // other target panel(s): panel routing has already matched `panel` to one of the\n // notification's targets, so any non-`modal` panel reaching here is a valid home.\n return panel !== 'modal';\n }\n\n if (!modalManagerHasOpenDialog) return true;\n\n return panel === 'modal';\n };\n\nconst ModalNotificationConfiguration = ({\n children,\n notificationDisplayFilter,\n}: PropsWithChildren<{\n notificationDisplayFilter?: NotificationDisplayFilter;\n}>) => {\n const openedModalDialogCount = useOpenedDialogCount({\n dialogManagerId: modalDialogManagerId,\n });\n const modalManagerHasOpenDialog = openedModalDialogCount > 0;\n const displayFilter = useMemo<NotificationDisplayFilter>(\n () =>\n notificationDisplayFilter ??\n createDefaultNotificationDisplayFilter(modalManagerHasOpenDialog),\n [modalManagerHasOpenDialog, notificationDisplayFilter],\n );\n\n return (\n <NotificationConfigurationProvider displayFilter={displayFilter}>\n {children}\n </NotificationConfigurationProvider>\n );\n};\n\nexport type ChatProps = {\n /** The StreamChat client object */\n client: StreamChat;\n /** Object containing custom CSS classnames to override the library's default container CSS */\n customClasses?: CustomClasses;\n /** Sets the default fallback language for UI component translation, defaults to 'en' for English */\n defaultLanguage?: SupportedTranslations;\n /** Instance of Stream i18n */\n i18nInstance?: Streami18n;\n /** Instance of SearchController class that allows to control all the search operations. */\n searchController?: SearchController;\n /** Controls whether a notification can be displayed by a NotificationList. */\n notificationDisplayFilter?: NotificationDisplayFilter;\n /** Used for injecting className/s to the Channel and ChannelList components */\n theme?: string;\n /**\n * Windows 10 does not support country flag emojis out of the box. It chooses to render these emojis as characters instead. Stream\n * Chat can override this behavior by loading a custom web font that will render images instead (PNGs or SVGs depending on the platform).\n * Set this prop to true if you want to use these custom emojis for Windows users.\n *\n * Note: requires importing `stream-chat-react/css/v2/emoji-replacement.css` style sheet\n */\n useImageFlagEmojisOnWindows?: boolean;\n} & Partial<Pick<MessageContextValue, 'isMessageAIGenerated'>>;\n\n/**\n * Wrapper component for a StreamChat application. Chat needs to be placed around any other chat components\n * as it provides the ChatContext.\n */\nexport const Chat = (props: PropsWithChildren<ChatProps>) => {\n const {\n children,\n client,\n customClasses,\n defaultLanguage,\n i18nInstance,\n isMessageAIGenerated,\n notificationDisplayFilter,\n searchController: customChannelSearchController,\n theme = 'messaging light',\n useImageFlagEmojisOnWindows = false,\n } = props;\n\n const {\n channel,\n getAppSettings,\n latestMessageDatesByChannels,\n mutes,\n setActiveChannel,\n translators,\n } = useChat({\n client,\n defaultLanguage,\n i18nInstance,\n });\n\n const channelsQueryState = useChannelsQueryState();\n\n const searchController = useMemo(\n () =>\n customChannelSearchController ??\n new SearchController({\n sources: [\n new ChannelSearchSource(client),\n new UserSearchSource(client),\n new MessageSearchSource(client),\n ],\n }),\n [client, customChannelSearchController],\n );\n\n const chatContextValue = useCreateChatContext({\n channel,\n channelsQueryState,\n client,\n customClasses,\n getAppSettings,\n isMessageAIGenerated,\n latestMessageDatesByChannels,\n mutes,\n searchController,\n setActiveChannel,\n theme,\n useImageFlagEmojisOnWindows,\n });\n const { NotificationAnnouncer = DefaultNotificationAnnouncer } = useComponentContext();\n\n if (!translators.t) return null;\n\n return (\n <ChatProvider value={chatContextValue}>\n <TranslationProvider value={translators}>\n <AriaLiveAnnouncerProvider>\n <ModalDialogManagerProvider>\n <ModalNotificationConfiguration\n notificationDisplayFilter={notificationDisplayFilter}\n >\n <NetworkConnectionNotificationReporter />\n <NotificationAnnouncer />\n {children}\n <AriaLiveOutlet portal />\n </ModalNotificationConfiguration>\n </ModalDialogManagerProvider>\n </AriaLiveAnnouncerProvider>\n </TranslationProvider>\n </ChatProvider>\n );\n};\n","import { useEffect, useState } from 'react';\n\nimport { StreamChat } from 'stream-chat';\n\nimport type {\n OwnUserResponse,\n StreamChatOptions,\n TokenOrProvider,\n UserResponse,\n} from 'stream-chat';\n\n/**\n * React hook to create, connect and return `StreamChat` client.\n */\nexport const useCreateChatClient = ({\n apiKey,\n options,\n tokenOrProvider,\n userData,\n}: {\n apiKey: string;\n tokenOrProvider: TokenOrProvider;\n userData: OwnUserResponse | UserResponse;\n options?: StreamChatOptions;\n}) => {\n const [chatClient, setChatClient] = useState<StreamChat | null>(null);\n const [cachedUserData, setCachedUserData] = useState(userData);\n\n if (userData.id !== cachedUserData.id) {\n setCachedUserData(userData);\n }\n\n const [cachedOptions] = useState(options);\n\n useEffect(() => {\n const client = new StreamChat(apiKey, undefined, cachedOptions);\n let didUserConnectInterrupt = false;\n\n const connectionPromise = client\n .connectUser(cachedUserData, tokenOrProvider)\n .then(() => {\n if (!didUserConnectInterrupt) setChatClient(client);\n });\n\n return () => {\n didUserConnectInterrupt = true;\n setChatClient(null);\n connectionPromise\n .then(() => client.disconnectUser())\n .then(() => {\n console.log(`Connection for user \"${cachedUserData.id}\" has been closed`);\n });\n };\n }, [apiKey, cachedUserData, cachedOptions, tokenOrProvider]);\n\n return chatClient;\n};\n","import type { PropsWithChildren } from 'react';\nimport React from 'react';\nimport clsx from 'clsx';\n\nimport type { LocalMessage } from 'stream-chat';\nimport { useChannelStateContext } from '../../context/ChannelStateContext';\n\nexport type WindowProps = {\n /** optional prop to force addition of class str-chat__main-panel---with-thread-opn to the Window root element */\n thread?: LocalMessage;\n};\n\nconst UnMemoizedWindow = (props: PropsWithChildren<WindowProps>) => {\n const { children, thread: propThread } = props;\n\n const { thread: contextThread } = useChannelStateContext('Window');\n\n return (\n <div\n className={clsx('str-chat__main-panel', {\n 'str-chat__main-panel--thread-open': contextThread || propThread,\n })}\n >\n {children}\n </div>\n );\n};\n\n/**\n * A UI component for conditionally displaying a Thread or Channel\n */\nexport const Window = React.memo(UnMemoizedWindow) as typeof UnMemoizedWindow;\n"],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}