stream-chat-react-native-core 9.0.0-beta.12 → 9.0.0-beta.14

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 (198) hide show
  1. package/lib/commonjs/components/AttachmentPicker/AttachmentPicker.js +12 -0
  2. package/lib/commonjs/components/AttachmentPicker/AttachmentPicker.js.map +1 -1
  3. package/lib/commonjs/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js +30 -30
  4. package/lib/commonjs/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js.map +1 -1
  5. package/lib/commonjs/components/ImageGallery/ImageGallery.js +2 -0
  6. package/lib/commonjs/components/ImageGallery/ImageGallery.js.map +1 -1
  7. package/lib/commonjs/components/Message/Message.js +3 -2
  8. package/lib/commonjs/components/Message/Message.js.map +1 -1
  9. package/lib/commonjs/components/Message/MessageItemView/MessageBubble.js +6 -3
  10. package/lib/commonjs/components/Message/MessageItemView/MessageBubble.js.map +1 -1
  11. package/lib/commonjs/components/Message/MessageItemView/MessageReplies.js +17 -11
  12. package/lib/commonjs/components/Message/MessageItemView/MessageReplies.js.map +1 -1
  13. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.js +52 -10
  14. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.js.map +1 -1
  15. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.js +10 -8
  16. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.js.map +1 -1
  17. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.js +8 -2
  18. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.js.map +1 -1
  19. package/lib/commonjs/components/Poll/CreatePollContent.js +11 -5
  20. package/lib/commonjs/components/Poll/CreatePollContent.js.map +1 -1
  21. package/lib/commonjs/components/Poll/Poll.js +4 -2
  22. package/lib/commonjs/components/Poll/Poll.js.map +1 -1
  23. package/lib/commonjs/components/Poll/components/CreatePollOptions.js +6 -3
  24. package/lib/commonjs/components/Poll/components/CreatePollOptions.js.map +1 -1
  25. package/lib/commonjs/components/Poll/components/MultipleAnswersField.js +7 -3
  26. package/lib/commonjs/components/Poll/components/MultipleAnswersField.js.map +1 -1
  27. package/lib/commonjs/components/Poll/components/MultipleVotesSettings.js +9 -4
  28. package/lib/commonjs/components/Poll/components/MultipleVotesSettings.js.map +1 -1
  29. package/lib/commonjs/components/Poll/components/PollAnswersList.js +2 -2
  30. package/lib/commonjs/components/Poll/components/PollAnswersList.js.map +1 -1
  31. package/lib/commonjs/components/Poll/components/PollInputDialog.js +2 -1
  32. package/lib/commonjs/components/Poll/components/PollInputDialog.js.map +1 -1
  33. package/lib/commonjs/components/Poll/components/PollOption.js +12 -5
  34. package/lib/commonjs/components/Poll/components/PollOption.js.map +1 -1
  35. package/lib/commonjs/components/Poll/components/PollResults/PollOptionFullResults.js +7 -5
  36. package/lib/commonjs/components/Poll/components/PollResults/PollOptionFullResults.js.map +1 -1
  37. package/lib/commonjs/components/Poll/components/PollResults/PollResultItem.js +6 -3
  38. package/lib/commonjs/components/Poll/components/PollResults/PollResultItem.js.map +1 -1
  39. package/lib/commonjs/components/Poll/components/PollResults/PollResults.js +8 -3
  40. package/lib/commonjs/components/Poll/components/PollResults/PollResults.js.map +1 -1
  41. package/lib/commonjs/components/Poll/components/PollResults/PollVote.js +4 -2
  42. package/lib/commonjs/components/Poll/components/PollResults/PollVote.js.map +1 -1
  43. package/lib/commonjs/components/ProgressControl/ProgressControl.js +7 -5
  44. package/lib/commonjs/components/ProgressControl/ProgressControl.js.map +1 -1
  45. package/lib/commonjs/components/ProgressControl/WaveProgressBar.js +6 -4
  46. package/lib/commonjs/components/ProgressControl/WaveProgressBar.js.map +1 -1
  47. package/lib/commonjs/components/Reply/Reply.js +14 -7
  48. package/lib/commonjs/components/Reply/Reply.js.map +1 -1
  49. package/lib/commonjs/components/Reply/ReplyMessageView.js +2 -1
  50. package/lib/commonjs/components/Reply/ReplyMessageView.js.map +1 -1
  51. package/lib/commonjs/components/ThreadList/ThreadListItem.js +2 -1
  52. package/lib/commonjs/components/ThreadList/ThreadListItem.js.map +1 -1
  53. package/lib/commonjs/components/UIComponents/SwipableWrapper.js +41 -12
  54. package/lib/commonjs/components/UIComponents/SwipableWrapper.js.map +1 -1
  55. package/lib/commonjs/components/ui/Input/Input.js +8 -4
  56. package/lib/commonjs/components/ui/Input/Input.js.map +1 -1
  57. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +1 -0
  58. package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  59. package/lib/commonjs/contexts/overlayContext/MessageOverlayHostLayer.js +14 -6
  60. package/lib/commonjs/contexts/overlayContext/MessageOverlayHostLayer.js.map +1 -1
  61. package/lib/commonjs/index.js +12 -0
  62. package/lib/commonjs/index.js.map +1 -1
  63. package/lib/commonjs/middlewares/attachments.js +33 -1
  64. package/lib/commonjs/middlewares/attachments.js.map +1 -1
  65. package/lib/commonjs/utils/createGenerateVideoThumbnails.js +41 -0
  66. package/lib/commonjs/utils/createGenerateVideoThumbnails.js.map +1 -0
  67. package/lib/commonjs/version.json +1 -1
  68. package/lib/module/components/AttachmentPicker/AttachmentPicker.js +12 -0
  69. package/lib/module/components/AttachmentPicker/AttachmentPicker.js.map +1 -1
  70. package/lib/module/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js +30 -30
  71. package/lib/module/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.js.map +1 -1
  72. package/lib/module/components/ImageGallery/ImageGallery.js +2 -0
  73. package/lib/module/components/ImageGallery/ImageGallery.js.map +1 -1
  74. package/lib/module/components/Message/Message.js +3 -2
  75. package/lib/module/components/Message/Message.js.map +1 -1
  76. package/lib/module/components/Message/MessageItemView/MessageBubble.js +6 -3
  77. package/lib/module/components/Message/MessageItemView/MessageBubble.js.map +1 -1
  78. package/lib/module/components/Message/MessageItemView/MessageReplies.js +17 -11
  79. package/lib/module/components/Message/MessageItemView/MessageReplies.js.map +1 -1
  80. package/lib/module/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.js +52 -10
  81. package/lib/module/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.js.map +1 -1
  82. package/lib/module/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.js +10 -8
  83. package/lib/module/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.js.map +1 -1
  84. package/lib/module/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.js +8 -2
  85. package/lib/module/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.js.map +1 -1
  86. package/lib/module/components/Poll/CreatePollContent.js +11 -5
  87. package/lib/module/components/Poll/CreatePollContent.js.map +1 -1
  88. package/lib/module/components/Poll/Poll.js +4 -2
  89. package/lib/module/components/Poll/Poll.js.map +1 -1
  90. package/lib/module/components/Poll/components/CreatePollOptions.js +6 -3
  91. package/lib/module/components/Poll/components/CreatePollOptions.js.map +1 -1
  92. package/lib/module/components/Poll/components/MultipleAnswersField.js +7 -3
  93. package/lib/module/components/Poll/components/MultipleAnswersField.js.map +1 -1
  94. package/lib/module/components/Poll/components/MultipleVotesSettings.js +9 -4
  95. package/lib/module/components/Poll/components/MultipleVotesSettings.js.map +1 -1
  96. package/lib/module/components/Poll/components/PollAnswersList.js +2 -2
  97. package/lib/module/components/Poll/components/PollAnswersList.js.map +1 -1
  98. package/lib/module/components/Poll/components/PollInputDialog.js +2 -1
  99. package/lib/module/components/Poll/components/PollInputDialog.js.map +1 -1
  100. package/lib/module/components/Poll/components/PollOption.js +12 -5
  101. package/lib/module/components/Poll/components/PollOption.js.map +1 -1
  102. package/lib/module/components/Poll/components/PollResults/PollOptionFullResults.js +7 -5
  103. package/lib/module/components/Poll/components/PollResults/PollOptionFullResults.js.map +1 -1
  104. package/lib/module/components/Poll/components/PollResults/PollResultItem.js +6 -3
  105. package/lib/module/components/Poll/components/PollResults/PollResultItem.js.map +1 -1
  106. package/lib/module/components/Poll/components/PollResults/PollResults.js +8 -3
  107. package/lib/module/components/Poll/components/PollResults/PollResults.js.map +1 -1
  108. package/lib/module/components/Poll/components/PollResults/PollVote.js +4 -2
  109. package/lib/module/components/Poll/components/PollResults/PollVote.js.map +1 -1
  110. package/lib/module/components/ProgressControl/ProgressControl.js +7 -5
  111. package/lib/module/components/ProgressControl/ProgressControl.js.map +1 -1
  112. package/lib/module/components/ProgressControl/WaveProgressBar.js +6 -4
  113. package/lib/module/components/ProgressControl/WaveProgressBar.js.map +1 -1
  114. package/lib/module/components/Reply/Reply.js +14 -7
  115. package/lib/module/components/Reply/Reply.js.map +1 -1
  116. package/lib/module/components/Reply/ReplyMessageView.js +2 -1
  117. package/lib/module/components/Reply/ReplyMessageView.js.map +1 -1
  118. package/lib/module/components/ThreadList/ThreadListItem.js +2 -1
  119. package/lib/module/components/ThreadList/ThreadListItem.js.map +1 -1
  120. package/lib/module/components/UIComponents/SwipableWrapper.js +41 -12
  121. package/lib/module/components/UIComponents/SwipableWrapper.js.map +1 -1
  122. package/lib/module/components/ui/Input/Input.js +8 -4
  123. package/lib/module/components/ui/Input/Input.js.map +1 -1
  124. package/lib/module/contexts/messageInputContext/MessageInputContext.js +1 -0
  125. package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
  126. package/lib/module/contexts/overlayContext/MessageOverlayHostLayer.js +14 -6
  127. package/lib/module/contexts/overlayContext/MessageOverlayHostLayer.js.map +1 -1
  128. package/lib/module/index.js +12 -0
  129. package/lib/module/index.js.map +1 -1
  130. package/lib/module/middlewares/attachments.js +33 -1
  131. package/lib/module/middlewares/attachments.js.map +1 -1
  132. package/lib/module/utils/createGenerateVideoThumbnails.js +41 -0
  133. package/lib/module/utils/createGenerateVideoThumbnails.js.map +1 -0
  134. package/lib/module/version.json +1 -1
  135. package/lib/typescript/components/AttachmentPicker/AttachmentPicker.d.ts.map +1 -1
  136. package/lib/typescript/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.d.ts.map +1 -1
  137. package/lib/typescript/components/ImageGallery/ImageGallery.d.ts.map +1 -1
  138. package/lib/typescript/components/Message/Message.d.ts.map +1 -1
  139. package/lib/typescript/components/Message/MessageItemView/MessageBubble.d.ts.map +1 -1
  140. package/lib/typescript/components/Message/MessageItemView/MessageReplies.d.ts +1 -1
  141. package/lib/typescript/components/Message/MessageItemView/MessageReplies.d.ts.map +1 -1
  142. package/lib/typescript/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.d.ts.map +1 -1
  143. package/lib/typescript/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.d.ts.map +1 -1
  144. package/lib/typescript/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.d.ts.map +1 -1
  145. package/lib/typescript/components/Poll/components/CreatePollOptions.d.ts.map +1 -1
  146. package/lib/typescript/components/Poll/components/PollInputDialog.d.ts.map +1 -1
  147. package/lib/typescript/components/Poll/components/PollOption.d.ts.map +1 -1
  148. package/lib/typescript/components/Poll/components/PollResults/PollResults.d.ts.map +1 -1
  149. package/lib/typescript/components/ProgressControl/ProgressControl.d.ts.map +1 -1
  150. package/lib/typescript/components/ProgressControl/WaveProgressBar.d.ts.map +1 -1
  151. package/lib/typescript/components/Reply/Reply.d.ts.map +1 -1
  152. package/lib/typescript/components/UIComponents/SwipableWrapper.d.ts +4 -1
  153. package/lib/typescript/components/UIComponents/SwipableWrapper.d.ts.map +1 -1
  154. package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts.map +1 -1
  155. package/lib/typescript/contexts/overlayContext/MessageOverlayHostLayer.d.ts.map +1 -1
  156. package/lib/typescript/index.d.ts +1 -0
  157. package/lib/typescript/index.d.ts.map +1 -1
  158. package/lib/typescript/middlewares/attachments.d.ts +1 -0
  159. package/lib/typescript/middlewares/attachments.d.ts.map +1 -1
  160. package/lib/typescript/utils/createGenerateVideoThumbnails.d.ts +8 -0
  161. package/lib/typescript/utils/createGenerateVideoThumbnails.d.ts.map +1 -0
  162. package/package.json +1 -1
  163. package/src/components/AttachmentPicker/AttachmentPicker.tsx +14 -0
  164. package/src/components/AttachmentPicker/components/AttachmentMediaPicker/AttachmentPickerItem.tsx +32 -34
  165. package/src/components/ImageGallery/ImageGallery.tsx +5 -1
  166. package/src/components/ImageGallery/__tests__/ImageGallery.test.tsx +33 -0
  167. package/src/components/Message/Message.tsx +15 -3
  168. package/src/components/Message/MessageItemView/MessageBubble.tsx +15 -4
  169. package/src/components/Message/MessageItemView/MessageReplies.tsx +24 -12
  170. package/src/components/MessageInput/components/AttachmentPreview/AttachmentUploadPreviewList.tsx +62 -11
  171. package/src/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.tsx +10 -9
  172. package/src/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.tsx +12 -2
  173. package/src/components/Poll/CreatePollContent.tsx +10 -2
  174. package/src/components/Poll/Poll.tsx +2 -0
  175. package/src/components/Poll/components/CreatePollOptions.tsx +12 -1
  176. package/src/components/Poll/components/MultipleAnswersField.tsx +4 -0
  177. package/src/components/Poll/components/MultipleVotesSettings.tsx +6 -1
  178. package/src/components/Poll/components/PollAnswersList.tsx +1 -2
  179. package/src/components/Poll/components/PollInputDialog.tsx +2 -0
  180. package/src/components/Poll/components/PollOption.tsx +47 -39
  181. package/src/components/Poll/components/PollResults/PollOptionFullResults.tsx +41 -37
  182. package/src/components/Poll/components/PollResults/PollResultItem.tsx +63 -62
  183. package/src/components/Poll/components/PollResults/PollResults.tsx +39 -33
  184. package/src/components/Poll/components/PollResults/PollVote.tsx +27 -27
  185. package/src/components/ProgressControl/ProgressControl.tsx +8 -6
  186. package/src/components/ProgressControl/WaveProgressBar.tsx +9 -7
  187. package/src/components/Reply/Reply.tsx +19 -7
  188. package/src/components/Reply/ReplyMessageView.tsx +1 -0
  189. package/src/components/ThreadList/ThreadListItem.tsx +1 -0
  190. package/src/components/UIComponents/SwipableWrapper.tsx +54 -16
  191. package/src/components/UIComponents/__tests__/SwipableWrapper.test.tsx +98 -0
  192. package/src/components/ui/Input/Input.tsx +4 -0
  193. package/src/contexts/messageInputContext/MessageInputContext.tsx +3 -0
  194. package/src/contexts/overlayContext/MessageOverlayHostLayer.tsx +14 -3
  195. package/src/index.ts +1 -0
  196. package/src/middlewares/attachments.ts +34 -0
  197. package/src/utils/createGenerateVideoThumbnails.ts +45 -0
  198. package/src/version.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo } from 'react';
2
- import { Image, StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native';
2
+ import { I18nManager, Image, StyleSheet, Text, TextStyle, View, ViewStyle } from 'react-native';
3
3
 
4
4
  import {
5
5
  isFileAttachment,
@@ -251,6 +251,7 @@ const useStyles = () => {
251
251
  const { client } = useChatContext();
252
252
 
253
253
  const isMyMessage = client.user?.id === quotedMessageFromComposer?.user?.id;
254
+ const isRTL = I18nManager.isRTL;
254
255
 
255
256
  return useMemo(
256
257
  () =>
@@ -262,7 +263,7 @@ const useStyles = () => {
262
263
  },
263
264
  container: {
264
265
  borderRadius: primitives.radiusLg,
265
- flexDirection: 'row',
266
+ flexDirection: isRTL ? 'row-reverse' : 'row',
266
267
  padding: primitives.spacingXs,
267
268
  backgroundColor: isMyMessage ? semantics.chatBgOutgoing : semantics.chatBgIncoming,
268
269
  },
@@ -282,14 +283,24 @@ const useStyles = () => {
282
283
  top: 0,
283
284
  },
284
285
  leftContainer: {
285
- borderLeftWidth: 2,
286
286
  flex: 1,
287
287
  justifyContent: 'center',
288
288
  paddingHorizontal: primitives.spacingXs,
289
- borderLeftColor: isMyMessage
290
- ? semantics.chatReplyIndicatorOutgoing
291
- : semantics.chatReplyIndicatorIncoming,
292
289
  gap: primitives.spacingXxxs,
290
+ alignItems: 'flex-start',
291
+ ...(isRTL
292
+ ? {
293
+ borderRightColor: isMyMessage
294
+ ? semantics.chatReplyIndicatorOutgoing
295
+ : semantics.chatReplyIndicatorIncoming,
296
+ borderRightWidth: 2,
297
+ }
298
+ : {
299
+ borderLeftColor: isMyMessage
300
+ ? semantics.chatReplyIndicatorOutgoing
301
+ : semantics.chatReplyIndicatorIncoming,
302
+ borderLeftWidth: 2,
303
+ }),
293
304
  },
294
305
  rightContainer: {},
295
306
  title: {
@@ -298,11 +309,12 @@ const useStyles = () => {
298
309
  fontWeight: primitives.typographyFontWeightSemiBold,
299
310
  includeFontPadding: false,
300
311
  lineHeight: primitives.typographyLineHeightTight,
312
+ textAlign: isRTL ? 'right' : 'left',
301
313
  },
302
314
  wrapper: {
303
315
  padding: primitives.spacingXxs,
304
316
  },
305
317
  }),
306
- [isMyMessage, semantics],
318
+ [isMyMessage, isRTL, semantics],
307
319
  );
308
320
  };
@@ -50,6 +50,7 @@ const useStyles = ({ isMyMessage = false }: { isMyMessage?: boolean }) => {
50
50
  alignItems: 'center',
51
51
  gap: primitives.spacingXxs,
52
52
  flexShrink: 1,
53
+ alignSelf: 'flex-start',
53
54
  ...messagePreview.container,
54
55
  },
55
56
  subtitle: {
@@ -260,6 +260,7 @@ const useStyles = () => {
260
260
  fontSize: primitives.typographyFontSizeSm,
261
261
  fontWeight: primitives.typographyFontWeightSemiBold,
262
262
  lineHeight: primitives.typographyLineHeightNormal,
263
+ textAlign: 'left',
263
264
  ...threadListItem.channelName,
264
265
  },
265
266
  content: {
@@ -1,5 +1,5 @@
1
1
  import React, { PropsWithChildren, useEffect, useMemo, useRef } from 'react';
2
- import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
2
+ import { I18nManager, StyleProp, StyleSheet, View, ViewStyle } from 'react-native';
3
3
 
4
4
  import { Pressable } from 'react-native-gesture-handler';
5
5
  import Animated, {
@@ -42,6 +42,8 @@ export type SwipableWrapperProps = PropsWithChildren<{
42
42
  swipableProps?: SwipeableProps;
43
43
  }>;
44
44
 
45
+ type ActionSide = 'left' | 'right';
46
+
45
47
  export const getRightActionsLayout = (itemCount: number) => {
46
48
  if (!itemCount) {
47
49
  return { containerWidth: 0, itemWidth: 0 };
@@ -55,19 +57,27 @@ export const getRightActionsLayout = (itemCount: number) => {
55
57
 
56
58
  export const RightActions = ({
57
59
  items,
60
+ side,
58
61
  translation,
59
62
  }: {
60
63
  items: SwipableActionItem[];
64
+ side?: ActionSide;
61
65
  translation: SharedValue<number>;
62
66
  }) => {
67
+ const resolvedSide = side ?? (I18nManager.isRTL ? 'left' : 'right');
63
68
  const { containerWidth, itemWidth } = useMemo(
64
69
  () => getRightActionsLayout(items.length),
65
70
  [items.length],
66
71
  );
72
+ const actionItems = useMemo(
73
+ () => (resolvedSide === 'left' ? [...items].reverse() : items),
74
+ [items, resolvedSide],
75
+ );
76
+ const translationDirection = resolvedSide === 'right' ? -1 : 1;
67
77
 
68
78
  const animatedActionWidthStyle = useAnimatedStyle(() => ({
69
79
  width: interpolate(
70
- -translation.value,
80
+ translationDirection * translation.value,
71
81
  [0, containerWidth, containerWidth + 40],
72
82
  [0, itemWidth, itemWidth + 8],
73
83
  Extrapolation.CLAMP,
@@ -78,7 +88,7 @@ export const RightActions = ({
78
88
  transform: [
79
89
  {
80
90
  scale: interpolate(
81
- -translation.value,
91
+ translationDirection * translation.value,
82
92
  [0, containerWidth, containerWidth + 40],
83
93
  [0, 1, 1],
84
94
  Extrapolation.CLAMP,
@@ -88,8 +98,13 @@ export const RightActions = ({
88
98
  }));
89
99
 
90
100
  return (
91
- <Animated.View style={[styles.rightActionsContainer, { width: containerWidth }]}>
92
- {items.map((item) => {
101
+ <Animated.View
102
+ style={[
103
+ resolvedSide === 'left' ? styles.leftActionsContainer : styles.rightActionsContainer,
104
+ { width: containerWidth },
105
+ ]}
106
+ >
107
+ {actionItems.map((item) => {
93
108
  const Content = item.Content;
94
109
  return (
95
110
  <AnimatedPressable
@@ -110,6 +125,7 @@ export const RightActions = ({
110
125
  };
111
126
 
112
127
  export const SwipableWrapper = ({ children, swipeableId, swipableProps }: SwipableWrapperProps) => {
128
+ const isRTL = I18nManager.isRTL;
113
129
  const swipeRegistry = useSwipeRegistryContext();
114
130
  const swipeableRef = useRef<SwipeableMethods | null>(null);
115
131
 
@@ -128,28 +144,43 @@ export const SwipableWrapper = ({ children, swipeableId, swipableProps }: Swipab
128
144
  if (swipeRegistry && swipeableId) {
129
145
  swipeRegistry.notifyWillOpen(swipeableId);
130
146
  }
131
- swipableProps?.onSwipeableWillOpen?.(direction);
147
+
148
+ swipableProps?.onSwipeableOpenStartDrag?.(direction);
132
149
  },
133
150
  );
134
151
 
135
- const onSwipeableWillClose = useStableCallback(() => {
136
- if (swipeableId) {
137
- swipeRegistry?.updateOpenTracker(swipeableId, false);
138
- }
139
- });
152
+ const onSwipeableWillClose = useStableCallback(
153
+ (direction: SwipeDirection.LEFT | SwipeDirection.RIGHT) => {
154
+ if (swipeableId) {
155
+ swipeRegistry?.updateOpenTracker(swipeableId, false);
156
+ }
157
+
158
+ swipableProps?.onSwipeableWillClose?.(direction);
159
+ },
160
+ );
161
+
162
+ const rtlAwareSwipeableProps = useMemo<SwipeableProps>(() => {
163
+ const { overshootLeft, overshootRight, renderLeftActions, renderRightActions, ...rest } =
164
+ swipableProps ?? {};
165
+
166
+ return {
167
+ ...rest,
168
+ overshootLeft: isRTL ? (overshootRight ?? true) : (overshootLeft ?? false),
169
+ overshootRight: isRTL ? (overshootLeft ?? false) : (overshootRight ?? true),
170
+ renderLeftActions: isRTL ? renderRightActions : renderLeftActions,
171
+ renderRightActions: isRTL ? renderLeftActions : renderRightActions,
172
+ };
173
+ }, [isRTL, swipableProps]);
140
174
 
141
175
  return (
142
176
  <ReanimatedSwipeable
143
177
  ref={swipeableRef}
144
- onSwipeableOpenStartDrag={onSwipeableOpenStartDrag}
145
178
  animationOptions={animationOptions}
146
179
  friction={1.5}
180
+ onSwipeableOpenStartDrag={onSwipeableOpenStartDrag}
147
181
  onSwipeableWillClose={onSwipeableWillClose}
148
- overshootLeft={false}
149
- overshootRight={true}
150
182
  overshootFriction={16}
151
- renderLeftActions={undefined}
152
- {...swipableProps}
183
+ {...rtlAwareSwipeableProps}
153
184
  >
154
185
  {children}
155
186
  </ReanimatedSwipeable>
@@ -157,7 +188,14 @@ export const SwipableWrapper = ({ children, swipeableId, swipableProps }: Swipab
157
188
  };
158
189
 
159
190
  const styles = StyleSheet.create({
191
+ leftActionsContainer: {
192
+ direction: 'ltr',
193
+ flexDirection: 'row',
194
+ justifyContent: 'flex-start',
195
+ overflow: 'visible',
196
+ },
160
197
  rightActionsContainer: {
198
+ direction: 'ltr',
161
199
  flexDirection: 'row',
162
200
  justifyContent: 'flex-end',
163
201
  overflow: 'visible',
@@ -0,0 +1,98 @@
1
+ import React from 'react';
2
+ import { I18nManager, Text, View } from 'react-native';
3
+
4
+ import { render } from '@testing-library/react-native';
5
+
6
+ import { SwipeRegistryProvider } from '../../../contexts/swipeableContext/SwipeRegistryContext';
7
+ import { SwipableWrapper } from '../SwipableWrapper';
8
+
9
+ const mockReanimatedSwipeable = jest.fn(({ children }: React.PropsWithChildren) => (
10
+ <View>{children}</View>
11
+ ));
12
+
13
+ jest.mock('react-native-gesture-handler/ReanimatedSwipeable', () => ({
14
+ __esModule: true,
15
+ default: (...args: unknown[]) => mockReanimatedSwipeable(...args),
16
+ SwipeDirection: {
17
+ LEFT: 'left',
18
+ RIGHT: 'right',
19
+ },
20
+ }));
21
+
22
+ describe('SwipableWrapper', () => {
23
+ const originalIsRTL = I18nManager.isRTL;
24
+
25
+ const setRTL = (value: boolean) => {
26
+ Object.defineProperty(I18nManager, 'isRTL', {
27
+ configurable: true,
28
+ value,
29
+ });
30
+ };
31
+
32
+ const renderWithRegistry = (ui: React.ReactElement) =>
33
+ render(<SwipeRegistryProvider>{ui}</SwipeRegistryProvider>);
34
+
35
+ beforeEach(() => {
36
+ mockReanimatedSwipeable.mockClear();
37
+ });
38
+
39
+ afterEach(() => {
40
+ setRTL(originalIsRTL);
41
+ });
42
+
43
+ it('uses right-side overshoot defaults in ltr', () => {
44
+ setRTL(false);
45
+
46
+ renderWithRegistry(
47
+ <SwipableWrapper>
48
+ <Text>child</Text>
49
+ </SwipableWrapper>,
50
+ );
51
+
52
+ expect(mockReanimatedSwipeable).toHaveBeenCalledWith(
53
+ expect.objectContaining({
54
+ overshootLeft: false,
55
+ overshootRight: true,
56
+ }),
57
+ undefined,
58
+ );
59
+ });
60
+
61
+ it('uses left-side overshoot defaults in rtl', () => {
62
+ setRTL(true);
63
+
64
+ renderWithRegistry(
65
+ <SwipableWrapper>
66
+ <Text>child</Text>
67
+ </SwipableWrapper>,
68
+ );
69
+
70
+ expect(mockReanimatedSwipeable).toHaveBeenCalledWith(
71
+ expect.objectContaining({
72
+ overshootLeft: true,
73
+ overshootRight: false,
74
+ }),
75
+ undefined,
76
+ );
77
+ });
78
+
79
+ it('maps logical right actions to left actions in rtl', () => {
80
+ setRTL(true);
81
+
82
+ const renderRightActions = jest.fn(() => null);
83
+
84
+ renderWithRegistry(
85
+ <SwipableWrapper swipableProps={{ renderRightActions }}>
86
+ <Text>child</Text>
87
+ </SwipableWrapper>,
88
+ );
89
+
90
+ expect(mockReanimatedSwipeable).toHaveBeenCalledWith(
91
+ expect.objectContaining({
92
+ renderLeftActions: renderRightActions,
93
+ renderRightActions: undefined,
94
+ }),
95
+ undefined,
96
+ );
97
+ });
98
+ });
@@ -166,12 +166,14 @@ const useStyles = () => {
166
166
  fontSize: primitives.typographyFontSizeMd,
167
167
  fontWeight: primitives.typographyFontWeightSemiBold,
168
168
  lineHeight: primitives.typographyLineHeightNormal,
169
+ textAlign: 'left',
169
170
  },
170
171
  description: {
171
172
  color: semantics.textTertiary,
172
173
  fontSize: primitives.typographyFontSizeSm,
173
174
  fontWeight: primitives.typographyFontWeightRegular,
174
175
  lineHeight: primitives.typographyLineHeightNormal,
176
+ textAlign: 'left',
175
177
  },
176
178
  inputContainer: {
177
179
  alignItems: 'center',
@@ -190,6 +192,7 @@ const useStyles = () => {
190
192
  fontWeight: primitives.typographyFontWeightRegular,
191
193
  color: semantics.inputTextDefault,
192
194
  paddingVertical: 0, // android is adding extra padding so we remove it
195
+ textAlign: I18nManager.isRTL ? 'right' : 'left',
193
196
  },
194
197
  helperContainer: {
195
198
  alignItems: 'center',
@@ -201,6 +204,7 @@ const useStyles = () => {
201
204
  fontSize: primitives.typographyFontSizeSm,
202
205
  fontWeight: primitives.typographyFontWeightRegular,
203
206
  lineHeight: primitives.typographyLineHeightNormal,
207
+ textAlign: 'left',
204
208
  },
205
209
  });
206
210
  }, [semantics]);
@@ -56,6 +56,7 @@ import { useStableCallback } from '../../hooks/useStableCallback';
56
56
  import {
57
57
  createAttachmentsCompositionMiddleware,
58
58
  createDraftAttachmentsCompositionMiddleware,
59
+ setupVideoAttachmentPreviewMiddleware,
59
60
  } from '../../middlewares/attachments';
60
61
 
61
62
  import { isDocumentPickerAvailable, MediaTypes, NativeHandlers } from '../../native';
@@ -424,6 +425,8 @@ export const MessageInputProvider = ({
424
425
  attachmentManager.setCustomUploadFn(value.doFileUploadRequest);
425
426
  }
426
427
 
428
+ setupVideoAttachmentPreviewMiddleware(messageComposer);
429
+
427
430
  if (allowSendBeforeAttachmentsUpload) {
428
431
  messageComposer.compositionMiddlewareExecutor.replace([
429
432
  createAttachmentsCompositionMiddleware(messageComposer),
@@ -1,5 +1,12 @@
1
1
  import React, { useEffect, useMemo } from 'react';
2
- import { Platform, Pressable, StyleSheet, useWindowDimensions, View } from 'react-native';
2
+ import {
3
+ I18nManager,
4
+ Platform,
5
+ Pressable,
6
+ StyleSheet,
7
+ useWindowDimensions,
8
+ View,
9
+ } from 'react-native';
3
10
  import { Gesture, GestureDetector } from 'react-native-gesture-handler';
4
11
  import Animated, {
5
12
  clamp,
@@ -151,12 +158,13 @@ export const MessageOverlayHostLayer = ({ BackgroundComponent }: MessageOverlayH
151
158
 
152
159
  const topItemStyle = useAnimatedStyle(() => {
153
160
  if (!topH.value) return { height: 0 };
161
+ const horizontalPosition = I18nManager.isRTL ? { right: topH.value.x } : { left: topH.value.x };
154
162
  return {
155
163
  height: topH.value.h,
156
- left: topH.value.x,
157
164
  position: 'absolute',
158
165
  top: topH.value.y,
159
166
  width: topH.value.w,
167
+ ...horizontalPosition,
160
168
  };
161
169
  });
162
170
 
@@ -172,12 +180,15 @@ export const MessageOverlayHostLayer = ({ BackgroundComponent }: MessageOverlayH
172
180
 
173
181
  const bottomItemStyle = useAnimatedStyle(() => {
174
182
  if (!bottomH.value) return { height: 0 };
183
+ const horizontalPosition = I18nManager.isRTL
184
+ ? { right: bottomH.value.x }
185
+ : { left: bottomH.value.x };
175
186
  return {
176
187
  height: bottomH.value.h,
177
- left: bottomH.value.x,
178
188
  position: 'absolute',
179
189
  top: bottomH.value.y,
180
190
  width: bottomH.value.w,
191
+ ...horizontalPosition,
181
192
  };
182
193
  });
183
194
 
package/src/index.ts CHANGED
@@ -16,6 +16,7 @@ export * from './types/types';
16
16
  export * from './utils/patchMessageTextCommand';
17
17
  export * from './utils/i18n/Streami18n';
18
18
  export * from './utils/setupCommandUIMiddlewares';
19
+ export * from './utils/createGenerateVideoThumbnails';
19
20
  export * from './utils/utils';
20
21
 
21
22
  export { default as enTranslations } from './i18n/en.json';
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  Attachment,
3
+ AttachmentPreUploadMiddleware,
3
4
  FileReference,
4
5
  isLocalImageAttachment,
6
+ isLocalVideoAttachment,
5
7
  LocalAttachment,
6
8
  MessageComposer,
7
9
  MessageComposerMiddlewareState,
@@ -100,3 +102,35 @@ export const createDraftAttachmentsCompositionMiddleware = (
100
102
  },
101
103
  id: 'stream-io/message-composer-middleware/draft-attachments',
102
104
  });
105
+
106
+ const createVideoAttachmentPreviewMiddleware = (): AttachmentPreUploadMiddleware => ({
107
+ id: 'stream-io/message-composer-ui-middleware/video-attachment-preview',
108
+ handlers: {
109
+ prepare: ({ next, forward, state }) => {
110
+ const { attachment } = state;
111
+
112
+ if (!attachment || !isLocalVideoAttachment(attachment)) {
113
+ return forward();
114
+ }
115
+
116
+ return next({
117
+ ...state,
118
+ attachment: {
119
+ ...attachment,
120
+ localMetadata: {
121
+ ...attachment.localMetadata,
122
+ previewUri: attachment.thumb_url,
123
+ },
124
+ },
125
+ });
126
+ },
127
+ },
128
+ });
129
+
130
+ export const setupVideoAttachmentPreviewMiddleware = (messageComposer: MessageComposer) => {
131
+ messageComposer.attachmentManager.preUploadMiddlewareExecutor.insert({
132
+ middleware: [createVideoAttachmentPreviewMiddleware()],
133
+ position: { after: 'stream-io/attachment-manager-middleware/file-upload-config-check' },
134
+ unique: true,
135
+ });
136
+ };
@@ -0,0 +1,45 @@
1
+ export type GenerateVideoThumbnailResult = {
2
+ error?: string | null;
3
+ uri?: string | null;
4
+ };
5
+
6
+ export const createGenerateVideoThumbnails = ({
7
+ createVideoThumbnails,
8
+ }: {
9
+ createVideoThumbnails: (uris: string[]) => Promise<GenerateVideoThumbnailResult[]>;
10
+ }) => {
11
+ return async (uris: string[]): Promise<Record<string, GenerateVideoThumbnailResult>> => {
12
+ if (!uris.length) {
13
+ return {};
14
+ }
15
+
16
+ const uniqueUris: string[] = [];
17
+ const seenUris = new Set<string>();
18
+
19
+ uris.forEach((uri) => {
20
+ if (!seenUris.has(uri)) {
21
+ seenUris.add(uri);
22
+ uniqueUris.push(uri);
23
+ }
24
+ });
25
+
26
+ const uniqueResults = await createVideoThumbnails(uniqueUris);
27
+
28
+ return uniqueUris.reduce<Record<string, GenerateVideoThumbnailResult>>(
29
+ (resultMap, uri, index) => {
30
+ const result = uniqueResults[index] ?? {
31
+ error: 'Thumbnail generation returned no result',
32
+ uri: null,
33
+ };
34
+
35
+ if (result.error) {
36
+ console.warn(`Failed to generate thumbnail for ${uri}: ${result.error}`);
37
+ }
38
+
39
+ resultMap[uri] = result;
40
+ return resultMap;
41
+ },
42
+ {},
43
+ );
44
+ };
45
+ };
package/src/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "9.0.0-beta.12"
2
+ "version": "9.0.0-beta.14"
3
3
  }