@codewithvincent/react-native-love-chat 0.1.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/CHANGELOG.md +8 -0
- package/LICENSE +21 -0
- package/README.md +152 -0
- package/dist/Chat.d.ts +3 -0
- package/dist/Chat.js +78 -0
- package/dist/components/Bubble.d.ts +21 -0
- package/dist/components/Bubble.js +55 -0
- package/dist/components/Composer.d.ts +14 -0
- package/dist/components/Composer.js +44 -0
- package/dist/components/FooterReplyPreview.d.ts +7 -0
- package/dist/components/FooterReplyPreview.js +130 -0
- package/dist/components/Icons.d.ts +21 -0
- package/dist/components/Icons.js +71 -0
- package/dist/components/InputToolbar.d.ts +17 -0
- package/dist/components/InputToolbar.js +110 -0
- package/dist/components/Message.d.ts +21 -0
- package/dist/components/Message.js +131 -0
- package/dist/components/MessageList.d.ts +6 -0
- package/dist/components/MessageList.js +111 -0
- package/dist/components/MessageStatus.d.ts +6 -0
- package/dist/components/MessageStatus.js +59 -0
- package/dist/components/ReactionBubble.d.ts +55 -0
- package/dist/components/ReactionBubble.js +262 -0
- package/dist/components/ReplyPreview.d.ts +7 -0
- package/dist/components/ReplyPreview.js +102 -0
- package/dist/components/UploadFooter.d.ts +4 -0
- package/dist/components/UploadFooter.js +33 -0
- package/dist/components/adapters/UniversalAudio.d.ts +8 -0
- package/dist/components/adapters/UniversalAudio.js +23 -0
- package/dist/components/adapters/UniversalBlurView.d.ts +3 -0
- package/dist/components/adapters/UniversalBlurView.js +26 -0
- package/dist/components/adapters/UniversalVideo.d.ts +8 -0
- package/dist/components/adapters/UniversalVideo.js +20 -0
- package/dist/components/media/AudioCard.d.ts +7 -0
- package/dist/components/media/AudioCard.js +187 -0
- package/dist/components/media/FileCard.d.ts +8 -0
- package/dist/components/media/FileCard.js +68 -0
- package/dist/components/media/ImageCard.d.ts +9 -0
- package/dist/components/media/ImageCard.js +76 -0
- package/dist/components/media/VideoCard.d.ts +10 -0
- package/dist/components/media/VideoCard.js +232 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +36 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.js +2 -0
- package/dist/utils/index.d.ts +14 -0
- package/dist/utils/index.js +44 -0
- package/dist/utils/theme.d.ts +77 -0
- package/dist/utils/theme.js +55 -0
- package/package.json +67 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# React Native Standalone Chat
|
|
2
|
+
|
|
3
|
+
A customizable chat UI component for React Native with replies, reactions, media attachments, theming, and performance optimizations.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Replies and swipe-to-reply interactions
|
|
8
|
+
- Reactions with overlay UI
|
|
9
|
+
- Image, video, audio, and generic file attachments
|
|
10
|
+
- Load earlier messages header
|
|
11
|
+
- Theming via theme prop override
|
|
12
|
+
- FlashList-backed message rendering
|
|
13
|
+
- TypeScript types included
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Install the package and required peers:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @codewithvincent/react-native-love-chat
|
|
21
|
+
# or
|
|
22
|
+
yarn add @codewithvincent/react-native-love-chat
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Peer dependencies (install as needed):
|
|
26
|
+
|
|
27
|
+
- react
|
|
28
|
+
- react-native
|
|
29
|
+
- react-native-gesture-handler
|
|
30
|
+
- react-native-reanimated
|
|
31
|
+
- react-native-safe-area-context
|
|
32
|
+
- react-native-root-siblings
|
|
33
|
+
- @shopify/flash-list
|
|
34
|
+
- react-native-svg
|
|
35
|
+
- Optional blur providers: @react-native-community/blur or expo-blur
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import React, { useState, useCallback, useEffect } from 'react';
|
|
41
|
+
import { Chat, IMessage } from '@codewithvincent/react-native-love-chat';
|
|
42
|
+
|
|
43
|
+
export default function ChatScreen() {
|
|
44
|
+
const [messages, setMessages] = useState<IMessage[]>([]);
|
|
45
|
+
const user = { _id: 1, name: 'Developer' };
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
setMessages([
|
|
49
|
+
{
|
|
50
|
+
_id: 1,
|
|
51
|
+
text: 'Hello developer',
|
|
52
|
+
createdAt: new Date(),
|
|
53
|
+
user: {
|
|
54
|
+
_id: 2,
|
|
55
|
+
name: 'React Native',
|
|
56
|
+
avatar: 'https://placeimg.com/140/140/any',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
]);
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
const onSend = useCallback((newMessages: IMessage[] = []) => {
|
|
63
|
+
setMessages((previousMessages) => [...newMessages, ...previousMessages]);
|
|
64
|
+
}, []);
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Chat messages={messages} onSend={onSend} user={user} placeholder="Type your message here..." />
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## API Reference
|
|
73
|
+
|
|
74
|
+
### Essential Props
|
|
75
|
+
|
|
76
|
+
- messages: IMessage[] — array of messages (newest first if inverted)
|
|
77
|
+
- user: IUser — current user object
|
|
78
|
+
- onSend: (messages: IMessage[]) => void — send handler
|
|
79
|
+
- placeholder?: string
|
|
80
|
+
- isTyping?: boolean
|
|
81
|
+
- loadEarlier?: boolean
|
|
82
|
+
- isLoadingEarlier?: boolean
|
|
83
|
+
- onLoadEarlier?: () => void
|
|
84
|
+
- onPressAttachment?: (type: string) => void
|
|
85
|
+
- onReaction?: (msg: IMessage, emoji: string) => void
|
|
86
|
+
- onDeleteMessage?: (msg: IMessage) => void
|
|
87
|
+
- onDownloadFile?: (msg: IMessage) => void
|
|
88
|
+
- renderUploadFooter?: (props) => ReactNode
|
|
89
|
+
- theme?: PartialTheme — to override default theme colors
|
|
90
|
+
|
|
91
|
+
## Data Structures
|
|
92
|
+
|
|
93
|
+
### IMessage
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
interface IMessage {
|
|
97
|
+
_id: string | number;
|
|
98
|
+
text: string;
|
|
99
|
+
createdAt: Date | number;
|
|
100
|
+
user: IUser;
|
|
101
|
+
image?: string;
|
|
102
|
+
video?: string;
|
|
103
|
+
audio?: string;
|
|
104
|
+
system?: boolean;
|
|
105
|
+
sent?: boolean;
|
|
106
|
+
received?: boolean;
|
|
107
|
+
pending?: boolean;
|
|
108
|
+
// ... custom fields
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### IUser
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
interface IUser {
|
|
116
|
+
_id: string | number;
|
|
117
|
+
name?: string;
|
|
118
|
+
avatar?: string | number;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Theming
|
|
123
|
+
|
|
124
|
+
Override with the `theme` prop. Example:
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
<Chat
|
|
128
|
+
messages={messages}
|
|
129
|
+
user={user}
|
|
130
|
+
onSend={onSend}
|
|
131
|
+
theme={{
|
|
132
|
+
colors: {
|
|
133
|
+
primary: '#4fd1a5',
|
|
134
|
+
darkRed: '#ff5757',
|
|
135
|
+
},
|
|
136
|
+
}}
|
|
137
|
+
/>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Examples
|
|
141
|
+
|
|
142
|
+
See the `examples` folder for complete usage samples.
|
|
143
|
+
|
|
144
|
+
## Contributing
|
|
145
|
+
|
|
146
|
+
- Fork the repo and create a feature branch
|
|
147
|
+
- Run tests and build before submitting a PR
|
|
148
|
+
- Follow semantic commit messages
|
|
149
|
+
|
|
150
|
+
## License
|
|
151
|
+
|
|
152
|
+
MIT © Contributors
|
package/dist/Chat.d.ts
ADDED
package/dist/Chat.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
const react_native_1 = require("react-native");
|
|
9
|
+
const MessageList_1 = __importDefault(require("./components/MessageList"));
|
|
10
|
+
const InputToolbar_1 = __importDefault(require("./components/InputToolbar"));
|
|
11
|
+
const theme_1 = require("./utils/theme");
|
|
12
|
+
const InnerChat = (props) => {
|
|
13
|
+
const theme = (0, theme_1.useTheme)();
|
|
14
|
+
const { messages = [], text: propText, onInputTextChanged, onSend, renderInputToolbar, renderChatFooter, containerStyle, keyboardShouldPersistTaps = 'never', onPressAttachment, onReply, onClearReply, renderUploadFooter, onDeleteMessage, onDownloadFile, } = props;
|
|
15
|
+
const [text, setText] = (0, react_1.useState)(propText || '');
|
|
16
|
+
const [replyMessage, setReplyMessage] = (0, react_1.useState)(null);
|
|
17
|
+
(0, react_1.useEffect)(() => {
|
|
18
|
+
if (propText !== undefined && propText !== text) {
|
|
19
|
+
setText(propText);
|
|
20
|
+
}
|
|
21
|
+
}, [propText]);
|
|
22
|
+
const handleInputTextChanged = (newText) => {
|
|
23
|
+
setText(newText);
|
|
24
|
+
if (onInputTextChanged) {
|
|
25
|
+
onInputTextChanged(newText);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const handleSend = (newMessages) => {
|
|
29
|
+
if (Array.isArray(newMessages)) {
|
|
30
|
+
onSend(newMessages);
|
|
31
|
+
}
|
|
32
|
+
setText('');
|
|
33
|
+
if (onInputTextChanged) {
|
|
34
|
+
onInputTextChanged('');
|
|
35
|
+
}
|
|
36
|
+
setReplyMessage(null);
|
|
37
|
+
};
|
|
38
|
+
const handleReply = (message) => {
|
|
39
|
+
setReplyMessage(message);
|
|
40
|
+
onReply === null || onReply === void 0 ? void 0 : onReply(message);
|
|
41
|
+
};
|
|
42
|
+
const handleClearReply = () => {
|
|
43
|
+
setReplyMessage(null);
|
|
44
|
+
onClearReply === null || onClearReply === void 0 ? void 0 : onClearReply();
|
|
45
|
+
};
|
|
46
|
+
const renderInput = () => {
|
|
47
|
+
const inputProps = {
|
|
48
|
+
...props,
|
|
49
|
+
text,
|
|
50
|
+
onTextChanged: handleInputTextChanged,
|
|
51
|
+
onSend: handleSend,
|
|
52
|
+
onPressAttachment,
|
|
53
|
+
replyMessage,
|
|
54
|
+
onClearReply: handleClearReply,
|
|
55
|
+
renderUploadFooter,
|
|
56
|
+
};
|
|
57
|
+
if (renderInputToolbar) {
|
|
58
|
+
return renderInputToolbar(inputProps);
|
|
59
|
+
}
|
|
60
|
+
return ((0, jsx_runtime_1.jsx)(InputToolbar_1.default, { ...inputProps }));
|
|
61
|
+
};
|
|
62
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.SafeAreaView, { style: [styles.container, { backgroundColor: theme.colors.white }, containerStyle], children: (0, jsx_runtime_1.jsx)(react_native_1.KeyboardAvoidingView, { style: styles.keyboardAvoidingView, behavior: react_native_1.Platform.OS === 'ios' ? 'padding' : undefined, keyboardVerticalOffset: react_native_1.Platform.OS === 'ios' ? 0 : 0, children: (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.contentContainer, children: [(0, jsx_runtime_1.jsx)(MessageList_1.default, { ...props, messages: messages, keyboardShouldPersistTaps: keyboardShouldPersistTaps, onReply: handleReply }), renderChatFooter === null || renderChatFooter === void 0 ? void 0 : renderChatFooter(), renderInput()] }) }) }));
|
|
63
|
+
};
|
|
64
|
+
const Chat = (props) => ((0, jsx_runtime_1.jsx)(theme_1.ThemeProvider, { theme: props.theme, children: (0, jsx_runtime_1.jsx)(InnerChat, { ...props }) }));
|
|
65
|
+
const styles = react_native_1.StyleSheet.create({
|
|
66
|
+
container: {
|
|
67
|
+
flex: 1,
|
|
68
|
+
backgroundColor: theme_1.defaultTheme.colors.white,
|
|
69
|
+
},
|
|
70
|
+
keyboardAvoidingView: {
|
|
71
|
+
flex: 1,
|
|
72
|
+
},
|
|
73
|
+
contentContainer: {
|
|
74
|
+
flex: 1,
|
|
75
|
+
overflow: 'hidden',
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
exports.default = Chat;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ViewStyle } from 'react-native';
|
|
3
|
+
interface ChatBubbleProps {
|
|
4
|
+
isOwnMessage: boolean;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
bubbleColor?: string;
|
|
7
|
+
tailColor?: string;
|
|
8
|
+
withTail?: boolean;
|
|
9
|
+
style?: ViewStyle;
|
|
10
|
+
onPress?: () => void;
|
|
11
|
+
hitSlop?: number | {
|
|
12
|
+
top: number;
|
|
13
|
+
bottom: number;
|
|
14
|
+
left: number;
|
|
15
|
+
right: number;
|
|
16
|
+
};
|
|
17
|
+
maxWidth?: number;
|
|
18
|
+
isMedia?: boolean;
|
|
19
|
+
}
|
|
20
|
+
declare const ChatBubble: React.FC<ChatBubbleProps>;
|
|
21
|
+
export default ChatBubble;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
|
+
const react_native_1 = require("react-native");
|
|
5
|
+
const react_native_svg_1 = require("react-native-svg");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
const theme_1 = require("../utils/theme");
|
|
8
|
+
const ChatBubble = ({ isOwnMessage, children, bubbleColor, tailColor, withTail = true, style, onPress, hitSlop, maxWidth, isMedia, ...rest }) => {
|
|
9
|
+
const theme = (0, theme_1.useTheme)();
|
|
10
|
+
const effectiveBubbleColor = bubbleColor || (isOwnMessage ? theme.colors.ownMessageBubble : theme.colors.otherMessageBubble);
|
|
11
|
+
const tailFillColor = tailColor || effectiveBubbleColor;
|
|
12
|
+
const styles = getStyleObj({ isOwnMessage, maxWidth, isMedia });
|
|
13
|
+
const SvgContainerStyle = isOwnMessage
|
|
14
|
+
? styles.svgContainerOwn
|
|
15
|
+
: styles.svgContainerOther;
|
|
16
|
+
const Container = onPress ? react_native_1.Pressable : react_native_1.View;
|
|
17
|
+
const tailPath = isOwnMessage
|
|
18
|
+
? 'M48,35c-7-4-6-8.75-6-17.5C28,17.5,29,35,48,35z'
|
|
19
|
+
: 'M38.484,17.5c0,8.75,1,13.5-6,17.5C51.484,35,52.484,17.5,38.484,17.5z';
|
|
20
|
+
const bubbleStyle = {
|
|
21
|
+
...styles.bubble,
|
|
22
|
+
...style,
|
|
23
|
+
backgroundColor: effectiveBubbleColor,
|
|
24
|
+
};
|
|
25
|
+
return ((0, jsx_runtime_1.jsxs)(Container, { ...rest, hitSlop: hitSlop, onPress: onPress, children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: bubbleStyle, children: children }), withTail && ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.svgContainer, SvgContainerStyle], children: (0, jsx_runtime_1.jsx)(react_native_svg_1.Svg, { width: utils_1.appSize.width(4.5), height: utils_1.appSize.height(2.5), viewBox: "32.485 17.5 15.515 17.5", children: (0, jsx_runtime_1.jsx)(react_native_svg_1.Path, { d: tailPath, fill: tailFillColor }) }) }))] }));
|
|
26
|
+
};
|
|
27
|
+
exports.default = ChatBubble;
|
|
28
|
+
const getStyleObj = ({ isOwnMessage, maxWidth, isMedia, }) => ({
|
|
29
|
+
bubble: {
|
|
30
|
+
maxWidth: maxWidth || utils_1.appSize.width(80),
|
|
31
|
+
alignSelf: isOwnMessage ? 'flex-end' : 'flex-start',
|
|
32
|
+
paddingHorizontal: isMedia ? 0 : utils_1.appSize.width(3),
|
|
33
|
+
paddingTop: isMedia ? 0 : utils_1.appSize.height(0.5),
|
|
34
|
+
paddingBottom: isMedia ? 0 : utils_1.appSize.height(0.8),
|
|
35
|
+
borderRadius: utils_1.appSize.width(2),
|
|
36
|
+
marginVertical: utils_1.appSize.height(0.5),
|
|
37
|
+
},
|
|
38
|
+
svgContainer: {
|
|
39
|
+
position: 'absolute',
|
|
40
|
+
top: 0,
|
|
41
|
+
left: 0,
|
|
42
|
+
right: 0,
|
|
43
|
+
bottom: 0,
|
|
44
|
+
zIndex: -1,
|
|
45
|
+
flex: 1,
|
|
46
|
+
},
|
|
47
|
+
svgContainerOwn: {
|
|
48
|
+
justifyContent: 'flex-end',
|
|
49
|
+
alignItems: 'flex-end',
|
|
50
|
+
},
|
|
51
|
+
svgContainerOther: {
|
|
52
|
+
justifyContent: 'flex-end',
|
|
53
|
+
alignItems: 'flex-start',
|
|
54
|
+
},
|
|
55
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface ComposerProps {
|
|
2
|
+
text?: string;
|
|
3
|
+
placeholder?: string;
|
|
4
|
+
placeholderTextColor?: string;
|
|
5
|
+
textInputProps?: any;
|
|
6
|
+
onTextChanged?: (text: string) => void;
|
|
7
|
+
onSend?: () => void;
|
|
8
|
+
textInputStyle?: any;
|
|
9
|
+
multiline?: boolean;
|
|
10
|
+
maxComposerHeight?: number;
|
|
11
|
+
minComposerHeight?: number;
|
|
12
|
+
}
|
|
13
|
+
declare const Composer: (props: ComposerProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export default Composer;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const react_native_1 = require("react-native");
|
|
6
|
+
const theme_1 = require("../utils/theme");
|
|
7
|
+
const Composer = (props) => {
|
|
8
|
+
const theme = (0, theme_1.useTheme)();
|
|
9
|
+
const { text = '', placeholder = 'Type a message...', placeholderTextColor = theme.colors.gray, textInputProps, onTextChanged, textInputStyle, multiline = true, maxComposerHeight = 100, minComposerHeight = 40, } = props;
|
|
10
|
+
const [composerHeight, setComposerHeight] = (0, react_1.useState)(minComposerHeight);
|
|
11
|
+
const handleContentSizeChange = (e) => {
|
|
12
|
+
const contentSize = e.nativeEvent.contentSize;
|
|
13
|
+
if (!contentSize)
|
|
14
|
+
return;
|
|
15
|
+
if (!composerHeight ||
|
|
16
|
+
(composerHeight && composerHeight < maxComposerHeight) ||
|
|
17
|
+
(composerHeight === maxComposerHeight && contentSize.height < maxComposerHeight)) {
|
|
18
|
+
setComposerHeight(Math.max(minComposerHeight, Math.min(maxComposerHeight, contentSize.height)));
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.TextInput, { testID: placeholder, accessible: true, accessibilityLabel: placeholder, placeholder: placeholder, placeholderTextColor: placeholderTextColor, multiline: multiline, onChangeText: onTextChanged, onContentSizeChange: handleContentSizeChange, style: [
|
|
22
|
+
styles.textInput,
|
|
23
|
+
{ color: theme.colors.black, backgroundColor: theme.colors.primary },
|
|
24
|
+
textInputStyle,
|
|
25
|
+
{
|
|
26
|
+
height: composerHeight,
|
|
27
|
+
},
|
|
28
|
+
], autoFocus: false, value: text, enablesReturnKeyAutomatically: true, underlineColorAndroid: "transparent", blurOnSubmit: false, ...textInputProps }));
|
|
29
|
+
};
|
|
30
|
+
const styles = react_native_1.StyleSheet.create({
|
|
31
|
+
textInput: {
|
|
32
|
+
flex: 1,
|
|
33
|
+
fontSize: 16,
|
|
34
|
+
lineHeight: 22,
|
|
35
|
+
color: theme_1.defaultTheme.colors.black,
|
|
36
|
+
backgroundColor: theme_1.defaultTheme.colors.primary,
|
|
37
|
+
borderRadius: 20,
|
|
38
|
+
paddingHorizontal: 12,
|
|
39
|
+
paddingTop: react_native_1.Platform.OS === 'ios' ? 8 : 4,
|
|
40
|
+
paddingBottom: react_native_1.Platform.OS === 'ios' ? 8 : 4,
|
|
41
|
+
marginHorizontal: 8,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
exports.default = Composer;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface FooterReplyPreviewProps {
|
|
2
|
+
chatMessage: any;
|
|
3
|
+
clearReply?: () => void;
|
|
4
|
+
userId: string;
|
|
5
|
+
}
|
|
6
|
+
declare const FooterReplyPreview: ({ chatMessage, clearReply, userId }: FooterReplyPreviewProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default FooterReplyPreview;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
|
+
const react_native_1 = require("react-native");
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const theme_1 = require("../utils/theme");
|
|
7
|
+
const Icons_1 = require("./Icons");
|
|
8
|
+
const FooterReplyPreview = ({ chatMessage, clearReply, userId }) => {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
console.log('chatMessage', chatMessage);
|
|
11
|
+
const theme = (0, theme_1.useTheme)();
|
|
12
|
+
if (!chatMessage)
|
|
13
|
+
return null;
|
|
14
|
+
const isMine = ((_a = chatMessage.user) === null || _a === void 0 ? void 0 : _a._id) === userId;
|
|
15
|
+
const senderName = isMine ? 'You' : ((_b = chatMessage.user) === null || _b === void 0 ? void 0 : _b.name) || 'Unknown';
|
|
16
|
+
const getFileNameFromUrl = (url) => {
|
|
17
|
+
if (!url)
|
|
18
|
+
return undefined;
|
|
19
|
+
try {
|
|
20
|
+
const clean = url.split('?')[0];
|
|
21
|
+
const parts = clean.split('/');
|
|
22
|
+
const last = parts[parts.length - 1];
|
|
23
|
+
return last || undefined;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const getExtension = (name) => {
|
|
30
|
+
if (!name)
|
|
31
|
+
return undefined;
|
|
32
|
+
const ext = name.split('.').pop();
|
|
33
|
+
return ext ? ext.toLowerCase() : undefined;
|
|
34
|
+
};
|
|
35
|
+
const computedFileName = chatMessage.fileName || getFileNameFromUrl(chatMessage.fileUrl);
|
|
36
|
+
const extension = getExtension(computedFileName);
|
|
37
|
+
const isAudioByExt = extension ? ['mp3', 'wav', 'm4a', 'aac', 'ogg'].includes(extension) : false;
|
|
38
|
+
const rawFileType = typeof chatMessage.fileType === 'string'
|
|
39
|
+
? chatMessage.fileType.toLowerCase()
|
|
40
|
+
: chatMessage.fileType;
|
|
41
|
+
const fileType = rawFileType ||
|
|
42
|
+
(chatMessage.image
|
|
43
|
+
? 'image'
|
|
44
|
+
: chatMessage.video
|
|
45
|
+
? 'video'
|
|
46
|
+
: chatMessage.audio
|
|
47
|
+
? 'audio'
|
|
48
|
+
: computedFileName
|
|
49
|
+
? isAudioByExt
|
|
50
|
+
? 'audio'
|
|
51
|
+
: 'file'
|
|
52
|
+
: null);
|
|
53
|
+
const renderContent = () => {
|
|
54
|
+
switch (fileType) {
|
|
55
|
+
case 'image':
|
|
56
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.Image, { source: { uri: chatMessage.image || chatMessage.fileUrl }, style: styles.replyImage, resizeMode: "cover" }));
|
|
57
|
+
case 'video':
|
|
58
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.View, { style: styles.replyMediaContainer, children: (0, jsx_runtime_1.jsx)(Icons_1.VideoIcon, { size: 20, color: theme.colors.darkBrown }) }));
|
|
59
|
+
case 'audio':
|
|
60
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.replyFileContainer, children: [(0, jsx_runtime_1.jsx)(Icons_1.AudioIcon, { size: 18, color: theme.colors.darkBrown }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { numberOfLines: 1, style: [styles.replyFileName, { color: theme.colors.darkBrown }], children: computedFileName || 'Audio' })] }));
|
|
61
|
+
case 'file':
|
|
62
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.replyFileContainer, children: [(0, jsx_runtime_1.jsx)(Icons_1.FileIcon, { size: 18, color: theme.colors.darkBrown }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { numberOfLines: 1, style: [styles.replyFileName, { color: theme.colors.darkBrown }], children: computedFileName || (extension ? extension.toUpperCase() : 'File') })] }));
|
|
63
|
+
default:
|
|
64
|
+
if (computedFileName) {
|
|
65
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.replyFileContainer, children: [isAudioByExt ? ((0, jsx_runtime_1.jsx)(Icons_1.AudioIcon, { size: 18, color: theme.colors.darkBrown })) : ((0, jsx_runtime_1.jsx)(Icons_1.FileIcon, { size: 18, color: theme.colors.darkBrown })), (0, jsx_runtime_1.jsx)(react_native_1.Text, { numberOfLines: 1, style: [styles.replyFileName, { color: theme.colors.darkBrown }], children: computedFileName })] }));
|
|
66
|
+
}
|
|
67
|
+
return ((0, jsx_runtime_1.jsx)(react_native_1.Text, { numberOfLines: 1, style: [styles.replySnippet, { color: theme.colors.darkBrown }], children: chatMessage.text || chatMessage.caption || '' }));
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
|
|
71
|
+
styles.replyPreviewContainer,
|
|
72
|
+
{ backgroundColor: theme.colors.softRed, borderLeftColor: theme.colors.primary },
|
|
73
|
+
], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.replyLine, { backgroundColor: theme.colors.primary }] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: styles.repContainer, children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { style: { flex: 1 }, children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [styles.replyTitle, { color: theme.colors.darkBrown }], children: senderName }), renderContent()] }), clearReply && ((0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { onPress: clearReply, children: (0, jsx_runtime_1.jsx)(Icons_1.XCircleIcon, { size: 16, color: theme.colors.darkRed }) }))] })] }));
|
|
74
|
+
};
|
|
75
|
+
const styles = react_native_1.StyleSheet.create({
|
|
76
|
+
replyPreviewContainer: {
|
|
77
|
+
flexDirection: 'row',
|
|
78
|
+
alignItems: 'center',
|
|
79
|
+
backgroundColor: theme_1.defaultTheme.colors.softRed,
|
|
80
|
+
padding: 10,
|
|
81
|
+
borderLeftWidth: 4,
|
|
82
|
+
borderLeftColor: theme_1.defaultTheme.colors.primary,
|
|
83
|
+
borderBottomWidth: 0.3,
|
|
84
|
+
borderBottomColor: '#ddd',
|
|
85
|
+
},
|
|
86
|
+
replyLine: {
|
|
87
|
+
width: 4,
|
|
88
|
+
height: '100%',
|
|
89
|
+
backgroundColor: theme_1.defaultTheme.colors.primary,
|
|
90
|
+
marginRight: 8,
|
|
91
|
+
},
|
|
92
|
+
repContainer: {
|
|
93
|
+
flex: 1,
|
|
94
|
+
flexDirection: 'row',
|
|
95
|
+
justifyContent: 'space-between',
|
|
96
|
+
alignItems: 'center',
|
|
97
|
+
},
|
|
98
|
+
replyTitle: {
|
|
99
|
+
fontSize: utils_1.appSize.font(11),
|
|
100
|
+
fontWeight: '600',
|
|
101
|
+
color: theme_1.defaultTheme.colors.darkBrown,
|
|
102
|
+
},
|
|
103
|
+
replySnippet: {
|
|
104
|
+
fontSize: utils_1.appSize.font(13.5),
|
|
105
|
+
color: theme_1.defaultTheme.colors.darkBrown,
|
|
106
|
+
marginTop: 2,
|
|
107
|
+
},
|
|
108
|
+
replyImage: {
|
|
109
|
+
width: 40,
|
|
110
|
+
height: 40,
|
|
111
|
+
borderRadius: 4,
|
|
112
|
+
},
|
|
113
|
+
replyMediaContainer: {
|
|
114
|
+
width: 40,
|
|
115
|
+
height: 40,
|
|
116
|
+
justifyContent: 'center',
|
|
117
|
+
alignItems: 'center',
|
|
118
|
+
backgroundColor: '#eee',
|
|
119
|
+
borderRadius: 4,
|
|
120
|
+
},
|
|
121
|
+
replyFileContainer: {
|
|
122
|
+
flexDirection: 'row',
|
|
123
|
+
alignItems: 'center',
|
|
124
|
+
},
|
|
125
|
+
replyFileName: {
|
|
126
|
+
marginLeft: 6,
|
|
127
|
+
color: theme_1.defaultTheme.colors.darkBrown,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
exports.default = FooterReplyPreview;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface IconProps {
|
|
2
|
+
color?: string;
|
|
3
|
+
size?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare const PlusIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare const SendIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare const MicIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare const CloseIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare const PlayIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare const PauseIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare const FileIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare const ImageIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare const VideoIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare const AudioIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare const ChevronRightIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
export declare const LockIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export declare const XCircleIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
export declare const ReplyIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export declare const TrashIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export declare const DownloadIcon: ({ color, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DownloadIcon = exports.TrashIcon = exports.ReplyIcon = exports.XCircleIcon = exports.LockIcon = exports.ChevronRightIcon = exports.AudioIcon = exports.VideoIcon = exports.ImageIcon = exports.FileIcon = exports.PauseIcon = exports.PlayIcon = exports.CloseIcon = exports.MicIcon = exports.SendIcon = exports.PlusIcon = void 0;
|
|
37
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
|
+
const react_native_svg_1 = __importStar(require("react-native-svg"));
|
|
39
|
+
const theme_1 = require("../utils/theme");
|
|
40
|
+
const PlusIcon = ({ color = theme_1.defaultTheme.colors.darkRed, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Line, { x1: "12", y1: "5", x2: "12", y2: "19" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Line, { x1: "5", y1: "12", x2: "19", y2: "12" })] }));
|
|
41
|
+
exports.PlusIcon = PlusIcon;
|
|
42
|
+
const SendIcon = ({ color = theme_1.defaultTheme.colors.white, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Line, { x1: "22", y1: "2", x2: "11", y2: "13" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Polygon, { points: "22 2 15 22 11 13 2 9 22 2" })] }));
|
|
43
|
+
exports.SendIcon = SendIcon;
|
|
44
|
+
const MicIcon = ({ color = theme_1.defaultTheme.colors.darkRed, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Path, { d: "M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Path, { d: "M19 10v2a7 7 0 0 1-14 0v-2" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Line, { x1: "12", y1: "19", x2: "12", y2: "23" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Line, { x1: "8", y1: "23", x2: "16", y2: "23" })] }));
|
|
45
|
+
exports.MicIcon = MicIcon;
|
|
46
|
+
const CloseIcon = ({ color = theme_1.defaultTheme.colors.gray, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Line, { x1: "18", y1: "6", x2: "6", y2: "18" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Line, { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
|
|
47
|
+
exports.CloseIcon = CloseIcon;
|
|
48
|
+
const PlayIcon = ({ color = theme_1.defaultTheme.colors.white, size = 24 }) => ((0, jsx_runtime_1.jsx)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)(react_native_svg_1.Polygon, { points: "5 3 19 12 5 21 5 3" }) }));
|
|
49
|
+
exports.PlayIcon = PlayIcon;
|
|
50
|
+
const PauseIcon = ({ color = theme_1.defaultTheme.colors.white, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Rect, { x: "6", y: "4", width: "4", height: "16" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Rect, { x: "14", y: "4", width: "4", height: "16" })] }));
|
|
51
|
+
exports.PauseIcon = PauseIcon;
|
|
52
|
+
const FileIcon = ({ color = theme_1.defaultTheme.colors.gray, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Path, { d: "M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Polyline, { points: "13 2 13 9 20 9" })] }));
|
|
53
|
+
exports.FileIcon = FileIcon;
|
|
54
|
+
const ImageIcon = ({ color = theme_1.defaultTheme.colors.gray, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Rect, { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Circle, { cx: "8.5", cy: "8.5", r: "1.5" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Polyline, { points: "21 15 16 10 5 21" })] }));
|
|
55
|
+
exports.ImageIcon = ImageIcon;
|
|
56
|
+
const VideoIcon = ({ color = theme_1.defaultTheme.colors.gray, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Polygon, { points: "23 7 16 12 23 17 23 7" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Rect, { x: "1", y: "5", width: "15", height: "14", rx: "2", ry: "2" })] }));
|
|
57
|
+
exports.VideoIcon = VideoIcon;
|
|
58
|
+
const AudioIcon = ({ color = theme_1.defaultTheme.colors.gray, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Path, { d: "M9 18V5l12-2v13" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Circle, { cx: "6", cy: "18", r: "3" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Circle, { cx: "18", cy: "16", r: "3" })] }));
|
|
59
|
+
exports.AudioIcon = AudioIcon;
|
|
60
|
+
const ChevronRightIcon = ({ color = theme_1.defaultTheme.colors.gray, size = 24 }) => ((0, jsx_runtime_1.jsx)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)(react_native_svg_1.Polyline, { points: "9 18 15 12 9 6" }) }));
|
|
61
|
+
exports.ChevronRightIcon = ChevronRightIcon;
|
|
62
|
+
const LockIcon = ({ color = theme_1.defaultTheme.colors.white, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Rect, { x: "3", y: "11", width: "18", height: "11", rx: "2", ry: "2" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Path, { d: "M7 11V7a5 5 0 0 1 10 0v4" })] }));
|
|
63
|
+
exports.LockIcon = LockIcon;
|
|
64
|
+
const XCircleIcon = ({ color = theme_1.defaultTheme.colors.darkRed, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Circle, { cx: "12", cy: "12", r: "10" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Line, { x1: "15", y1: "9", x2: "9", y2: "15" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Line, { x1: "9", y1: "9", x2: "15", y2: "15" })] }));
|
|
65
|
+
exports.XCircleIcon = XCircleIcon;
|
|
66
|
+
const ReplyIcon = ({ color = theme_1.defaultTheme.colors.white, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Polyline, { points: "9 10 4 15 9 20" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Path, { d: "M20 4v7a4 4 0 0 1-4 4H4" })] }));
|
|
67
|
+
exports.ReplyIcon = ReplyIcon;
|
|
68
|
+
const TrashIcon = ({ color = theme_1.defaultTheme.colors.darkRed, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Polyline, { points: "3 6 5 6 21 6" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Path, { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })] }));
|
|
69
|
+
exports.TrashIcon = TrashIcon;
|
|
70
|
+
const DownloadIcon = ({ color = theme_1.defaultTheme.colors.white, size = 24 }) => ((0, jsx_runtime_1.jsxs)(react_native_svg_1.default, { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)(react_native_svg_1.Path, { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Polyline, { points: "7 10 12 15 17 10" }), (0, jsx_runtime_1.jsx)(react_native_svg_1.Line, { x1: "12", y1: "15", x2: "12", y2: "3" })] }));
|
|
71
|
+
exports.DownloadIcon = DownloadIcon;
|