@usechat/react-native 1.0.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/LICENSE +117 -0
- package/README.md +317 -0
- package/dist/clipboard-LTWXJADM.mjs +64 -0
- package/dist/index.d.mts +967 -0
- package/dist/index.d.ts +967 -0
- package/dist/index.js +5395 -0
- package/dist/index.mjs +5288 -0
- package/package.json +111 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
UseChat SDK License Agreement
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Lukasz Ko and UseChat Team. All rights reserved.
|
|
4
|
+
|
|
5
|
+
USECHAT SDK LICENSE AGREEMENT
|
|
6
|
+
|
|
7
|
+
This License Agreement ("Agreement") governs your use of the UseChat SDK ("Software"),
|
|
8
|
+
a React Native chat UI SDK developed by Lukasz Ko and the UseChat Team ("Licensor").
|
|
9
|
+
|
|
10
|
+
BY USING, INSTALLING, OR ACCESSING THE SOFTWARE, YOU AGREE TO BE BOUND BY THE TERMS
|
|
11
|
+
OF THIS AGREEMENT. IF YOU DO NOT AGREE TO THESE TERMS, DO NOT USE THE SOFTWARE.
|
|
12
|
+
|
|
13
|
+
1. GRANT OF LICENSE
|
|
14
|
+
|
|
15
|
+
Subject to the terms and conditions of this Agreement, Licensor hereby grants you a
|
|
16
|
+
limited, non-exclusive, non-transferable license to use the Software under the
|
|
17
|
+
following terms:
|
|
18
|
+
|
|
19
|
+
a) PERSONAL AND EDUCATIONAL USE: You may use the Software for personal projects,
|
|
20
|
+
educational purposes, and non-commercial applications at no cost.
|
|
21
|
+
|
|
22
|
+
b) COMMERCIAL USE: For commercial applications, you must obtain a commercial license
|
|
23
|
+
by contacting the Licensor. Commercial use includes but is not limited to:
|
|
24
|
+
- Applications that generate revenue
|
|
25
|
+
- Applications used by businesses or organizations
|
|
26
|
+
- Applications with more than 1,000 monthly active users
|
|
27
|
+
- Applications that compete directly with UseChat services
|
|
28
|
+
|
|
29
|
+
c) OPEN SOURCE PROJECTS: You may use the Software in open source projects that are
|
|
30
|
+
licensed under OSI-approved licenses, provided proper attribution is given.
|
|
31
|
+
|
|
32
|
+
2. ATTRIBUTION REQUIREMENTS
|
|
33
|
+
|
|
34
|
+
When using the Software, you must:
|
|
35
|
+
- Include proper attribution to "UseChat SDK by Lukasz Ko" in your application
|
|
36
|
+
- Retain all copyright notices and license information
|
|
37
|
+
- Include a link to the official UseChat website or repository where feasible
|
|
38
|
+
|
|
39
|
+
3. RESTRICTIONS
|
|
40
|
+
|
|
41
|
+
You may NOT:
|
|
42
|
+
- Remove or alter any copyright, trademark, or other proprietary notices
|
|
43
|
+
- Reverse engineer, decompile, or disassemble the Software
|
|
44
|
+
- Redistribute the Software as a standalone product
|
|
45
|
+
- Use the Software to create competing chat SDK products
|
|
46
|
+
- Use the Software in applications that violate laws or regulations
|
|
47
|
+
- Use the Software for harmful, malicious, or illegal purposes
|
|
48
|
+
|
|
49
|
+
4. COMMERCIAL LICENSE TERMS
|
|
50
|
+
|
|
51
|
+
Commercial licenses are available with the following benefits:
|
|
52
|
+
- Removal of attribution requirements
|
|
53
|
+
- Priority support and updates
|
|
54
|
+
- Custom feature development
|
|
55
|
+
- White-label usage rights
|
|
56
|
+
- Extended warranty and liability coverage
|
|
57
|
+
|
|
58
|
+
Contact: hello@usechat.dev for commercial licensing inquiries.
|
|
59
|
+
|
|
60
|
+
5. INTELLECTUAL PROPERTY
|
|
61
|
+
|
|
62
|
+
The Software and all intellectual property rights therein are and shall remain the
|
|
63
|
+
exclusive property of the Licensor. This Agreement does not grant you any ownership
|
|
64
|
+
rights in the Software.
|
|
65
|
+
|
|
66
|
+
6. UPDATES AND MODIFICATIONS
|
|
67
|
+
|
|
68
|
+
Licensor may update or modify the Software at any time. Updates will be governed by
|
|
69
|
+
this Agreement unless accompanied by a new license agreement.
|
|
70
|
+
|
|
71
|
+
7. SUPPORT AND MAINTENANCE
|
|
72
|
+
|
|
73
|
+
This license does not entitle you to support or maintenance services. Commercial
|
|
74
|
+
license holders may receive support as specified in their commercial agreement.
|
|
75
|
+
|
|
76
|
+
8. WARRANTY DISCLAIMER
|
|
77
|
+
|
|
78
|
+
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
79
|
+
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
80
|
+
PARTICULAR PURPOSE, AND NON-INFRINGEMENT. IN NO EVENT SHALL THE LICENSOR BE LIABLE
|
|
81
|
+
FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM THE USE OF THE SOFTWARE.
|
|
82
|
+
|
|
83
|
+
9. LIMITATION OF LIABILITY
|
|
84
|
+
|
|
85
|
+
IN NO EVENT SHALL THE LICENSOR BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
|
|
86
|
+
CONSEQUENTIAL, OR PUNITIVE DAMAGES, INCLUDING WITHOUT LIMITATION, LOSS OF PROFITS,
|
|
87
|
+
DATA, OR USE, ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT OR THE USE OF
|
|
88
|
+
THE SOFTWARE.
|
|
89
|
+
|
|
90
|
+
10. TERMINATION
|
|
91
|
+
|
|
92
|
+
This Agreement is effective until terminated. Your rights under this Agreement will
|
|
93
|
+
terminate automatically if you fail to comply with any terms. Upon termination, you
|
|
94
|
+
must cease all use of the Software and destroy all copies.
|
|
95
|
+
|
|
96
|
+
11. GOVERNING LAW
|
|
97
|
+
|
|
98
|
+
This Agreement shall be governed by and construed in accordance with the laws of
|
|
99
|
+
[Your Jurisdiction]. Any disputes shall be resolved in the courts of [Your Jurisdiction].
|
|
100
|
+
|
|
101
|
+
12. ENTIRE AGREEMENT
|
|
102
|
+
|
|
103
|
+
This Agreement constitutes the entire agreement between you and the Licensor regarding
|
|
104
|
+
the Software and supersedes all prior agreements and understandings.
|
|
105
|
+
|
|
106
|
+
13. CONTACT INFORMATION
|
|
107
|
+
|
|
108
|
+
For questions about this license or to request commercial licensing:
|
|
109
|
+
- Email: hello@usechat.dev
|
|
110
|
+
- Website: https://usechat.dev
|
|
111
|
+
- GitHub: https://github.com/usechat-dev
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
UseChat SDK - Professional React Native Chat Solution
|
|
116
|
+
Copyright (c) 2024 Lukasz Ko and UseChat Team
|
|
117
|
+
All rights reserved.
|
package/README.md
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# UseChat SDK - React Native Chat UI Library
|
|
2
|
+
|
|
3
|
+
A professional, customizable chat component library for React Native with a modern architecture that separates UI from logic.
|
|
4
|
+
|
|
5
|
+
> **Note:** UseChat SDK is licensed under a custom license. See [LICENSING.md](./LICENSING.md) for details. Free for personal/educational use, commercial license required for business applications.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Render Props Architecture**: Customize any part of the UI using render props
|
|
10
|
+
- **Standalone Hooks**: Use chat logic without UI components
|
|
11
|
+
- **Pluggable Attachment System**: Easy integration with your backend
|
|
12
|
+
- **TypeScript First**: Full type safety and IntelliSense support
|
|
13
|
+
- **Customizable Components**: Override any component with your own implementation
|
|
14
|
+
|
|
15
|
+
## Architecture Overview
|
|
16
|
+
|
|
17
|
+
The library follows a clean separation of concerns:
|
|
18
|
+
|
|
19
|
+
- **Components**: UI components that can be customized via render props
|
|
20
|
+
- **Hooks**: Logic-only hooks that can be used independently
|
|
21
|
+
- **Types**: Shared TypeScript interfaces
|
|
22
|
+
- **Plugins**: Optional attachment plugins for different file types
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### Basic Usage
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { Chat } from '@your-org/chat';
|
|
30
|
+
|
|
31
|
+
const MyChat = () => (
|
|
32
|
+
<Chat
|
|
33
|
+
chatName="My Chat"
|
|
34
|
+
onMessageSend={(message) => console.log('Message sent:', message)}
|
|
35
|
+
onBack={() => navigation.goBack()}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Using Render Props
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
<Chat
|
|
44
|
+
chatName="Custom Chat"
|
|
45
|
+
renderProps={{
|
|
46
|
+
renderMessage: (props) => <CustomMessage {...props} />,
|
|
47
|
+
renderInput: (props) => <CustomInput {...props} />,
|
|
48
|
+
renderHeader: (props) => <CustomHeader {...props} />,
|
|
49
|
+
}}
|
|
50
|
+
onMessageSend={handleMessageSend}
|
|
51
|
+
/>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Using Standalone Hooks
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
## Components
|
|
58
|
+
|
|
59
|
+
### Chat
|
|
60
|
+
|
|
61
|
+
The main chat component that orchestrates all functionality.
|
|
62
|
+
|
|
63
|
+
**Props:**
|
|
64
|
+
- `chatName`: Name displayed in the header
|
|
65
|
+
- `messages`: Array of messages to display
|
|
66
|
+
- `renderProps`: Object containing render functions for customization
|
|
67
|
+
- `components`: Object containing component overrides
|
|
68
|
+
- `attachmentUploader`: Function to handle file uploads
|
|
69
|
+
- `maxAttachments`: Maximum number of attachments per message
|
|
70
|
+
- `maxFileSize`: Maximum file size in bytes
|
|
71
|
+
- `allowedFileTypes`: Array of allowed MIME types
|
|
72
|
+
|
|
73
|
+
**Render Props:**
|
|
74
|
+
- `renderMessage`: Custom message rendering
|
|
75
|
+
- `renderInput`: Custom input component
|
|
76
|
+
- `renderHeader`: Custom header component
|
|
77
|
+
- `renderActionSheet`: Custom action sheet
|
|
78
|
+
- `renderReactionDetails`: Custom reaction details
|
|
79
|
+
|
|
80
|
+
### MessageList
|
|
81
|
+
|
|
82
|
+
Displays a list of messages with scrolling and typing indicators.
|
|
83
|
+
|
|
84
|
+
### MessageInput
|
|
85
|
+
|
|
86
|
+
Handles text input, attachments, and message sending.
|
|
87
|
+
|
|
88
|
+
### ChatScreenHeader
|
|
89
|
+
|
|
90
|
+
Displays chat information and action buttons.
|
|
91
|
+
|
|
92
|
+
### MessageActionSheet
|
|
93
|
+
|
|
94
|
+
Shows message actions (reply, copy, delete, reactions).
|
|
95
|
+
|
|
96
|
+
### ReactionDetailsSheet
|
|
97
|
+
|
|
98
|
+
Displays detailed reaction information.
|
|
99
|
+
|
|
100
|
+
## Hooks
|
|
101
|
+
|
|
102
|
+
### useAttachments
|
|
103
|
+
|
|
104
|
+
Manages attachment lifecycle and uploads.
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
const {
|
|
108
|
+
attachments,
|
|
109
|
+
openPicker,
|
|
110
|
+
addAttachment,
|
|
111
|
+
removeAttachment,
|
|
112
|
+
uploadAttachments,
|
|
113
|
+
isUploading,
|
|
114
|
+
} = useAttachments({
|
|
115
|
+
uploader: myUploader,
|
|
116
|
+
maxAttachments: 10,
|
|
117
|
+
maxFileSize: 10 * 1024 * 1024,
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### useTypingIndicator
|
|
122
|
+
|
|
123
|
+
Manages typing indicator state.
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
const {
|
|
127
|
+
isTyping,
|
|
128
|
+
startTyping,
|
|
129
|
+
stopTyping,
|
|
130
|
+
typingUsers,
|
|
131
|
+
} = useTypingIndicator({
|
|
132
|
+
typingTimeout: 3000,
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### useMessageList
|
|
137
|
+
|
|
138
|
+
Manages message list scrolling and interactions.
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
const {
|
|
142
|
+
messageListRef,
|
|
143
|
+
showScrollToBottomButton,
|
|
144
|
+
scrollToBottom,
|
|
145
|
+
handleScroll,
|
|
146
|
+
} = useMessageList({
|
|
147
|
+
messages,
|
|
148
|
+
onMessageLongPress,
|
|
149
|
+
onReactionPress,
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### useMessageInput
|
|
154
|
+
|
|
155
|
+
Manages message input state and validation.
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
const {
|
|
159
|
+
message,
|
|
160
|
+
composerHeight,
|
|
161
|
+
handleTextChange,
|
|
162
|
+
handleSend,
|
|
163
|
+
handleFocus,
|
|
164
|
+
} = useMessageInput({
|
|
165
|
+
onSend: handleMessageSend,
|
|
166
|
+
maxLength: 1000,
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Attachment System
|
|
171
|
+
|
|
172
|
+
The library provides a pluggable attachment system that supports:
|
|
173
|
+
|
|
174
|
+
- **Image Picker**: Select images from gallery or camera
|
|
175
|
+
- **Document Picker**: Select documents and files
|
|
176
|
+
- **Location Sharing**: Share current location
|
|
177
|
+
- **Contact Sharing**: Share contact information
|
|
178
|
+
|
|
179
|
+
### Custom Uploader
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
const myUploader: AttachmentUploader = {
|
|
183
|
+
upload: async (file) => {
|
|
184
|
+
const formData = new FormData();
|
|
185
|
+
formData.append('file', file);
|
|
186
|
+
|
|
187
|
+
const response = await fetch('/api/upload', {
|
|
188
|
+
method: 'POST',
|
|
189
|
+
body: formData,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const result = await response.json();
|
|
193
|
+
return {
|
|
194
|
+
url: result.url,
|
|
195
|
+
metadata: result.metadata,
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
validate: (file) => {
|
|
200
|
+
if (file.size > 10 * 1024 * 1024) {
|
|
201
|
+
return 'File too large';
|
|
202
|
+
}
|
|
203
|
+
return true;
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Customization Examples
|
|
209
|
+
|
|
210
|
+
### Custom Message Component
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
const CustomMessage = ({ message, onLongPress, onReactionPress }) => (
|
|
214
|
+
<View style={styles.message}>
|
|
215
|
+
<Text style={styles.text}>{message.text}</Text>
|
|
216
|
+
<Text style={styles.time}>
|
|
217
|
+
{new Date(message.timestamp).toLocaleTimeString()}
|
|
218
|
+
</Text>
|
|
219
|
+
{message.reactions?.map((reaction, index) => (
|
|
220
|
+
<TouchableOpacity
|
|
221
|
+
key={index}
|
|
222
|
+
onPress={() => onReactionPress(message)}
|
|
223
|
+
>
|
|
224
|
+
<Text>{reaction.emoji} {reaction.count}</Text>
|
|
225
|
+
</TouchableOpacity>
|
|
226
|
+
))}
|
|
227
|
+
</View>
|
|
228
|
+
);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Custom Input Component
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
const CustomInput = ({
|
|
235
|
+
value,
|
|
236
|
+
onChangeText,
|
|
237
|
+
onSend,
|
|
238
|
+
attachments,
|
|
239
|
+
onAttachmentAdd,
|
|
240
|
+
onAttachmentRemove
|
|
241
|
+
}) => (
|
|
242
|
+
<View style={styles.inputContainer}>
|
|
243
|
+
<TextInput
|
|
244
|
+
value={value}
|
|
245
|
+
onChangeText={onChangeText}
|
|
246
|
+
placeholder="Type a message..."
|
|
247
|
+
style={styles.textInput}
|
|
248
|
+
/>
|
|
249
|
+
<TouchableOpacity onPress={onSend} style={styles.sendButton}>
|
|
250
|
+
<Text>Send</Text>
|
|
251
|
+
</TouchableOpacity>
|
|
252
|
+
|
|
253
|
+
{attachments.map(attachment => (
|
|
254
|
+
<View key={attachment.id} style={styles.attachment}>
|
|
255
|
+
<Text>{attachment.fileName}</Text>
|
|
256
|
+
<TouchableOpacity onPress={() => onAttachmentRemove(attachment.id)}>
|
|
257
|
+
<Text>×</Text>
|
|
258
|
+
</TouchableOpacity>
|
|
259
|
+
</View>
|
|
260
|
+
))}
|
|
261
|
+
</View>
|
|
262
|
+
);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## TypeScript Support
|
|
266
|
+
|
|
267
|
+
All components and hooks are fully typed with TypeScript. The library exports comprehensive type definitions for:
|
|
268
|
+
|
|
269
|
+
- Message and attachment interfaces
|
|
270
|
+
- Hook return types
|
|
271
|
+
- Component prop types
|
|
272
|
+
- Render prop interfaces
|
|
273
|
+
|
|
274
|
+
## Migration from v1
|
|
275
|
+
|
|
276
|
+
If you're upgrading from the previous version:
|
|
277
|
+
|
|
278
|
+
1. **Replace `onMessageSend`**: The callback now receives a `Message` object instead of separate parameters
|
|
279
|
+
2. **Update attachment handling**: Use the new `useAttachments` hook or `attachmentUploader` prop
|
|
280
|
+
3. **Component overrides**: Use `renderProps` instead of `components` for UI customization
|
|
281
|
+
4. **Hooks**: Extract logic into standalone hooks for better reusability
|
|
282
|
+
|
|
283
|
+
## 📄 License
|
|
284
|
+
|
|
285
|
+
UseChat SDK is licensed under a **Custom License Agreement**:
|
|
286
|
+
|
|
287
|
+
- ✅ **Free** for personal, educational, and small-scale use
|
|
288
|
+
- 💼 **Commercial license required** for business applications
|
|
289
|
+
- 📋 **Full details:** See [LICENSING.md](./LICENSING.md)
|
|
290
|
+
|
|
291
|
+
### Quick Licensing Guide
|
|
292
|
+
|
|
293
|
+
| Use Case | License Required | Attribution |
|
|
294
|
+
|----------|------------------|-------------|
|
|
295
|
+
| Personal projects | Free | Required |
|
|
296
|
+
| Educational use | Free | Required |
|
|
297
|
+
| Open source projects | Free | Required |
|
|
298
|
+
| Apps with <1,000 MAU | Free | Required |
|
|
299
|
+
| Commercial/Business apps | Commercial | Optional |
|
|
300
|
+
| Apps with 1,000+ MAU | Commercial | Optional |
|
|
301
|
+
|
|
302
|
+
**Contact:** hello@usechat.dev for commercial licensing
|
|
303
|
+
|
|
304
|
+
## 🤝 Contributing
|
|
305
|
+
|
|
306
|
+
1. Fork the repository
|
|
307
|
+
2. Create a feature branch
|
|
308
|
+
3. Make your changes
|
|
309
|
+
4. Add tests if applicable
|
|
310
|
+
5. Submit a pull request
|
|
311
|
+
|
|
312
|
+
## 📞 Support
|
|
313
|
+
|
|
314
|
+
- **Documentation:** https://docs.usechat.dev
|
|
315
|
+
- **Issues:** [GitHub Issues](https://github.com/usechat-dev/react-native-chat/issues)
|
|
316
|
+
- **Email:** support@usechat.dev
|
|
317
|
+
- **Website:** https://usechat.dev
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
// src/utils/clipboard.ts
|
|
4
|
+
var copyToClipboard = async (text) => {
|
|
5
|
+
console.log("copyToClipboard called with text:", text);
|
|
6
|
+
try {
|
|
7
|
+
try {
|
|
8
|
+
const { setStringAsync } = await import("expo-clipboard");
|
|
9
|
+
console.log("expo-clipboard imported successfully");
|
|
10
|
+
console.log("setStringAsync function:", setStringAsync);
|
|
11
|
+
await setStringAsync(text);
|
|
12
|
+
console.log("Text copied to clipboard successfully");
|
|
13
|
+
} catch (importError) {
|
|
14
|
+
console.error("Failed to import expo-clipboard:", importError);
|
|
15
|
+
throw new Error("expo-clipboard not available");
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const toastModule = await import("react-native-toast-message");
|
|
19
|
+
const Toast = toastModule.default || toastModule;
|
|
20
|
+
console.log("react-native-toast-message imported successfully");
|
|
21
|
+
Toast.show({
|
|
22
|
+
type: "success",
|
|
23
|
+
text1: "Copied to clipboard",
|
|
24
|
+
text2: "Message copied successfully",
|
|
25
|
+
position: "bottom",
|
|
26
|
+
visibilityTime: 2e3
|
|
27
|
+
});
|
|
28
|
+
console.log("Toast shown successfully");
|
|
29
|
+
} catch (toastError) {
|
|
30
|
+
console.log("Toast not available, but message copied to clipboard");
|
|
31
|
+
console.error("Toast import error:", toastError);
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error("Failed to copy to clipboard:", error);
|
|
36
|
+
try {
|
|
37
|
+
const toastModule = await import("react-native-toast-message");
|
|
38
|
+
const Toast = toastModule.default || toastModule;
|
|
39
|
+
Toast.show({
|
|
40
|
+
type: "error",
|
|
41
|
+
text1: "Copy failed",
|
|
42
|
+
text2: "Failed to copy message to clipboard",
|
|
43
|
+
position: "bottom",
|
|
44
|
+
visibilityTime: 2e3
|
|
45
|
+
});
|
|
46
|
+
} catch (toastError) {
|
|
47
|
+
console.error("Copy failed: expo-clipboard not available");
|
|
48
|
+
console.error("Toast import error:", toastError);
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var isClipboardAvailable = async () => {
|
|
54
|
+
try {
|
|
55
|
+
await import("expo-clipboard");
|
|
56
|
+
return true;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
export {
|
|
62
|
+
copyToClipboard,
|
|
63
|
+
isClipboardAvailable
|
|
64
|
+
};
|