stream-chat-react-native-core 3.9.0-next.8 → 3.9.2-next.1

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 (61) hide show
  1. package/lib/commonjs/components/Attachment/Gallery.js +3 -5
  2. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  3. package/lib/commonjs/components/AutoCompleteInput/AutoCompleteInput.js +5 -5
  4. package/lib/commonjs/components/AutoCompleteInput/AutoCompleteInput.js.map +1 -1
  5. package/lib/commonjs/components/ChannelList/ChannelListLoadingIndicator.js +6 -4
  6. package/lib/commonjs/components/ChannelList/ChannelListLoadingIndicator.js.map +1 -1
  7. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js +32 -11
  8. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  9. package/lib/commonjs/components/ChannelPreview/ChannelPreviewMessage.js +1 -1
  10. package/lib/commonjs/components/ChannelPreview/ChannelPreviewMessage.js.map +1 -1
  11. package/lib/commonjs/components/Chat/hooks/useIsOnline.js +23 -24
  12. package/lib/commonjs/components/Chat/hooks/useIsOnline.js.map +1 -1
  13. package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js +1 -1
  14. package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js.map +1 -1
  15. package/lib/commonjs/contexts/themeContext/utils/theme.js +3 -0
  16. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  17. package/lib/commonjs/hooks/useIsMountedRef.js +19 -0
  18. package/lib/commonjs/hooks/useIsMountedRef.js.map +1 -0
  19. package/lib/commonjs/hooks/useStreami18n.js +4 -1
  20. package/lib/commonjs/hooks/useStreami18n.js.map +1 -1
  21. package/lib/commonjs/i18n/fr.json +1 -1
  22. package/lib/commonjs/version.json +1 -1
  23. package/lib/module/components/Attachment/Gallery.js +3 -5
  24. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  25. package/lib/module/components/AutoCompleteInput/AutoCompleteInput.js +5 -5
  26. package/lib/module/components/AutoCompleteInput/AutoCompleteInput.js.map +1 -1
  27. package/lib/module/components/ChannelList/ChannelListLoadingIndicator.js +6 -4
  28. package/lib/module/components/ChannelList/ChannelListLoadingIndicator.js.map +1 -1
  29. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js +32 -11
  30. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  31. package/lib/module/components/ChannelPreview/ChannelPreviewMessage.js +1 -1
  32. package/lib/module/components/ChannelPreview/ChannelPreviewMessage.js.map +1 -1
  33. package/lib/module/components/Chat/hooks/useIsOnline.js +23 -24
  34. package/lib/module/components/Chat/hooks/useIsOnline.js.map +1 -1
  35. package/lib/module/components/Message/MessageSimple/utils/renderText.js +1 -1
  36. package/lib/module/components/Message/MessageSimple/utils/renderText.js.map +1 -1
  37. package/lib/module/contexts/themeContext/utils/theme.js +3 -0
  38. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  39. package/lib/module/hooks/useIsMountedRef.js +19 -0
  40. package/lib/module/hooks/useIsMountedRef.js.map +1 -0
  41. package/lib/module/hooks/useStreami18n.js +4 -1
  42. package/lib/module/hooks/useStreami18n.js.map +1 -1
  43. package/lib/module/i18n/fr.json +1 -1
  44. package/lib/module/version.json +1 -1
  45. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +3 -0
  46. package/lib/typescript/hooks/useIsMountedRef.d.ts +20 -0
  47. package/lib/typescript/hooks/useStreami18n.d.ts +1 -1
  48. package/lib/typescript/i18n/fr.json +1 -1
  49. package/package.json +1 -1
  50. package/src/components/Attachment/Gallery.tsx +3 -3
  51. package/src/components/AutoCompleteInput/AutoCompleteInput.tsx +3 -8
  52. package/src/components/ChannelList/ChannelListLoadingIndicator.tsx +2 -1
  53. package/src/components/ChannelList/hooks/usePaginatedChannels.ts +7 -1
  54. package/src/components/ChannelPreview/ChannelPreviewMessage.tsx +1 -1
  55. package/src/components/Chat/hooks/useIsOnline.ts +16 -17
  56. package/src/components/Message/MessageSimple/utils/renderText.tsx +1 -1
  57. package/src/contexts/themeContext/utils/theme.ts +6 -0
  58. package/src/hooks/useIsMountedRef.ts +36 -0
  59. package/src/hooks/useStreami18n.ts +5 -3
  60. package/src/i18n/fr.json +1 -1
  61. package/src/version.json +1 -1
@@ -288,12 +288,7 @@ const AutoCompleteInputWithContext = <
288
288
 
289
289
  const textToModify = text.slice(0, selectionEnd.current);
290
290
 
291
- const startOfTokenPosition = textToModify.search(
292
- /**
293
- * It's important to escape the trigger char for chars like [, (,...
294
- */
295
- new RegExp(`\\${trigger}${`[^\\${trigger}${'\\s'}]`}*$`),
296
- );
291
+ const startOfTokenPosition = textToModify.lastIndexOf(trigger, selectionEnd.current);
297
292
 
298
293
  const newCaretPosition = computeCaretPosition(newTokenString, startOfTokenPosition);
299
294
 
@@ -335,7 +330,7 @@ const AutoCompleteInputWithContext = <
335
330
  };
336
331
 
337
332
  const handleMentions = ({ tokenMatch }: { tokenMatch: RegExpMatchArray | null }) => {
338
- const lastToken = tokenMatch?.[tokenMatch.length - 1].trim();
333
+ const lastToken = tokenMatch?.[tokenMatch.length - 1];
339
334
  const handleMentionsTrigger =
340
335
  (lastToken && Object.keys(triggerSettings).find((trigger) => trigger === lastToken[0])) ||
341
336
  null;
@@ -401,7 +396,7 @@ const AutoCompleteInputWithContext = <
401
396
  } else if (giphyEnabled && !(await handleCommand(text))) {
402
397
  const mentionTokenMatch = text
403
398
  .slice(0, selectionEnd.current)
404
- .match(/(?!^|\W)?@[^\s]*\s?[^\s]*$/g);
399
+ .match(/(?!^|\W)?@[^\s@]*\s?[^\s@]*$/g);
405
400
  if (mentionTokenMatch) {
406
401
  handleMentions({ tokenMatch: mentionTokenMatch });
407
402
  } else {
@@ -13,6 +13,7 @@ const styles = StyleSheet.create({
13
13
  export const ChannelListLoadingIndicator: React.FC = () => {
14
14
  const {
15
15
  theme: {
16
+ channelListLoadingIndicator: { container },
16
17
  colors: { white_snow },
17
18
  },
18
19
  } = useTheme();
@@ -20,7 +21,7 @@ export const ChannelListLoadingIndicator: React.FC = () => {
20
21
 
21
22
  return (
22
23
  <View
23
- style={[styles.container, { backgroundColor: white_snow }]}
24
+ style={[styles.container, { backgroundColor: white_snow }, container]}
24
25
  testID='channel-list-loading-indicator'
25
26
  >
26
27
  {Array.from(Array(numberOfSkeletons)).map((_, index) => (
@@ -3,6 +3,7 @@ import { useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { MAX_QUERY_CHANNELS_LIMIT } from '../utils';
4
4
 
5
5
  import { useChatContext } from '../../../contexts/chatContext/ChatContext';
6
+ import { useIsMountedRef } from '../../../hooks/useIsMountedRef';
6
7
 
7
8
  import type { Channel, ChannelFilters, ChannelOptions, ChannelSort } from 'stream-chat';
8
9
 
@@ -58,9 +59,10 @@ export const usePaginatedChannels = <
58
59
  const [loadingChannels, setLoadingChannels] = useState(false);
59
60
  const [loadingNextPage, setLoadingNextPage] = useState(false);
60
61
  const [refreshing, setRefreshing] = useState(false);
62
+ const isMounted = useIsMountedRef();
61
63
 
62
64
  const queryChannels = async (queryType = '', retryCount = 0): Promise<void> => {
63
- if (!client || loadingChannels || loadingNextPage || refreshing) return;
65
+ if (!client || loadingChannels || loadingNextPage || refreshing || !isMounted.current) return;
64
66
 
65
67
  if (queryType === 'reload') {
66
68
  setLoadingChannels(true);
@@ -79,6 +81,8 @@ export const usePaginatedChannels = <
79
81
  try {
80
82
  const channelQueryResponse = await client.queryChannels(filters, sort, newOptions);
81
83
 
84
+ if (!isMounted.current) return;
85
+
82
86
  channelQueryResponse.forEach((channel) => channel.state.setIsUpToDate(true));
83
87
 
84
88
  const newChannels =
@@ -92,6 +96,8 @@ export const usePaginatedChannels = <
92
96
  } catch (err) {
93
97
  await wait(2000);
94
98
 
99
+ if (!isMounted.current) return;
100
+
95
101
  if (retryCount === 3) {
96
102
  setLoadingChannels(false);
97
103
  setLoadingNextPage(false);
@@ -51,7 +51,7 @@ export const ChannelPreviewMessage: React.FC<ChannelPreviewMessageProps> = ({
51
51
  preview.text ? (
52
52
  <Text
53
53
  key={`${preview.text}_${index}`}
54
- style={[{ color: grey }, preview.bold ? styles.bold : {}]}
54
+ style={[{ color: grey }, preview.bold ? styles.bold : {}, message]}
55
55
  >
56
56
  {preview.text}
57
57
  </Text>
@@ -1,6 +1,7 @@
1
1
  import { useCallback, useEffect, useState } from 'react';
2
2
 
3
3
  import { useAppStateListener } from '../../../hooks/useAppStateListener';
4
+ import { useIsMountedRef } from '../../../hooks/useIsMountedRef';
4
5
  import { NetInfo } from '../../../native';
5
6
 
6
7
  import type { NetInfoSubscription } from '@react-native-community/netinfo';
@@ -35,10 +36,9 @@ export const useIsOnline = <
35
36
  client: StreamChat<At, Ch, Co, Ev, Me, Re, Us>,
36
37
  closeConnectionOnBackground = true,
37
38
  ) => {
38
- const [unsubscribeNetInfo, setUnsubscribeNetInfo] = useState<NetInfoSubscription>();
39
39
  const [isOnline, setIsOnline] = useState(true);
40
40
  const [connectionRecovering, setConnectionRecovering] = useState(false);
41
-
41
+ const isMounted = useIsMountedRef();
42
42
  const clientExits = !!client;
43
43
 
44
44
  const onBackground = useCallback(() => {
@@ -83,35 +83,34 @@ export const useIsOnline = <
83
83
  }
84
84
  };
85
85
 
86
- const setConnectionListener = () => {
86
+ let unsubscribeNetInfo: NetInfoSubscription;
87
+ const setNetInfoListener = () => {
87
88
  NetInfo.fetch().then((netInfoState) => {
88
89
  notifyChatClient(netInfoState);
89
90
  });
90
- setUnsubscribeNetInfo(
91
- NetInfo.addEventListener((netInfoState) => {
92
- notifyChatClient(netInfoState);
93
- }),
94
- );
91
+ unsubscribeNetInfo = NetInfo.addEventListener((netInfoState) => {
92
+ notifyChatClient(netInfoState);
93
+ });
95
94
  };
96
95
 
97
96
  const setInitialOnlineState = async () => {
98
97
  const status = await NetInfo.fetch();
99
- setIsOnline(status);
98
+
99
+ if (isMounted.current) setIsOnline(status);
100
100
  };
101
101
 
102
102
  setInitialOnlineState();
103
+ const chatListeners: Array<ReturnType<StreamChat['on']>> = [];
104
+
103
105
  if (client) {
104
- client.on('connection.changed', handleChangedEvent);
105
- client.on('connection.recovered', handleRecoveredEvent);
106
- setConnectionListener();
106
+ chatListeners.push(client.on('connection.changed', handleChangedEvent));
107
+ chatListeners.push(client.on('connection.recovered', handleRecoveredEvent));
108
+ setNetInfoListener();
107
109
  }
108
110
 
109
111
  return () => {
110
- client.off('connection.changed', handleChangedEvent);
111
- client.off('connection.recovered', handleRecoveredEvent);
112
- if (unsubscribeNetInfo) {
113
- unsubscribeNetInfo();
114
- }
112
+ chatListeners.forEach((listener) => listener.unsubscribe?.());
113
+ unsubscribeNetInfo?.();
115
114
  };
116
115
  }, [clientExits]);
117
116
 
@@ -262,7 +262,7 @@ export const renderText = <
262
262
  <Markdown
263
263
  key={`${JSON.stringify(mentioned_users)}-${onlyEmojis}-${
264
264
  messageOverlay ? JSON.stringify(markdownStyles) : undefined
265
- }`}
265
+ }-${JSON.stringify(colors)}`}
266
266
  onLink={onLink}
267
267
  rules={{
268
268
  ...customRules,
@@ -110,6 +110,9 @@ export type Theme = {
110
110
  container: ViewStyle;
111
111
  errorText: TextStyle;
112
112
  };
113
+ channelListLoadingIndicator: {
114
+ container: ViewStyle;
115
+ };
113
116
  channelListMessenger: {
114
117
  flatList: ViewStyle;
115
118
  flatListContent: ViewStyle;
@@ -531,6 +534,9 @@ export const defaultTheme: Theme = {
531
534
  container: {},
532
535
  errorText: {},
533
536
  },
537
+ channelListLoadingIndicator: {
538
+ container: {},
539
+ },
534
540
  channelListMessenger: {
535
541
  flatList: {},
536
542
  flatListContent: {},
@@ -0,0 +1,36 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ /**
4
+ * Returns mount status of component. This hook can be used for purpose of avoiding any
5
+ * setState calls (within async operation) after component gets unmounted.
6
+ *
7
+ * @example
8
+ * ```
9
+ * const isMounted = useIsMountedRef();
10
+ * const [dummyValue, setDummyValue] = useState(false);
11
+ *
12
+ * useEffect(() => {
13
+ * someAsyncOperation().then(() => {
14
+ * if (isMounted.current) setDummyValue(true);
15
+ * })
16
+ * })
17
+ * ```
18
+ *
19
+ * @returns isMounted {Object} Mount status ref for the component.
20
+ */
21
+ export const useIsMountedRef = () => {
22
+ // Initial value has been set to true, since this hook exist only for sole purpose of
23
+ // avoiding any setState calls (within async operation) after component gets unmounted.
24
+ // Basically we don't need to know about state change from component being initialized -> mounted.
25
+ // We only need a state change from initialized or mounted state -> unmounted state.
26
+ const isMounted = useRef(true);
27
+
28
+ useEffect(
29
+ () => () => {
30
+ isMounted.current = false;
31
+ },
32
+ [],
33
+ );
34
+
35
+ return isMounted;
36
+ };
@@ -1,8 +1,10 @@
1
1
  import { useEffect, useState } from 'react';
2
2
 
3
- import type { TranslationContextValue } from '../contexts/translationContext/TranslationContext';
3
+ import { useIsMountedRef } from './useIsMountedRef';
4
4
  import { Streami18n } from '../utils/Streami18n';
5
5
 
6
+ import type { TranslationContextValue } from '../contexts/translationContext/TranslationContext';
7
+
6
8
  export const useStreami18n = ({
7
9
  i18nInstance,
8
10
  setTranslators,
@@ -11,7 +13,7 @@ export const useStreami18n = ({
11
13
  i18nInstance?: Streami18n;
12
14
  }) => {
13
15
  const [loadingTranslators, setLoadingTranslators] = useState(true);
14
-
16
+ const isMounted = useIsMountedRef();
15
17
  const i18nInstanceExists = !!i18nInstance;
16
18
  useEffect(() => {
17
19
  let streami18n: Streami18n;
@@ -26,7 +28,7 @@ export const useStreami18n = ({
26
28
  setTranslators((prevTranslator) => ({ ...prevTranslator, t })),
27
29
  );
28
30
  streami18n.getTranslators().then((translator) => {
29
- if (translator) setTranslators(translator);
31
+ if (translator && isMounted.current) setTranslators(translator);
30
32
  });
31
33
 
32
34
  setLoadingTranslators(false);
package/src/i18n/fr.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "Copy Message": "Copier le message",
10
10
  "Delete": "Supprimer",
11
11
  "Delete Message": "Supprimer un message",
12
- "Dismiss": "Rejeter",
12
+ "Dismiss": "Fermer",
13
13
  "Do you want to send a copy of this message to a moderator for further investigation?": "Voulez-vous envoyer une copie de ce message à un modérateur pour une enquête plus approfondie?",
14
14
  "Edit Message": "Éditer un message",
15
15
  "Editing Message": "Édite un message",
package/src/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "3.9.0-next.8"
2
+ "version": "3.9.2-next.1"
3
3
  }