movius-chats 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -88
- package/lib/commonjs/assets/Icons/ArrowBack2RoundedIcon.js +1 -1
- package/lib/commonjs/assets/Icons/ArrowBack2RoundedIcon.js.map +1 -1
- package/lib/commonjs/components/ChatBubble/ChatBubble.js +1 -1
- package/lib/commonjs/components/ChatBubble/ChatBubble.js.map +1 -1
- package/lib/commonjs/components/ChatBubble/MessageContent.js +1 -1
- package/lib/commonjs/components/ChatBubble/MessageContent.js.map +1 -1
- package/lib/commonjs/components/TypingComponent/TypingIndicator.js +1 -1
- package/lib/commonjs/components/TypingComponent/TypingIndicator.js.map +1 -1
- package/lib/module/assets/Icons/ArrowBack2RoundedIcon.js +1 -1
- package/lib/module/assets/Icons/ArrowBack2RoundedIcon.js.map +1 -1
- package/lib/module/components/ChatBubble/ChatBubble.js +1 -1
- package/lib/module/components/ChatBubble/ChatBubble.js.map +1 -1
- package/lib/module/components/ChatBubble/MessageContent.js +1 -1
- package/lib/module/components/ChatBubble/MessageContent.js.map +1 -1
- package/lib/module/components/TypingComponent/TypingIndicator.js +1 -1
- package/lib/module/components/TypingComponent/TypingIndicator.js.map +1 -1
- package/lib/typescript/assets/Icons/ArrowBack2RoundedIcon.d.ts +1 -1
- package/lib/typescript/types/index.d.ts +3 -2
- package/package.json +1 -1
- package/src/assets/Icons/ArrowBack2RoundedIcon.tsx +5 -5
- package/src/components/ChatBubble/ChatBubble.tsx +1 -1
- package/src/components/ChatBubble/MessageContent.tsx +5 -2
- package/src/components/TypingComponent/TypingIndicator.tsx +1 -1
- package/src/types/index.ts +3 -2
package/README.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
A highly customizable, feature-rich chats interface component for React Native applications. Built with performance and flexibility in mind, this component provides a complete solution for implementing chats functionality in your mobile applications.
|
|
4
4
|
|
|
5
|
+
## ⚠️ Important Implementation Notes
|
|
6
|
+
|
|
7
|
+
- **Native Rebuild Required**: This package uses native modules that require rebuilding your application after installation.
|
|
8
|
+
- **Expo Go Compatibility**: This package is **not compatible** with Expo Go due to its native dependencies. You must use a development build or eject from Expo Go to use this library.
|
|
9
|
+
- **Development Build**: For Expo users, you'll need to create a [Development Build](https://docs.expo.dev/develop/development-builds/introduction/) to use this package.
|
|
10
|
+
|
|
5
11
|
## Features
|
|
6
12
|
|
|
7
13
|
- 🚀 Full TypeScript support
|
|
@@ -16,6 +22,9 @@ A highly customizable, feature-rich chats interface component for React Native a
|
|
|
16
22
|
- 💬 Message status indicators (sent, delivered, read)
|
|
17
23
|
- 🎯 Custom component injection
|
|
18
24
|
- 🔧 Comprehensive styling API
|
|
25
|
+
- 🔄 Lazy loading for media messages
|
|
26
|
+
- 📡 Debounced typing indicators
|
|
27
|
+
- 🖼️ Avatar image caching
|
|
19
28
|
|
|
20
29
|
## Installation
|
|
21
30
|
|
|
@@ -47,6 +56,24 @@ module.exports = {
|
|
|
47
56
|
};
|
|
48
57
|
```
|
|
49
58
|
|
|
59
|
+
### Post-Installation Steps
|
|
60
|
+
|
|
61
|
+
After installing this package and its dependencies:
|
|
62
|
+
|
|
63
|
+
1. **For React Native CLI Projects**:
|
|
64
|
+
```bash
|
|
65
|
+
npx pod-install # For iOS
|
|
66
|
+
npx react-native run-android # Rebuild for Android
|
|
67
|
+
npx react-native run-ios # Rebuild for iOS
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
2. **For Expo Projects**:
|
|
71
|
+
```bash
|
|
72
|
+
npx expo prebuild # Generate native code
|
|
73
|
+
npx expo run:android # Build and run on Android
|
|
74
|
+
npx expo run:ios # Build and run on iOS
|
|
75
|
+
```
|
|
76
|
+
|
|
50
77
|
## Basic Usage
|
|
51
78
|
|
|
52
79
|
```typescript
|
|
@@ -88,86 +115,62 @@ const App = () => {
|
|
|
88
115
|
| messages | Message[] | Yes | Array of message objects to display |
|
|
89
116
|
| currentUserId | string | Yes | ID of the current user |
|
|
90
117
|
| onSendMessage | (message: Omit<Message, "id" \| "time" \| "status">) => void | Yes | Callback when a message is sent |
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
audio?: string;
|
|
101
|
-
senderId: string;
|
|
102
|
-
time: string;
|
|
103
|
-
status: "read" | "delivered" | "sent";
|
|
104
|
-
senderName?: string;
|
|
105
|
-
senderAvatar?: string;
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Feature Flags
|
|
110
|
-
|
|
111
|
-
| Prop | Type | Default | Description |
|
|
112
|
-
|------|------|---------|-------------|
|
|
113
|
-
| showAvatars | boolean | false | Show user avatars |
|
|
114
|
-
| showUserNames | boolean | false | Display usernames above messages |
|
|
115
|
-
| showEmojiButton | boolean | true | Show emoji picker button |
|
|
116
|
-
| showAttachmentsButton | boolean | true | Show attachments button |
|
|
117
|
-
| showCameraButton | boolean | true | Show camera access button |
|
|
118
|
-
| showVoiceRecordButton | boolean | true | Show voice recording button |
|
|
119
|
-
| showBubbleTail | boolean | true | Show message bubble tails |
|
|
120
|
-
| showMessageStatus | boolean | true | Show message status indicators |
|
|
121
|
-
|
|
122
|
-
### Event Handlers
|
|
123
|
-
|
|
124
|
-
| Prop | Type | Description |
|
|
125
|
-
|------|------|-------------|
|
|
126
|
-
| onMessageLongPress | (message: Message) => void | Callback for long-pressing a message |
|
|
127
|
-
| onAttachmentPress | () => void | Callback for attachment button press |
|
|
128
|
-
| onAudioRecordStart | () => void | Callback when audio recording starts |
|
|
129
|
-
| onAudioRecordEnd | () => void | Callback when audio recording ends |
|
|
130
|
-
| onCameraPress | () => void | Callback for camera button press |
|
|
131
|
-
| onTypingStart | () => void | Callback when user starts typing |
|
|
132
|
-
| onTypingEnd | () => void | Callback when user stops typing |
|
|
118
|
+
| onMessageLongPress | (message: Message) => void | No | Callback for long-pressing a message |
|
|
119
|
+
| onAttachmentPress | () => void | No | Callback for attachment button press |
|
|
120
|
+
| onAudioRecordStart | () => void | No | Callback when audio recording starts |
|
|
121
|
+
| onAudioRecordEnd | () => void | No | Callback when audio recording ends |
|
|
122
|
+
| onCameraPress | () => void | No | Callback for camera button press |
|
|
123
|
+
| onTypingStart | () => void | No | Callback when user starts typing |
|
|
124
|
+
| onTypingEnd | () => void | No | Callback when user stops typing |
|
|
125
|
+
| placeholder | string | No | Input placeholder text |
|
|
126
|
+
| typingUsers | Array<{ id: string; avatar: string; name: string }> | No | List of users who are typing |
|
|
133
127
|
|
|
134
128
|
### Theming
|
|
135
129
|
|
|
136
130
|
The component supports extensive theming through the `theme` prop:
|
|
137
131
|
|
|
138
132
|
```typescript
|
|
139
|
-
theme?: {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
133
|
+
theme?: {
|
|
134
|
+
colors?: {
|
|
135
|
+
sentMessageTailColor?: string;
|
|
136
|
+
receivedMessageTailColor?: string;
|
|
137
|
+
timestamp?: string;
|
|
138
|
+
inputsIconsColor?: string;
|
|
139
|
+
sendIconsColor?: string;
|
|
140
|
+
placeholderTextColor?: string;
|
|
141
|
+
audioPlayIconColor?: string;
|
|
142
|
+
audioPauseIconColor?: string;
|
|
143
|
+
videoPlayIconColor?: string;
|
|
144
|
+
};
|
|
145
|
+
bubbleStyle?: {
|
|
146
|
+
sent?: ViewStyle;
|
|
147
|
+
received?: ViewStyle;
|
|
148
|
+
avatarTextStyle?: TextStyle;
|
|
149
|
+
userNameStyle?: TextStyle;
|
|
150
|
+
avatarImageStyle?: ImageStyle;
|
|
151
|
+
typingContainerStyle?: ViewStyle;
|
|
152
|
+
additionalTypingUsersContainerStyle?: ViewStyle;
|
|
153
|
+
additionalTypingUsersTextStyle?: TextStyle;
|
|
154
|
+
};
|
|
155
|
+
messageStyle?: {
|
|
156
|
+
sentTextStyle?: TextStyle;
|
|
157
|
+
receivedTextStyle?: TextStyle;
|
|
158
|
+
audioPlayButtonStyle?: ViewStyle;
|
|
159
|
+
audioKnobStyle?: ViewStyle;
|
|
160
|
+
progressBarStyle?: ViewStyle;
|
|
161
|
+
activeProgressBarStyle?: ViewStyle;
|
|
162
|
+
audioDurationStyle?: TextStyle;
|
|
163
|
+
};
|
|
164
|
+
inputStyles?: {
|
|
165
|
+
inputSectionContainerStyle?: ViewStyle;
|
|
166
|
+
inputContainerStyle?: ViewStyle;
|
|
167
|
+
sendButtonStyle?: ViewStyle;
|
|
168
|
+
};
|
|
163
169
|
};
|
|
164
|
-
}
|
|
165
170
|
```
|
|
166
171
|
|
|
167
172
|
### Custom Components
|
|
168
173
|
|
|
169
|
-
You can provide custom components for various elements:
|
|
170
|
-
|
|
171
174
|
| Prop | Type | Description |
|
|
172
175
|
|------|------|-------------|
|
|
173
176
|
| renderCustomInput | () => React.ReactNode | Custom input component |
|
|
@@ -210,33 +213,42 @@ You can provide custom components for various elements:
|
|
|
210
213
|
/>
|
|
211
214
|
```
|
|
212
215
|
|
|
213
|
-
###
|
|
216
|
+
### Expo Usage
|
|
214
217
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
/>
|
|
229
|
-
)}
|
|
230
|
-
/>
|
|
231
|
-
```
|
|
218
|
+
If you're using Expo, follow these steps:
|
|
219
|
+
|
|
220
|
+
1. Create a development build of your app:
|
|
221
|
+
```bash
|
|
222
|
+
npx expo prebuild
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
2. Run on your desired platform:
|
|
226
|
+
```bash
|
|
227
|
+
npx expo run:android
|
|
228
|
+
# or
|
|
229
|
+
npx expo run:ios
|
|
230
|
+
```
|
|
232
231
|
|
|
233
|
-
|
|
232
|
+
3. For subsequent updates to the native modules, you'll need to rebuild:
|
|
233
|
+
```bash
|
|
234
|
+
npx expo prebuild --clean
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Performance Considerations
|
|
234
238
|
|
|
235
239
|
- Messages are rendered using `FlatList` for optimal performance
|
|
236
240
|
- Avatar images are cached automatically
|
|
237
241
|
- Media messages use lazy loading
|
|
238
242
|
- Typing indicators are debounced
|
|
239
243
|
|
|
244
|
+
## Troubleshooting
|
|
245
|
+
|
|
246
|
+
### Common Issues
|
|
247
|
+
|
|
248
|
+
- **"Native module not found" error**: Ensure you've rebuilt your app after installing the package.
|
|
249
|
+
- **Crashes in Expo Go**: This package uses native modules that are not compatible with Expo Go. Use a development build instead.
|
|
250
|
+
- **Audio/Video not working**: Check that you've installed all required dependencies and rebuilt the app.
|
|
251
|
+
|
|
240
252
|
## Contributing
|
|
241
253
|
|
|
242
254
|
We welcome contributions! Please see our contributing guide for details.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react-native-svg"),r=require("react/jsx-runtime");exports.ArrowBack2RoundedIcon=({style:o,color:t})=>r.jsx(e,{style:o,
|
|
1
|
+
"use strict";var e=require("react-native-svg"),r=require("react/jsx-runtime");exports.ArrowBack2RoundedIcon=({style:o,color:t})=>r.jsx(e,{style:o,viewBox:"0 0 48 48",children:r.jsx(e.Path,{fill:t,fillRule:"evenodd",stroke:t,strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"4",d:"M8 9.115c0-1.82 2.235-2.694 3.47-1.356l29.432 31.884c1.182 1.282.273 3.357-1.47 3.357H10a2 2 0 0 1-2-2z",clipRule:"evenodd"})});
|
|
2
2
|
//# sourceMappingURL=ArrowBack2RoundedIcon.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArrowBack2RoundedIcon.js","sources":["../../../../src/assets/Icons/ArrowBack2RoundedIcon.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"ArrowBack2RoundedIcon.js","sources":["../../../../src/assets/Icons/ArrowBack2RoundedIcon.tsx"],"sourcesContent":["import { ViewStyle } from 'react-native';\nimport Svg, { Path } from 'react-native-svg';\n\nexport const ArrowBack2RoundedIcon = ({\n style,\n color,\n}: {\n style?: ViewStyle;\n color?: string;\n}) => {\n return (\n <Svg style={style} viewBox=\"0 0 48 48\">\n <Path\n fill={color}\n fillRule=\"evenodd\"\n stroke={color}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"4\"\n d=\"M8 9.115c0-1.82 2.235-2.694 3.47-1.356l29.432 31.884c1.182 1.282.273 3.357-1.47 3.357H10a2 2 0 0 1-2-2z\"\n clipRule=\"evenodd\"\n ></Path>\n </Svg>\n );\n};\n"],"names":["ArrowBack2RoundedIcon","style","color","_jsx","Svg","viewBox","children","jsx","Path","fill","fillRule","stroke","strokeLinecap","strokeLinejoin","strokeWidth","d","clipRule"],"mappings":"4GAGqCA,EACnCC,QACAC,WAMEC,EAAAA,IAACC,EAAG,CAACH,MAAOA,EAAOI,QAAQ,YAAWC,SACpCH,EAAAI,IAACC,OAAI,CACHC,KAAMP,EACNQ,SAAS,UACTC,OAAQT,EACRU,cAAc,QACdC,eAAe,QACfC,YAAY,IACZC,EAAE,0GACFC,SAAS"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react"),t=require("react-native"),s=require("twrnc"),r=require("../../assets/Icons/ArrowBack2RoundedIcon.js"),
|
|
1
|
+
"use strict";var e=require("react"),t=require("react-native"),s=require("twrnc"),r=require("../../assets/Icons/ArrowBack2RoundedIcon.js"),a=require("../../context/ChatContext.js"),l=require("./MessageContent.js"),o=require("./MessageStatus.js"),i=require("react/jsx-runtime");const n=({message:e,isCurrentUser:n,isFirstInSequence:u,onLongPress:d})=>{const{theme:c,showAvatars:b,showUserNames:m,showBubbleTail:x,setMediaUrl:g,setIsVideoPlaying:h,isVideoPlaying:y}=a.useChatContext();return i.jsxs(t.Pressable,{onLongPress:d,style:[s`px-2 my-1 max-w-[75%] relative`,n?s`self-end mr-3`:s`self-start ml-9`,u?n?s`bg-green-500 rounded-tr-none`:s`bg-white rounded-tl-none`:n?s`bg-green-500`:s`bg-white`,{borderRadius:8,...n?c?.bubbleStyle?.sent:c?.bubbleStyle?.received}],children:[!n&&u&&b&&i.jsxs(i.Fragment,{children:[i.jsx(t.View,{style:s`absolute w-6 h-6 rounded-full top-0 -left-9 flex-row items-center`,children:e.senderAvatar?i.jsx(t.Image,{source:{uri:e.senderAvatar},style:[s`w-full h-full rounded-full`,c?.bubbleStyle?.avatarImageStyle],resizeMode:"cover"}):i.jsx(t.Text,{style:[s`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,c?.bubbleStyle?.avatarTextStyle],children:e.senderName?.charAt(0)})}),m&&e.senderName&&i.jsx(t.Text,{style:[s`text-sm text-black font-semibold mt-1 capitalize`,c?.bubbleStyle?.userNameStyle],children:e.senderName})]}),u&&x&&i.jsx(r.ArrowBack2RoundedIcon,{style:s.style("absolute -top-1 w-6 h-6 stroke-transparent",n?"-right-3.5":"-left-3.5 mt-[1.25px]",{transform:[{rotate:n?"90deg":"180deg"}]}),color:n?`${c?.colors?.sentMessageTailColor||"rgba(34, 197, 94,1)"}`:`${c?.colors?.receivedMessageTailColor||"white"}`}),i.jsx(l,{message:e,isCurrentUser:n,isFirstInSequence:u,onMediaPress:(e,t)=>{g({imageUrl:"image"===e?t:"",videoUrl:"video"===e?t:""}),"video"===e&&h(!0)},isVideoPlaying:y}),i.jsx(o,{time:e.time,status:n?e.status:void 0,isCurrentUser:n,hasText:!!e.text,hasAudio:!!e.audio})]})};var u=e.memo(n);module.exports=u;
|
|
2
2
|
//# sourceMappingURL=ChatBubble.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatBubble.js","sources":["../../../../src/components/ChatBubble/ChatBubble.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport tw from 'twrnc';\nimport { ArrowBack2RoundedIcon } from '../../assets/Icons/ArrowBack2RoundedIcon';\nimport { useChatContext } from '../../context/ChatContext';\nimport MessageContent from './MessageContent';\nimport MessageStatus from './MessageStatus';\nimport { ChatBubbleProps } from './types';\n\nconst ChatBubble: React.FC<ChatBubbleProps> = ({\n message,\n isCurrentUser,\n isFirstInSequence,\n onLongPress,\n}) => {\n const {\n theme,\n showAvatars,\n showUserNames,\n showBubbleTail,\n setMediaUrl,\n setIsVideoPlaying,\n isVideoPlaying,\n } = useChatContext();\n\n const handleMediaPress = (type: 'image' | 'video', url: string) => {\n setMediaUrl({\n imageUrl: type === 'image' ? url : '',\n videoUrl: type === 'video' ? url : '',\n });\n if (type === 'video') {\n setIsVideoPlaying(true);\n }\n };\n\n return (\n <Pressable\n onLongPress={onLongPress}\n style={[\n tw`px-2 my-1 max-w-[75%] relative`,\n isCurrentUser ? tw`self-end mr-3` : tw`self-start ml-9`,\n isFirstInSequence\n ? isCurrentUser\n ? tw`bg-green-500 rounded-tr-none`\n : tw`bg-white rounded-tl-none`\n : isCurrentUser\n ? tw`bg-green-500`\n : tw`bg-white`,\n {\n borderRadius: 8,\n ...(isCurrentUser\n ? theme?.bubbleStyle?.sent\n : theme?.bubbleStyle?.received),\n },\n ]}\n >\n {/* Avatar & Sender Name for Group Chat */}\n {!isCurrentUser && isFirstInSequence && showAvatars && (\n <>\n <View\n style={tw`absolute w-6 h-6 rounded-full top-0 -left-9 flex-row items-center`}\n >\n {message.senderAvatar ? (\n <Image\n source={{ uri: message.senderAvatar }}\n style={[\n tw`w-full h-full rounded-full`,\n theme?.bubbleStyle?.avatarImageStyle,\n ]}\n resizeMode=\"cover\"\n />\n ) : (\n <Text\n style={[\n tw`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,\n theme?.bubbleStyle?.avatarTextStyle,\n ]}\n >\n {message.senderName?.charAt(0)}\n </Text>\n )}\n </View>\n {showUserNames && message.senderName && (\n <Text\n style={[\n tw`text-sm text-black font-semibold mt-1 capitalize`,\n theme?.bubbleStyle?.userNameStyle,\n ]}\n >\n {message.senderName}\n </Text>\n )}\n </>\n )}\n\n {/* Bubble Tail */}\n {isFirstInSequence && showBubbleTail && (\n <ArrowBack2RoundedIcon\n style={tw.style(\n 'absolute -top-1 w-6 h-6',\n isCurrentUser ? '-right-3.5' : '-left-3.5 mt-[1.25px]',\n {\n transform: [{ rotate: isCurrentUser ? '90deg' : '180deg' }],\n }\n )}\n color={\n isCurrentUser\n ? `${\n theme?.colors?.sentMessageTailColor || 'rgba(34, 197, 94,1)'\n }`\n : `${theme?.colors?.receivedMessageTailColor || 'white'}`\n }\n />\n )}\n\n {/* Message Content */}\n <MessageContent\n message={message}\n isCurrentUser={isCurrentUser}\n isFirstInSequence={isFirstInSequence}\n onMediaPress={handleMediaPress}\n isVideoPlaying={isVideoPlaying}\n />\n\n {/* Message Status */}\n <MessageStatus\n time={message.time}\n status={isCurrentUser ? message.status : undefined}\n isCurrentUser={isCurrentUser}\n hasText={!!message.text}\n hasAudio={!!message.audio}\n />\n </Pressable>\n );\n};\n\nexport default React.memo(ChatBubble);\n"],"names":["ChatBubble","message","isCurrentUser","isFirstInSequence","onLongPress","theme","showAvatars","showUserNames","showBubbleTail","setMediaUrl","setIsVideoPlaying","isVideoPlaying","useChatContext","_jsxs","Pressable","style","tw","borderRadius","bubbleStyle","sent","received","children","jsxs","_Fragment","_jsx","jsx","View","senderAvatar","Image","source","uri","avatarImageStyle","resizeMode","Text","avatarTextStyle","senderName","charAt","userNameStyle","ArrowBack2RoundedIcon","transform","rotate","color","colors","sentMessageTailColor","receivedMessageTailColor","MessageContent","onMediaPress","handleMediaPress","type","url","imageUrl","videoUrl","MessageStatus","time","status","undefined","hasText","text","hasAudio","audio","ChatBubble$1","React","memo"],"mappings":"oRASA,MAAMA,EAAwCA,EAC5CC,UACAC,gBACAC,oBACAC,kBAEA,MAAMC,MACJA,EAAKC,YACLA,EAAWC,cACXA,EAAaC,eACbA,EAAcC,YACdA,EAAWC,kBACXA,EAAiBC,eACjBA,GACEC,mBAYJ,OACEC,EAAAA,KAACC,EAAAA,UAAS,CACRV,YAAaA,EACbW,MAAO,CACLC,CAAE,iCACFd,EAAgBc,CAAE,gBAAkBA,CAAE,kBACtCb,EACID,EACEc,CAAE,+BACFA,CAAE,2BACJd,EACEc,CAAE,eACFA,CAAE,WACR,CACEC,aAAc,KACVf,EACAG,GAAOa,aAAaC,KACpBd,GAAOa,aAAaE,WAE1BC,SAAA,EAGAnB,GAAiBC,GAAqBG,GACtCO,EAAAS,KAAAC,WAAA,CAAAF,SAAA,CACEG,EAAAC,IAACC,OAAI,CACHX,MAAOC,CAAE,oEAAoEK,SAE5EpB,EAAQ0B,aACPH,EAAAA,IAACI,EAAAA,MAAK,CACJC,OAAQ,CAAEC,IAAK7B,EAAQ0B,cACvBZ,MAAO,CACLC,CAAE,6BACFX,GAAOa,aAAaa,kBAEtBC,WAAW,UAGbR,EAAAC,IAACQ,OAAI,CACHlB,MAAO,CACLC,CAAE,wGACFX,GAAOa,aAAagB,iBACpBb,SAEDpB,EAAQkC,YAAYC,OAAO,OAIjC7B,GAAiBN,EAAQkC,YACxBX,EAAAA,IAACS,EAAAA,KAAI,CACHlB,MAAO,CACLC,CAAE,mDACFX,GAAOa,aAAamB,eACpBhB,SAEDpB,EAAQkC,gBAOhBhC,GAAqBK,GACpBgB,EAAAA,IAACc,EAAAA,sBAAqB,CACpBvB,MAAOC,EAAGD,MACR,
|
|
1
|
+
{"version":3,"file":"ChatBubble.js","sources":["../../../../src/components/ChatBubble/ChatBubble.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport tw from 'twrnc';\nimport { ArrowBack2RoundedIcon } from '../../assets/Icons/ArrowBack2RoundedIcon';\nimport { useChatContext } from '../../context/ChatContext';\nimport MessageContent from './MessageContent';\nimport MessageStatus from './MessageStatus';\nimport { ChatBubbleProps } from './types';\n\nconst ChatBubble: React.FC<ChatBubbleProps> = ({\n message,\n isCurrentUser,\n isFirstInSequence,\n onLongPress,\n}) => {\n const {\n theme,\n showAvatars,\n showUserNames,\n showBubbleTail,\n setMediaUrl,\n setIsVideoPlaying,\n isVideoPlaying,\n } = useChatContext();\n\n const handleMediaPress = (type: 'image' | 'video', url: string) => {\n setMediaUrl({\n imageUrl: type === 'image' ? url : '',\n videoUrl: type === 'video' ? url : '',\n });\n if (type === 'video') {\n setIsVideoPlaying(true);\n }\n };\n\n return (\n <Pressable\n onLongPress={onLongPress}\n style={[\n tw`px-2 my-1 max-w-[75%] relative`,\n isCurrentUser ? tw`self-end mr-3` : tw`self-start ml-9`,\n isFirstInSequence\n ? isCurrentUser\n ? tw`bg-green-500 rounded-tr-none`\n : tw`bg-white rounded-tl-none`\n : isCurrentUser\n ? tw`bg-green-500`\n : tw`bg-white`,\n {\n borderRadius: 8,\n ...(isCurrentUser\n ? theme?.bubbleStyle?.sent\n : theme?.bubbleStyle?.received),\n },\n ]}\n >\n {/* Avatar & Sender Name for Group Chat */}\n {!isCurrentUser && isFirstInSequence && showAvatars && (\n <>\n <View\n style={tw`absolute w-6 h-6 rounded-full top-0 -left-9 flex-row items-center`}\n >\n {message.senderAvatar ? (\n <Image\n source={{ uri: message.senderAvatar }}\n style={[\n tw`w-full h-full rounded-full`,\n theme?.bubbleStyle?.avatarImageStyle,\n ]}\n resizeMode=\"cover\"\n />\n ) : (\n <Text\n style={[\n tw`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,\n theme?.bubbleStyle?.avatarTextStyle,\n ]}\n >\n {message.senderName?.charAt(0)}\n </Text>\n )}\n </View>\n {showUserNames && message.senderName && (\n <Text\n style={[\n tw`text-sm text-black font-semibold mt-1 capitalize`,\n theme?.bubbleStyle?.userNameStyle,\n ]}\n >\n {message.senderName}\n </Text>\n )}\n </>\n )}\n\n {/* Bubble Tail */}\n {isFirstInSequence && showBubbleTail && (\n <ArrowBack2RoundedIcon\n style={tw.style(\n 'absolute -top-1 w-6 h-6 stroke-transparent',\n isCurrentUser ? '-right-3.5' : '-left-3.5 mt-[1.25px]',\n {\n transform: [{ rotate: isCurrentUser ? '90deg' : '180deg' }],\n }\n )}\n color={\n isCurrentUser\n ? `${\n theme?.colors?.sentMessageTailColor || 'rgba(34, 197, 94,1)'\n }`\n : `${theme?.colors?.receivedMessageTailColor || 'white'}`\n }\n />\n )}\n\n {/* Message Content */}\n <MessageContent\n message={message}\n isCurrentUser={isCurrentUser}\n isFirstInSequence={isFirstInSequence}\n onMediaPress={handleMediaPress}\n isVideoPlaying={isVideoPlaying}\n />\n\n {/* Message Status */}\n <MessageStatus\n time={message.time}\n status={isCurrentUser ? message.status : undefined}\n isCurrentUser={isCurrentUser}\n hasText={!!message.text}\n hasAudio={!!message.audio}\n />\n </Pressable>\n );\n};\n\nexport default React.memo(ChatBubble);\n"],"names":["ChatBubble","message","isCurrentUser","isFirstInSequence","onLongPress","theme","showAvatars","showUserNames","showBubbleTail","setMediaUrl","setIsVideoPlaying","isVideoPlaying","useChatContext","_jsxs","Pressable","style","tw","borderRadius","bubbleStyle","sent","received","children","jsxs","_Fragment","_jsx","jsx","View","senderAvatar","Image","source","uri","avatarImageStyle","resizeMode","Text","avatarTextStyle","senderName","charAt","userNameStyle","ArrowBack2RoundedIcon","transform","rotate","color","colors","sentMessageTailColor","receivedMessageTailColor","MessageContent","onMediaPress","handleMediaPress","type","url","imageUrl","videoUrl","MessageStatus","time","status","undefined","hasText","text","hasAudio","audio","ChatBubble$1","React","memo"],"mappings":"oRASA,MAAMA,EAAwCA,EAC5CC,UACAC,gBACAC,oBACAC,kBAEA,MAAMC,MACJA,EAAKC,YACLA,EAAWC,cACXA,EAAaC,eACbA,EAAcC,YACdA,EAAWC,kBACXA,EAAiBC,eACjBA,GACEC,mBAYJ,OACEC,EAAAA,KAACC,EAAAA,UAAS,CACRV,YAAaA,EACbW,MAAO,CACLC,CAAE,iCACFd,EAAgBc,CAAE,gBAAkBA,CAAE,kBACtCb,EACID,EACEc,CAAE,+BACFA,CAAE,2BACJd,EACEc,CAAE,eACFA,CAAE,WACR,CACEC,aAAc,KACVf,EACAG,GAAOa,aAAaC,KACpBd,GAAOa,aAAaE,WAE1BC,SAAA,EAGAnB,GAAiBC,GAAqBG,GACtCO,EAAAS,KAAAC,WAAA,CAAAF,SAAA,CACEG,EAAAC,IAACC,OAAI,CACHX,MAAOC,CAAE,oEAAoEK,SAE5EpB,EAAQ0B,aACPH,EAAAA,IAACI,EAAAA,MAAK,CACJC,OAAQ,CAAEC,IAAK7B,EAAQ0B,cACvBZ,MAAO,CACLC,CAAE,6BACFX,GAAOa,aAAaa,kBAEtBC,WAAW,UAGbR,EAAAC,IAACQ,OAAI,CACHlB,MAAO,CACLC,CAAE,wGACFX,GAAOa,aAAagB,iBACpBb,SAEDpB,EAAQkC,YAAYC,OAAO,OAIjC7B,GAAiBN,EAAQkC,YACxBX,EAAAA,IAACS,EAAAA,KAAI,CACHlB,MAAO,CACLC,CAAE,mDACFX,GAAOa,aAAamB,eACpBhB,SAEDpB,EAAQkC,gBAOhBhC,GAAqBK,GACpBgB,EAAAA,IAACc,EAAAA,sBAAqB,CACpBvB,MAAOC,EAAGD,MACR,6CACAb,EAAgB,aAAe,wBAC/B,CACEqC,UAAW,CAAC,CAAEC,OAAQtC,EAAgB,QAAU,aAGpDuC,MACEvC,EACI,GACEG,GAAOqC,QAAQC,sBAAwB,wBAEzC,GAAGtC,GAAOqC,QAAQE,0BAA4B,YAMxDpB,EAAAC,IAACoB,EAAc,CACb5C,QAASA,EACTC,cAAeA,EACfC,kBAAmBA,EACnB2C,aA/FmBC,CAACC,EAAyBC,KACjDxC,EAAY,CACVyC,SAAmB,UAATF,EAAmBC,EAAM,GACnCE,SAAmB,UAATH,EAAmBC,EAAM,KAExB,UAATD,GACFtC,GAAkB,EACpB,EAyFIC,eAAgBA,IAIlBa,EAAAC,IAAC2B,EAAa,CACZC,KAAMpD,EAAQoD,KACdC,OAAQpD,EAAgBD,EAAQqD,YAASC,EACzCrD,cAAeA,EACfsD,UAAWvD,EAAQwD,KACnBC,WAAYzD,EAAQ0D,UAEZ,EAIhB,IAAAC,EAAeC,EAAMC,KAAK9D"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react"),t=require("react-native"),s=require("react-native-video"),r=require("twrnc"),i=require("../../assets/Icons/LoadingIcon.js"),o=require("../../assets/Icons/PlayIcon.js"),l=require("../../context/ChatContext.js"),a=require("../../utils/datefunc.js"),n=require("../AudioPlayer/AudioPlayer.js"),d=require("react/jsx-runtime");const u=({message:u,onMediaPress:c,isVideoPlaying:x})=>{const{theme:
|
|
1
|
+
"use strict";var e=require("react"),t=require("react-native"),s=require("react-native-video"),r=require("twrnc"),i=require("../../assets/Icons/LoadingIcon.js"),o=require("../../assets/Icons/PlayIcon.js"),l=require("../../context/ChatContext.js"),a=require("../../utils/datefunc.js"),n=require("../AudioPlayer/AudioPlayer.js"),d=require("react/jsx-runtime");const u=({message:u,onMediaPress:c,isVideoPlaying:x,isCurrentUser:y})=>{const{theme:h,showMessageStatus:j,CustomPlayIcon:m,renderCustomVideoBubbleError:b}=l.useChatContext(),f=e.useRef(null),[w,g]=e.useState(0),[v,P]=e.useState(!1),[p,q]=e.useState(!1);return d.jsxs(t.View,{children:[u.image&&d.jsx(t.Pressable,{onPress:()=>c("image",u.image),style:r`w-60 h-80 my-2`,children:d.jsx(t.Image,{source:{uri:u.image},style:r`w-full h-full object-contain rounded-lg`})}),u.video&&d.jsxs(t.Pressable,{onPress:()=>c("video",u.video),style:r`w-60 h-80 my-2 justify-center items-center`,disabled:v,children:[d.jsx(s,{source:{uri:u.video},ref:f,paused:!0,style:{width:"100%",height:"100%",borderRadius:8,position:"relative"},resizeMode:"cover",onLoadStart:()=>{P(!0),q(!1)},onLoad:e=>{g(e.duration),P(!1)},onBuffer:({isBuffering:e})=>P(e),onError:()=>{q(!0),P(!1)}}),v?d.jsx(t.View,{style:r`absolute inset-0 flex items-center justify-center bg-black/40 rounded-full`,children:d.jsx(i.LoadingIcon,{style:r.style("h-12 w-12 fill-white animate-spin")})}):p?b?b():d.jsx(t.View,{style:r`absolute inset-0 flex items-center justify-center bg-red-500/60 p-2`,children:d.jsx(t.Text,{style:r`text-white font-bold`,children:"Failed to load video"})}):d.jsxs(d.Fragment,{children:[d.jsx(t.View,{style:r`absolute bg-black/40 rounded-full`,children:m?d.jsx(m,{}):d.jsx(o.PlayIcon,{style:r.style("h-16 w-16"),color:h?.colors?.audioPlayIconColor||"white"})}),d.jsx(t.View,{style:r`absolute bottom-2 left-2 bg-black/50 px-2 py-1 rounded-md`,children:d.jsx(t.Text,{style:r`text-white text-xs font-semibold`,children:a.formatDuration(w)})})]})]}),u.audio&&d.jsx(t.View,{style:r`my-2`,children:d.jsx(n,{audioUrl:u.audio,audioId:u.id,isVideoPlaying:x})}),u.text&&d.jsx(t.Text,{style:[r`pt-1`,j?r`pb-0`:r`pb-2`,{wordBreak:"break-word",overflowWrap:"break-word"},y?h?.messageStyle?.sentTextStyle:h?.messageStyle?.receivedTextStyle],children:u.text})]})};var c=e.memo(u);module.exports=c;
|
|
2
2
|
//# sourceMappingURL=MessageContent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageContent.js","sources":["../../../../src/components/ChatBubble/MessageContent.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport Video, { VideoRef } from 'react-native-video';\nimport tw from 'twrnc';\nimport { LoadingIcon } from '../../assets/Icons/LoadingIcon';\nimport { PlayIcon } from '../../assets/Icons/PlayIcon';\nimport { useChatContext } from '../../context/ChatContext';\nimport { formatDuration } from '../../utils/datefunc';\nimport AudioPlayer from '../AudioPlayer/AudioPlayer';\nimport { MessageContentProps } from './types';\n\nconst MessageContent: React.FC<MessageContentProps> = ({\n message,\n onMediaPress,\n isVideoPlaying,\n}) => {\n const {\n theme,\n showMessageStatus,\n CustomPlayIcon,\n renderCustomVideoBubbleError,\n } = useChatContext();\n const videoRef = React.useRef<VideoRef>(null);\n const [duration, setDuration] = React.useState(0);\n const [videoIsLoading, setVideoIsLoading] = React.useState(false);\n const [videoHasError, setVideoHasError] = React.useState(false);\n\n return (\n <View>\n {message.image && (\n <Pressable\n onPress={() => onMediaPress('image', message.image as string)}\n style={tw`w-60 h-80 my-2`}\n >\n <Image\n source={{ uri: message.image }}\n style={tw`w-full h-full object-contain rounded-lg`}\n />\n </Pressable>\n )}\n\n {message.video && (\n <Pressable\n onPress={() => onMediaPress('video', message.video as string)}\n style={tw`w-60 h-80 my-2 justify-center items-center`}\n disabled={videoIsLoading}\n >\n <Video\n source={{ uri: message.video }}\n ref={videoRef}\n paused={true}\n style={{\n width: '100%',\n height: '100%',\n borderRadius: 8,\n position: 'relative',\n }}\n resizeMode=\"cover\"\n onLoadStart={() => {\n setVideoIsLoading(true);\n setVideoHasError(false);\n }}\n onLoad={(data) => {\n setDuration(data.duration);\n setVideoIsLoading(false);\n }}\n onBuffer={({ isBuffering }) => setVideoIsLoading(isBuffering)}\n onError={() => {\n setVideoHasError(true);\n setVideoIsLoading(false);\n }}\n />\n {videoIsLoading ? (\n <View\n style={tw`absolute inset-0 flex items-center justify-center bg-black/40 rounded-full`}\n >\n <LoadingIcon\n style={tw.style('h-12 w-12 fill-white animate-spin')}\n />\n </View>\n ) : videoHasError ? (\n renderCustomVideoBubbleError ? (\n renderCustomVideoBubbleError()\n ) : (\n <View\n style={tw`absolute inset-0 flex items-center justify-center bg-red-500/60 p-2`}\n >\n <Text style={tw`text-white font-bold`}>\n Failed to load video\n </Text>\n </View>\n )\n ) : (\n <>\n <View style={tw`absolute bg-black/40 rounded-full`}>\n {CustomPlayIcon ? (\n <CustomPlayIcon />\n ) : (\n <PlayIcon\n style={tw.style('h-16 w-16')}\n color={theme?.colors?.audioPlayIconColor || 'white'}\n />\n )}\n </View>\n <View\n style={tw`absolute bottom-2 left-2 bg-black/50 px-2 py-1 rounded-md`}\n >\n <Text style={tw`text-white text-xs font-semibold`}>\n {formatDuration(duration)}\n </Text>\n </View>\n </>\n )}\n </Pressable>\n )}\n\n {message.audio && (\n <View style={tw`my-2`}>\n <AudioPlayer\n audioUrl={message.audio}\n audioId={message.id}\n isVideoPlaying={isVideoPlaying as boolean}\n />\n </View>\n )}\n\n {message.text && (\n <Text\n style={[\n tw`
|
|
1
|
+
{"version":3,"file":"MessageContent.js","sources":["../../../../src/components/ChatBubble/MessageContent.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport Video, { VideoRef } from 'react-native-video';\nimport tw from 'twrnc';\nimport { LoadingIcon } from '../../assets/Icons/LoadingIcon';\nimport { PlayIcon } from '../../assets/Icons/PlayIcon';\nimport { useChatContext } from '../../context/ChatContext';\nimport { formatDuration } from '../../utils/datefunc';\nimport AudioPlayer from '../AudioPlayer/AudioPlayer';\nimport { MessageContentProps } from './types';\n\nconst MessageContent: React.FC<MessageContentProps> = ({\n message,\n onMediaPress,\n isVideoPlaying,\n isCurrentUser,\n}) => {\n const {\n theme,\n showMessageStatus,\n CustomPlayIcon,\n renderCustomVideoBubbleError,\n } = useChatContext();\n const videoRef = React.useRef<VideoRef>(null);\n const [duration, setDuration] = React.useState(0);\n const [videoIsLoading, setVideoIsLoading] = React.useState(false);\n const [videoHasError, setVideoHasError] = React.useState(false);\n\n return (\n <View>\n {message.image && (\n <Pressable\n onPress={() => onMediaPress('image', message.image as string)}\n style={tw`w-60 h-80 my-2`}\n >\n <Image\n source={{ uri: message.image }}\n style={tw`w-full h-full object-contain rounded-lg`}\n />\n </Pressable>\n )}\n\n {message.video && (\n <Pressable\n onPress={() => onMediaPress('video', message.video as string)}\n style={tw`w-60 h-80 my-2 justify-center items-center`}\n disabled={videoIsLoading}\n >\n <Video\n source={{ uri: message.video }}\n ref={videoRef}\n paused={true}\n style={{\n width: '100%',\n height: '100%',\n borderRadius: 8,\n position: 'relative',\n }}\n resizeMode=\"cover\"\n onLoadStart={() => {\n setVideoIsLoading(true);\n setVideoHasError(false);\n }}\n onLoad={(data) => {\n setDuration(data.duration);\n setVideoIsLoading(false);\n }}\n onBuffer={({ isBuffering }) => setVideoIsLoading(isBuffering)}\n onError={() => {\n setVideoHasError(true);\n setVideoIsLoading(false);\n }}\n />\n {videoIsLoading ? (\n <View\n style={tw`absolute inset-0 flex items-center justify-center bg-black/40 rounded-full`}\n >\n <LoadingIcon\n style={tw.style('h-12 w-12 fill-white animate-spin')}\n />\n </View>\n ) : videoHasError ? (\n renderCustomVideoBubbleError ? (\n renderCustomVideoBubbleError()\n ) : (\n <View\n style={tw`absolute inset-0 flex items-center justify-center bg-red-500/60 p-2`}\n >\n <Text style={tw`text-white font-bold`}>\n Failed to load video\n </Text>\n </View>\n )\n ) : (\n <>\n <View style={tw`absolute bg-black/40 rounded-full`}>\n {CustomPlayIcon ? (\n <CustomPlayIcon />\n ) : (\n <PlayIcon\n style={tw.style('h-16 w-16')}\n color={theme?.colors?.audioPlayIconColor || 'white'}\n />\n )}\n </View>\n <View\n style={tw`absolute bottom-2 left-2 bg-black/50 px-2 py-1 rounded-md`}\n >\n <Text style={tw`text-white text-xs font-semibold`}>\n {formatDuration(duration)}\n </Text>\n </View>\n </>\n )}\n </Pressable>\n )}\n\n {message.audio && (\n <View style={tw`my-2`}>\n <AudioPlayer\n audioUrl={message.audio}\n audioId={message.id}\n isVideoPlaying={isVideoPlaying as boolean}\n />\n </View>\n )}\n\n {message.text && (\n <Text\n style={[\n tw`pt-1`,\n showMessageStatus ? tw`pb-0` : tw`pb-2`,\n { wordBreak: 'break-word', overflowWrap: 'break-word' },\n isCurrentUser\n ? theme?.messageStyle?.sentTextStyle\n : theme?.messageStyle?.receivedTextStyle,\n ]}\n >\n {message.text}\n </Text>\n )}\n </View>\n );\n};\n\nexport default React.memo(MessageContent);\n"],"names":["MessageContent","message","onMediaPress","isVideoPlaying","isCurrentUser","theme","showMessageStatus","CustomPlayIcon","renderCustomVideoBubbleError","useChatContext","videoRef","React","useRef","duration","setDuration","useState","videoIsLoading","setVideoIsLoading","videoHasError","setVideoHasError","_jsxs","View","children","image","_jsx","Pressable","onPress","style","tw","jsx","Image","source","uri","video","disabled","Video","ref","paused","width","height","borderRadius","position","resizeMode","onLoadStart","onLoad","data","onBuffer","isBuffering","onError","LoadingIcon","Text","jsxs","_Fragment","PlayIcon","color","colors","audioPlayIconColor","formatDuration","audio","AudioPlayer","audioUrl","audioId","id","text","wordBreak","overflowWrap","messageStyle","sentTextStyle","receivedTextStyle","MessageContent$1","memo"],"mappings":"qWAWA,MAAMA,EAAgDA,EACpDC,UACAC,eACAC,iBACAC,oBAEA,MAAMC,MACJA,EAAKC,kBACLA,EAAiBC,eACjBA,EAAcC,6BACdA,GACEC,mBACEC,EAAWC,EAAMC,OAAiB,OACjCC,EAAUC,GAAeH,EAAMI,SAAS,IACxCC,EAAgBC,GAAqBN,EAAMI,UAAS,IACpDG,EAAeC,GAAoBR,EAAMI,UAAS,GAEzD,OACEK,EAAAA,KAACC,EAAAA,KAAI,CAAAC,UACFrB,EAAQsB,OACPC,EAAAA,IAACC,EAAAA,UAAS,CACRC,QAASA,IAAMxB,EAAa,QAASD,EAAQsB,OAC7CI,MAAOC,CAAE,iBAAiBN,SAE1BE,EAAAK,IAACC,QAAK,CACJC,OAAQ,CAAEC,IAAK/B,EAAQsB,OACvBI,MAAOC,CAAE,8CAKd3B,EAAQgC,OACPb,EAAAA,KAACK,EAAAA,UAAS,CACRC,QAASA,IAAMxB,EAAa,QAASD,EAAQgC,OAC7CN,MAAOC,CAAE,6CACTM,SAAUlB,EAAeM,SAAA,CAEzBE,EAAAK,IAACM,EAAK,CACJJ,OAAQ,CAAEC,IAAK/B,EAAQgC,OACvBG,IAAK1B,EACL2B,QAAQ,EACRV,MAAO,CACLW,MAAO,OACPC,OAAQ,OACRC,aAAc,EACdC,SAAU,YAEZC,WAAW,QACXC,YAAaA,KACX1B,GAAkB,GAClBE,GAAiB,EAAM,EAEzByB,OAASC,IACP/B,EAAY+B,EAAKhC,UACjBI,GAAkB,EAAM,EAE1B6B,SAAUA,EAAGC,iBAAkB9B,EAAkB8B,GACjDC,QAASA,KACP7B,GAAiB,GACjBF,GAAkB,EAAM,IAG3BD,EACCQ,EAAAK,IAACR,OAAI,CACHM,MAAOC,CAAE,6EAA6EN,SAEtFE,EAAAK,IAACoB,cAAW,CACVtB,MAAOC,EAAGD,MAAM,yCAGlBT,EACFV,EACEA,IAEAgB,EAAAA,IAACH,EAAAA,KAAI,CACHM,MAAOC,CAAE,sEAAsEN,SAE/EE,EAAAK,IAACqB,OAAI,CAACvB,MAAOC,CAAE,uBAAuBN,SAAC,2BAM3CF,EAAA+B,KAAAC,WAAA,CAAA9B,SAAA,CACEE,EAAAK,IAACR,OAAI,CAACM,MAAOC,CAAE,oCAAoCN,SAChDf,EACCiB,MAACjB,EAAc,CAAA,GAEfiB,EAAAK,IAACwB,WAAQ,CACP1B,MAAOC,EAAGD,MAAM,aAChB2B,MAAOjD,GAAOkD,QAAQC,oBAAsB,YAIlDhC,EAAAK,IAACR,OAAI,CACHM,MAAOC,CAAE,4DAA4DN,SAErEE,EAAAK,IAACqB,OAAI,CAACvB,MAAOC,CAAE,mCAAmCN,SAC/CmC,EAAcA,eAAC5C,aAQ3BZ,EAAQyD,OACPlC,EAAAA,IAACH,EAAAA,KAAI,CAACM,MAAOC,CAAE,OAAON,SACpBE,EAAAK,IAAC8B,EAAW,CACVC,SAAU3D,EAAQyD,MAClBG,QAAS5D,EAAQ6D,GACjB3D,eAAgBA,MAKrBF,EAAQ8D,MACPvC,EAAAA,IAAC0B,EAAAA,KAAI,CACHvB,MAAO,CACLC,CAAE,OACFtB,EAAoBsB,CAAE,OAASA,CAAE,OACjC,CAAEoC,UAAW,aAAcC,aAAc,cACzC7D,EACIC,GAAO6D,cAAcC,cACrB9D,GAAO6D,cAAcE,mBACzB9C,SAEDrB,EAAQ8D,SAGR,EAIX,IAAAM,EAAe1D,EAAM2D,KAAKtE"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e=require("react-native"),t=require("twrnc"),r=require("../../assets/Icons/ArrowBack2RoundedIcon.js"),l=require("../../context/ChatContext.js"),n=require("react/jsx-runtime");exports.TypingIndicator=({typingUsers:s,currentUserId:i})=>{const{theme:a,showAvatars:o,renderCustomTyping:c,showBubbleTail:d}=l.useChatContext(),u=s.filter((e=>e.id!==i));if(!u.length)return null;const x=u.slice(0,2),y=u.length-2;return n.jsxs(e.View,{style:t`my-1 max-w-[75%] self-start flex-row`,children:[o&&n.jsxs(e.View,{style:t`flex-row`,children:[x.map(((r,l)=>n.jsx(e.View,{style:[t`bg-gray-400 w-6 h-6 rounded-full items-center`,{marginLeft:l>0?-10:0,zIndex:x.length+l}],children:r.avatar?n.jsx(e.Image,{source:{uri:r.avatar},style:[t`w-full h-full object-cover rounded-full`,a?.bubbleStyle?.avatarImageStyle]}):n.jsx(e.Text,{style:[t`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,a?.bubbleStyle?.avatarTextStyle],children:r.name?.charAt(0)})},r.id))),y>0&&n.jsx(e.View,{style:[t`bg-gray-400 w-6 h-6 rounded-full items-center justify-center`,{marginLeft:-10,zIndex:3},{...a?.bubbleStyle?.additionalTypingUsersContainerStyle}],children:n.jsxs(e.Text,{style:[t`text-white text-xs font-semibold`,a?.bubbleStyle?.additionalTypingUsersTextStyle],children:["+",y]})})]}),d&&n.jsx(r.ArrowBack2RoundedIcon,{style:t.style("w-6 h-6 fill-white mt-[1.25px]",{transform:[{rotate:"180deg"},{translateX:6}]}),color:`${a?.colors?.receivedMessageTailColor||"white"}`}),n.jsx(e.View,{style:[t`px-2 my-1 bg-white rounded-tl-none rounded-lg`,a?.bubbleStyle?.typingContainerStyle],children:c?c():n.jsx(e.View,{style:t`flex-row items-center py-3 px-2 justify-center`,children:n.jsx(e.Text,{style:t`text-gray-600`,children:"Typing..."})})})]})};
|
|
1
|
+
"use strict";var e=require("react-native"),t=require("twrnc"),r=require("../../assets/Icons/ArrowBack2RoundedIcon.js"),l=require("../../context/ChatContext.js"),n=require("react/jsx-runtime");exports.TypingIndicator=({typingUsers:s,currentUserId:i})=>{const{theme:a,showAvatars:o,renderCustomTyping:c,showBubbleTail:d}=l.useChatContext(),u=s.filter((e=>e.id!==i));if(!u.length)return null;const x=u.slice(0,2),y=u.length-2;return n.jsxs(e.View,{style:t`my-1 max-w-[75%] self-start flex-row`,children:[o&&n.jsxs(e.View,{style:t`flex-row`,children:[x.map(((r,l)=>n.jsx(e.View,{style:[t`bg-gray-400 w-6 h-6 rounded-full items-center`,{marginLeft:l>0?-10:0,zIndex:x.length+l}],children:r.avatar?n.jsx(e.Image,{source:{uri:r.avatar},style:[t`w-full h-full object-cover rounded-full`,a?.bubbleStyle?.avatarImageStyle]}):n.jsx(e.Text,{style:[t`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,a?.bubbleStyle?.avatarTextStyle],children:r.name?.charAt(0)})},r.id))),y>0&&n.jsx(e.View,{style:[t`bg-gray-400 w-6 h-6 rounded-full items-center justify-center`,{marginLeft:-10,zIndex:3},{...a?.bubbleStyle?.additionalTypingUsersContainerStyle}],children:n.jsxs(e.Text,{style:[t`text-white text-xs font-semibold`,a?.bubbleStyle?.additionalTypingUsersTextStyle],children:["+",y]})})]}),d&&n.jsx(r.ArrowBack2RoundedIcon,{style:t.style("w-6 h-6 fill-white mt-[1.25px] stroke-transparent",{transform:[{rotate:"180deg"},{translateX:6}]}),color:`${a?.colors?.receivedMessageTailColor||"white"}`}),n.jsx(e.View,{style:[t`px-2 my-1 bg-white rounded-tl-none rounded-lg`,a?.bubbleStyle?.typingContainerStyle],children:c?c():n.jsx(e.View,{style:t`flex-row items-center py-3 px-2 justify-center`,children:n.jsx(e.Text,{style:t`text-gray-600`,children:"Typing..."})})})]})};
|
|
2
2
|
//# sourceMappingURL=TypingIndicator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TypingIndicator.js","sources":["../../../../src/components/TypingComponent/TypingIndicator.tsx"],"sourcesContent":["import { Image, Text, View } from 'react-native';\nimport tw from 'twrnc';\nimport { ArrowBack2RoundedIcon } from '../../assets/Icons/ArrowBack2RoundedIcon';\nimport { useChatContext } from '../../context/ChatContext';\n\nexport interface TypingUser {\n id: string;\n avatar: string;\n name: string;\n}\n\ninterface TypingIndicatorProps {\n typingUsers: TypingUser[];\n currentUserId: string;\n}\n\nexport const TypingIndicator = ({\n typingUsers,\n currentUserId,\n}: TypingIndicatorProps) => {\n const { theme, showAvatars, renderCustomTyping, showBubbleTail } =\n useChatContext();\n\n const otherTypingUsers = typingUsers.filter(\n (user) => user.id !== currentUserId\n );\n\n if (!otherTypingUsers.length) return null;\n\n const displayedUsers = otherTypingUsers.slice(0, 2);\n const additionalUsers = otherTypingUsers.length - 2;\n\n return (\n <View style={tw`my-1 max-w-[75%] self-start flex-row`}>\n {showAvatars && (\n <View style={tw`flex-row`}>\n {displayedUsers.map((user, index) => (\n <View\n key={user.id}\n style={[\n tw`bg-gray-400 w-6 h-6 rounded-full items-center`,\n {\n marginLeft: index > 0 ? -10 : 0,\n zIndex: displayedUsers.length + index,\n },\n ]}\n >\n {user.avatar ? (\n <Image\n source={{ uri: user.avatar }}\n style={[\n tw`w-full h-full object-cover rounded-full`,\n theme?.bubbleStyle?.avatarImageStyle,\n ]}\n />\n ) : (\n <Text\n style={[\n tw`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,\n theme?.bubbleStyle?.avatarTextStyle,\n ]}\n >\n {user.name?.charAt(0)}\n </Text>\n )}\n </View>\n ))}\n {additionalUsers > 0 && (\n <View\n style={[\n tw`bg-gray-400 w-6 h-6 rounded-full items-center justify-center`,\n {\n marginLeft: -10,\n zIndex: 3,\n },\n { ...theme?.bubbleStyle?.additionalTypingUsersContainerStyle },\n ]}\n >\n <Text\n style={[\n tw`text-white text-xs font-semibold`,\n theme?.bubbleStyle?.additionalTypingUsersTextStyle,\n ]}\n >\n +{additionalUsers}\n </Text>\n </View>\n )}\n </View>\n )}\n {showBubbleTail && (\n <ArrowBack2RoundedIcon\n style={tw.style(\n 'w-6 h-6 fill-white mt-[1.25px]', \n {\n transform: [{ rotate: '180deg' }, { translateX: 6 }],\n }\n )}\n color={`${theme?.colors?.receivedMessageTailColor || 'white'}`}\n />\n )}\n\n <View\n style={[\n tw`px-2 my-1 bg-white rounded-tl-none rounded-lg`,\n theme?.bubbleStyle?.typingContainerStyle,\n ]}\n >\n {renderCustomTyping ? (\n renderCustomTyping()\n ) : (\n <View style={tw`flex-row items-center py-3 px-2 justify-center`}>\n <Text style={tw`text-gray-600`}>Typing...</Text>\n </View>\n )}\n </View>\n </View>\n );\n};\n"],"names":["TypingIndicator","typingUsers","currentUserId","theme","showAvatars","renderCustomTyping","showBubbleTail","useChatContext","otherTypingUsers","filter","user","id","length","displayedUsers","slice","additionalUsers","_jsxs","View","style","tw","children","jsxs","map","index","_jsx","jsx","marginLeft","zIndex","avatar","Image","source","uri","bubbleStyle","avatarImageStyle","Text","avatarTextStyle","name","charAt","additionalTypingUsersContainerStyle","additionalTypingUsersTextStyle","ArrowBack2RoundedIcon","transform","rotate","translateX","color","colors","receivedMessageTailColor","typingContainerStyle"],"mappings":"wNAgB+BA,EAC7BC,cACAC,oBAEA,MAAMC,MAAEA,EAAKC,YAAEA,EAAWC,mBAAEA,EAAkBC,eAAEA,GAC9CC,mBAEIC,EAAmBP,EAAYQ,QAClCC,GAASA,EAAKC,KAAOT,IAGxB,IAAKM,EAAiBI,OAAQ,OAAO,KAErC,MAAMC,EAAiBL,EAAiBM,MAAM,EAAG,GAC3CC,EAAkBP,EAAiBI,OAAS,EAElD,OACEI,EAAAA,KAACC,EAAAA,KAAI,CAACC,MAAOC,CAAE,uCAAuCC,SACnDhB,CAAAA,GACCY,EAAAK,KAACJ,OAAI,CAACC,MAAOC,CAAE,WAAWC,SACvBP,CAAAA,EAAeS,KAAI,CAACZ,EAAMa,IACzBC,EAAAC,IAACR,OAAI,CAEHC,MAAO,CACLC,CAAE,gDACF,CACEO,WAAYH,EAAQ,GAAI,GAAM,EAC9BI,OAAQd,EAAeD,OAASW,IAElCH,SAEDV,EAAKkB,OACJJ,EAAAA,IAACK,EAAAA,MAAK,CACJC,OAAQ,CAAEC,IAAKrB,EAAKkB,QACpBV,MAAO,CACLC,CAAE,0CACFhB,GAAO6B,aAAaC,oBAIxBT,EAAAC,IAACS,OAAI,CACHhB,MAAO,CACLC,CAAE,wGACFhB,GAAO6B,aAAaG,iBACpBf,SAEDV,EAAK0B,MAAMC,OAAO,MAxBlB3B,EAAKC,MA6BbI,EAAkB,GACjBS,EAAAC,IAACR,OAAI,CACHC,MAAO,CACLC,CAAE,+DACF,CACEO,YAAe,GACfC,OAAQ,GAEV,IAAKxB,GAAO6B,aAAaM,sCACzBlB,SAEFJ,EAAAK,KAACa,OAAI,CACHhB,MAAO,CACLC,CAAE,mCACFhB,GAAO6B,aAAaO,gCACpBnB,SAAA,CACH,IACGL,UAMXT,GACCkB,EAAAC,IAACe,wBAAqB,CACpBtB,MAAOC,EAAGD,MACR,
|
|
1
|
+
{"version":3,"file":"TypingIndicator.js","sources":["../../../../src/components/TypingComponent/TypingIndicator.tsx"],"sourcesContent":["import { Image, Text, View } from 'react-native';\nimport tw from 'twrnc';\nimport { ArrowBack2RoundedIcon } from '../../assets/Icons/ArrowBack2RoundedIcon';\nimport { useChatContext } from '../../context/ChatContext';\n\nexport interface TypingUser {\n id: string;\n avatar: string;\n name: string;\n}\n\ninterface TypingIndicatorProps {\n typingUsers: TypingUser[];\n currentUserId: string;\n}\n\nexport const TypingIndicator = ({\n typingUsers,\n currentUserId,\n}: TypingIndicatorProps) => {\n const { theme, showAvatars, renderCustomTyping, showBubbleTail } =\n useChatContext();\n\n const otherTypingUsers = typingUsers.filter(\n (user) => user.id !== currentUserId\n );\n\n if (!otherTypingUsers.length) return null;\n\n const displayedUsers = otherTypingUsers.slice(0, 2);\n const additionalUsers = otherTypingUsers.length - 2;\n\n return (\n <View style={tw`my-1 max-w-[75%] self-start flex-row`}>\n {showAvatars && (\n <View style={tw`flex-row`}>\n {displayedUsers.map((user, index) => (\n <View\n key={user.id}\n style={[\n tw`bg-gray-400 w-6 h-6 rounded-full items-center`,\n {\n marginLeft: index > 0 ? -10 : 0,\n zIndex: displayedUsers.length + index,\n },\n ]}\n >\n {user.avatar ? (\n <Image\n source={{ uri: user.avatar }}\n style={[\n tw`w-full h-full object-cover rounded-full`,\n theme?.bubbleStyle?.avatarImageStyle,\n ]}\n />\n ) : (\n <Text\n style={[\n tw`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,\n theme?.bubbleStyle?.avatarTextStyle,\n ]}\n >\n {user.name?.charAt(0)}\n </Text>\n )}\n </View>\n ))}\n {additionalUsers > 0 && (\n <View\n style={[\n tw`bg-gray-400 w-6 h-6 rounded-full items-center justify-center`,\n {\n marginLeft: -10,\n zIndex: 3,\n },\n { ...theme?.bubbleStyle?.additionalTypingUsersContainerStyle },\n ]}\n >\n <Text\n style={[\n tw`text-white text-xs font-semibold`,\n theme?.bubbleStyle?.additionalTypingUsersTextStyle,\n ]}\n >\n +{additionalUsers}\n </Text>\n </View>\n )}\n </View>\n )}\n {showBubbleTail && (\n <ArrowBack2RoundedIcon\n style={tw.style(\n 'w-6 h-6 fill-white mt-[1.25px] stroke-transparent', \n {\n transform: [{ rotate: '180deg' }, { translateX: 6 }],\n }\n )}\n color={`${theme?.colors?.receivedMessageTailColor || 'white'}`}\n />\n )}\n\n <View\n style={[\n tw`px-2 my-1 bg-white rounded-tl-none rounded-lg`,\n theme?.bubbleStyle?.typingContainerStyle,\n ]}\n >\n {renderCustomTyping ? (\n renderCustomTyping()\n ) : (\n <View style={tw`flex-row items-center py-3 px-2 justify-center`}>\n <Text style={tw`text-gray-600`}>Typing...</Text>\n </View>\n )}\n </View>\n </View>\n );\n};\n"],"names":["TypingIndicator","typingUsers","currentUserId","theme","showAvatars","renderCustomTyping","showBubbleTail","useChatContext","otherTypingUsers","filter","user","id","length","displayedUsers","slice","additionalUsers","_jsxs","View","style","tw","children","jsxs","map","index","_jsx","jsx","marginLeft","zIndex","avatar","Image","source","uri","bubbleStyle","avatarImageStyle","Text","avatarTextStyle","name","charAt","additionalTypingUsersContainerStyle","additionalTypingUsersTextStyle","ArrowBack2RoundedIcon","transform","rotate","translateX","color","colors","receivedMessageTailColor","typingContainerStyle"],"mappings":"wNAgB+BA,EAC7BC,cACAC,oBAEA,MAAMC,MAAEA,EAAKC,YAAEA,EAAWC,mBAAEA,EAAkBC,eAAEA,GAC9CC,mBAEIC,EAAmBP,EAAYQ,QAClCC,GAASA,EAAKC,KAAOT,IAGxB,IAAKM,EAAiBI,OAAQ,OAAO,KAErC,MAAMC,EAAiBL,EAAiBM,MAAM,EAAG,GAC3CC,EAAkBP,EAAiBI,OAAS,EAElD,OACEI,EAAAA,KAACC,EAAAA,KAAI,CAACC,MAAOC,CAAE,uCAAuCC,SACnDhB,CAAAA,GACCY,EAAAK,KAACJ,OAAI,CAACC,MAAOC,CAAE,WAAWC,SACvBP,CAAAA,EAAeS,KAAI,CAACZ,EAAMa,IACzBC,EAAAC,IAACR,OAAI,CAEHC,MAAO,CACLC,CAAE,gDACF,CACEO,WAAYH,EAAQ,GAAI,GAAM,EAC9BI,OAAQd,EAAeD,OAASW,IAElCH,SAEDV,EAAKkB,OACJJ,EAAAA,IAACK,EAAAA,MAAK,CACJC,OAAQ,CAAEC,IAAKrB,EAAKkB,QACpBV,MAAO,CACLC,CAAE,0CACFhB,GAAO6B,aAAaC,oBAIxBT,EAAAC,IAACS,OAAI,CACHhB,MAAO,CACLC,CAAE,wGACFhB,GAAO6B,aAAaG,iBACpBf,SAEDV,EAAK0B,MAAMC,OAAO,MAxBlB3B,EAAKC,MA6BbI,EAAkB,GACjBS,EAAAC,IAACR,OAAI,CACHC,MAAO,CACLC,CAAE,+DACF,CACEO,YAAe,GACfC,OAAQ,GAEV,IAAKxB,GAAO6B,aAAaM,sCACzBlB,SAEFJ,EAAAK,KAACa,OAAI,CACHhB,MAAO,CACLC,CAAE,mCACFhB,GAAO6B,aAAaO,gCACpBnB,SAAA,CACH,IACGL,UAMXT,GACCkB,EAAAC,IAACe,wBAAqB,CACpBtB,MAAOC,EAAGD,MACR,oDACA,CACEuB,UAAW,CAAC,CAAEC,OAAQ,UAAY,CAAEC,WAAY,MAGpDC,MAAO,GAAGzC,GAAO0C,QAAQC,0BAA4B,YAIzDtB,EAAAC,IAACR,OAAI,CACHC,MAAO,CACLC,CAAE,gDACFhB,GAAO6B,aAAae,sBACpB3B,SAEDf,EACCA,IAEAmB,EAAAA,IAACP,EAAAA,KAAI,CAACC,MAAOC,CAAE,iDAAiDC,SAC9DI,EAAAC,IAACS,OAAI,CAAChB,MAAOC,CAAE,gBAAgBC,SAAC,oBAIjC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e,{Path as o}from"react-native-svg";import{jsx as r}from"react/jsx-runtime";const t=({style:t,color:i})=>r(e,{style:t,
|
|
1
|
+
import e,{Path as o}from"react-native-svg";import{jsx as r}from"react/jsx-runtime";const t=({style:t,color:i})=>r(e,{style:t,viewBox:"0 0 48 48",children:r(o,{fill:i,fillRule:"evenodd",stroke:i,strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"4",d:"M8 9.115c0-1.82 2.235-2.694 3.47-1.356l29.432 31.884c1.182 1.282.273 3.357-1.47 3.357H10a2 2 0 0 1-2-2z",clipRule:"evenodd"})});export{t as ArrowBack2RoundedIcon};
|
|
2
2
|
//# sourceMappingURL=ArrowBack2RoundedIcon.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArrowBack2RoundedIcon.js","sources":["../../../../src/assets/Icons/ArrowBack2RoundedIcon.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"ArrowBack2RoundedIcon.js","sources":["../../../../src/assets/Icons/ArrowBack2RoundedIcon.tsx"],"sourcesContent":["import { ViewStyle } from 'react-native';\nimport Svg, { Path } from 'react-native-svg';\n\nexport const ArrowBack2RoundedIcon = ({\n style,\n color,\n}: {\n style?: ViewStyle;\n color?: string;\n}) => {\n return (\n <Svg style={style} viewBox=\"0 0 48 48\">\n <Path\n fill={color}\n fillRule=\"evenodd\"\n stroke={color}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"4\"\n d=\"M8 9.115c0-1.82 2.235-2.694 3.47-1.356l29.432 31.884c1.182 1.282.273 3.357-1.47 3.357H10a2 2 0 0 1-2-2z\"\n clipRule=\"evenodd\"\n ></Path>\n </Svg>\n );\n};\n"],"names":["ArrowBack2RoundedIcon","style","color","_jsx","Svg","viewBox","children","Path","fill","fillRule","stroke","strokeLinecap","strokeLinejoin","strokeWidth","d","clipRule"],"mappings":"mFAGO,MAAMA,EAAwBA,EACnCC,QACAC,WAMEC,EAACC,EAAG,CAACH,MAAOA,EAAOI,QAAQ,YAAWC,SACpCH,EAACI,EAAI,CACHC,KAAMN,EACNO,SAAS,UACTC,OAAQR,EACRS,cAAc,QACdC,eAAe,QACfC,YAAY,IACZC,EAAE,0GACFC,SAAS"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"react";import{Pressable as t,View as r,Image as s,Text as o}from"react-native";import l from"twrnc";import{ArrowBack2RoundedIcon as a}from"../../assets/Icons/ArrowBack2RoundedIcon.js";import{useChatContext as i}from"../../context/ChatContext.js";import n from"./MessageContent.js";import d from"./MessageStatus.js";import{jsxs as m,jsx as u,Fragment as c}from"react/jsx-runtime";const b=({message:e,isCurrentUser:b,isFirstInSequence:g,onLongPress:f})=>{const{theme:h,showAvatars:y,showUserNames:p,showBubbleTail:x,setMediaUrl:v,setIsVideoPlaying:w,isVideoPlaying:S}=i();return m(t,{onLongPress:f,style:[l`px-2 my-1 max-w-[75%] relative`,b?l`self-end mr-3`:l`self-start ml-9`,g?b?l`bg-green-500 rounded-tr-none`:l`bg-white rounded-tl-none`:b?l`bg-green-500`:l`bg-white`,{borderRadius:8,...b?h?.bubbleStyle?.sent:h?.bubbleStyle?.received}],children:[!b&&g&&y&&m(c,{children:[u(r,{style:l`absolute w-6 h-6 rounded-full top-0 -left-9 flex-row items-center`,children:e.senderAvatar?u(s,{source:{uri:e.senderAvatar},style:[l`w-full h-full rounded-full`,h?.bubbleStyle?.avatarImageStyle],resizeMode:"cover"}):u(o,{style:[l`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,h?.bubbleStyle?.avatarTextStyle],children:e.senderName?.charAt(0)})}),p&&e.senderName&&u(o,{style:[l`text-sm text-black font-semibold mt-1 capitalize`,h?.bubbleStyle?.userNameStyle],children:e.senderName})]}),g&&x&&u(a,{style:l.style("absolute -top-1 w-6 h-6",b?"-right-3.5":"-left-3.5 mt-[1.25px]",{transform:[{rotate:b?"90deg":"180deg"}]}),color:b?`${h?.colors?.sentMessageTailColor||"rgba(34, 197, 94,1)"}`:`${h?.colors?.receivedMessageTailColor||"white"}`}),u(n,{message:e,isCurrentUser:b,isFirstInSequence:g,onMediaPress:(e,t)=>{v({imageUrl:"image"===e?t:"",videoUrl:"video"===e?t:""}),"video"===e&&w(!0)},isVideoPlaying:S}),u(d,{time:e.time,status:b?e.status:void 0,isCurrentUser:b,hasText:!!e.text,hasAudio:!!e.audio})]})};var g=e.memo(b);export{g as default};
|
|
1
|
+
import e from"react";import{Pressable as t,View as r,Image as s,Text as o}from"react-native";import l from"twrnc";import{ArrowBack2RoundedIcon as a}from"../../assets/Icons/ArrowBack2RoundedIcon.js";import{useChatContext as i}from"../../context/ChatContext.js";import n from"./MessageContent.js";import d from"./MessageStatus.js";import{jsxs as m,jsx as u,Fragment as c}from"react/jsx-runtime";const b=({message:e,isCurrentUser:b,isFirstInSequence:g,onLongPress:f})=>{const{theme:h,showAvatars:y,showUserNames:p,showBubbleTail:x,setMediaUrl:v,setIsVideoPlaying:w,isVideoPlaying:S}=i();return m(t,{onLongPress:f,style:[l`px-2 my-1 max-w-[75%] relative`,b?l`self-end mr-3`:l`self-start ml-9`,g?b?l`bg-green-500 rounded-tr-none`:l`bg-white rounded-tl-none`:b?l`bg-green-500`:l`bg-white`,{borderRadius:8,...b?h?.bubbleStyle?.sent:h?.bubbleStyle?.received}],children:[!b&&g&&y&&m(c,{children:[u(r,{style:l`absolute w-6 h-6 rounded-full top-0 -left-9 flex-row items-center`,children:e.senderAvatar?u(s,{source:{uri:e.senderAvatar},style:[l`w-full h-full rounded-full`,h?.bubbleStyle?.avatarImageStyle],resizeMode:"cover"}):u(o,{style:[l`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,h?.bubbleStyle?.avatarTextStyle],children:e.senderName?.charAt(0)})}),p&&e.senderName&&u(o,{style:[l`text-sm text-black font-semibold mt-1 capitalize`,h?.bubbleStyle?.userNameStyle],children:e.senderName})]}),g&&x&&u(a,{style:l.style("absolute -top-1 w-6 h-6 stroke-transparent",b?"-right-3.5":"-left-3.5 mt-[1.25px]",{transform:[{rotate:b?"90deg":"180deg"}]}),color:b?`${h?.colors?.sentMessageTailColor||"rgba(34, 197, 94,1)"}`:`${h?.colors?.receivedMessageTailColor||"white"}`}),u(n,{message:e,isCurrentUser:b,isFirstInSequence:g,onMediaPress:(e,t)=>{v({imageUrl:"image"===e?t:"",videoUrl:"video"===e?t:""}),"video"===e&&w(!0)},isVideoPlaying:S}),u(d,{time:e.time,status:b?e.status:void 0,isCurrentUser:b,hasText:!!e.text,hasAudio:!!e.audio})]})};var g=e.memo(b);export{g as default};
|
|
2
2
|
//# sourceMappingURL=ChatBubble.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatBubble.js","sources":["../../../../src/components/ChatBubble/ChatBubble.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport tw from 'twrnc';\nimport { ArrowBack2RoundedIcon } from '../../assets/Icons/ArrowBack2RoundedIcon';\nimport { useChatContext } from '../../context/ChatContext';\nimport MessageContent from './MessageContent';\nimport MessageStatus from './MessageStatus';\nimport { ChatBubbleProps } from './types';\n\nconst ChatBubble: React.FC<ChatBubbleProps> = ({\n message,\n isCurrentUser,\n isFirstInSequence,\n onLongPress,\n}) => {\n const {\n theme,\n showAvatars,\n showUserNames,\n showBubbleTail,\n setMediaUrl,\n setIsVideoPlaying,\n isVideoPlaying,\n } = useChatContext();\n\n const handleMediaPress = (type: 'image' | 'video', url: string) => {\n setMediaUrl({\n imageUrl: type === 'image' ? url : '',\n videoUrl: type === 'video' ? url : '',\n });\n if (type === 'video') {\n setIsVideoPlaying(true);\n }\n };\n\n return (\n <Pressable\n onLongPress={onLongPress}\n style={[\n tw`px-2 my-1 max-w-[75%] relative`,\n isCurrentUser ? tw`self-end mr-3` : tw`self-start ml-9`,\n isFirstInSequence\n ? isCurrentUser\n ? tw`bg-green-500 rounded-tr-none`\n : tw`bg-white rounded-tl-none`\n : isCurrentUser\n ? tw`bg-green-500`\n : tw`bg-white`,\n {\n borderRadius: 8,\n ...(isCurrentUser\n ? theme?.bubbleStyle?.sent\n : theme?.bubbleStyle?.received),\n },\n ]}\n >\n {/* Avatar & Sender Name for Group Chat */}\n {!isCurrentUser && isFirstInSequence && showAvatars && (\n <>\n <View\n style={tw`absolute w-6 h-6 rounded-full top-0 -left-9 flex-row items-center`}\n >\n {message.senderAvatar ? (\n <Image\n source={{ uri: message.senderAvatar }}\n style={[\n tw`w-full h-full rounded-full`,\n theme?.bubbleStyle?.avatarImageStyle,\n ]}\n resizeMode=\"cover\"\n />\n ) : (\n <Text\n style={[\n tw`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,\n theme?.bubbleStyle?.avatarTextStyle,\n ]}\n >\n {message.senderName?.charAt(0)}\n </Text>\n )}\n </View>\n {showUserNames && message.senderName && (\n <Text\n style={[\n tw`text-sm text-black font-semibold mt-1 capitalize`,\n theme?.bubbleStyle?.userNameStyle,\n ]}\n >\n {message.senderName}\n </Text>\n )}\n </>\n )}\n\n {/* Bubble Tail */}\n {isFirstInSequence && showBubbleTail && (\n <ArrowBack2RoundedIcon\n style={tw.style(\n 'absolute -top-1 w-6 h-6',\n isCurrentUser ? '-right-3.5' : '-left-3.5 mt-[1.25px]',\n {\n transform: [{ rotate: isCurrentUser ? '90deg' : '180deg' }],\n }\n )}\n color={\n isCurrentUser\n ? `${\n theme?.colors?.sentMessageTailColor || 'rgba(34, 197, 94,1)'\n }`\n : `${theme?.colors?.receivedMessageTailColor || 'white'}`\n }\n />\n )}\n\n {/* Message Content */}\n <MessageContent\n message={message}\n isCurrentUser={isCurrentUser}\n isFirstInSequence={isFirstInSequence}\n onMediaPress={handleMediaPress}\n isVideoPlaying={isVideoPlaying}\n />\n\n {/* Message Status */}\n <MessageStatus\n time={message.time}\n status={isCurrentUser ? message.status : undefined}\n isCurrentUser={isCurrentUser}\n hasText={!!message.text}\n hasAudio={!!message.audio}\n />\n </Pressable>\n );\n};\n\nexport default React.memo(ChatBubble);\n"],"names":["ChatBubble","message","isCurrentUser","isFirstInSequence","onLongPress","theme","showAvatars","showUserNames","showBubbleTail","setMediaUrl","setIsVideoPlaying","isVideoPlaying","useChatContext","_jsxs","Pressable","style","tw","borderRadius","bubbleStyle","sent","received","children","_Fragment","_jsx","View","senderAvatar","Image","source","uri","avatarImageStyle","resizeMode","Text","avatarTextStyle","senderName","charAt","userNameStyle","ArrowBack2RoundedIcon","transform","rotate","color","colors","sentMessageTailColor","receivedMessageTailColor","MessageContent","onMediaPress","handleMediaPress","type","url","imageUrl","videoUrl","MessageStatus","time","status","undefined","hasText","text","hasAudio","audio","ChatBubble$1","React","memo"],"mappings":"yYASA,MAAMA,EAAwCA,EAC5CC,UACAC,gBACAC,oBACAC,kBAEA,MAAMC,MACJA,EAAKC,YACLA,EAAWC,cACXA,EAAaC,eACbA,EAAcC,YACdA,EAAWC,kBACXA,EAAiBC,eACjBA,GACEC,IAYJ,OACEC,EAACC,EAAS,CACRV,YAAaA,EACbW,MAAO,CACLC,CAAE,iCACFd,EAAgBc,CAAE,gBAAkBA,CAAE,kBACtCb,EACID,EACEc,CAAE,+BACFA,CAAE,2BACJd,EACEc,CAAE,eACFA,CAAE,WACR,CACEC,aAAc,KACVf,EACAG,GAAOa,aAAaC,KACpBd,GAAOa,aAAaE,WAE1BC,SAAA,EAGAnB,GAAiBC,GAAqBG,GACtCO,EAAAS,EAAA,CAAAD,SAAA,CACEE,EAACC,EAAI,CACHT,MAAOC,CAAE,oEAAoEK,SAE5EpB,EAAQwB,aACPF,EAACG,EAAK,CACJC,OAAQ,CAAEC,IAAK3B,EAAQwB,cACvBV,MAAO,CACLC,CAAE,6BACFX,GAAOa,aAAaW,kBAEtBC,WAAW,UAGbP,EAACQ,EAAI,CACHhB,MAAO,CACLC,CAAE,wGACFX,GAAOa,aAAac,iBACpBX,SAEDpB,EAAQgC,YAAYC,OAAO,OAIjC3B,GAAiBN,EAAQgC,YACxBV,EAACQ,EAAI,CACHhB,MAAO,CACLC,CAAE,mDACFX,GAAOa,aAAaiB,eACpBd,SAEDpB,EAAQgC,gBAOhB9B,GAAqBK,GACpBe,EAACa,EAAqB,CACpBrB,MAAOC,EAAGD,MACR,
|
|
1
|
+
{"version":3,"file":"ChatBubble.js","sources":["../../../../src/components/ChatBubble/ChatBubble.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport tw from 'twrnc';\nimport { ArrowBack2RoundedIcon } from '../../assets/Icons/ArrowBack2RoundedIcon';\nimport { useChatContext } from '../../context/ChatContext';\nimport MessageContent from './MessageContent';\nimport MessageStatus from './MessageStatus';\nimport { ChatBubbleProps } from './types';\n\nconst ChatBubble: React.FC<ChatBubbleProps> = ({\n message,\n isCurrentUser,\n isFirstInSequence,\n onLongPress,\n}) => {\n const {\n theme,\n showAvatars,\n showUserNames,\n showBubbleTail,\n setMediaUrl,\n setIsVideoPlaying,\n isVideoPlaying,\n } = useChatContext();\n\n const handleMediaPress = (type: 'image' | 'video', url: string) => {\n setMediaUrl({\n imageUrl: type === 'image' ? url : '',\n videoUrl: type === 'video' ? url : '',\n });\n if (type === 'video') {\n setIsVideoPlaying(true);\n }\n };\n\n return (\n <Pressable\n onLongPress={onLongPress}\n style={[\n tw`px-2 my-1 max-w-[75%] relative`,\n isCurrentUser ? tw`self-end mr-3` : tw`self-start ml-9`,\n isFirstInSequence\n ? isCurrentUser\n ? tw`bg-green-500 rounded-tr-none`\n : tw`bg-white rounded-tl-none`\n : isCurrentUser\n ? tw`bg-green-500`\n : tw`bg-white`,\n {\n borderRadius: 8,\n ...(isCurrentUser\n ? theme?.bubbleStyle?.sent\n : theme?.bubbleStyle?.received),\n },\n ]}\n >\n {/* Avatar & Sender Name for Group Chat */}\n {!isCurrentUser && isFirstInSequence && showAvatars && (\n <>\n <View\n style={tw`absolute w-6 h-6 rounded-full top-0 -left-9 flex-row items-center`}\n >\n {message.senderAvatar ? (\n <Image\n source={{ uri: message.senderAvatar }}\n style={[\n tw`w-full h-full rounded-full`,\n theme?.bubbleStyle?.avatarImageStyle,\n ]}\n resizeMode=\"cover\"\n />\n ) : (\n <Text\n style={[\n tw`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,\n theme?.bubbleStyle?.avatarTextStyle,\n ]}\n >\n {message.senderName?.charAt(0)}\n </Text>\n )}\n </View>\n {showUserNames && message.senderName && (\n <Text\n style={[\n tw`text-sm text-black font-semibold mt-1 capitalize`,\n theme?.bubbleStyle?.userNameStyle,\n ]}\n >\n {message.senderName}\n </Text>\n )}\n </>\n )}\n\n {/* Bubble Tail */}\n {isFirstInSequence && showBubbleTail && (\n <ArrowBack2RoundedIcon\n style={tw.style(\n 'absolute -top-1 w-6 h-6 stroke-transparent',\n isCurrentUser ? '-right-3.5' : '-left-3.5 mt-[1.25px]',\n {\n transform: [{ rotate: isCurrentUser ? '90deg' : '180deg' }],\n }\n )}\n color={\n isCurrentUser\n ? `${\n theme?.colors?.sentMessageTailColor || 'rgba(34, 197, 94,1)'\n }`\n : `${theme?.colors?.receivedMessageTailColor || 'white'}`\n }\n />\n )}\n\n {/* Message Content */}\n <MessageContent\n message={message}\n isCurrentUser={isCurrentUser}\n isFirstInSequence={isFirstInSequence}\n onMediaPress={handleMediaPress}\n isVideoPlaying={isVideoPlaying}\n />\n\n {/* Message Status */}\n <MessageStatus\n time={message.time}\n status={isCurrentUser ? message.status : undefined}\n isCurrentUser={isCurrentUser}\n hasText={!!message.text}\n hasAudio={!!message.audio}\n />\n </Pressable>\n );\n};\n\nexport default React.memo(ChatBubble);\n"],"names":["ChatBubble","message","isCurrentUser","isFirstInSequence","onLongPress","theme","showAvatars","showUserNames","showBubbleTail","setMediaUrl","setIsVideoPlaying","isVideoPlaying","useChatContext","_jsxs","Pressable","style","tw","borderRadius","bubbleStyle","sent","received","children","_Fragment","_jsx","View","senderAvatar","Image","source","uri","avatarImageStyle","resizeMode","Text","avatarTextStyle","senderName","charAt","userNameStyle","ArrowBack2RoundedIcon","transform","rotate","color","colors","sentMessageTailColor","receivedMessageTailColor","MessageContent","onMediaPress","handleMediaPress","type","url","imageUrl","videoUrl","MessageStatus","time","status","undefined","hasText","text","hasAudio","audio","ChatBubble$1","React","memo"],"mappings":"yYASA,MAAMA,EAAwCA,EAC5CC,UACAC,gBACAC,oBACAC,kBAEA,MAAMC,MACJA,EAAKC,YACLA,EAAWC,cACXA,EAAaC,eACbA,EAAcC,YACdA,EAAWC,kBACXA,EAAiBC,eACjBA,GACEC,IAYJ,OACEC,EAACC,EAAS,CACRV,YAAaA,EACbW,MAAO,CACLC,CAAE,iCACFd,EAAgBc,CAAE,gBAAkBA,CAAE,kBACtCb,EACID,EACEc,CAAE,+BACFA,CAAE,2BACJd,EACEc,CAAE,eACFA,CAAE,WACR,CACEC,aAAc,KACVf,EACAG,GAAOa,aAAaC,KACpBd,GAAOa,aAAaE,WAE1BC,SAAA,EAGAnB,GAAiBC,GAAqBG,GACtCO,EAAAS,EAAA,CAAAD,SAAA,CACEE,EAACC,EAAI,CACHT,MAAOC,CAAE,oEAAoEK,SAE5EpB,EAAQwB,aACPF,EAACG,EAAK,CACJC,OAAQ,CAAEC,IAAK3B,EAAQwB,cACvBV,MAAO,CACLC,CAAE,6BACFX,GAAOa,aAAaW,kBAEtBC,WAAW,UAGbP,EAACQ,EAAI,CACHhB,MAAO,CACLC,CAAE,wGACFX,GAAOa,aAAac,iBACpBX,SAEDpB,EAAQgC,YAAYC,OAAO,OAIjC3B,GAAiBN,EAAQgC,YACxBV,EAACQ,EAAI,CACHhB,MAAO,CACLC,CAAE,mDACFX,GAAOa,aAAaiB,eACpBd,SAEDpB,EAAQgC,gBAOhB9B,GAAqBK,GACpBe,EAACa,EAAqB,CACpBrB,MAAOC,EAAGD,MACR,6CACAb,EAAgB,aAAe,wBAC/B,CACEmC,UAAW,CAAC,CAAEC,OAAQpC,EAAgB,QAAU,aAGpDqC,MACErC,EACI,GACEG,GAAOmC,QAAQC,sBAAwB,wBAEzC,GAAGpC,GAAOmC,QAAQE,0BAA4B,YAMxDnB,EAACoB,EAAc,CACb1C,QAASA,EACTC,cAAeA,EACfC,kBAAmBA,EACnByC,aA/FmBC,CAACC,EAAyBC,KACjDtC,EAAY,CACVuC,SAAmB,UAATF,EAAmBC,EAAM,GACnCE,SAAmB,UAATH,EAAmBC,EAAM,KAExB,UAATD,GACFpC,GAAkB,EACpB,EAyFIC,eAAgBA,IAIlBY,EAAC2B,EAAa,CACZC,KAAMlD,EAAQkD,KACdC,OAAQlD,EAAgBD,EAAQmD,YAASC,EACzCnD,cAAeA,EACfoD,UAAWrD,EAAQsD,KACnBC,WAAYvD,EAAQwD,UAEZ,EAIhB,IAAAC,EAAeC,EAAMC,KAAK5D"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"react";import{View as t,Pressable as o,Image as r,Text as i}from"react-native";import s from"react-native-video";import l from"twrnc";import{LoadingIcon as a}from"../../assets/Icons/LoadingIcon.js";import{PlayIcon as d}from"../../assets/Icons/PlayIcon.js";import{useChatContext as n}from"../../context/ChatContext.js";import{formatDuration as u}from"../../utils/datefunc.js";import c from"../AudioPlayer/AudioPlayer.js";import{jsxs as m,jsx as y,Fragment as f}from"react/jsx-runtime";const h=({message:h,onMediaPress:b,isVideoPlaying:p})=>{const{theme:
|
|
1
|
+
import e from"react";import{View as t,Pressable as o,Image as r,Text as i}from"react-native";import s from"react-native-video";import l from"twrnc";import{LoadingIcon as a}from"../../assets/Icons/LoadingIcon.js";import{PlayIcon as d}from"../../assets/Icons/PlayIcon.js";import{useChatContext as n}from"../../context/ChatContext.js";import{formatDuration as u}from"../../utils/datefunc.js";import c from"../AudioPlayer/AudioPlayer.js";import{jsxs as m,jsx as y,Fragment as f}from"react/jsx-runtime";const h=({message:h,onMediaPress:b,isVideoPlaying:p,isCurrentUser:g})=>{const{theme:w,showMessageStatus:x,CustomPlayIcon:v,renderCustomVideoBubbleError:j}=n(),P=e.useRef(null),[S,I]=e.useState(0),[k,C]=e.useState(!1),[B,L]=e.useState(!1);return m(t,{children:[h.image&&y(o,{onPress:()=>b("image",h.image),style:l`w-60 h-80 my-2`,children:y(r,{source:{uri:h.image},style:l`w-full h-full object-contain rounded-lg`})}),h.video&&m(o,{onPress:()=>b("video",h.video),style:l`w-60 h-80 my-2 justify-center items-center`,disabled:k,children:[y(s,{source:{uri:h.video},ref:P,paused:!0,style:{width:"100%",height:"100%",borderRadius:8,position:"relative"},resizeMode:"cover",onLoadStart:()=>{C(!0),L(!1)},onLoad:e=>{I(e.duration),C(!1)},onBuffer:({isBuffering:e})=>C(e),onError:()=>{L(!0),C(!1)}}),k?y(t,{style:l`absolute inset-0 flex items-center justify-center bg-black/40 rounded-full`,children:y(a,{style:l.style("h-12 w-12 fill-white animate-spin")})}):B?j?j():y(t,{style:l`absolute inset-0 flex items-center justify-center bg-red-500/60 p-2`,children:y(i,{style:l`text-white font-bold`,children:"Failed to load video"})}):m(f,{children:[y(t,{style:l`absolute bg-black/40 rounded-full`,children:v?y(v,{}):y(d,{style:l.style("h-16 w-16"),color:w?.colors?.audioPlayIconColor||"white"})}),y(t,{style:l`absolute bottom-2 left-2 bg-black/50 px-2 py-1 rounded-md`,children:y(i,{style:l`text-white text-xs font-semibold`,children:u(S)})})]})]}),h.audio&&y(t,{style:l`my-2`,children:y(c,{audioUrl:h.audio,audioId:h.id,isVideoPlaying:p})}),h.text&&y(i,{style:[l`pt-1`,x?l`pb-0`:l`pb-2`,{wordBreak:"break-word",overflowWrap:"break-word"},g?w?.messageStyle?.sentTextStyle:w?.messageStyle?.receivedTextStyle],children:h.text})]})};var b=e.memo(h);export{b as default};
|
|
2
2
|
//# sourceMappingURL=MessageContent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageContent.js","sources":["../../../../src/components/ChatBubble/MessageContent.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport Video, { VideoRef } from 'react-native-video';\nimport tw from 'twrnc';\nimport { LoadingIcon } from '../../assets/Icons/LoadingIcon';\nimport { PlayIcon } from '../../assets/Icons/PlayIcon';\nimport { useChatContext } from '../../context/ChatContext';\nimport { formatDuration } from '../../utils/datefunc';\nimport AudioPlayer from '../AudioPlayer/AudioPlayer';\nimport { MessageContentProps } from './types';\n\nconst MessageContent: React.FC<MessageContentProps> = ({\n message,\n onMediaPress,\n isVideoPlaying,\n}) => {\n const {\n theme,\n showMessageStatus,\n CustomPlayIcon,\n renderCustomVideoBubbleError,\n } = useChatContext();\n const videoRef = React.useRef<VideoRef>(null);\n const [duration, setDuration] = React.useState(0);\n const [videoIsLoading, setVideoIsLoading] = React.useState(false);\n const [videoHasError, setVideoHasError] = React.useState(false);\n\n return (\n <View>\n {message.image && (\n <Pressable\n onPress={() => onMediaPress('image', message.image as string)}\n style={tw`w-60 h-80 my-2`}\n >\n <Image\n source={{ uri: message.image }}\n style={tw`w-full h-full object-contain rounded-lg`}\n />\n </Pressable>\n )}\n\n {message.video && (\n <Pressable\n onPress={() => onMediaPress('video', message.video as string)}\n style={tw`w-60 h-80 my-2 justify-center items-center`}\n disabled={videoIsLoading}\n >\n <Video\n source={{ uri: message.video }}\n ref={videoRef}\n paused={true}\n style={{\n width: '100%',\n height: '100%',\n borderRadius: 8,\n position: 'relative',\n }}\n resizeMode=\"cover\"\n onLoadStart={() => {\n setVideoIsLoading(true);\n setVideoHasError(false);\n }}\n onLoad={(data) => {\n setDuration(data.duration);\n setVideoIsLoading(false);\n }}\n onBuffer={({ isBuffering }) => setVideoIsLoading(isBuffering)}\n onError={() => {\n setVideoHasError(true);\n setVideoIsLoading(false);\n }}\n />\n {videoIsLoading ? (\n <View\n style={tw`absolute inset-0 flex items-center justify-center bg-black/40 rounded-full`}\n >\n <LoadingIcon\n style={tw.style('h-12 w-12 fill-white animate-spin')}\n />\n </View>\n ) : videoHasError ? (\n renderCustomVideoBubbleError ? (\n renderCustomVideoBubbleError()\n ) : (\n <View\n style={tw`absolute inset-0 flex items-center justify-center bg-red-500/60 p-2`}\n >\n <Text style={tw`text-white font-bold`}>\n Failed to load video\n </Text>\n </View>\n )\n ) : (\n <>\n <View style={tw`absolute bg-black/40 rounded-full`}>\n {CustomPlayIcon ? (\n <CustomPlayIcon />\n ) : (\n <PlayIcon\n style={tw.style('h-16 w-16')}\n color={theme?.colors?.audioPlayIconColor || 'white'}\n />\n )}\n </View>\n <View\n style={tw`absolute bottom-2 left-2 bg-black/50 px-2 py-1 rounded-md`}\n >\n <Text style={tw`text-white text-xs font-semibold`}>\n {formatDuration(duration)}\n </Text>\n </View>\n </>\n )}\n </Pressable>\n )}\n\n {message.audio && (\n <View style={tw`my-2`}>\n <AudioPlayer\n audioUrl={message.audio}\n audioId={message.id}\n isVideoPlaying={isVideoPlaying as boolean}\n />\n </View>\n )}\n\n {message.text && (\n <Text\n style={[\n tw`
|
|
1
|
+
{"version":3,"file":"MessageContent.js","sources":["../../../../src/components/ChatBubble/MessageContent.tsx"],"sourcesContent":["import React from 'react';\nimport { Image, Pressable, Text, View } from 'react-native';\nimport Video, { VideoRef } from 'react-native-video';\nimport tw from 'twrnc';\nimport { LoadingIcon } from '../../assets/Icons/LoadingIcon';\nimport { PlayIcon } from '../../assets/Icons/PlayIcon';\nimport { useChatContext } from '../../context/ChatContext';\nimport { formatDuration } from '../../utils/datefunc';\nimport AudioPlayer from '../AudioPlayer/AudioPlayer';\nimport { MessageContentProps } from './types';\n\nconst MessageContent: React.FC<MessageContentProps> = ({\n message,\n onMediaPress,\n isVideoPlaying,\n isCurrentUser,\n}) => {\n const {\n theme,\n showMessageStatus,\n CustomPlayIcon,\n renderCustomVideoBubbleError,\n } = useChatContext();\n const videoRef = React.useRef<VideoRef>(null);\n const [duration, setDuration] = React.useState(0);\n const [videoIsLoading, setVideoIsLoading] = React.useState(false);\n const [videoHasError, setVideoHasError] = React.useState(false);\n\n return (\n <View>\n {message.image && (\n <Pressable\n onPress={() => onMediaPress('image', message.image as string)}\n style={tw`w-60 h-80 my-2`}\n >\n <Image\n source={{ uri: message.image }}\n style={tw`w-full h-full object-contain rounded-lg`}\n />\n </Pressable>\n )}\n\n {message.video && (\n <Pressable\n onPress={() => onMediaPress('video', message.video as string)}\n style={tw`w-60 h-80 my-2 justify-center items-center`}\n disabled={videoIsLoading}\n >\n <Video\n source={{ uri: message.video }}\n ref={videoRef}\n paused={true}\n style={{\n width: '100%',\n height: '100%',\n borderRadius: 8,\n position: 'relative',\n }}\n resizeMode=\"cover\"\n onLoadStart={() => {\n setVideoIsLoading(true);\n setVideoHasError(false);\n }}\n onLoad={(data) => {\n setDuration(data.duration);\n setVideoIsLoading(false);\n }}\n onBuffer={({ isBuffering }) => setVideoIsLoading(isBuffering)}\n onError={() => {\n setVideoHasError(true);\n setVideoIsLoading(false);\n }}\n />\n {videoIsLoading ? (\n <View\n style={tw`absolute inset-0 flex items-center justify-center bg-black/40 rounded-full`}\n >\n <LoadingIcon\n style={tw.style('h-12 w-12 fill-white animate-spin')}\n />\n </View>\n ) : videoHasError ? (\n renderCustomVideoBubbleError ? (\n renderCustomVideoBubbleError()\n ) : (\n <View\n style={tw`absolute inset-0 flex items-center justify-center bg-red-500/60 p-2`}\n >\n <Text style={tw`text-white font-bold`}>\n Failed to load video\n </Text>\n </View>\n )\n ) : (\n <>\n <View style={tw`absolute bg-black/40 rounded-full`}>\n {CustomPlayIcon ? (\n <CustomPlayIcon />\n ) : (\n <PlayIcon\n style={tw.style('h-16 w-16')}\n color={theme?.colors?.audioPlayIconColor || 'white'}\n />\n )}\n </View>\n <View\n style={tw`absolute bottom-2 left-2 bg-black/50 px-2 py-1 rounded-md`}\n >\n <Text style={tw`text-white text-xs font-semibold`}>\n {formatDuration(duration)}\n </Text>\n </View>\n </>\n )}\n </Pressable>\n )}\n\n {message.audio && (\n <View style={tw`my-2`}>\n <AudioPlayer\n audioUrl={message.audio}\n audioId={message.id}\n isVideoPlaying={isVideoPlaying as boolean}\n />\n </View>\n )}\n\n {message.text && (\n <Text\n style={[\n tw`pt-1`,\n showMessageStatus ? tw`pb-0` : tw`pb-2`,\n { wordBreak: 'break-word', overflowWrap: 'break-word' },\n isCurrentUser\n ? theme?.messageStyle?.sentTextStyle\n : theme?.messageStyle?.receivedTextStyle,\n ]}\n >\n {message.text}\n </Text>\n )}\n </View>\n );\n};\n\nexport default React.memo(MessageContent);\n"],"names":["MessageContent","message","onMediaPress","isVideoPlaying","isCurrentUser","theme","showMessageStatus","CustomPlayIcon","renderCustomVideoBubbleError","useChatContext","videoRef","React","useRef","duration","setDuration","useState","videoIsLoading","setVideoIsLoading","videoHasError","setVideoHasError","_jsxs","View","children","image","_jsx","Pressable","onPress","style","tw","Image","source","uri","video","disabled","Video","ref","paused","width","height","borderRadius","position","resizeMode","onLoadStart","onLoad","data","onBuffer","isBuffering","onError","LoadingIcon","Text","_Fragment","PlayIcon","color","colors","audioPlayIconColor","formatDuration","audio","AudioPlayer","audioUrl","audioId","id","text","wordBreak","overflowWrap","messageStyle","sentTextStyle","receivedTextStyle","MessageContent$1","memo"],"mappings":"kfAWA,MAAMA,EAAgDA,EACpDC,UACAC,eACAC,iBACAC,oBAEA,MAAMC,MACJA,EAAKC,kBACLA,EAAiBC,eACjBA,EAAcC,6BACdA,GACEC,IACEC,EAAWC,EAAMC,OAAiB,OACjCC,EAAUC,GAAeH,EAAMI,SAAS,IACxCC,EAAgBC,GAAqBN,EAAMI,UAAS,IACpDG,EAAeC,GAAoBR,EAAMI,UAAS,GAEzD,OACEK,EAACC,EAAI,CAAAC,UACFrB,EAAQsB,OACPC,EAACC,EAAS,CACRC,QAASA,IAAMxB,EAAa,QAASD,EAAQsB,OAC7CI,MAAOC,CAAE,iBAAiBN,SAE1BE,EAACK,EAAK,CACJC,OAAQ,CAAEC,IAAK9B,EAAQsB,OACvBI,MAAOC,CAAE,8CAKd3B,EAAQ+B,OACPZ,EAACK,EAAS,CACRC,QAASA,IAAMxB,EAAa,QAASD,EAAQ+B,OAC7CL,MAAOC,CAAE,6CACTK,SAAUjB,EAAeM,SAAA,CAEzBE,EAACU,EAAK,CACJJ,OAAQ,CAAEC,IAAK9B,EAAQ+B,OACvBG,IAAKzB,EACL0B,QAAQ,EACRT,MAAO,CACLU,MAAO,OACPC,OAAQ,OACRC,aAAc,EACdC,SAAU,YAEZC,WAAW,QACXC,YAAaA,KACXzB,GAAkB,GAClBE,GAAiB,EAAM,EAEzBwB,OAASC,IACP9B,EAAY8B,EAAK/B,UACjBI,GAAkB,EAAM,EAE1B4B,SAAUA,EAAGC,iBAAkB7B,EAAkB6B,GACjDC,QAASA,KACP5B,GAAiB,GACjBF,GAAkB,EAAM,IAG3BD,EACCQ,EAACH,EAAI,CACHM,MAAOC,CAAE,6EAA6EN,SAEtFE,EAACwB,EAAW,CACVrB,MAAOC,EAAGD,MAAM,yCAGlBT,EACFV,EACEA,IAEAgB,EAACH,EAAI,CACHM,MAAOC,CAAE,sEAAsEN,SAE/EE,EAACyB,EAAI,CAACtB,MAAOC,CAAE,uBAAuBN,SAAC,2BAM3CF,EAAA8B,EAAA,CAAA5B,SAAA,CACEE,EAACH,EAAI,CAACM,MAAOC,CAAE,oCAAoCN,SAChDf,EACCiB,EAACjB,EAAc,CAAA,GAEfiB,EAAC2B,EAAQ,CACPxB,MAAOC,EAAGD,MAAM,aAChByB,MAAO/C,GAAOgD,QAAQC,oBAAsB,YAIlD9B,EAACH,EAAI,CACHM,MAAOC,CAAE,4DAA4DN,SAErEE,EAACyB,EAAI,CAACtB,MAAOC,CAAE,mCAAmCN,SAC/CiC,EAAe1C,aAQ3BZ,EAAQuD,OACPhC,EAACH,EAAI,CAACM,MAAOC,CAAE,OAAON,SACpBE,EAACiC,EAAW,CACVC,SAAUzD,EAAQuD,MAClBG,QAAS1D,EAAQ2D,GACjBzD,eAAgBA,MAKrBF,EAAQ4D,MACPrC,EAACyB,EAAI,CACHtB,MAAO,CACLC,CAAE,OACFtB,EAAoBsB,CAAE,OAASA,CAAE,OACjC,CAAEkC,UAAW,aAAcC,aAAc,cACzC3D,EACIC,GAAO2D,cAAcC,cACrB5D,GAAO2D,cAAcE,mBACzB5C,SAEDrB,EAAQ4D,SAGR,EAIX,IAAAM,EAAexD,EAAMyD,KAAKpE"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{View as e,Image as t,Text as
|
|
1
|
+
import{View as e,Image as t,Text as r}from"react-native";import l from"twrnc";import{ArrowBack2RoundedIcon as n}from"../../assets/Icons/ArrowBack2RoundedIcon.js";import{useChatContext as i}from"../../context/ChatContext.js";import{jsxs as o,jsx as s}from"react/jsx-runtime";const a=({typingUsers:a,currentUserId:c})=>{const{theme:d,showAvatars:y,renderCustomTyping:u,showBubbleTail:m}=i(),f=a.filter((e=>e.id!==c));if(!f.length)return null;const h=f.slice(0,2),b=f.length-2;return o(e,{style:l`my-1 max-w-[75%] self-start flex-row`,children:[y&&o(e,{style:l`flex-row`,children:[h.map(((n,i)=>s(e,{style:[l`bg-gray-400 w-6 h-6 rounded-full items-center`,{marginLeft:i>0?-10:0,zIndex:h.length+i}],children:n.avatar?s(t,{source:{uri:n.avatar},style:[l`w-full h-full object-cover rounded-full`,d?.bubbleStyle?.avatarImageStyle]}):s(r,{style:[l`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,d?.bubbleStyle?.avatarTextStyle],children:n.name?.charAt(0)})},n.id))),b>0&&s(e,{style:[l`bg-gray-400 w-6 h-6 rounded-full items-center justify-center`,{marginLeft:-10,zIndex:3},{...d?.bubbleStyle?.additionalTypingUsersContainerStyle}],children:o(r,{style:[l`text-white text-xs font-semibold`,d?.bubbleStyle?.additionalTypingUsersTextStyle],children:["+",b]})})]}),m&&s(n,{style:l.style("w-6 h-6 fill-white mt-[1.25px] stroke-transparent",{transform:[{rotate:"180deg"},{translateX:6}]}),color:`${d?.colors?.receivedMessageTailColor||"white"}`}),s(e,{style:[l`px-2 my-1 bg-white rounded-tl-none rounded-lg`,d?.bubbleStyle?.typingContainerStyle],children:u?u():s(e,{style:l`flex-row items-center py-3 px-2 justify-center`,children:s(r,{style:l`text-gray-600`,children:"Typing..."})})})]})};export{a as TypingIndicator};
|
|
2
2
|
//# sourceMappingURL=TypingIndicator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TypingIndicator.js","sources":["../../../../src/components/TypingComponent/TypingIndicator.tsx"],"sourcesContent":["import { Image, Text, View } from 'react-native';\nimport tw from 'twrnc';\nimport { ArrowBack2RoundedIcon } from '../../assets/Icons/ArrowBack2RoundedIcon';\nimport { useChatContext } from '../../context/ChatContext';\n\nexport interface TypingUser {\n id: string;\n avatar: string;\n name: string;\n}\n\ninterface TypingIndicatorProps {\n typingUsers: TypingUser[];\n currentUserId: string;\n}\n\nexport const TypingIndicator = ({\n typingUsers,\n currentUserId,\n}: TypingIndicatorProps) => {\n const { theme, showAvatars, renderCustomTyping, showBubbleTail } =\n useChatContext();\n\n const otherTypingUsers = typingUsers.filter(\n (user) => user.id !== currentUserId\n );\n\n if (!otherTypingUsers.length) return null;\n\n const displayedUsers = otherTypingUsers.slice(0, 2);\n const additionalUsers = otherTypingUsers.length - 2;\n\n return (\n <View style={tw`my-1 max-w-[75%] self-start flex-row`}>\n {showAvatars && (\n <View style={tw`flex-row`}>\n {displayedUsers.map((user, index) => (\n <View\n key={user.id}\n style={[\n tw`bg-gray-400 w-6 h-6 rounded-full items-center`,\n {\n marginLeft: index > 0 ? -10 : 0,\n zIndex: displayedUsers.length + index,\n },\n ]}\n >\n {user.avatar ? (\n <Image\n source={{ uri: user.avatar }}\n style={[\n tw`w-full h-full object-cover rounded-full`,\n theme?.bubbleStyle?.avatarImageStyle,\n ]}\n />\n ) : (\n <Text\n style={[\n tw`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,\n theme?.bubbleStyle?.avatarTextStyle,\n ]}\n >\n {user.name?.charAt(0)}\n </Text>\n )}\n </View>\n ))}\n {additionalUsers > 0 && (\n <View\n style={[\n tw`bg-gray-400 w-6 h-6 rounded-full items-center justify-center`,\n {\n marginLeft: -10,\n zIndex: 3,\n },\n { ...theme?.bubbleStyle?.additionalTypingUsersContainerStyle },\n ]}\n >\n <Text\n style={[\n tw`text-white text-xs font-semibold`,\n theme?.bubbleStyle?.additionalTypingUsersTextStyle,\n ]}\n >\n +{additionalUsers}\n </Text>\n </View>\n )}\n </View>\n )}\n {showBubbleTail && (\n <ArrowBack2RoundedIcon\n style={tw.style(\n 'w-6 h-6 fill-white mt-[1.25px]', \n {\n transform: [{ rotate: '180deg' }, { translateX: 6 }],\n }\n )}\n color={`${theme?.colors?.receivedMessageTailColor || 'white'}`}\n />\n )}\n\n <View\n style={[\n tw`px-2 my-1 bg-white rounded-tl-none rounded-lg`,\n theme?.bubbleStyle?.typingContainerStyle,\n ]}\n >\n {renderCustomTyping ? (\n renderCustomTyping()\n ) : (\n <View style={tw`flex-row items-center py-3 px-2 justify-center`}>\n <Text style={tw`text-gray-600`}>Typing...</Text>\n </View>\n )}\n </View>\n </View>\n );\n};\n"],"names":["TypingIndicator","typingUsers","currentUserId","theme","showAvatars","renderCustomTyping","showBubbleTail","useChatContext","otherTypingUsers","filter","user","id","length","displayedUsers","slice","additionalUsers","_jsxs","View","style","tw","children","map","index","_jsx","marginLeft","zIndex","avatar","Image","source","uri","bubbleStyle","avatarImageStyle","Text","avatarTextStyle","name","charAt","additionalTypingUsersContainerStyle","additionalTypingUsersTextStyle","ArrowBack2RoundedIcon","transform","rotate","translateX","color","colors","receivedMessageTailColor","typingContainerStyle"],"mappings":"kRAgBO,MAAMA,EAAkBA,EAC7BC,cACAC,oBAEA,MAAMC,MAAEA,EAAKC,YAAEA,EAAWC,mBAAEA,EAAkBC,eAAEA,GAC9CC,IAEIC,EAAmBP,EAAYQ,QAClCC,GAASA,EAAKC,KAAOT,IAGxB,IAAKM,EAAiBI,OAAQ,OAAO,KAErC,MAAMC,EAAiBL,EAAiBM,MAAM,EAAG,GAC3CC,EAAkBP,EAAiBI,OAAS,EAElD,OACEI,EAACC,EAAI,CAACC,MAAOC,CAAE,uCAAuCC,SACnDhB,CAAAA,GACCY,EAACC,EAAI,CAACC,MAAOC,CAAE,WAAWC,SACvBP,CAAAA,EAAeQ,KAAI,CAACX,EAAMY,IACzBC,EAACN,EAAI,CAEHC,MAAO,CACLC,CAAE,gDACF,CACEK,WAAYF,EAAQ,GAAI,GAAM,EAC9BG,OAAQZ,EAAeD,OAASU,IAElCF,SAEDV,EAAKgB,OACJH,EAACI,EAAK,CACJC,OAAQ,CAAEC,IAAKnB,EAAKgB,QACpBR,MAAO,CACLC,CAAE,0CACFhB,GAAO2B,aAAaC,oBAIxBR,EAACS,EAAI,CACHd,MAAO,CACLC,CAAE,wGACFhB,GAAO2B,aAAaG,iBACpBb,SAEDV,EAAKwB,MAAMC,OAAO,MAxBlBzB,EAAKC,MA6BbI,EAAkB,GACjBQ,EAACN,EAAI,CACHC,MAAO,CACLC,CAAE,+DACF,CACEK,YAAe,GACfC,OAAQ,GAEV,IAAKtB,GAAO2B,aAAaM,sCACzBhB,SAEFJ,EAACgB,EAAI,CACHd,MAAO,CACLC,CAAE,mCACFhB,GAAO2B,aAAaO,gCACpBjB,SAAA,CACH,IACGL,UAMXT,GACCiB,EAACe,EAAqB,CACpBpB,MAAOC,EAAGD,MACR,
|
|
1
|
+
{"version":3,"file":"TypingIndicator.js","sources":["../../../../src/components/TypingComponent/TypingIndicator.tsx"],"sourcesContent":["import { Image, Text, View } from 'react-native';\nimport tw from 'twrnc';\nimport { ArrowBack2RoundedIcon } from '../../assets/Icons/ArrowBack2RoundedIcon';\nimport { useChatContext } from '../../context/ChatContext';\n\nexport interface TypingUser {\n id: string;\n avatar: string;\n name: string;\n}\n\ninterface TypingIndicatorProps {\n typingUsers: TypingUser[];\n currentUserId: string;\n}\n\nexport const TypingIndicator = ({\n typingUsers,\n currentUserId,\n}: TypingIndicatorProps) => {\n const { theme, showAvatars, renderCustomTyping, showBubbleTail } =\n useChatContext();\n\n const otherTypingUsers = typingUsers.filter(\n (user) => user.id !== currentUserId\n );\n\n if (!otherTypingUsers.length) return null;\n\n const displayedUsers = otherTypingUsers.slice(0, 2);\n const additionalUsers = otherTypingUsers.length - 2;\n\n return (\n <View style={tw`my-1 max-w-[75%] self-start flex-row`}>\n {showAvatars && (\n <View style={tw`flex-row`}>\n {displayedUsers.map((user, index) => (\n <View\n key={user.id}\n style={[\n tw`bg-gray-400 w-6 h-6 rounded-full items-center`,\n {\n marginLeft: index > 0 ? -10 : 0,\n zIndex: displayedUsers.length + index,\n },\n ]}\n >\n {user.avatar ? (\n <Image\n source={{ uri: user.avatar }}\n style={[\n tw`w-full h-full object-cover rounded-full`,\n theme?.bubbleStyle?.avatarImageStyle,\n ]}\n />\n ) : (\n <Text\n style={[\n tw`text-sm text-black font-semibold capitalize rounded-full bg-zinc-300 w-full h-full text-center pt-0.5`,\n theme?.bubbleStyle?.avatarTextStyle,\n ]}\n >\n {user.name?.charAt(0)}\n </Text>\n )}\n </View>\n ))}\n {additionalUsers > 0 && (\n <View\n style={[\n tw`bg-gray-400 w-6 h-6 rounded-full items-center justify-center`,\n {\n marginLeft: -10,\n zIndex: 3,\n },\n { ...theme?.bubbleStyle?.additionalTypingUsersContainerStyle },\n ]}\n >\n <Text\n style={[\n tw`text-white text-xs font-semibold`,\n theme?.bubbleStyle?.additionalTypingUsersTextStyle,\n ]}\n >\n +{additionalUsers}\n </Text>\n </View>\n )}\n </View>\n )}\n {showBubbleTail && (\n <ArrowBack2RoundedIcon\n style={tw.style(\n 'w-6 h-6 fill-white mt-[1.25px] stroke-transparent', \n {\n transform: [{ rotate: '180deg' }, { translateX: 6 }],\n }\n )}\n color={`${theme?.colors?.receivedMessageTailColor || 'white'}`}\n />\n )}\n\n <View\n style={[\n tw`px-2 my-1 bg-white rounded-tl-none rounded-lg`,\n theme?.bubbleStyle?.typingContainerStyle,\n ]}\n >\n {renderCustomTyping ? (\n renderCustomTyping()\n ) : (\n <View style={tw`flex-row items-center py-3 px-2 justify-center`}>\n <Text style={tw`text-gray-600`}>Typing...</Text>\n </View>\n )}\n </View>\n </View>\n );\n};\n"],"names":["TypingIndicator","typingUsers","currentUserId","theme","showAvatars","renderCustomTyping","showBubbleTail","useChatContext","otherTypingUsers","filter","user","id","length","displayedUsers","slice","additionalUsers","_jsxs","View","style","tw","children","map","index","_jsx","marginLeft","zIndex","avatar","Image","source","uri","bubbleStyle","avatarImageStyle","Text","avatarTextStyle","name","charAt","additionalTypingUsersContainerStyle","additionalTypingUsersTextStyle","ArrowBack2RoundedIcon","transform","rotate","translateX","color","colors","receivedMessageTailColor","typingContainerStyle"],"mappings":"kRAgBO,MAAMA,EAAkBA,EAC7BC,cACAC,oBAEA,MAAMC,MAAEA,EAAKC,YAAEA,EAAWC,mBAAEA,EAAkBC,eAAEA,GAC9CC,IAEIC,EAAmBP,EAAYQ,QAClCC,GAASA,EAAKC,KAAOT,IAGxB,IAAKM,EAAiBI,OAAQ,OAAO,KAErC,MAAMC,EAAiBL,EAAiBM,MAAM,EAAG,GAC3CC,EAAkBP,EAAiBI,OAAS,EAElD,OACEI,EAACC,EAAI,CAACC,MAAOC,CAAE,uCAAuCC,SACnDhB,CAAAA,GACCY,EAACC,EAAI,CAACC,MAAOC,CAAE,WAAWC,SACvBP,CAAAA,EAAeQ,KAAI,CAACX,EAAMY,IACzBC,EAACN,EAAI,CAEHC,MAAO,CACLC,CAAE,gDACF,CACEK,WAAYF,EAAQ,GAAI,GAAM,EAC9BG,OAAQZ,EAAeD,OAASU,IAElCF,SAEDV,EAAKgB,OACJH,EAACI,EAAK,CACJC,OAAQ,CAAEC,IAAKnB,EAAKgB,QACpBR,MAAO,CACLC,CAAE,0CACFhB,GAAO2B,aAAaC,oBAIxBR,EAACS,EAAI,CACHd,MAAO,CACLC,CAAE,wGACFhB,GAAO2B,aAAaG,iBACpBb,SAEDV,EAAKwB,MAAMC,OAAO,MAxBlBzB,EAAKC,MA6BbI,EAAkB,GACjBQ,EAACN,EAAI,CACHC,MAAO,CACLC,CAAE,+DACF,CACEK,YAAe,GACfC,OAAQ,GAEV,IAAKtB,GAAO2B,aAAaM,sCACzBhB,SAEFJ,EAACgB,EAAI,CACHd,MAAO,CACLC,CAAE,mCACFhB,GAAO2B,aAAaO,gCACpBjB,SAAA,CACH,IACGL,UAMXT,GACCiB,EAACe,EAAqB,CACpBpB,MAAOC,EAAGD,MACR,oDACA,CACEqB,UAAW,CAAC,CAAEC,OAAQ,UAAY,CAAEC,WAAY,MAGpDC,MAAO,GAAGvC,GAAOwC,QAAQC,0BAA4B,YAIzDrB,EAACN,EAAI,CACHC,MAAO,CACLC,CAAE,gDACFhB,GAAO2B,aAAae,sBACpBzB,SAEDf,EACCA,IAEAkB,EAACN,EAAI,CAACC,MAAOC,CAAE,iDAAiDC,SAC9DG,EAACS,EAAI,CAACd,MAAOC,CAAE,gBAAgBC,SAAC,oBAIjC"}
|
|
@@ -14,7 +14,7 @@ export interface Message {
|
|
|
14
14
|
export interface ChatScreenProps {
|
|
15
15
|
messages: Message[];
|
|
16
16
|
currentUserId: string;
|
|
17
|
-
onSendMessage: (message: Omit<Message,
|
|
17
|
+
onSendMessage: (message: Omit<Message, 'id' | 'time' | 'status'>) => void;
|
|
18
18
|
onMessageLongPress?: (message: Message) => void;
|
|
19
19
|
onAttachmentPress?: () => void;
|
|
20
20
|
onAudioRecordEnd?: () => void;
|
|
@@ -51,7 +51,8 @@ export interface ChatScreenProps {
|
|
|
51
51
|
additionalTypingUsersTextStyle?: TextStyle;
|
|
52
52
|
};
|
|
53
53
|
messageStyle?: {
|
|
54
|
-
|
|
54
|
+
sentTextStyle?: TextStyle;
|
|
55
|
+
receivedTextStyle?: TextStyle;
|
|
55
56
|
audioPlayButtonStyle?: ViewStyle;
|
|
56
57
|
audioKnobStyle?: ViewStyle;
|
|
57
58
|
progressBarStyle?: ViewStyle;
|
package/package.json
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import Svg, { Path } from "react-native-svg";
|
|
1
|
+
import { ViewStyle } from 'react-native';
|
|
2
|
+
import Svg, { Path } from 'react-native-svg';
|
|
4
3
|
|
|
5
4
|
export const ArrowBack2RoundedIcon = ({
|
|
6
5
|
style,
|
|
@@ -10,10 +9,11 @@ export const ArrowBack2RoundedIcon = ({
|
|
|
10
9
|
color?: string;
|
|
11
10
|
}) => {
|
|
12
11
|
return (
|
|
13
|
-
<Svg style={style}
|
|
12
|
+
<Svg style={style} viewBox="0 0 48 48">
|
|
14
13
|
<Path
|
|
14
|
+
fill={color}
|
|
15
15
|
fillRule="evenodd"
|
|
16
|
-
stroke=
|
|
16
|
+
stroke={color}
|
|
17
17
|
strokeLinecap="round"
|
|
18
18
|
strokeLinejoin="round"
|
|
19
19
|
strokeWidth="4"
|
|
@@ -97,7 +97,7 @@ const ChatBubble: React.FC<ChatBubbleProps> = ({
|
|
|
97
97
|
{isFirstInSequence && showBubbleTail && (
|
|
98
98
|
<ArrowBack2RoundedIcon
|
|
99
99
|
style={tw.style(
|
|
100
|
-
'absolute -top-1 w-6 h-6',
|
|
100
|
+
'absolute -top-1 w-6 h-6 stroke-transparent',
|
|
101
101
|
isCurrentUser ? '-right-3.5' : '-left-3.5 mt-[1.25px]',
|
|
102
102
|
{
|
|
103
103
|
transform: [{ rotate: isCurrentUser ? '90deg' : '180deg' }],
|
|
@@ -13,6 +13,7 @@ const MessageContent: React.FC<MessageContentProps> = ({
|
|
|
13
13
|
message,
|
|
14
14
|
onMediaPress,
|
|
15
15
|
isVideoPlaying,
|
|
16
|
+
isCurrentUser,
|
|
16
17
|
}) => {
|
|
17
18
|
const {
|
|
18
19
|
theme,
|
|
@@ -127,10 +128,12 @@ const MessageContent: React.FC<MessageContentProps> = ({
|
|
|
127
128
|
{message.text && (
|
|
128
129
|
<Text
|
|
129
130
|
style={[
|
|
130
|
-
tw`
|
|
131
|
+
tw`pt-1`,
|
|
131
132
|
showMessageStatus ? tw`pb-0` : tw`pb-2`,
|
|
132
133
|
{ wordBreak: 'break-word', overflowWrap: 'break-word' },
|
|
133
|
-
|
|
134
|
+
isCurrentUser
|
|
135
|
+
? theme?.messageStyle?.sentTextStyle
|
|
136
|
+
: theme?.messageStyle?.receivedTextStyle,
|
|
134
137
|
]}
|
|
135
138
|
>
|
|
136
139
|
{message.text}
|
|
@@ -91,7 +91,7 @@ export const TypingIndicator = ({
|
|
|
91
91
|
{showBubbleTail && (
|
|
92
92
|
<ArrowBack2RoundedIcon
|
|
93
93
|
style={tw.style(
|
|
94
|
-
'w-6 h-6 fill-white mt-[1.25px]',
|
|
94
|
+
'w-6 h-6 fill-white mt-[1.25px] stroke-transparent',
|
|
95
95
|
{
|
|
96
96
|
transform: [{ rotate: '180deg' }, { translateX: 6 }],
|
|
97
97
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface ChatScreenProps {
|
|
|
17
17
|
// Message handling
|
|
18
18
|
messages: Message[];
|
|
19
19
|
currentUserId: string;
|
|
20
|
-
onSendMessage: (message: Omit<Message,
|
|
20
|
+
onSendMessage: (message: Omit<Message, 'id' | 'time' | 'status'>) => void;
|
|
21
21
|
onMessageLongPress?: (message: Message) => void;
|
|
22
22
|
onAttachmentPress?: () => void;
|
|
23
23
|
onAudioRecordEnd?: () => void;
|
|
@@ -54,7 +54,8 @@ export interface ChatScreenProps {
|
|
|
54
54
|
additionalTypingUsersTextStyle?: TextStyle;
|
|
55
55
|
};
|
|
56
56
|
messageStyle?: {
|
|
57
|
-
|
|
57
|
+
sentTextStyle?: TextStyle;
|
|
58
|
+
receivedTextStyle?: TextStyle;
|
|
58
59
|
audioPlayButtonStyle?: ViewStyle;
|
|
59
60
|
audioKnobStyle?: ViewStyle;
|
|
60
61
|
progressBarStyle?: ViewStyle;
|