stream-chat-react 12.0.0-rc.1 → 12.0.0-rc.11

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 (218) hide show
  1. package/README.md +11 -1
  2. package/dist/components/Attachment/components/WaveProgressBar.d.ts +3 -1
  3. package/dist/components/Attachment/components/WaveProgressBar.js +44 -9
  4. package/dist/components/Avatar/Avatar.js +5 -1
  5. package/dist/components/Channel/Channel.d.ts +3 -4
  6. package/dist/components/Channel/Channel.js +95 -56
  7. package/dist/components/Channel/channelState.js +1 -0
  8. package/dist/components/Channel/hooks/useCreateChannelStateContext.js +1 -1
  9. package/dist/components/ChannelList/ChannelList.js +1 -1
  10. package/dist/components/Chat/Chat.d.ts +1 -1
  11. package/dist/components/Chat/hooks/useChat.d.ts +2 -2
  12. package/dist/components/Chat/hooks/useChat.js +11 -8
  13. package/dist/components/Chat/hooks/useCreateChatClient.d.ts +4 -2
  14. package/dist/components/Chat/hooks/useCreateChatClient.js +5 -4
  15. package/dist/components/ChatView/ChatView.d.ts +18 -0
  16. package/dist/components/ChatView/ChatView.js +100 -0
  17. package/dist/components/ChatView/index.d.ts +1 -0
  18. package/dist/components/ChatView/index.js +1 -0
  19. package/dist/components/DateSeparator/DateSeparator.d.ts +1 -1
  20. package/dist/components/DateSeparator/DateSeparator.js +1 -1
  21. package/dist/components/EventComponent/EventComponent.d.ts +1 -1
  22. package/dist/components/EventComponent/EventComponent.js +1 -1
  23. package/dist/components/InfiniteScrollPaginator/InfiniteScroll.js +9 -3
  24. package/dist/components/MediaRecorder/AudioRecorder/AudioRecordingInProgress.js +3 -0
  25. package/dist/components/MediaRecorder/classes/MediaRecorderController.d.ts +6 -7
  26. package/dist/components/MediaRecorder/classes/MediaRecorderController.js +0 -5
  27. package/dist/components/MediaRecorder/hooks/index.d.ts +1 -1
  28. package/dist/components/MediaRecorder/hooks/useMediaRecorder.d.ts +1 -2
  29. package/dist/components/MediaRecorder/hooks/useMediaRecorder.js +1 -1
  30. package/dist/components/MediaRecorder/index.d.ts +1 -0
  31. package/dist/components/MediaRecorder/transcode/index.d.ts +6 -5
  32. package/dist/components/MediaRecorder/transcode/index.js +5 -15
  33. package/dist/components/Message/Message.js +2 -1
  34. package/dist/components/Message/MessageOptions.js +3 -4
  35. package/dist/components/Message/MessageSimple.js +3 -2
  36. package/dist/components/Message/MessageStatus.js +3 -2
  37. package/dist/components/Message/MessageTimestamp.d.ts +1 -2
  38. package/dist/components/Message/MessageTimestamp.js +0 -1
  39. package/dist/components/Message/QuotedMessage.js +2 -1
  40. package/dist/components/Message/Timestamp.d.ts +1 -2
  41. package/dist/components/Message/Timestamp.js +4 -5
  42. package/dist/components/Message/hooks/useReactionHandler.js +7 -0
  43. package/dist/components/Message/renderText/rehypePlugins/mentionsMarkdownPlugin.d.ts +1 -1
  44. package/dist/components/Message/renderText/remarkPlugins/htmlToTextPlugin.d.ts +1 -1
  45. package/dist/components/Message/renderText/remarkPlugins/keepLineBreaksPlugin.d.ts +1 -1
  46. package/dist/components/Message/renderText/remarkPlugins/keepLineBreaksPlugin.js +2 -6
  47. package/dist/components/Message/renderText/renderText.d.ts +2 -2
  48. package/dist/components/Message/renderText/renderText.js +8 -6
  49. package/dist/components/Message/utils.d.ts +10 -1
  50. package/dist/components/Message/utils.js +18 -7
  51. package/dist/components/MessageActions/MessageActions.js +14 -9
  52. package/dist/components/MessageInput/AttachmentPreviewList/AttachmentPreviewList.js +23 -27
  53. package/dist/components/MessageInput/AttachmentPreviewList/FileAttachmentPreview.d.ts +1 -0
  54. package/dist/components/MessageInput/AttachmentPreviewList/FileAttachmentPreview.js +1 -1
  55. package/dist/components/MessageInput/AttachmentPreviewList/ImageAttachmentPreview.js +2 -1
  56. package/dist/components/MessageInput/MessageInput.d.ts +4 -6
  57. package/dist/components/MessageInput/MessageInputFlat.js +5 -8
  58. package/dist/components/MessageInput/QuotedMessagePreview.js +2 -1
  59. package/dist/components/MessageInput/hooks/useAttachments.d.ts +1 -5
  60. package/dist/components/MessageInput/hooks/useAttachments.js +65 -52
  61. package/dist/components/MessageInput/hooks/useCreateMessageInputContext.js +2 -19
  62. package/dist/components/MessageInput/hooks/useMessageInputState.d.ts +2 -35
  63. package/dist/components/MessageInput/hooks/useMessageInputState.js +2 -107
  64. package/dist/components/MessageInput/hooks/usePasteHandler.js +1 -3
  65. package/dist/components/MessageInput/hooks/useSubmitHandler.js +19 -71
  66. package/dist/components/MessageInput/hooks/useTimeElapsed.js +5 -4
  67. package/dist/components/MessageInput/hooks/utils.d.ts +1 -2
  68. package/dist/components/MessageInput/icons.d.ts +0 -1
  69. package/dist/components/MessageInput/icons.js +0 -3
  70. package/dist/components/MessageInput/types.d.ts +3 -30
  71. package/dist/components/MessageList/MessageList.d.ts +3 -1
  72. package/dist/components/MessageList/MessageList.js +3 -4
  73. package/dist/components/MessageList/VirtualizedMessageList.d.ts +5 -2
  74. package/dist/components/MessageList/VirtualizedMessageList.js +8 -5
  75. package/dist/components/MessageList/VirtualizedMessageListComponents.d.ts +1 -1
  76. package/dist/components/MessageList/VirtualizedMessageListComponents.js +7 -6
  77. package/dist/components/MessageList/hooks/MessageList/useEnrichedMessages.d.ts +2 -1
  78. package/dist/components/MessageList/hooks/MessageList/useEnrichedMessages.js +3 -3
  79. package/dist/components/MessageList/renderMessages.d.ts +2 -2
  80. package/dist/components/MessageList/renderMessages.js +4 -1
  81. package/dist/components/MessageList/utils.d.ts +1 -1
  82. package/dist/components/MessageList/utils.js +17 -7
  83. package/dist/components/ReactFileUtilities/types.d.ts +0 -29
  84. package/dist/components/ReactFileUtilities/utils.d.ts +2 -0
  85. package/dist/components/ReactFileUtilities/utils.js +2 -0
  86. package/dist/components/Reactions/ReactionSelector.d.ts +5 -2
  87. package/dist/components/Reactions/ReactionSelector.js +2 -1
  88. package/dist/components/Reactions/ReactionsList.d.ts +4 -1
  89. package/dist/components/Reactions/hooks/useProcessReactions.js +2 -1
  90. package/dist/components/Thread/Thread.d.ts +0 -2
  91. package/dist/components/Thread/Thread.js +38 -12
  92. package/dist/components/Threads/ThreadContext.d.ts +9 -0
  93. package/dist/components/Threads/ThreadContext.js +9 -0
  94. package/dist/components/Threads/ThreadList/ThreadList.d.ts +9 -0
  95. package/dist/components/Threads/ThreadList/ThreadList.js +41 -0
  96. package/dist/components/Threads/ThreadList/ThreadListEmptyPlaceholder.d.ts +2 -0
  97. package/dist/components/Threads/ThreadList/ThreadListEmptyPlaceholder.js +5 -0
  98. package/dist/components/Threads/ThreadList/ThreadListItem.d.ts +9 -0
  99. package/dist/components/Threads/ThreadList/ThreadListItem.js +52 -0
  100. package/dist/components/Threads/ThreadList/ThreadListItemUI.d.ts +18 -0
  101. package/dist/components/Threads/ThreadList/ThreadListItemUI.js +76 -0
  102. package/dist/components/Threads/ThreadList/ThreadListLoadingIndicator.d.ts +2 -0
  103. package/dist/components/Threads/ThreadList/ThreadListLoadingIndicator.js +14 -0
  104. package/dist/components/Threads/ThreadList/ThreadListUnseenThreadsBanner.d.ts +2 -0
  105. package/dist/components/Threads/ThreadList/ThreadListUnseenThreadsBanner.js +16 -0
  106. package/dist/components/Threads/ThreadList/index.d.ts +3 -0
  107. package/dist/components/Threads/ThreadList/index.js +3 -0
  108. package/dist/components/Threads/UnreadCountBadge.d.ts +6 -0
  109. package/dist/components/Threads/UnreadCountBadge.js +5 -0
  110. package/dist/components/Threads/hooks/useStateStore.d.ts +3 -0
  111. package/dist/components/Threads/hooks/useStateStore.js +15 -0
  112. package/dist/components/Threads/hooks/useThreadManagerState.d.ts +2 -0
  113. package/dist/components/Threads/hooks/useThreadManagerState.js +6 -0
  114. package/dist/components/Threads/hooks/useThreadState.d.ts +5 -0
  115. package/dist/components/Threads/hooks/useThreadState.js +11 -0
  116. package/dist/components/Threads/icons.d.ts +8 -0
  117. package/dist/components/Threads/icons.js +13 -0
  118. package/dist/components/Threads/index.d.ts +3 -0
  119. package/dist/components/Threads/index.js +3 -0
  120. package/dist/components/UtilityComponents/ErrorBoundary.d.ts +16 -0
  121. package/dist/components/UtilityComponents/ErrorBoundary.js +19 -0
  122. package/dist/components/UtilityComponents/index.d.ts +1 -0
  123. package/dist/components/UtilityComponents/index.js +1 -0
  124. package/dist/components/Window/Window.d.ts +1 -3
  125. package/dist/components/Window/Window.js +2 -2
  126. package/dist/components/index.d.ts +2 -0
  127. package/dist/components/index.js +2 -0
  128. package/dist/context/ChannelActionContext.d.ts +2 -2
  129. package/dist/context/ComponentContext.d.ts +15 -40
  130. package/dist/context/ComponentContext.js +7 -9
  131. package/dist/context/MessageContext.d.ts +1 -1
  132. package/dist/context/MessageContext.js +3 -2
  133. package/dist/context/MessageInputContext.d.ts +1 -5
  134. package/dist/context/TranslationContext.d.ts +1 -11
  135. package/dist/context/TranslationContext.js +1 -9
  136. package/dist/context/WithComponents.d.ts +5 -0
  137. package/dist/context/WithComponents.js +7 -0
  138. package/dist/context/index.d.ts +1 -0
  139. package/dist/context/index.js +1 -0
  140. package/dist/css/v2/emoji-replacement.css +1 -1
  141. package/dist/css/v2/index.css +2 -2
  142. package/dist/css/v2/index.layout.css +2 -2
  143. package/dist/i18n/Streami18n.d.ts +3 -3
  144. package/dist/i18n/Streami18n.js +1 -2
  145. package/dist/i18n/de.json +3 -1
  146. package/dist/i18n/en.json +3 -1
  147. package/dist/i18n/es.json +3 -1
  148. package/dist/i18n/fr.json +3 -1
  149. package/dist/i18n/hi.json +3 -1
  150. package/dist/i18n/index.d.ts +2 -1
  151. package/dist/i18n/index.js +2 -0
  152. package/dist/i18n/it.json +3 -1
  153. package/dist/i18n/ja.json +3 -1
  154. package/dist/i18n/ko.json +3 -1
  155. package/dist/i18n/nl.json +3 -1
  156. package/dist/i18n/pt.json +3 -1
  157. package/dist/i18n/ru.json +3 -1
  158. package/dist/i18n/tr.json +3 -1
  159. package/dist/i18n/types.d.ts +26 -0
  160. package/dist/i18n/types.js +1 -0
  161. package/dist/i18n/utils.d.ts +9 -20
  162. package/dist/i18n/utils.js +10 -1
  163. package/dist/index.browser.cjs +47726 -0
  164. package/dist/index.browser.cjs.map +7 -0
  165. package/dist/{index.cjs.js → index.node.cjs} +21289 -32183
  166. package/dist/index.node.cjs.map +7 -0
  167. package/dist/{components → plugins}/Emojis/EmojiPicker.js +1 -1
  168. package/dist/plugins/Emojis/icons.d.ts +2 -0
  169. package/dist/plugins/Emojis/icons.js +4 -0
  170. package/dist/plugins/Emojis/index.browser.cjs +167 -0
  171. package/dist/plugins/Emojis/index.browser.cjs.map +7 -0
  172. package/dist/plugins/Emojis/index.d.ts +2 -0
  173. package/dist/plugins/Emojis/index.js +2 -0
  174. package/dist/{components/Emojis/index.cjs.js → plugins/Emojis/index.node.cjs} +31 -192
  175. package/dist/plugins/Emojis/index.node.cjs.map +7 -0
  176. package/dist/plugins/encoders/mp3.browser.cjs +105 -0
  177. package/dist/plugins/encoders/mp3.browser.cjs.map +7 -0
  178. package/dist/{components/MediaRecorder/transcode → plugins/encoders}/mp3.js +3 -3
  179. package/dist/plugins/encoders/mp3.node.cjs +109 -0
  180. package/dist/plugins/encoders/mp3.node.cjs.map +7 -0
  181. package/dist/scss/v2/Autocomplete/Autocomplete-layout.scss +1 -1
  182. package/dist/scss/v2/Autocomplete/Autocomplete-theme.scss +4 -2
  183. package/dist/scss/v2/Avatar/Avatar-layout.scss +38 -22
  184. package/dist/scss/v2/Avatar/Avatar-theme.scss +5 -0
  185. package/dist/scss/v2/Channel/Channel-layout.scss +0 -4
  186. package/dist/scss/v2/ChannelList/ChannelList-layout.scss +0 -5
  187. package/dist/scss/v2/ChannelSearch/ChannelSearch-layout.scss +1 -0
  188. package/dist/scss/v2/ChatView/ChatView-layout.scss +43 -0
  189. package/dist/scss/v2/ChatView/ChatView-theme.scss +31 -0
  190. package/dist/scss/v2/EditMessageForm/EditMessageForm-theme.scss +9 -9
  191. package/dist/scss/v2/LoadingIndicator/LoadingIndicator-layout.scss +16 -0
  192. package/dist/scss/v2/Message/Message-layout.scss +39 -6
  193. package/dist/scss/v2/MessageList/MessageList-layout.scss +0 -6
  194. package/dist/scss/v2/MessageList/VirtualizedMessageList-layout.scss +0 -12
  195. package/dist/scss/v2/MessageReactions/MessageReactionsSelector-layout.scss +18 -0
  196. package/dist/scss/v2/MessageReactions/MessageReactionsSelector-theme.scss +5 -0
  197. package/dist/scss/v2/Thread/Thread-layout.scss +13 -4
  198. package/dist/scss/v2/ThreadList/ThreadList-layout.scss +149 -0
  199. package/dist/scss/v2/ThreadList/ThreadList-theme.scss +73 -0
  200. package/dist/scss/v2/UnreadCountBadge/UnreadCountBadge-layout.scss +49 -0
  201. package/dist/scss/v2/UnreadCountBadge/UnreadCountBadge-theme.scss +10 -0
  202. package/dist/scss/v2/_base.scss +1 -0
  203. package/dist/scss/v2/_emoji-replacement.scss +4 -2
  204. package/dist/scss/v2/index.layout.scss +3 -0
  205. package/dist/scss/v2/index.scss +3 -0
  206. package/package.json +51 -19
  207. package/dist/components/Emojis/index.cjs.js.map +0 -7
  208. package/dist/components/Emojis/index.d.ts +0 -1
  209. package/dist/components/Emojis/index.js +0 -1
  210. package/dist/components/MessageInput/AttachmentPreviewList/UploadPreviewItem.d.ts +0 -11
  211. package/dist/components/MessageInput/AttachmentPreviewList/UploadPreviewItem.js +0 -51
  212. package/dist/components/MessageInput/hooks/useFileUploads.d.ts +0 -7
  213. package/dist/components/MessageInput/hooks/useFileUploads.js +0 -85
  214. package/dist/components/MessageInput/hooks/useImageUploads.d.ts +0 -8
  215. package/dist/components/MessageInput/hooks/useImageUploads.js +0 -94
  216. package/dist/index.cjs.js.map +0 -7
  217. /package/dist/{components → plugins}/Emojis/EmojiPicker.d.ts +0 -0
  218. /package/dist/{components/MediaRecorder/transcode → plugins/encoders}/mp3.d.ts +0 -0
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import type { PropsWithChildren } from 'react';
3
+ import type { Thread } from 'stream-chat';
4
+ export declare const ChatView: {
5
+ ({ children }: PropsWithChildren): React.JSX.Element;
6
+ Channels: ({ children }: PropsWithChildren) => React.JSX.Element | null;
7
+ Threads: ({ children }: PropsWithChildren) => React.JSX.Element | null;
8
+ ThreadAdapter: ({ children }: PropsWithChildren) => React.JSX.Element;
9
+ Selector: () => React.JSX.Element;
10
+ };
11
+ export type ThreadsViewContextValue = {
12
+ activeThread: Thread | undefined;
13
+ setActiveThread: (cv: ThreadsViewContextValue['activeThread']) => void;
14
+ };
15
+ export declare const useThreadsViewContext: () => ThreadsViewContextValue;
16
+ export declare const useActiveThread: ({ activeThread }: {
17
+ activeThread?: Thread;
18
+ }) => void;
@@ -0,0 +1,100 @@
1
+ import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
2
+ import { ThreadProvider, useStateStore } from '../Threads';
3
+ import { Icon } from '../Threads/icons';
4
+ import { UnreadCountBadge } from '../Threads/UnreadCountBadge';
5
+ import { useChatContext } from '../../context';
6
+ const availableChatViews = ['channels', 'threads'];
7
+ const ChatViewContext = createContext({
8
+ activeChatView: 'channels',
9
+ setActiveChatView: () => undefined,
10
+ });
11
+ export const ChatView = ({ children }) => {
12
+ const [activeChatView, setActiveChatView] = useState('channels');
13
+ const value = useMemo(() => ({ activeChatView, setActiveChatView }), [activeChatView]);
14
+ return (React.createElement(ChatViewContext.Provider, { value: value },
15
+ React.createElement("div", { className: 'str-chat str-chat__chat-view' }, children)));
16
+ };
17
+ const ChannelsView = ({ children }) => {
18
+ const { activeChatView } = useContext(ChatViewContext);
19
+ if (activeChatView !== 'channels')
20
+ return null;
21
+ return React.createElement("div", { className: 'str-chat__chat-view__channels' }, children);
22
+ };
23
+ const ThreadsViewContext = createContext({
24
+ activeThread: undefined,
25
+ setActiveThread: () => undefined,
26
+ });
27
+ export const useThreadsViewContext = () => useContext(ThreadsViewContext);
28
+ const ThreadsView = ({ children }) => {
29
+ const { activeChatView } = useContext(ChatViewContext);
30
+ const [activeThread, setActiveThread] = useState(undefined);
31
+ const value = useMemo(() => ({ activeThread, setActiveThread }), [activeThread]);
32
+ if (activeChatView !== 'threads')
33
+ return null;
34
+ return (React.createElement(ThreadsViewContext.Provider, { value: value },
35
+ React.createElement("div", { className: 'str-chat__chat-view__threads' }, children)));
36
+ };
37
+ // thread business logic that's impossible to keep within client but encapsulated for ease of use
38
+ export const useActiveThread = ({ activeThread }) => {
39
+ useEffect(() => {
40
+ if (!activeThread)
41
+ return;
42
+ const handleVisibilityChange = () => {
43
+ if (document.visibilityState === 'visible' && document.hasFocus()) {
44
+ activeThread.activate();
45
+ }
46
+ if (document.visibilityState === 'hidden' || !document.hasFocus()) {
47
+ activeThread.deactivate();
48
+ }
49
+ };
50
+ handleVisibilityChange();
51
+ window.addEventListener('focus', handleVisibilityChange);
52
+ window.addEventListener('blur', handleVisibilityChange);
53
+ return () => {
54
+ activeThread.deactivate();
55
+ window.addEventListener('blur', handleVisibilityChange);
56
+ window.removeEventListener('focus', handleVisibilityChange);
57
+ };
58
+ }, [activeThread]);
59
+ };
60
+ // ThreadList under View.Threads context, will access setting function and on item click will set activeThread
61
+ // which can be accessed for the ease of use by ThreadAdapter which forwards it to required ThreadProvider
62
+ // ThreadList can easily live without this context and click handler can be overriden, ThreadAdapter is then no longer needed
63
+ /**
64
+ * // this setup still works
65
+ * const MyCustomComponent = () => {
66
+ * const [activeThread, setActiveThread] = useState();
67
+ *
68
+ * return <>
69
+ * // simplified
70
+ * <ThreadList onItemPointerDown={setActiveThread} />
71
+ * <ThreadProvider thread={activeThread}>
72
+ * <Thread />
73
+ * </ThreadProvider>
74
+ * </>
75
+ * }
76
+ *
77
+ */
78
+ const ThreadAdapter = ({ children }) => {
79
+ const { activeThread } = useThreadsViewContext();
80
+ useActiveThread({ activeThread });
81
+ return React.createElement(ThreadProvider, { thread: activeThread }, children);
82
+ };
83
+ const selector = (nextValue) => [nextValue.unreadThreadCount];
84
+ const ChatViewSelector = () => {
85
+ const { client } = useChatContext();
86
+ const [unreadThreadCount] = useStateStore(client.threads.state, selector);
87
+ const { activeChatView, setActiveChatView } = useContext(ChatViewContext);
88
+ return (React.createElement("div", { className: 'str-chat__chat-view__selector' },
89
+ React.createElement("button", { "aria-selected": activeChatView === 'channels', className: 'str-chat__chat-view__selector-button', onPointerDown: () => setActiveChatView('channels'), role: 'tab' },
90
+ React.createElement(Icon.MessageBubbleEmpty, null),
91
+ React.createElement("div", { className: 'str-chat__chat-view__selector-button-text' }, "Channels")),
92
+ React.createElement("button", { "aria-selected": activeChatView === 'threads', className: 'str-chat__chat-view__selector-button', onPointerDown: () => setActiveChatView('threads'), role: 'tab' },
93
+ React.createElement(UnreadCountBadge, { count: unreadThreadCount, position: 'top-right' },
94
+ React.createElement(Icon.MessageBubble, null)),
95
+ React.createElement("div", { className: 'str-chat__chat-view__selector-button-text' }, "Threads"))));
96
+ };
97
+ ChatView.Channels = ChannelsView;
98
+ ChatView.Threads = ThreadsView;
99
+ ChatView.ThreadAdapter = ThreadAdapter;
100
+ ChatView.Selector = ChatViewSelector;
@@ -0,0 +1 @@
1
+ export * from './ChatView';
@@ -0,0 +1 @@
1
+ export * from './ChatView';
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { TimestampFormatterOptions } from '../../i18n/utils';
2
+ import type { TimestampFormatterOptions } from '../../i18n/types';
3
3
  export type DateSeparatorProps = TimestampFormatterOptions & {
4
4
  /** The date to format */
5
5
  date: Date;
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { useTranslationContext } from '../../context/TranslationContext';
3
3
  import { getDateString } from '../../i18n/utils';
4
4
  const UnMemoizedDateSeparator = (props) => {
5
- const { calendar = true, date: messageCreatedAt, formatDate, position = 'right', unread, ...restTimestampFormatterOptions } = props;
5
+ const { calendar, date: messageCreatedAt, formatDate, position = 'right', unread, ...restTimestampFormatterOptions } = props;
6
6
  const { t, tDateTimeParser } = useTranslationContext('DateSeparator');
7
7
  const formattedDate = getDateString({
8
8
  calendar,
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { AvatarProps } from '../Avatar';
3
3
  import type { StreamMessage } from '../../context/ChannelStateContext';
4
4
  import type { DefaultStreamChatGenerics } from '../../types/types';
5
- import { TimestampFormatterOptions } from '../../i18n/utils';
5
+ import type { TimestampFormatterOptions } from '../../i18n/types';
6
6
  export type EventComponentProps<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = TimestampFormatterOptions & {
7
7
  /** Message object */
8
8
  message: StreamMessage<StreamChatGenerics>;
@@ -6,7 +6,7 @@ import { getDateString } from '../../i18n/utils';
6
6
  * Component to display system and channel event messages
7
7
  */
8
8
  const UnMemoizedEventComponent = (props) => {
9
- const { calendar, calendarFormats, format = 'dddd L', Avatar = DefaultAvatar, message } = props;
9
+ const { calendar, calendarFormats, format, Avatar = DefaultAvatar, message } = props;
10
10
  const { t, tDateTimeParser } = useTranslationContext('EventComponent');
11
11
  const { created_at = '', event, text, type } = message;
12
12
  const getDateOptions = { messageCreatedAt: created_at.toString(), tDateTimeParser };
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useLayoutEffect, useRef } from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import { deprecationAndReplacementWarning } from '../../utils/deprecationWarning';
3
3
  import { DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD } from '../../constants/limits';
4
4
  /**
@@ -17,6 +17,8 @@ export const InfiniteScroll = (props) => {
17
17
  const hasNextPageFlag = hasNextPage || hasMoreNewer;
18
18
  const hasPreviousPageFlag = hasPreviousPage || hasMore;
19
19
  const scrollComponent = useRef();
20
+ const previousOffset = useRef();
21
+ const previousReverseOffset = useRef();
20
22
  const scrollListenerRef = useRef();
21
23
  scrollListenerRef.current = () => {
22
24
  const element = scrollComponent.current;
@@ -32,7 +34,11 @@ export const InfiniteScroll = (props) => {
32
34
  }
33
35
  if (isLoading)
34
36
  return;
35
- // FIXME: this triggers loadMore call when a user types messages in thread and the scroll container container expands
37
+ if (previousOffset.current === offset && previousReverseOffset.current === reverseOffset)
38
+ return;
39
+ previousOffset.current = offset;
40
+ previousReverseOffset.current = reverseOffset;
41
+ // FIXME: this triggers loadMore call when a user types messages in thread and the scroll container expands
36
42
  if (reverseOffset < Number(threshold) &&
37
43
  typeof loadPreviousPageFn === 'function' &&
38
44
  hasPreviousPageFlag) {
@@ -51,7 +57,7 @@ export const InfiniteScroll = (props) => {
51
57
  ], 'InfiniteScroll');
52
58
  // eslint-disable-next-line react-hooks/exhaustive-deps
53
59
  }, []);
54
- useLayoutEffect(() => {
60
+ useEffect(() => {
55
61
  const scrollElement = scrollComponent.current?.parentNode;
56
62
  if (!scrollElement)
57
63
  return;
@@ -29,6 +29,9 @@ export const AudioRecordingInProgress = () => {
29
29
  if (!recorder?.mediaRecorder)
30
30
  return;
31
31
  const { mediaRecorder } = recorder;
32
+ if (mediaRecorder.state === 'recording') {
33
+ startCounter();
34
+ }
32
35
  mediaRecorder.addEventListener('start', startCounter);
33
36
  mediaRecorder.addEventListener('resume', startCounter);
34
37
  mediaRecorder.addEventListener('stop', stopCounter);
@@ -1,26 +1,25 @@
1
1
  import { AmplitudeRecorder, AmplitudeRecorderConfig } from './AmplitudeRecorder';
2
2
  import { BrowserPermission } from './BrowserPermission';
3
3
  import { BehaviorSubject, Subject } from '../observable';
4
+ import { TranscoderConfig } from '../transcode';
4
5
  import { RecordedMediaType } from '../../ReactFileUtilities';
5
6
  import { TranslationContextValue } from '../../../context';
6
7
  import type { LocalVoiceRecordingAttachment } from '../../MessageInput';
7
8
  import type { DefaultStreamChatGenerics } from '../../../types';
8
- export declare const POSSIBLE_TRANSCODING_MIME_TYPES: readonly ["audio/wav", "audio/mp3"];
9
9
  export declare const DEFAULT_MEDIA_RECORDER_CONFIG: MediaRecorderConfig;
10
10
  export declare const DEFAULT_AUDIO_TRANSCODER_CONFIG: TranscoderConfig;
11
- type SupportedTranscodeMimeTypes = typeof POSSIBLE_TRANSCODING_MIME_TYPES[number];
12
- export type TranscoderConfig = {
13
- sampleRate: number;
14
- targetMimeType: SupportedTranscodeMimeTypes;
15
- };
16
11
  type MediaRecorderConfig = Omit<MediaRecorderOptions, 'mimeType'> & Required<Pick<MediaRecorderOptions, 'mimeType'>>;
17
12
  export type AudioRecorderConfig = {
18
13
  amplitudeRecorderConfig: AmplitudeRecorderConfig;
19
14
  mediaRecorderConfig: MediaRecorderOptions;
20
15
  transcoderConfig: TranscoderConfig;
21
16
  };
17
+ type PartialValues<T> = {
18
+ [P in keyof T]?: Partial<T[P]>;
19
+ };
20
+ export type CustomAudioRecordingConfig = PartialValues<AudioRecorderConfig>;
22
21
  export type AudioRecorderOptions = {
23
- config?: Partial<AudioRecorderConfig>;
22
+ config?: CustomAudioRecordingConfig;
24
23
  generateRecordingTitle?: (mimeType: string) => string;
25
24
  t?: TranslationContextValue['t'];
26
25
  };
@@ -15,7 +15,6 @@ const RECORDED_MIME_TYPE_BY_BROWSER = {
15
15
  safari: 'audio/mp4;codecs=mp4a.40.2',
16
16
  },
17
17
  };
18
- export const POSSIBLE_TRANSCODING_MIME_TYPES = ['audio/wav', 'audio/mp3'];
19
18
  export const DEFAULT_MEDIA_RECORDER_CONFIG = {
20
19
  mimeType: isSafari()
21
20
  ? RECORDED_MIME_TYPE_BY_BROWSER.audio.safari
@@ -23,7 +22,6 @@ export const DEFAULT_MEDIA_RECORDER_CONFIG = {
23
22
  };
24
23
  export const DEFAULT_AUDIO_TRANSCODER_CONFIG = {
25
24
  sampleRate: 16000,
26
- targetMimeType: 'audio/mp3',
27
25
  };
28
26
  const disposeOfMediaStream = (stream) => {
29
27
  if (!stream?.active)
@@ -245,9 +243,6 @@ export class MediaRecorderController {
245
243
  this.amplitudeRecorderConfig = mergeDeepUndefined({ ...config?.amplitudeRecorderConfig }, DEFAULT_AMPLITUDE_RECORDER_CONFIG);
246
244
  this.mediaRecorderConfig = mergeDeepUndefined({ ...config?.mediaRecorderConfig }, DEFAULT_MEDIA_RECORDER_CONFIG);
247
245
  this.transcoderConfig = mergeDeepUndefined({ ...config?.transcoderConfig }, DEFAULT_AUDIO_TRANSCODER_CONFIG);
248
- if (!POSSIBLE_TRANSCODING_MIME_TYPES.includes(this.transcoderConfig.targetMimeType)) {
249
- this.transcoderConfig.targetMimeType = DEFAULT_AUDIO_TRANSCODER_CONFIG.targetMimeType;
250
- }
251
246
  const mediaType = getRecordedMediaTypeFromMimeType(this.mediaRecorderConfig.mimeType);
252
247
  if (!mediaType) {
253
248
  throw new Error(`Unsupported media type (supported audio or video only). Provided mimeType: ${this.mediaRecorderConfig.mimeType}`);
@@ -1 +1 @@
1
- export type { CustomAudioRecordingConfig, RecordingController } from './useMediaRecorder';
1
+ export type { RecordingController } from './useMediaRecorder';
@@ -1,8 +1,7 @@
1
1
  import { MessageInputContextValue } from '../../../context';
2
- import { AudioRecorderConfig, MediaRecorderController, MediaRecordingState } from '../classes';
2
+ import { CustomAudioRecordingConfig, MediaRecorderController, MediaRecordingState } from '../classes';
3
3
  import type { LocalVoiceRecordingAttachment } from '../../MessageInput';
4
4
  import type { DefaultStreamChatGenerics } from '../../../types';
5
- export type CustomAudioRecordingConfig = Partial<AudioRecorderConfig>;
6
5
  export type RecordingController<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = {
7
6
  completeRecording: () => void;
8
7
  permissionState?: PermissionState;
@@ -1,6 +1,6 @@
1
1
  import { useCallback, useEffect, useMemo, useState } from 'react';
2
2
  import { useTranslationContext } from '../../../context';
3
- import { MediaRecorderController } from '../classes';
3
+ import { MediaRecorderController, } from '../classes';
4
4
  export const useMediaRecorder = ({ asyncMessagesMultiSendEnabled, enabled, generateRecordingTitle, handleSubmit, recordingConfig, uploadAttachment, }) => {
5
5
  const { t } = useTranslationContext('useMediaRecorder');
6
6
  const [recording, setRecording] = useState();
@@ -3,3 +3,4 @@ export * from './AudioRecorder';
3
3
  export * from './hooks';
4
4
  export { MediaRecordingState } from './classes/MediaRecorderController';
5
5
  export { RecordingPermission } from './classes/BrowserPermission';
6
+ export type { CustomAudioRecordingConfig } from './classes';
@@ -1,7 +1,8 @@
1
- type TranscodeParams = {
2
- blob: Blob;
1
+ export type TranscoderConfig = {
3
2
  sampleRate: number;
4
- targetMimeType: string;
3
+ encoder?: (file: File, sampleRate: number) => Promise<Blob>;
4
+ };
5
+ export type TranscodeParams = TranscoderConfig & {
6
+ blob: Blob;
5
7
  };
6
- export declare const transcode: ({ blob, sampleRate, targetMimeType }: TranscodeParams) => Promise<Blob>;
7
- export {};
8
+ export declare const transcode: ({ blob, encoder, sampleRate, }: TranscodeParams) => Promise<Blob>;
@@ -1,17 +1,7 @@
1
1
  import { encodeToWaw } from './wav';
2
- import { encodeToMp3 } from './mp3';
3
2
  import { createFileFromBlobs, getExtensionFromMimeType } from '../../ReactFileUtilities';
4
- export const transcode = ({ blob, sampleRate, targetMimeType }) => {
5
- const file = createFileFromBlobs({
6
- blobsArray: [blob],
7
- fileName: `audio_recording_${new Date().toISOString()}.${getExtensionFromMimeType(blob.type)}`,
8
- mimeType: blob.type,
9
- });
10
- if (targetMimeType.match('audio/wav')) {
11
- return encodeToWaw(file, sampleRate);
12
- }
13
- if (targetMimeType.match('audio/mp3')) {
14
- return encodeToMp3(file, sampleRate);
15
- }
16
- return Promise.resolve(blob);
17
- };
3
+ export const transcode = ({ blob, encoder = encodeToWaw, sampleRate, }) => encoder(createFileFromBlobs({
4
+ blobsArray: [blob],
5
+ fileName: `audio_recording_${new Date().toISOString()}.${getExtensionFromMimeType(blob.type)}`,
6
+ mimeType: blob.type,
7
+ }), sampleRate);
@@ -2,13 +2,14 @@ import React, { useCallback, useMemo, useRef } from 'react';
2
2
  import { useActionHandler, useDeleteHandler, useEditHandler, useFlagHandler, useMarkUnreadHandler, useMentionsHandler, useMuteHandler, useOpenThreadHandler, usePinHandler, useReactionClick, useReactionHandler, useReactionsFetcher, useRetryHandler, useUserHandler, useUserRole, } from './hooks';
3
3
  import { areMessagePropsEqual, getMessageActions, MESSAGE_ACTIONS } from './utils';
4
4
  import { MessageProvider, useChannelActionContext, useChannelStateContext, useChatContext, useComponentContext, } from '../../context';
5
+ import { MessageSimple as DefaultMessage } from './MessageSimple';
5
6
  const MessageWithContext = (props) => {
6
7
  const { canPin, groupedByUser, Message: propMessage, message, messageActions = Object.keys(MESSAGE_ACTIONS), onUserClick: propOnUserClick, onUserHover: propOnUserHover, userRoles, } = props;
7
8
  const { client } = useChatContext('Message');
8
9
  const { read } = useChannelStateContext('Message');
9
10
  const { Message: contextMessage } = useComponentContext('Message');
10
11
  const actionsEnabled = message.type === 'regular' && message.status === 'received';
11
- const MessageUIComponent = propMessage || contextMessage;
12
+ const MessageUIComponent = propMessage ?? contextMessage ?? DefaultMessage;
12
13
  const { clearEdit, editing, setEdit } = useEditHandler();
13
14
  const { onUserClick, onUserHover } = useUserHandler(message, {
14
15
  onUserClickHandler: propOnUserClick,
@@ -1,16 +1,15 @@
1
1
  import React from 'react';
2
2
  import { ActionsIcon as DefaultActionsIcon, ReactionIcon as DefaultReactionIcon, ThreadIcon as DefaultThreadIcon, } from './icons';
3
- import { MESSAGE_ACTIONS, showMessageActionsBox } from './utils';
3
+ import { MESSAGE_ACTIONS } from './utils';
4
4
  import { MessageActions } from '../MessageActions';
5
5
  import { useMessageContext } from '../../context/MessageContext';
6
6
  import { useTranslationContext } from '../../context';
7
7
  const UnMemoizedMessageOptions = (props) => {
8
8
  const { ActionsIcon = DefaultActionsIcon, displayReplies = true, handleOpenThread: propHandleOpenThread, messageWrapperRef, ReactionIcon = DefaultReactionIcon, theme = 'simple', ThreadIcon = DefaultThreadIcon, } = props;
9
- const { customMessageActions, getMessageActions, handleOpenThread: contextHandleOpenThread, initialMessage, message, onReactionListClick, showDetailedReactions, threadList, } = useMessageContext('MessageOptions');
9
+ const { getMessageActions, handleOpenThread: contextHandleOpenThread, initialMessage, message, onReactionListClick, showDetailedReactions, threadList, } = useMessageContext('MessageOptions');
10
10
  const { t } = useTranslationContext('MessageOptions');
11
11
  const handleOpenThread = propHandleOpenThread || contextHandleOpenThread;
12
12
  const messageActions = getMessageActions();
13
- const showActionsBox = showMessageActionsBox(messageActions, threadList) || !!customMessageActions;
14
13
  const shouldShowReactions = messageActions.indexOf(MESSAGE_ACTIONS.react) > -1;
15
14
  const shouldShowReplies = messageActions.indexOf(MESSAGE_ACTIONS.reply) > -1 && displayReplies && !threadList;
16
15
  if (!message.type ||
@@ -24,7 +23,7 @@ const UnMemoizedMessageOptions = (props) => {
24
23
  }
25
24
  const rootClassName = `str-chat__message-${theme}__actions str-chat__message-options`;
26
25
  return (React.createElement("div", { className: rootClassName, "data-testid": 'message-options' },
27
- showActionsBox && (React.createElement(MessageActions, { ActionsIcon: ActionsIcon, messageWrapperRef: messageWrapperRef })),
26
+ React.createElement(MessageActions, { ActionsIcon: ActionsIcon, messageWrapperRef: messageWrapperRef }),
28
27
  shouldShowReplies && (React.createElement("button", { "aria-label": t('aria/Open Thread'), className: `str-chat__message-${theme}__actions__action str-chat__message-${theme}__actions__action--thread str-chat__message-reply-in-thread-button`, "data-testid": 'thread-action', onClick: handleOpenThread },
29
28
  React.createElement(ThreadIcon, { className: 'str-chat__message-action-icon' }))),
30
29
  shouldShowReactions && (React.createElement("button", { "aria-expanded": showDetailedReactions, "aria-label": t('aria/Open Reaction Selector'), className: `str-chat__message-${theme}__actions__action str-chat__message-${theme}__actions__action--reactions str-chat__message-reactions-button`, "data-testid": 'message-reaction-action', onClick: onReactionListClick },
@@ -10,6 +10,7 @@ import { MessageText } from './MessageText';
10
10
  import { MessageTimestamp as DefaultMessageTimestamp } from './MessageTimestamp';
11
11
  import { areMessageUIPropsEqual, isMessageBounced, isMessageEdited, messageHasAttachments, messageHasReactions, } from './utils';
12
12
  import { Avatar as DefaultAvatar } from '../Avatar';
13
+ import { Attachment as DefaultAttachment } from '../Attachment';
13
14
  import { CUSTOM_MESSAGE_TYPE } from '../../constants/messageTypes';
14
15
  import { EditMessageForm as DefaultEditMessageForm, MessageInput } from '../MessageInput';
15
16
  import { MML } from '../MML';
@@ -25,7 +26,7 @@ const MessageSimpleWithContext = (props) => {
25
26
  const { t } = useTranslationContext('MessageSimple');
26
27
  const [isBounceDialogOpen, setIsBounceDialogOpen] = useState(false);
27
28
  const [isEditedTimestampOpen, setEditedTimestampOpen] = useState(false);
28
- const { Attachment, Avatar = DefaultAvatar, EditMessageInput = DefaultEditMessageForm, MessageDeleted = DefaultMessageDeleted, MessageBouncePrompt = DefaultMessageBouncePrompt, MessageOptions = DefaultMessageOptions, MessageRepliesCountButton = DefaultMessageRepliesCountButton, MessageStatus = DefaultMessageStatus, MessageTimestamp = DefaultMessageTimestamp, ReactionSelector = DefaultReactionSelector, ReactionsList = DefaultReactionList, PinIndicator, } = useComponentContext('MessageSimple');
29
+ const { Attachment = DefaultAttachment, Avatar = DefaultAvatar, EditMessageInput = DefaultEditMessageForm, MessageDeleted = DefaultMessageDeleted, MessageBouncePrompt = DefaultMessageBouncePrompt, MessageOptions = DefaultMessageOptions, MessageRepliesCountButton = DefaultMessageRepliesCountButton, MessageStatus = DefaultMessageStatus, MessageTimestamp = DefaultMessageTimestamp, ReactionSelector = DefaultReactionSelector, ReactionsList = DefaultReactionList, PinIndicator, } = useComponentContext('MessageSimple');
29
30
  const hasAttachment = messageHasAttachments(message);
30
31
  const hasReactions = messageHasReactions(message);
31
32
  if (message.customType === CUSTOM_MESSAGE_TYPE.date) {
@@ -92,7 +93,7 @@ const MessageSimpleWithContext = (props) => {
92
93
  showMetadata && (React.createElement("div", { className: 'str-chat__message-metadata' },
93
94
  React.createElement(MessageStatus, null),
94
95
  !isMyMessage() && !!message.user && (React.createElement("span", { className: 'str-chat__message-simple-name' }, message.user.name || message.user.id)),
95
- React.createElement(MessageTimestamp, { calendar: true, customClass: 'str-chat__message-simple-timestamp' }),
96
+ React.createElement(MessageTimestamp, { customClass: 'str-chat__message-simple-timestamp' }),
96
97
  isEdited && (React.createElement("span", { className: 'str-chat__mesage-simple-edited' }, t('Edited'))),
97
98
  isEdited && React.createElement(MessageEditedTimestamp, { calendar: true, open: isEditedTimestampOpen }))))));
98
99
  };
@@ -26,9 +26,10 @@ const UnMemoizedMessageStatus = (props) => {
26
26
  const sending = message.status === 'sending';
27
27
  const delivered = message.status === 'received' && message.id === lastReceivedId && !threadList;
28
28
  const deliveredAndRead = !!(readBy?.length && !threadList && !justReadByMe);
29
- const [lastReadUser] = deliveredAndRead
29
+ const readersWithoutOwnUser = deliveredAndRead
30
30
  ? readBy.filter((item) => item.id !== client.user?.id)
31
31
  : [];
32
+ const [lastReadUser] = readersWithoutOwnUser;
32
33
  return (React.createElement("span", { className: rootClassName, "data-testid": clsx({
33
34
  'message-status-read-by': deliveredAndRead,
34
35
  'message-status-received': delivered && !deliveredAndRead,
@@ -47,6 +48,6 @@ const UnMemoizedMessageStatus = (props) => {
47
48
  (MessageReadStatus ? (React.createElement(MessageReadStatus, null)) : (React.createElement(React.Fragment, null,
48
49
  React.createElement(PopperTooltip, { offset: [0, 5], referenceElement: referenceElement, visible: tooltipVisible }, getReadByTooltipText(readBy, t, client, tooltipUserNameMapper)),
49
50
  React.createElement(Avatar, { className: 'str-chat__avatar--message-status', image: lastReadUser.image, name: lastReadUser.name || lastReadUser.id, user: lastReadUser }),
50
- readBy.length > 2 && (React.createElement("span", { className: `str-chat__message-${messageType}-status-number`, "data-testid": 'message-status-read-by-many' }, readBy.length - 1)))))));
51
+ readersWithoutOwnUser.length > 1 && (React.createElement("span", { className: `str-chat__message-${messageType}-status-number`, "data-testid": 'message-status-read-by-many' }, readersWithoutOwnUser.length)))))));
51
52
  };
52
53
  export const MessageStatus = React.memo(UnMemoizedMessageStatus);
@@ -1,8 +1,7 @@
1
1
  import React from 'react';
2
2
  import type { StreamMessage } from '../../context/ChannelStateContext';
3
+ import type { TimestampFormatterOptions } from '../../i18n/types';
3
4
  import type { DefaultStreamChatGenerics } from '../../types/types';
4
- import type { TimestampFormatterOptions } from '../../i18n/utils';
5
- export declare const defaultTimestampFormat = "h:mmA";
6
5
  export type MessageTimestampProps<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = TimestampFormatterOptions & {
7
6
  customClass?: string;
8
7
  message?: StreamMessage<StreamChatGenerics>;
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import { useMessageContext } from '../../context/MessageContext';
3
3
  import { Timestamp as DefaultTimestamp } from './Timestamp';
4
4
  import { useComponentContext } from '../../context';
5
- export const defaultTimestampFormat = 'h:mmA';
6
5
  const UnMemoizedMessageTimestamp = (props) => {
7
6
  const { message: propMessage, ...timestampProps } = props;
8
7
  const { message: contextMessage } = useMessageContext('MessageTimestamp');
@@ -5,8 +5,9 @@ import { useComponentContext } from '../../context/ComponentContext';
5
5
  import { useMessageContext } from '../../context/MessageContext';
6
6
  import { useTranslationContext } from '../../context/TranslationContext';
7
7
  import { useChannelActionContext } from '../../context/ChannelActionContext';
8
+ import { Attachment as DefaultAttachment } from '../Attachment';
8
9
  export const QuotedMessage = () => {
9
- const { Attachment, Avatar: ContextAvatar } = useComponentContext('QuotedMessage');
10
+ const { Attachment = DefaultAttachment, Avatar: ContextAvatar, } = useComponentContext('QuotedMessage');
10
11
  const { isMyMessage, message } = useMessageContext('QuotedMessage');
11
12
  const { t, userLanguage } = useTranslationContext('QuotedMessage');
12
13
  const { jumpToMessage } = useChannelActionContext('QuotedMessage');
@@ -1,8 +1,7 @@
1
1
  import React from 'react';
2
- import { TimestampFormatterOptions } from '../../i18n/utils';
2
+ import type { TimestampFormatterOptions } from '../../i18n/types';
3
3
  export interface TimestampProps extends TimestampFormatterOptions {
4
4
  customClass?: string;
5
5
  timestamp?: Date | string;
6
6
  }
7
- export declare const defaultTimestampFormat = "h:mmA";
8
7
  export declare function Timestamp(props: TimestampProps): React.JSX.Element | null;
@@ -1,10 +1,9 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import { useMessageContext } from '../../context/MessageContext';
3
- import { isDate, useTranslationContext } from '../../context/TranslationContext';
4
- import { getDateString } from '../../i18n/utils';
5
- export const defaultTimestampFormat = 'h:mmA';
3
+ import { useTranslationContext } from '../../context/TranslationContext';
4
+ import { getDateString, isDate } from '../../i18n/utils';
6
5
  export function Timestamp(props) {
7
- const { calendar, calendarFormats, customClass, format = defaultTimestampFormat, timestamp, } = props;
6
+ const { calendar, calendarFormats, customClass, format, timestamp } = props;
8
7
  const { formatDate } = useMessageContext('MessageTimestamp');
9
8
  const { t, tDateTimeParser } = useTranslationContext('MessageTimestamp');
10
9
  const normalizedTimestamp = timestamp && isDate(timestamp) ? timestamp.toISOString() : timestamp;
@@ -16,7 +15,7 @@ export function Timestamp(props) {
16
15
  messageCreatedAt: normalizedTimestamp,
17
16
  t,
18
17
  tDateTimeParser,
19
- timestampTranslationKey: 'timestamp/Timestamp',
18
+ timestampTranslationKey: 'timestamp/MessageTimestamp',
20
19
  }), [calendar, calendarFormats, format, formatDate, normalizedTimestamp, t, tDateTimeParser]);
21
20
  if (!when) {
22
21
  return null;
@@ -3,9 +3,11 @@ import throttle from 'lodash.throttle';
3
3
  import { useChannelActionContext } from '../../../context/ChannelActionContext';
4
4
  import { useChannelStateContext } from '../../../context/ChannelStateContext';
5
5
  import { useChatContext } from '../../../context/ChatContext';
6
+ import { useThreadContext } from '../../Threads';
6
7
  export const reactionHandlerWarning = `Reaction handler was called, but it is missing one of its required arguments.
7
8
  Make sure the ChannelAction and ChannelState contexts are properly set and the hook is initialized with a valid message.`;
8
9
  export const useReactionHandler = (message) => {
10
+ const thread = useThreadContext();
9
11
  const { updateMessage } = useChannelActionContext('useReactionHandler');
10
12
  const { channel, channelCapabilities } = useChannelStateContext('useReactionHandler');
11
13
  const { client } = useChatContext('useReactionHandler');
@@ -64,14 +66,19 @@ export const useReactionHandler = (message) => {
64
66
  const tempMessage = createMessagePreview(add, newReaction, message);
65
67
  try {
66
68
  updateMessage(tempMessage);
69
+ // @ts-expect-error
70
+ thread?.upsertReplyLocally({ message: tempMessage });
67
71
  const messageResponse = add
68
72
  ? await channel.sendReaction(id, { type })
69
73
  : await channel.deleteReaction(id, type);
74
+ // seems useless as we're expecting WS event to come in and replace this anyway
70
75
  updateMessage(messageResponse.message);
71
76
  }
72
77
  catch (error) {
73
78
  // revert to the original message if the API call fails
74
79
  updateMessage(message);
80
+ // @ts-expect-error
81
+ thread?.upsertReplyLocally({ message });
75
82
  }
76
83
  }, 1000);
77
84
  return async (reactionType, event) => {
@@ -1,4 +1,4 @@
1
1
  import type { Nodes } from 'hast-util-find-and-replace/lib';
2
2
  import type { UserResponse } from 'stream-chat';
3
- import type { DefaultStreamChatGenerics } from '../../../../types/types';
3
+ import type { DefaultStreamChatGenerics } from '../../../../types';
4
4
  export declare const mentionsMarkdownPlugin: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(mentioned_users: UserResponse<StreamChatGenerics>[]) => () => (tree: Nodes) => void;
@@ -1,2 +1,2 @@
1
- import type { Nodes } from 'react-markdown/lib';
1
+ import type { Nodes } from 'hast-util-find-and-replace/lib';
2
2
  export declare const htmlToTextPlugin: () => (tree: Nodes) => void;
@@ -1,2 +1,2 @@
1
- import type { Nodes } from 'react-markdown/lib';
1
+ import type { Nodes } from 'hast-util-find-and-replace/lib';
2
2
  export declare const keepLineBreaksPlugin: () => (tree: Nodes) => void;
@@ -1,17 +1,13 @@
1
1
  import { visit } from 'unist-util-visit';
2
2
  import { u } from 'unist-builder';
3
3
  const visitor = (node, index, parent) => {
4
- if (typeof index === 'undefined' || index === 0)
5
- return;
6
- if (typeof parent === 'undefined')
7
- return;
8
- if (!node.position)
4
+ if (!(index && parent && node.position))
9
5
  return;
10
6
  const prevSibling = parent.children.at(index - 1);
11
7
  if (!prevSibling?.position)
12
8
  return;
13
9
  if (node.position.start.line === prevSibling.position.start.line)
14
- return false;
10
+ return;
15
11
  const ownStartLine = node.position.start.line;
16
12
  const prevEndLine = prevSibling.position.end.line;
17
13
  // the -1 is adjustment for the single line break into which multiple line breaks are converted
@@ -1,8 +1,8 @@
1
1
  import React, { ComponentType } from 'react';
2
2
  import { Options } from 'react-markdown';
3
- import { MentionProps } from './componentRenderers';
4
- import type { PluggableList } from 'react-markdown/lib';
3
+ import type { PluggableList } from 'react-markdown/lib/react-markdown';
5
4
  import type { UserResponse } from 'stream-chat';
5
+ import { MentionProps } from './componentRenderers';
6
6
  import type { DefaultStreamChatGenerics } from '../../../types/types';
7
7
  export type RenderTextPluginConfigurator = (defaultPlugins: PluggableList) => PluggableList;
8
8
  export declare const defaultAllowedTagNames: Array<keyof JSX.IntrinsicElements | 'emoji' | 'mention'>;