stream-chat-react-native-core 5.2.0 → 5.3.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/lib/commonjs/components/Attachment/Card.js +29 -18
  2. package/lib/commonjs/components/Attachment/Card.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/Gallery.js +16 -20
  4. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  5. package/lib/commonjs/components/Attachment/GalleryImage.js +34 -6
  6. package/lib/commonjs/components/Attachment/GalleryImage.js.map +1 -1
  7. package/lib/commonjs/components/Attachment/Giphy.js +37 -29
  8. package/lib/commonjs/components/Attachment/Giphy.js.map +1 -1
  9. package/lib/commonjs/components/Avatar/Avatar.js +10 -8
  10. package/lib/commonjs/components/Avatar/Avatar.js.map +1 -1
  11. package/lib/commonjs/components/Avatar/GroupAvatar.js +3 -1
  12. package/lib/commonjs/components/Avatar/GroupAvatar.js.map +1 -1
  13. package/lib/commonjs/components/ChannelList/ChannelList.js +4 -4
  14. package/lib/commonjs/components/ChannelList/ChannelList.js.map +1 -1
  15. package/lib/commonjs/components/ChannelList/ChannelListMessenger.js +4 -4
  16. package/lib/commonjs/components/ChannelList/ChannelListMessenger.js.map +1 -1
  17. package/lib/commonjs/components/ChannelList/hooks/useCreateChannelsContext.js +1 -1
  18. package/lib/commonjs/components/ChannelList/hooks/useCreateChannelsContext.js.map +1 -1
  19. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js +6 -7
  20. package/lib/commonjs/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  21. package/lib/commonjs/components/ChannelPreview/ChannelAvatar.js +30 -6
  22. package/lib/commonjs/components/ChannelPreview/ChannelAvatar.js.map +1 -1
  23. package/lib/commonjs/components/Chat/Chat.js +8 -5
  24. package/lib/commonjs/components/Chat/Chat.js.map +1 -1
  25. package/lib/commonjs/components/Chat/hooks/useCreateChatContext.js +2 -0
  26. package/lib/commonjs/components/Chat/hooks/useCreateChatContext.js.map +1 -1
  27. package/lib/commonjs/components/ImageBackground.js +64 -0
  28. package/lib/commonjs/components/ImageBackground.js.map +1 -0
  29. package/lib/commonjs/components/Message/Message.js +15 -16
  30. package/lib/commonjs/components/Message/Message.js.map +1 -1
  31. package/lib/commonjs/components/Message/MessageSimple/MessageAvatar.js +12 -4
  32. package/lib/commonjs/components/Message/MessageSimple/MessageAvatar.js.map +1 -1
  33. package/lib/commonjs/components/Message/MessageSimple/MessageRepliesAvatars.js +26 -5
  34. package/lib/commonjs/components/Message/MessageSimple/MessageRepliesAvatars.js.map +1 -1
  35. package/lib/commonjs/components/MessageOverlay/MessageOverlay.js +58 -47
  36. package/lib/commonjs/components/MessageOverlay/MessageOverlay.js.map +1 -1
  37. package/lib/commonjs/contexts/channelsContext/ChannelsContext.js.map +1 -1
  38. package/lib/commonjs/contexts/chatContext/ChatContext.js +2 -2
  39. package/lib/commonjs/contexts/chatContext/ChatContext.js.map +1 -1
  40. package/lib/commonjs/contexts/messageOverlayContext/MessageOverlayContext.js +2 -2
  41. package/lib/commonjs/contexts/messageOverlayContext/MessageOverlayContext.js.map +1 -1
  42. package/lib/commonjs/native.js.map +1 -1
  43. package/lib/commonjs/version.json +1 -1
  44. package/lib/module/components/Attachment/Card.js +29 -18
  45. package/lib/module/components/Attachment/Card.js.map +1 -1
  46. package/lib/module/components/Attachment/Gallery.js +16 -20
  47. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  48. package/lib/module/components/Attachment/GalleryImage.js +34 -6
  49. package/lib/module/components/Attachment/GalleryImage.js.map +1 -1
  50. package/lib/module/components/Attachment/Giphy.js +37 -29
  51. package/lib/module/components/Attachment/Giphy.js.map +1 -1
  52. package/lib/module/components/Avatar/Avatar.js +10 -8
  53. package/lib/module/components/Avatar/Avatar.js.map +1 -1
  54. package/lib/module/components/Avatar/GroupAvatar.js +3 -1
  55. package/lib/module/components/Avatar/GroupAvatar.js.map +1 -1
  56. package/lib/module/components/ChannelList/ChannelList.js +4 -4
  57. package/lib/module/components/ChannelList/ChannelList.js.map +1 -1
  58. package/lib/module/components/ChannelList/ChannelListMessenger.js +4 -4
  59. package/lib/module/components/ChannelList/ChannelListMessenger.js.map +1 -1
  60. package/lib/module/components/ChannelList/hooks/useCreateChannelsContext.js +1 -1
  61. package/lib/module/components/ChannelList/hooks/useCreateChannelsContext.js.map +1 -1
  62. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js +6 -7
  63. package/lib/module/components/ChannelList/hooks/usePaginatedChannels.js.map +1 -1
  64. package/lib/module/components/ChannelPreview/ChannelAvatar.js +30 -6
  65. package/lib/module/components/ChannelPreview/ChannelAvatar.js.map +1 -1
  66. package/lib/module/components/Chat/Chat.js +8 -5
  67. package/lib/module/components/Chat/Chat.js.map +1 -1
  68. package/lib/module/components/Chat/hooks/useCreateChatContext.js +2 -0
  69. package/lib/module/components/Chat/hooks/useCreateChatContext.js.map +1 -1
  70. package/lib/module/components/ImageBackground.js +64 -0
  71. package/lib/module/components/ImageBackground.js.map +1 -0
  72. package/lib/module/components/Message/Message.js +15 -16
  73. package/lib/module/components/Message/Message.js.map +1 -1
  74. package/lib/module/components/Message/MessageSimple/MessageAvatar.js +12 -4
  75. package/lib/module/components/Message/MessageSimple/MessageAvatar.js.map +1 -1
  76. package/lib/module/components/Message/MessageSimple/MessageRepliesAvatars.js +26 -5
  77. package/lib/module/components/Message/MessageSimple/MessageRepliesAvatars.js.map +1 -1
  78. package/lib/module/components/MessageOverlay/MessageOverlay.js +58 -47
  79. package/lib/module/components/MessageOverlay/MessageOverlay.js.map +1 -1
  80. package/lib/module/contexts/channelsContext/ChannelsContext.js.map +1 -1
  81. package/lib/module/contexts/chatContext/ChatContext.js +2 -2
  82. package/lib/module/contexts/chatContext/ChatContext.js.map +1 -1
  83. package/lib/module/contexts/messageOverlayContext/MessageOverlayContext.js +2 -2
  84. package/lib/module/contexts/messageOverlayContext/MessageOverlayContext.js.map +1 -1
  85. package/lib/module/native.js.map +1 -1
  86. package/lib/module/version.json +1 -1
  87. package/lib/typescript/components/Attachment/Card.d.ts +3 -2
  88. package/lib/typescript/components/Attachment/GalleryImage.d.ts +8 -2
  89. package/lib/typescript/components/Attachment/Giphy.d.ts +2 -1
  90. package/lib/typescript/components/Avatar/Avatar.d.ts +2 -1
  91. package/lib/typescript/components/Avatar/GroupAvatar.d.ts +2 -1
  92. package/lib/typescript/components/ChannelList/hooks/usePaginatedChannels.d.ts +1 -1
  93. package/lib/typescript/components/ChannelPreview/ChannelAvatar.d.ts +2 -0
  94. package/lib/typescript/components/Chat/Chat.d.ts +1 -1
  95. package/lib/typescript/components/Chat/hooks/useCreateChatContext.d.ts +1 -1
  96. package/lib/typescript/components/ImageBackground.d.ts +33 -0
  97. package/lib/typescript/components/Message/Message.d.ts +2 -1
  98. package/lib/typescript/components/Message/MessageSimple/MessageAvatar.d.ts +2 -1
  99. package/lib/typescript/components/Message/MessageSimple/MessageRepliesAvatars.d.ts +2 -0
  100. package/lib/typescript/contexts/channelsContext/ChannelsContext.d.ts +1 -1
  101. package/lib/typescript/contexts/chatContext/ChatContext.d.ts +3 -1
  102. package/lib/typescript/contexts/messageOverlayContext/MessageOverlayContext.d.ts +4 -0
  103. package/lib/typescript/native.d.ts +2 -2
  104. package/package.json +1 -1
  105. package/src/__tests__/offline-feature.test.js +3 -1
  106. package/src/components/Attachment/Card.tsx +11 -2
  107. package/src/components/Attachment/Gallery.tsx +1 -7
  108. package/src/components/Attachment/GalleryImage.tsx +31 -9
  109. package/src/components/Attachment/Giphy.tsx +8 -2
  110. package/src/components/Avatar/Avatar.tsx +12 -2
  111. package/src/components/Avatar/GroupAvatar.tsx +4 -4
  112. package/src/components/ChannelList/ChannelList.tsx +3 -2
  113. package/src/components/ChannelList/ChannelListMessenger.tsx +3 -3
  114. package/src/components/ChannelList/__tests__/ChannelList.test.js +1 -1
  115. package/src/components/ChannelList/hooks/listeners/__tests__/useChannelUpdated.test.tsx +2 -1
  116. package/src/components/ChannelList/hooks/useCreateChannelsContext.ts +1 -1
  117. package/src/components/ChannelList/hooks/usePaginatedChannels.ts +12 -11
  118. package/src/components/ChannelPreview/ChannelAvatar.tsx +23 -4
  119. package/src/components/Chat/Chat.tsx +98 -95
  120. package/src/components/Chat/hooks/useCreateChatContext.ts +2 -0
  121. package/src/components/ImageBackground.tsx +77 -0
  122. package/src/components/Message/Message.tsx +8 -8
  123. package/src/components/Message/MessageSimple/MessageAvatar.tsx +6 -2
  124. package/src/components/Message/MessageSimple/MessageRepliesAvatars.tsx +15 -3
  125. package/src/components/MessageOverlay/MessageOverlay.tsx +210 -205
  126. package/src/contexts/channelsContext/ChannelsContext.tsx +1 -1
  127. package/src/contexts/chatContext/ChatContext.tsx +3 -1
  128. package/src/contexts/messageOverlayContext/MessageOverlayContext.tsx +8 -1
  129. package/src/native.ts +2 -2
  130. package/src/version.json +1 -1
@@ -3,6 +3,8 @@ import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
3
3
 
4
4
  import type { Attachment } from 'stream-chat';
5
5
 
6
+ import { ChatContextValue, useChatContext } from '../../contexts/chatContext/ChatContext';
7
+
6
8
  import {
7
9
  ImageGalleryContextValue,
8
10
  useImageGalleryContext,
@@ -145,6 +147,7 @@ export type GiphyPropsWithContext<
145
147
  | 'onPressIn'
146
148
  | 'preventPress'
147
149
  > &
150
+ Pick<ChatContextValue<StreamChatGenerics>, 'ImageComponent'> &
148
151
  Pick<
149
152
  MessagesContextValue<StreamChatGenerics>,
150
153
  | 'giphyVersion'
@@ -165,6 +168,7 @@ const GiphyWithContext = <
165
168
  attachment,
166
169
  giphyVersion,
167
170
  handleAction,
171
+ ImageComponent = Image,
168
172
  ImageLoadingFailedIndicator,
169
173
  ImageLoadingIndicator,
170
174
  isMyMessage,
@@ -241,7 +245,7 @@ const GiphyWithContext = <
241
245
  >{`/giphy ${title}`}</Text>
242
246
  </View>
243
247
  <View style={styles.selectionImageContainer}>
244
- <Image
248
+ <ImageComponent
245
249
  onError={(error) => {
246
250
  console.warn(error);
247
251
  setLoadingImage(false);
@@ -339,7 +343,7 @@ const GiphyWithContext = <
339
343
  container,
340
344
  ]}
341
345
  >
342
- <Image
346
+ <ImageComponent
343
347
  accessibilityLabel='Giphy Attachment Image'
344
348
  onError={(error) => {
345
349
  console.warn(error);
@@ -446,6 +450,7 @@ export const Giphy = <
446
450
  ) => {
447
451
  const { handleAction, isMyMessage, message, onLongPress, onPress, onPressIn, preventPress } =
448
452
  useMessageContext<StreamChatGenerics>();
453
+ const { ImageComponent } = useChatContext<StreamChatGenerics>();
449
454
  const { additionalTouchableProps, giphyVersion } = useMessagesContext<StreamChatGenerics>();
450
455
  const { setMessages, setSelectedMessage } = useImageGalleryContext<StreamChatGenerics>();
451
456
  const { setOverlay } = useOverlayContext();
@@ -464,6 +469,7 @@ export const Giphy = <
464
469
  additionalTouchableProps,
465
470
  giphyVersion,
466
471
  handleAction,
472
+ ImageComponent,
467
473
  ImageLoadingFailedIndicator,
468
474
  ImageLoadingIndicator,
469
475
  isMyMessage,
@@ -1,5 +1,13 @@
1
1
  import React from 'react';
2
- import { Image, ImageStyle, StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
2
+ import {
3
+ Image,
4
+ ImageProps,
5
+ ImageStyle,
6
+ StyleProp,
7
+ StyleSheet,
8
+ View,
9
+ ViewStyle,
10
+ } from 'react-native';
3
11
  import Svg, { Circle, CircleProps } from 'react-native-svg';
4
12
 
5
13
  import { useTheme } from '../../contexts/themeContext/ThemeContext';
@@ -38,6 +46,7 @@ export type AvatarProps = {
38
46
  containerStyle?: StyleProp<ViewStyle>;
39
47
  /** image url */
40
48
  image?: string;
49
+ ImageComponent?: React.ComponentType<ImageProps>;
41
50
  /** name of the picture, used for fallback */
42
51
  imageStyle?: StyleProp<ImageStyle>;
43
52
  name?: string;
@@ -53,6 +62,7 @@ export type AvatarProps = {
53
62
  export const Avatar: React.FC<AvatarProps> = (props) => {
54
63
  const {
55
64
  containerStyle,
65
+ ImageComponent = Image,
56
66
  image: imageProp,
57
67
  imageStyle,
58
68
  name,
@@ -95,7 +105,7 @@ export const Avatar: React.FC<AvatarProps> = (props) => {
95
105
  }}
96
106
  />
97
107
  ) : (
98
- <Image
108
+ <ImageComponent
99
109
  accessibilityLabel={testID || 'Avatar Image'}
100
110
  onError={() => setLoadingImageError(true)}
101
111
  source={{
@@ -1,10 +1,9 @@
1
1
  import React from 'react';
2
- import { Image, StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
2
+ import { Image, ImageProps, StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
3
3
 
4
4
  import { useTheme } from '../../contexts/themeContext/ThemeContext';
5
5
  import { useLoadingImage } from '../../hooks/useLoadingImage';
6
6
  import { getResizedImageUrl } from '../../utils/getResizedImageUrl';
7
-
8
7
  const randomImageBaseUrl = 'https://getstream.io/random_png/';
9
8
  const randomSvgBaseUrl = 'https://getstream.io/random_svg/';
10
9
  const streamCDN = 'stream-io-cdn.com';
@@ -27,6 +26,7 @@ export type GroupAvatarProps = {
27
26
  /** total size in pixels */
28
27
  size: number;
29
28
  containerStyle?: StyleProp<ViewStyle>;
29
+ ImageComponent?: React.ComponentType<ImageProps>;
30
30
  /** image urls */
31
31
  images?: string[];
32
32
  /** name of the users, used for fallback */
@@ -38,7 +38,7 @@ export type GroupAvatarProps = {
38
38
  * GroupAvatar - A round group of avatar images with fallbacks to users' initials
39
39
  */
40
40
  export const GroupAvatar: React.FC<GroupAvatarProps> = (props) => {
41
- const { containerStyle, images, names, size, testID } = props;
41
+ const { containerStyle, ImageComponent = Image, images, names, size, testID } = props;
42
42
  const {
43
43
  theme: {
44
44
  groupAvatar: { container, image },
@@ -136,7 +136,7 @@ export const GroupAvatar: React.FC<GroupAvatarProps> = (props) => {
136
136
  ]}
137
137
  >
138
138
  {column.map(({ height, name, url, width }, rowIndex) => (
139
- <Image
139
+ <ImageComponent
140
140
  accessibilityLabel={testID || 'Avatar Image'}
141
141
  key={`avatar-${url}-${rowIndex}`}
142
142
  onError={() => setLoadingImageError(true)}
@@ -314,12 +314,13 @@ export const ChannelList = <
314
314
  setChannels,
315
315
  });
316
316
 
317
- const channelIdsStr = channels.reduce((acc, channel) => `${acc}${channel.cid}`, '');
317
+ const channelIdsStr = channels?.reduce((acc, channel) => `${acc}${channel.cid}`, '');
318
318
 
319
319
  useEffect(() => {
320
- if (staticChannelsActive || !enableOfflineSupport) {
320
+ if (channels === null || staticChannelsActive || !enableOfflineSupport) {
321
321
  return;
322
322
  }
323
+
323
324
  upsertCidsForQuery({
324
325
  cids: channels.map((c) => c.cid),
325
326
  filters,
@@ -132,14 +132,14 @@ const ChannelListMessengerWithContext = <
132
132
  if (debugRef.current.setSendEventParams)
133
133
  debugRef.current.setSendEventParams({
134
134
  action: 'Channels',
135
- data: channels.map((channel) => ({
135
+ data: channels?.map((channel) => ({
136
136
  data: channel.data,
137
137
  members: channel.state.members,
138
138
  })),
139
139
  });
140
140
  }
141
141
 
142
- if (error && !refreshing && !loadingChannels && !channels?.length) {
142
+ if (error && !refreshing && !loadingChannels && channels === null) {
143
143
  return (
144
144
  <LoadingErrorIndicator
145
145
  error={error}
@@ -157,7 +157,7 @@ const ChannelListMessengerWithContext = <
157
157
  };
158
158
 
159
159
  const ListFooterComponent = () =>
160
- channels.length && ListHeaderComponent ? <ListHeaderComponent /> : null;
160
+ channels?.length && ListHeaderComponent ? <ListHeaderComponent /> : null;
161
161
 
162
162
  if (loadingChannels) {
163
163
  return <LoadingIndicator listType='channel' />;
@@ -43,7 +43,7 @@ const ChannelListComponent = (props) => {
43
43
  const { channels, onSelect } = useChannelsContext();
44
44
  return (
45
45
  <View testID='channel-list'>
46
- {channels.map((channel) => (
46
+ {channels?.map((channel) => (
47
47
  <ChannelPreviewComponent
48
48
  {...props}
49
49
  channel={channel}
@@ -1,5 +1,5 @@
1
1
  import React, { useState } from 'react';
2
- import { Text } from 'react-native';
2
+ import { Image, Text } from 'react-native';
3
3
 
4
4
  import { act } from 'react-test-renderer';
5
5
 
@@ -59,6 +59,7 @@ describe('useChannelUpdated', () => {
59
59
  client: mockClient,
60
60
  connectionRecovering: false,
61
61
  enableOfflineSupport: false,
62
+ ImageComponent: Image,
62
63
  isOnline: true,
63
64
  mutedUsers: [],
64
65
  setActiveChannel: () => null,
@@ -38,7 +38,7 @@ export const useCreateChannelsContext = <
38
38
  Skeleton,
39
39
  }: ChannelsContextValue<StreamChatGenerics>) => {
40
40
  const channelValueString = channels
41
- .map(
41
+ ?.map(
42
42
  (channel) =>
43
43
  `${channel.data?.name ?? ''}${channel.id ?? ''}${Object.values(channel.state.members)
44
44
  .map((member) => member.user?.online)
@@ -44,11 +44,8 @@ export const usePaginatedChannels = <
44
44
  sort = {},
45
45
  }: Parameters<StreamChatGenerics>) => {
46
46
  const { client } = useChatContext<StreamChatGenerics>();
47
- const initialChannelsStateRef = useRef([]);
48
- const [channels, setChannels] = useState<Channel<StreamChatGenerics>[]>(
49
- initialChannelsStateRef.current,
50
- );
51
- const [staticChannelsActive, setStaticChannelsActive] = useState<boolean>(true);
47
+ const [channels, setChannels] = useState<Channel<StreamChatGenerics>[] | null>(null);
48
+ const [staticChannelsActive, setStaticChannelsActive] = useState<boolean>(false);
52
49
  const activeChannels = useActiveChannelsRefContext();
53
50
 
54
51
  const [error, setError] = useState<Error>();
@@ -95,7 +92,8 @@ export const usePaginatedChannels = <
95
92
 
96
93
  const newOptions = {
97
94
  limit: options?.limit ?? MAX_QUERY_CHANNELS_LIMIT,
98
- offset: queryType === 'loadChannels' && !staticChannelsActive ? channels.length : 0,
95
+ offset:
96
+ queryType === 'loadChannels' && !staticChannelsActive && channels ? channels.length : 0,
99
97
  ...options,
100
98
  };
101
99
 
@@ -108,7 +106,7 @@ export const usePaginatedChannels = <
108
106
  return;
109
107
  }
110
108
  const newChannels =
111
- queryType === 'loadChannels' && !staticChannelsActive
109
+ queryType === 'loadChannels' && !staticChannelsActive && channels
112
110
  ? [...channels, ...channelQueryResponse]
113
111
  : channelQueryResponse;
114
112
 
@@ -195,6 +193,7 @@ export const usePaginatedChannels = <
195
193
  offlineMode: true,
196
194
  }),
197
195
  );
196
+ setStaticChannelsActive(true);
198
197
  }
199
198
  } catch (e) {
200
199
  console.warn('Failed to get channels from database: ', e);
@@ -212,15 +211,17 @@ export const usePaginatedChannels = <
212
211
  error,
213
212
  hasNextPage,
214
213
  loadingChannels:
215
- activeQueryType === 'queryLocalDB'
216
- ? true
217
- : activeQueryType === 'reload' && channels === initialChannelsStateRef.current,
214
+ activeQueryType === 'queryLocalDB' ? true : activeQueryType === 'reload' && channels === null,
218
215
  loadingNextPage: activeQueryType === 'loadChannels',
219
216
  loadNextPage,
220
217
  refreshing: activeQueryType === 'refresh',
221
218
  refreshList,
222
219
  reloadList,
223
- setChannels,
220
+ // Although channels can be null, there is no practical case where channels will be null
221
+ // when setChannels is used. setChannels is only recommended to be used for overriding
222
+ // event handler. Thus instead of adding if check for channels === null, its better to
223
+ // simply reassign types here.
224
+ setChannels: setChannels as React.Dispatch<React.SetStateAction<Channel<StreamChatGenerics>[]>>,
224
225
  staticChannelsActive,
225
226
  };
226
227
  };
@@ -4,6 +4,7 @@ import type { ChannelPreviewProps } from './ChannelPreview';
4
4
  import { useChannelPreviewDisplayAvatar } from './hooks/useChannelPreviewDisplayAvatar';
5
5
  import { useChannelPreviewDisplayPresence } from './hooks/useChannelPreviewDisplayPresence';
6
6
 
7
+ import { ChatContextValue, useChatContext } from '../../contexts/chatContext/ChatContext';
7
8
  import type { DefaultStreamChatGenerics } from '../../types/types';
8
9
  import { Avatar } from '../Avatar/Avatar';
9
10
  import { GroupAvatar } from '../Avatar/GroupAvatar';
@@ -15,26 +16,44 @@ export type ChannelAvatarProps<
15
16
  /**
16
17
  * This UI component displays an avatar for a particular channel.
17
18
  */
18
- export const ChannelAvatar = <
19
+ export const ChannelAvatarWithContext = <
19
20
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
20
21
  >(
21
- props: ChannelAvatarProps<StreamChatGenerics>,
22
+ props: ChannelAvatarProps<StreamChatGenerics> & Pick<ChatContextValue, 'ImageComponent'>,
22
23
  ) => {
23
- const { channel } = props;
24
+ const { channel, ImageComponent } = props;
24
25
 
25
26
  const displayAvatar = useChannelPreviewDisplayAvatar(channel);
26
27
  const displayPresence = useChannelPreviewDisplayPresence(channel);
27
28
 
28
29
  if (displayAvatar.images) {
29
- return <GroupAvatar images={displayAvatar.images} names={displayAvatar.names} size={40} />;
30
+ return (
31
+ <GroupAvatar
32
+ ImageComponent={ImageComponent}
33
+ images={displayAvatar.images}
34
+ names={displayAvatar.names}
35
+ size={40}
36
+ />
37
+ );
30
38
  }
31
39
 
32
40
  return (
33
41
  <Avatar
34
42
  image={displayAvatar.image}
43
+ ImageComponent={ImageComponent}
35
44
  name={displayAvatar.name}
36
45
  online={displayPresence}
37
46
  size={40}
38
47
  />
39
48
  );
40
49
  };
50
+
51
+ export const ChannelAvatar = <
52
+ StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
53
+ >(
54
+ props: ChannelAvatarProps<StreamChatGenerics>,
55
+ ) => {
56
+ const { ImageComponent } = useChatContext<StreamChatGenerics>();
57
+
58
+ return <ChannelAvatarWithContext {...props} ImageComponent={ImageComponent} />;
59
+ };
@@ -1,5 +1,5 @@
1
1
  import React, { PropsWithChildren, useEffect, useState } from 'react';
2
- import { Platform } from 'react-native';
2
+ import { Image, Platform } from 'react-native';
3
3
 
4
4
  import Dayjs from 'dayjs';
5
5
 
@@ -37,100 +37,101 @@ init();
37
37
 
38
38
  export type ChatProps<
39
39
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
40
- > = Pick<ChatContextValue<StreamChatGenerics>, 'client'> & {
41
- /**
42
- * When false, ws connection won't be disconnection upon backgrounding the app.
43
- * To receive push notifications, its necessary that user doesn't have active
44
- * websocket connection. So by default, we disconnect websocket connection when
45
- * app goes to background, and reconnect when app comes to foreground.
46
- */
47
- closeConnectionOnBackground?: boolean;
48
- /**
49
- * Enables offline storage and loading for chat data.
50
- */
51
- enableOfflineSupport?: boolean;
52
- /**
53
- * Instance of Streami18n class should be provided to Chat component to enable internationalization.
54
- *
55
- * Stream provides following list of in-built translations:
56
- * 1. English (en)
57
- * 2. Dutch (nl)
58
- * 3. ...
59
- * 4. ...
60
- *
61
- * Simplest way to start using chat components in one of the in-built languages would be following:
62
- *
63
- * ```
64
- * const i18n = new Streami18n('nl');
65
- * <Chat client={chatClient} i18nInstance={i18n}>
66
- * ...
67
- * </Chat>
68
- * ```
69
- *
70
- * If you would like to override certain keys in in-built translation.
71
- * UI will be automatically updated in this case.
72
- *
73
- * ```
74
- * const i18n = new Streami18n('nl');
75
- *
76
- * i18n.registerTranslation('nl', {
77
- * 'Nothing yet...': 'Nog Niet ...',
78
- * '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} en {{ secondUser }} zijn aan het typen...',
79
- * });
80
- *
81
- * <Chat client={chatClient} i18nInstance={i18n}>
82
- * ...
83
- * </Chat>
84
- * ```
85
- *
86
- * You can use the same function to add whole new language.
87
- *
88
- * ```
89
- * const i18n = new Streami18n('it');
90
- *
91
- * i18n.registerTranslation('it', {
92
- * 'Nothing yet...': 'Non ancora ...',
93
- * '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} a {{ secondUser }} stanno scrivendo...',
94
- * });
95
- *
96
- * // Make sure to call setLanguage to reflect new language in UI.
97
- * i18n.setLanguage('it');
98
- * <Chat client={chatClient} i18nInstance={i18n}>
99
- * ...
100
- * </Chat>
101
- * ```
102
- */
103
- i18nInstance?: Streami18n;
104
- /**
105
- * You can pass the theme object to customize the styles of Chat components. You can check the default theme in [theme.ts](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/contexts/themeContext/utils/theme.ts)
106
- *
107
- * Please check section about [themes in cookbook](https://github.com/GetStream/stream-chat-react-native/wiki/Cookbook-v3.0#theme) for details.
108
- *
109
- * ```
110
- * import type { DeepPartial, Theme } from 'stream-chat-react-native';
111
- *
112
- * const theme: DeepPartial<Theme> = {
113
- * messageSimple: {
114
- * file: {
115
- * container: {
116
- * backgroundColor: 'red',
117
- * },
118
- * icon: {
119
- * height: 16,
120
- * width: 16,
121
- * },
122
- * },
123
- * },
124
- * };
125
- *
126
- * <Chat style={theme}>
127
- * </Chat>
128
- * ```
129
- *
130
- * @overrideType object
131
- */
132
- style?: DeepPartial<Theme>;
133
- };
40
+ > = Pick<ChatContextValue<StreamChatGenerics>, 'client'> &
41
+ Partial<Pick<ChatContextValue<StreamChatGenerics>, 'ImageComponent'>> & {
42
+ /**
43
+ * When false, ws connection won't be disconnection upon backgrounding the app.
44
+ * To receive push notifications, its necessary that user doesn't have active
45
+ * websocket connection. So by default, we disconnect websocket connection when
46
+ * app goes to background, and reconnect when app comes to foreground.
47
+ */
48
+ closeConnectionOnBackground?: boolean;
49
+ /**
50
+ * Enables offline storage and loading for chat data.
51
+ */
52
+ enableOfflineSupport?: boolean;
53
+ /**
54
+ * Instance of Streami18n class should be provided to Chat component to enable internationalization.
55
+ *
56
+ * Stream provides following list of in-built translations:
57
+ * 1. English (en)
58
+ * 2. Dutch (nl)
59
+ * 3. ...
60
+ * 4. ...
61
+ *
62
+ * Simplest way to start using chat components in one of the in-built languages would be following:
63
+ *
64
+ * ```
65
+ * const i18n = new Streami18n('nl');
66
+ * <Chat client={chatClient} i18nInstance={i18n}>
67
+ * ...
68
+ * </Chat>
69
+ * ```
70
+ *
71
+ * If you would like to override certain keys in in-built translation.
72
+ * UI will be automatically updated in this case.
73
+ *
74
+ * ```
75
+ * const i18n = new Streami18n('nl');
76
+ *
77
+ * i18n.registerTranslation('nl', {
78
+ * 'Nothing yet...': 'Nog Niet ...',
79
+ * '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} en {{ secondUser }} zijn aan het typen...',
80
+ * });
81
+ *
82
+ * <Chat client={chatClient} i18nInstance={i18n}>
83
+ * ...
84
+ * </Chat>
85
+ * ```
86
+ *
87
+ * You can use the same function to add whole new language.
88
+ *
89
+ * ```
90
+ * const i18n = new Streami18n('it');
91
+ *
92
+ * i18n.registerTranslation('it', {
93
+ * 'Nothing yet...': 'Non ancora ...',
94
+ * '{{ firstUser }} and {{ secondUser }} are typing...': '{{ firstUser }} a {{ secondUser }} stanno scrivendo...',
95
+ * });
96
+ *
97
+ * // Make sure to call setLanguage to reflect new language in UI.
98
+ * i18n.setLanguage('it');
99
+ * <Chat client={chatClient} i18nInstance={i18n}>
100
+ * ...
101
+ * </Chat>
102
+ * ```
103
+ */
104
+ i18nInstance?: Streami18n;
105
+ /**
106
+ * You can pass the theme object to customize the styles of Chat components. You can check the default theme in [theme.ts](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/contexts/themeContext/utils/theme.ts)
107
+ *
108
+ * Please check section about [themes in cookbook](https://github.com/GetStream/stream-chat-react-native/wiki/Cookbook-v3.0#theme) for details.
109
+ *
110
+ * ```
111
+ * import type { DeepPartial, Theme } from 'stream-chat-react-native';
112
+ *
113
+ * const theme: DeepPartial<Theme> = {
114
+ * messageSimple: {
115
+ * file: {
116
+ * container: {
117
+ * backgroundColor: 'red',
118
+ * },
119
+ * icon: {
120
+ * height: 16,
121
+ * width: 16,
122
+ * },
123
+ * },
124
+ * },
125
+ * };
126
+ *
127
+ * <Chat style={theme}>
128
+ * </Chat>
129
+ * ```
130
+ *
131
+ * @overrideType object
132
+ */
133
+ style?: DeepPartial<Theme>;
134
+ };
134
135
 
135
136
  const ChatWithContext = <
136
137
  StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
@@ -143,6 +144,7 @@ const ChatWithContext = <
143
144
  closeConnectionOnBackground = true,
144
145
  enableOfflineSupport = false,
145
146
  i18nInstance,
147
+ ImageComponent = Image,
146
148
  style,
147
149
  } = props;
148
150
 
@@ -206,6 +208,7 @@ const ChatWithContext = <
206
208
  client,
207
209
  connectionRecovering,
208
210
  enableOfflineSupport,
211
+ ImageComponent,
209
212
  isOnline,
210
213
  mutedUsers,
211
214
  setActiveChannel,
@@ -11,6 +11,7 @@ export const useCreateChatContext = <
11
11
  client,
12
12
  connectionRecovering,
13
13
  enableOfflineSupport,
14
+ ImageComponent,
14
15
  isOnline,
15
16
  mutedUsers,
16
17
  setActiveChannel,
@@ -31,6 +32,7 @@ export const useCreateChatContext = <
31
32
  client,
32
33
  connectionRecovering,
33
34
  enableOfflineSupport,
35
+ ImageComponent,
34
36
  isOnline,
35
37
  mutedUsers,
36
38
  setActiveChannel,
@@ -0,0 +1,77 @@
1
+ import * as React from 'react';
2
+
3
+ import { Image, ImageBackgroundProps, ImageProps, StyleSheet, View } from 'react-native';
4
+
5
+ /**
6
+ * DISCLAIMER: This component has been pretty-much copied from react-native's source code
7
+ * https://github.com/facebook/react-native/blob/main/Libraries/Image/ImageBackground.js
8
+ * Few modifications have been done such as converting to functional component, removing ref related logic (since its not required).
9
+ * Also support for prop `ImageComponent` has been introduced to allow rendering custom
10
+ * component instead of `Image`.
11
+ *
12
+ *
13
+ * Very simple drop-in replacement for <Image> which supports nesting views.
14
+ *
15
+ * ```ReactNativeWebPlayer
16
+ * import React, { Component } from 'react';
17
+ * import { AppRegistry, View, ImageBackground, Text } from 'react-native';
18
+ *
19
+ * class DisplayAnImageBackground extends Component {
20
+ * render() {
21
+ * return (
22
+ * <ImageBackground
23
+ * style={{width: 50, height: 50}}
24
+ * source={{uri: 'https://reactnative.dev/img/opengraph.png'}}
25
+ * >
26
+ * <Text>React</Text>
27
+ * </ImageBackground>
28
+ * );
29
+ * }
30
+ * }
31
+ *
32
+ */
33
+
34
+ export const ImageBackground: React.ComponentType<
35
+ ImageBackgroundProps & {
36
+ ImageComponent?: React.ComponentType<ImageProps>;
37
+ }
38
+ > = (props) => {
39
+ const {
40
+ children,
41
+ ImageComponent = Image,
42
+ imageStyle,
43
+ importantForAccessibility,
44
+ style,
45
+ ...rest
46
+ } = props;
47
+
48
+ const flattenedStyle = StyleSheet.flatten(style);
49
+ return (
50
+ <View
51
+ accessibilityIgnoresInvertColors={true}
52
+ importantForAccessibility={importantForAccessibility}
53
+ style={style}
54
+ >
55
+ <ImageComponent
56
+ {...rest}
57
+ importantForAccessibility={importantForAccessibility}
58
+ style={[
59
+ StyleSheet.absoluteFill,
60
+ {
61
+ // Temporary Workaround:
62
+ // Current (imperfect yet) implementation of <Image> overwrites width and height styles
63
+ // (which is not quite correct), and these styles conflict with explicitly set styles
64
+ // of <ImageBackground> and with our internal layout model here.
65
+ // So, we have to proxy/reapply these styles explicitly for actual <Image> component.
66
+ // This workaround should be removed after implementing proper support of
67
+ // intrinsic content size of the <Image>.
68
+ height: flattenedStyle?.height,
69
+ width: flattenedStyle?.width,
70
+ },
71
+ imageStyle,
72
+ ]}
73
+ />
74
+ {children}
75
+ </View>
76
+ );
77
+ };