@parlr/react-native 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.
Files changed (223) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +918 -0
  3. package/lib/commonjs/components/AttachmentPicker.js +292 -0
  4. package/lib/commonjs/components/AttachmentPicker.js.map +1 -0
  5. package/lib/commonjs/components/AttachmentPreview.js +200 -0
  6. package/lib/commonjs/components/AttachmentPreview.js.map +1 -0
  7. package/lib/commonjs/components/ChatBubble.js +391 -0
  8. package/lib/commonjs/components/ChatBubble.js.map +1 -0
  9. package/lib/commonjs/components/EmptyState.js +115 -0
  10. package/lib/commonjs/components/EmptyState.js.map +1 -0
  11. package/lib/commonjs/components/ParlrChat.js +745 -0
  12. package/lib/commonjs/components/ParlrChat.js.map +1 -0
  13. package/lib/commonjs/components/ParlrConversationList.js +509 -0
  14. package/lib/commonjs/components/ParlrConversationList.js.map +1 -0
  15. package/lib/commonjs/components/PreChatForm.js +263 -0
  16. package/lib/commonjs/components/PreChatForm.js.map +1 -0
  17. package/lib/commonjs/components/RichMessage.js +284 -0
  18. package/lib/commonjs/components/RichMessage.js.map +1 -0
  19. package/lib/commonjs/components/SatisfactionSurvey.js +292 -0
  20. package/lib/commonjs/components/SatisfactionSurvey.js.map +1 -0
  21. package/lib/commonjs/components/TypingIndicator.js +86 -0
  22. package/lib/commonjs/components/TypingIndicator.js.map +1 -0
  23. package/lib/commonjs/core/api.js +310 -0
  24. package/lib/commonjs/core/api.js.map +1 -0
  25. package/lib/commonjs/core/config.js +40 -0
  26. package/lib/commonjs/core/config.js.map +1 -0
  27. package/lib/commonjs/core/errors.js +73 -0
  28. package/lib/commonjs/core/errors.js.map +1 -0
  29. package/lib/commonjs/core/offlineQueue.js +89 -0
  30. package/lib/commonjs/core/offlineQueue.js.map +1 -0
  31. package/lib/commonjs/core/pushNotifications.js +21 -0
  32. package/lib/commonjs/core/pushNotifications.js.map +1 -0
  33. package/lib/commonjs/core/session.js +130 -0
  34. package/lib/commonjs/core/session.js.map +1 -0
  35. package/lib/commonjs/core/theme.js +110 -0
  36. package/lib/commonjs/core/theme.js.map +1 -0
  37. package/lib/commonjs/core/types.js +6 -0
  38. package/lib/commonjs/core/types.js.map +1 -0
  39. package/lib/commonjs/core/websocket.js +245 -0
  40. package/lib/commonjs/core/websocket.js.map +1 -0
  41. package/lib/commonjs/hooks/useChat.js +462 -0
  42. package/lib/commonjs/hooks/useChat.js.map +1 -0
  43. package/lib/commonjs/hooks/useParlr.js +44 -0
  44. package/lib/commonjs/hooks/useParlr.js.map +1 -0
  45. package/lib/commonjs/index.js +185 -0
  46. package/lib/commonjs/index.js.map +1 -0
  47. package/lib/commonjs/package.json +1 -0
  48. package/lib/commonjs/provider/ParlrContext.js +38 -0
  49. package/lib/commonjs/provider/ParlrContext.js.map +1 -0
  50. package/lib/commonjs/provider/ParlrProvider.js +256 -0
  51. package/lib/commonjs/provider/ParlrProvider.js.map +1 -0
  52. package/lib/module/components/AttachmentPicker.js +287 -0
  53. package/lib/module/components/AttachmentPicker.js.map +1 -0
  54. package/lib/module/components/AttachmentPreview.js +195 -0
  55. package/lib/module/components/AttachmentPreview.js.map +1 -0
  56. package/lib/module/components/ChatBubble.js +386 -0
  57. package/lib/module/components/ChatBubble.js.map +1 -0
  58. package/lib/module/components/EmptyState.js +110 -0
  59. package/lib/module/components/EmptyState.js.map +1 -0
  60. package/lib/module/components/ParlrChat.js +740 -0
  61. package/lib/module/components/ParlrChat.js.map +1 -0
  62. package/lib/module/components/ParlrConversationList.js +504 -0
  63. package/lib/module/components/ParlrConversationList.js.map +1 -0
  64. package/lib/module/components/PreChatForm.js +258 -0
  65. package/lib/module/components/PreChatForm.js.map +1 -0
  66. package/lib/module/components/RichMessage.js +280 -0
  67. package/lib/module/components/RichMessage.js.map +1 -0
  68. package/lib/module/components/SatisfactionSurvey.js +287 -0
  69. package/lib/module/components/SatisfactionSurvey.js.map +1 -0
  70. package/lib/module/components/TypingIndicator.js +81 -0
  71. package/lib/module/components/TypingIndicator.js.map +1 -0
  72. package/lib/module/core/api.js +305 -0
  73. package/lib/module/core/api.js.map +1 -0
  74. package/lib/module/core/config.js +36 -0
  75. package/lib/module/core/config.js.map +1 -0
  76. package/lib/module/core/errors.js +64 -0
  77. package/lib/module/core/errors.js.map +1 -0
  78. package/lib/module/core/offlineQueue.js +82 -0
  79. package/lib/module/core/offlineQueue.js.map +1 -0
  80. package/lib/module/core/pushNotifications.js +16 -0
  81. package/lib/module/core/pushNotifications.js.map +1 -0
  82. package/lib/module/core/session.js +122 -0
  83. package/lib/module/core/session.js.map +1 -0
  84. package/lib/module/core/theme.js +105 -0
  85. package/lib/module/core/theme.js.map +1 -0
  86. package/lib/module/core/types.js +4 -0
  87. package/lib/module/core/types.js.map +1 -0
  88. package/lib/module/core/websocket.js +241 -0
  89. package/lib/module/core/websocket.js.map +1 -0
  90. package/lib/module/hooks/useChat.js +458 -0
  91. package/lib/module/hooks/useChat.js.map +1 -0
  92. package/lib/module/hooks/useParlr.js +40 -0
  93. package/lib/module/hooks/useParlr.js.map +1 -0
  94. package/lib/module/index.js +58 -0
  95. package/lib/module/index.js.map +1 -0
  96. package/lib/module/package.json +1 -0
  97. package/lib/module/provider/ParlrContext.js +35 -0
  98. package/lib/module/provider/ParlrContext.js.map +1 -0
  99. package/lib/module/provider/ParlrProvider.js +251 -0
  100. package/lib/module/provider/ParlrProvider.js.map +1 -0
  101. package/lib/typescript/commonjs/components/AttachmentPicker.d.ts +23 -0
  102. package/lib/typescript/commonjs/components/AttachmentPicker.d.ts.map +1 -0
  103. package/lib/typescript/commonjs/components/AttachmentPreview.d.ts +16 -0
  104. package/lib/typescript/commonjs/components/AttachmentPreview.d.ts.map +1 -0
  105. package/lib/typescript/commonjs/components/ChatBubble.d.ts +14 -0
  106. package/lib/typescript/commonjs/components/ChatBubble.d.ts.map +1 -0
  107. package/lib/typescript/commonjs/components/EmptyState.d.ts +10 -0
  108. package/lib/typescript/commonjs/components/EmptyState.d.ts.map +1 -0
  109. package/lib/typescript/commonjs/components/ParlrChat.d.ts +34 -0
  110. package/lib/typescript/commonjs/components/ParlrChat.d.ts.map +1 -0
  111. package/lib/typescript/commonjs/components/ParlrConversationList.d.ts +17 -0
  112. package/lib/typescript/commonjs/components/ParlrConversationList.d.ts.map +1 -0
  113. package/lib/typescript/commonjs/components/PreChatForm.d.ts +20 -0
  114. package/lib/typescript/commonjs/components/PreChatForm.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/components/RichMessage.d.ts +41 -0
  116. package/lib/typescript/commonjs/components/RichMessage.d.ts.map +1 -0
  117. package/lib/typescript/commonjs/components/SatisfactionSurvey.d.ts +17 -0
  118. package/lib/typescript/commonjs/components/SatisfactionSurvey.d.ts.map +1 -0
  119. package/lib/typescript/commonjs/components/TypingIndicator.d.ts +7 -0
  120. package/lib/typescript/commonjs/components/TypingIndicator.d.ts.map +1 -0
  121. package/lib/typescript/commonjs/core/api.d.ts +37 -0
  122. package/lib/typescript/commonjs/core/api.d.ts.map +1 -0
  123. package/lib/typescript/commonjs/core/config.d.ts +9 -0
  124. package/lib/typescript/commonjs/core/config.d.ts.map +1 -0
  125. package/lib/typescript/commonjs/core/errors.d.ts +35 -0
  126. package/lib/typescript/commonjs/core/errors.d.ts.map +1 -0
  127. package/lib/typescript/commonjs/core/offlineQueue.d.ts +16 -0
  128. package/lib/typescript/commonjs/core/offlineQueue.d.ts.map +1 -0
  129. package/lib/typescript/commonjs/core/pushNotifications.d.ts +6 -0
  130. package/lib/typescript/commonjs/core/pushNotifications.d.ts.map +1 -0
  131. package/lib/typescript/commonjs/core/session.d.ts +15 -0
  132. package/lib/typescript/commonjs/core/session.d.ts.map +1 -0
  133. package/lib/typescript/commonjs/core/theme.d.ts +43 -0
  134. package/lib/typescript/commonjs/core/theme.d.ts.map +1 -0
  135. package/lib/typescript/commonjs/core/types.d.ts +185 -0
  136. package/lib/typescript/commonjs/core/types.d.ts.map +1 -0
  137. package/lib/typescript/commonjs/core/websocket.d.ts +17 -0
  138. package/lib/typescript/commonjs/core/websocket.d.ts.map +1 -0
  139. package/lib/typescript/commonjs/hooks/useChat.d.ts +35 -0
  140. package/lib/typescript/commonjs/hooks/useChat.d.ts.map +1 -0
  141. package/lib/typescript/commonjs/hooks/useParlr.d.ts +11 -0
  142. package/lib/typescript/commonjs/hooks/useParlr.d.ts.map +1 -0
  143. package/lib/typescript/commonjs/index.d.ts +30 -0
  144. package/lib/typescript/commonjs/index.d.ts.map +1 -0
  145. package/lib/typescript/commonjs/package.json +1 -0
  146. package/lib/typescript/commonjs/provider/ParlrContext.d.ts +13 -0
  147. package/lib/typescript/commonjs/provider/ParlrContext.d.ts.map +1 -0
  148. package/lib/typescript/commonjs/provider/ParlrProvider.d.ts +5 -0
  149. package/lib/typescript/commonjs/provider/ParlrProvider.d.ts.map +1 -0
  150. package/lib/typescript/module/components/AttachmentPicker.d.ts +23 -0
  151. package/lib/typescript/module/components/AttachmentPicker.d.ts.map +1 -0
  152. package/lib/typescript/module/components/AttachmentPreview.d.ts +16 -0
  153. package/lib/typescript/module/components/AttachmentPreview.d.ts.map +1 -0
  154. package/lib/typescript/module/components/ChatBubble.d.ts +14 -0
  155. package/lib/typescript/module/components/ChatBubble.d.ts.map +1 -0
  156. package/lib/typescript/module/components/EmptyState.d.ts +10 -0
  157. package/lib/typescript/module/components/EmptyState.d.ts.map +1 -0
  158. package/lib/typescript/module/components/ParlrChat.d.ts +34 -0
  159. package/lib/typescript/module/components/ParlrChat.d.ts.map +1 -0
  160. package/lib/typescript/module/components/ParlrConversationList.d.ts +17 -0
  161. package/lib/typescript/module/components/ParlrConversationList.d.ts.map +1 -0
  162. package/lib/typescript/module/components/PreChatForm.d.ts +20 -0
  163. package/lib/typescript/module/components/PreChatForm.d.ts.map +1 -0
  164. package/lib/typescript/module/components/RichMessage.d.ts +41 -0
  165. package/lib/typescript/module/components/RichMessage.d.ts.map +1 -0
  166. package/lib/typescript/module/components/SatisfactionSurvey.d.ts +17 -0
  167. package/lib/typescript/module/components/SatisfactionSurvey.d.ts.map +1 -0
  168. package/lib/typescript/module/components/TypingIndicator.d.ts +7 -0
  169. package/lib/typescript/module/components/TypingIndicator.d.ts.map +1 -0
  170. package/lib/typescript/module/core/api.d.ts +37 -0
  171. package/lib/typescript/module/core/api.d.ts.map +1 -0
  172. package/lib/typescript/module/core/config.d.ts +9 -0
  173. package/lib/typescript/module/core/config.d.ts.map +1 -0
  174. package/lib/typescript/module/core/errors.d.ts +35 -0
  175. package/lib/typescript/module/core/errors.d.ts.map +1 -0
  176. package/lib/typescript/module/core/offlineQueue.d.ts +16 -0
  177. package/lib/typescript/module/core/offlineQueue.d.ts.map +1 -0
  178. package/lib/typescript/module/core/pushNotifications.d.ts +6 -0
  179. package/lib/typescript/module/core/pushNotifications.d.ts.map +1 -0
  180. package/lib/typescript/module/core/session.d.ts +15 -0
  181. package/lib/typescript/module/core/session.d.ts.map +1 -0
  182. package/lib/typescript/module/core/theme.d.ts +43 -0
  183. package/lib/typescript/module/core/theme.d.ts.map +1 -0
  184. package/lib/typescript/module/core/types.d.ts +185 -0
  185. package/lib/typescript/module/core/types.d.ts.map +1 -0
  186. package/lib/typescript/module/core/websocket.d.ts +17 -0
  187. package/lib/typescript/module/core/websocket.d.ts.map +1 -0
  188. package/lib/typescript/module/hooks/useChat.d.ts +35 -0
  189. package/lib/typescript/module/hooks/useChat.d.ts.map +1 -0
  190. package/lib/typescript/module/hooks/useParlr.d.ts +11 -0
  191. package/lib/typescript/module/hooks/useParlr.d.ts.map +1 -0
  192. package/lib/typescript/module/index.d.ts +30 -0
  193. package/lib/typescript/module/index.d.ts.map +1 -0
  194. package/lib/typescript/module/package.json +1 -0
  195. package/lib/typescript/module/provider/ParlrContext.d.ts +13 -0
  196. package/lib/typescript/module/provider/ParlrContext.d.ts.map +1 -0
  197. package/lib/typescript/module/provider/ParlrProvider.d.ts +5 -0
  198. package/lib/typescript/module/provider/ParlrProvider.d.ts.map +1 -0
  199. package/package.json +120 -0
  200. package/src/components/AttachmentPicker.tsx +310 -0
  201. package/src/components/AttachmentPreview.tsx +209 -0
  202. package/src/components/ChatBubble.tsx +424 -0
  203. package/src/components/EmptyState.tsx +118 -0
  204. package/src/components/ParlrChat.tsx +863 -0
  205. package/src/components/ParlrConversationList.tsx +559 -0
  206. package/src/components/PreChatForm.tsx +313 -0
  207. package/src/components/RichMessage.tsx +353 -0
  208. package/src/components/SatisfactionSurvey.tsx +333 -0
  209. package/src/components/TypingIndicator.tsx +89 -0
  210. package/src/core/api.ts +406 -0
  211. package/src/core/config.ts +39 -0
  212. package/src/core/errors.ts +68 -0
  213. package/src/core/offlineQueue.ts +94 -0
  214. package/src/core/pushNotifications.ts +22 -0
  215. package/src/core/session.ts +156 -0
  216. package/src/core/theme.ts +133 -0
  217. package/src/core/types.ts +237 -0
  218. package/src/core/websocket.ts +270 -0
  219. package/src/hooks/useChat.ts +534 -0
  220. package/src/hooks/useParlr.ts +43 -0
  221. package/src/index.ts +98 -0
  222. package/src/provider/ParlrContext.ts +40 -0
  223. package/src/provider/ParlrProvider.tsx +338 -0
@@ -0,0 +1,333 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Parlr React Native SDK - Satisfaction Survey (CSAT)
3
+ // ---------------------------------------------------------------------------
4
+ //
5
+ // Displays a 1-5 star rating + optional comment after a conversation is closed.
6
+ // ---------------------------------------------------------------------------
7
+
8
+ import React, { useCallback, useState } from 'react';
9
+ import {
10
+ ActivityIndicator,
11
+ Pressable,
12
+ StyleSheet,
13
+ Text,
14
+ TextInput,
15
+ View,
16
+ useColorScheme,
17
+ } from 'react-native';
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Props
21
+ // ---------------------------------------------------------------------------
22
+
23
+ export interface SatisfactionSurveyProps {
24
+ /** Called when the survey is submitted. */
25
+ onSubmit: (score: number, comment?: string) => Promise<void>;
26
+ /** Called when the user dismisses without rating. */
27
+ onDismiss?: () => void;
28
+ /** Title text. */
29
+ title?: string;
30
+ /** Description text. */
31
+ description?: string;
32
+ /** Accent color. */
33
+ accentColor?: string;
34
+ /** Locale for default text. */
35
+ locale?: string;
36
+ }
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // i18n
40
+ // ---------------------------------------------------------------------------
41
+
42
+ function getI18n(locale?: string) {
43
+ if (locale?.startsWith('en')) {
44
+ return {
45
+ title: 'How was your experience?',
46
+ description: 'Rate your conversation with our team.',
47
+ commentPlaceholder: 'Tell us more (optional)',
48
+ submit: 'Submit',
49
+ dismiss: 'Skip',
50
+ thanks: 'Thank you for your feedback!',
51
+ labels: ['Terrible', 'Bad', 'Okay', 'Good', 'Excellent'],
52
+ };
53
+ }
54
+ return {
55
+ title: 'Comment s\u2019est pass\u00e9e votre exp\u00e9rience ?',
56
+ description: '\u00c9valuez votre conversation avec notre \u00e9quipe.',
57
+ commentPlaceholder: 'Dites-nous en plus (optionnel)',
58
+ submit: 'Envoyer',
59
+ dismiss: 'Passer',
60
+ thanks: 'Merci pour votre retour !',
61
+ labels: ['Terrible', 'Mauvais', 'Correct', 'Bien', 'Excellent'],
62
+ };
63
+ }
64
+
65
+ // ---------------------------------------------------------------------------
66
+ // Star component
67
+ // ---------------------------------------------------------------------------
68
+
69
+ function Star({
70
+ filled,
71
+ onPress,
72
+ size = 36,
73
+ }: {
74
+ filled: boolean;
75
+ onPress: () => void;
76
+ size?: number;
77
+ }) {
78
+ return (
79
+ <Pressable
80
+ onPress={onPress}
81
+ hitSlop={4}
82
+ accessibilityRole="button"
83
+ >
84
+ <Text style={{ fontSize: size, color: filled ? '#f59e0b' : '#d1d5db' }}>
85
+ {filled ? '\u2605' : '\u2606'}
86
+ </Text>
87
+ </Pressable>
88
+ );
89
+ }
90
+
91
+ // ---------------------------------------------------------------------------
92
+ // Component
93
+ // ---------------------------------------------------------------------------
94
+
95
+ export function SatisfactionSurvey({
96
+ onSubmit,
97
+ onDismiss,
98
+ title,
99
+ description,
100
+ accentColor: accentColorProp,
101
+ locale,
102
+ }: SatisfactionSurveyProps) {
103
+ const isDark = useColorScheme() === 'dark';
104
+ const accentColor = accentColorProp ?? '#6366f1';
105
+ const i18n = getI18n(locale);
106
+
107
+ const [score, setScore] = useState(0);
108
+ const [comment, setComment] = useState('');
109
+ const [isSubmitting, setIsSubmitting] = useState(false);
110
+ const [submitted, setSubmitted] = useState(false);
111
+
112
+ const handleSubmit = useCallback(async () => {
113
+ if (score === 0) return;
114
+ setIsSubmitting(true);
115
+ try {
116
+ await onSubmit(score, comment.trim() || undefined);
117
+ setSubmitted(true);
118
+ } finally {
119
+ setIsSubmitting(false);
120
+ }
121
+ }, [score, comment, onSubmit]);
122
+
123
+ if (submitted) {
124
+ return (
125
+ <View style={[styles.root, isDark && styles.rootDark]}>
126
+ <View style={styles.container}>
127
+ <Text style={styles.checkmark}>{'\u2714'}</Text>
128
+ <Text style={[styles.thanksText, isDark && styles.thanksTextDark]}>
129
+ {i18n.thanks}
130
+ </Text>
131
+ </View>
132
+ </View>
133
+ );
134
+ }
135
+
136
+ return (
137
+ <View style={[styles.root, isDark && styles.rootDark]}>
138
+ <View style={styles.container}>
139
+ <Text style={[styles.title, isDark && styles.titleDark]}>
140
+ {title ?? i18n.title}
141
+ </Text>
142
+ <Text style={[styles.description, isDark && styles.descriptionDark]}>
143
+ {description ?? i18n.description}
144
+ </Text>
145
+
146
+ {/* Stars */}
147
+ <View style={styles.starsRow}>
148
+ {[1, 2, 3, 4, 5].map((value) => (
149
+ <Star
150
+ key={value}
151
+ filled={value <= score}
152
+ onPress={() => setScore(value)}
153
+ />
154
+ ))}
155
+ </View>
156
+
157
+ {/* Label */}
158
+ {score > 0 && (
159
+ <Text style={[styles.scoreLabel, isDark && styles.scoreLabelDark]}>
160
+ {i18n.labels[score - 1]}
161
+ </Text>
162
+ )}
163
+
164
+ {/* Comment */}
165
+ {score > 0 && (
166
+ <TextInput
167
+ style={[
168
+ styles.commentInput,
169
+ isDark ? styles.commentInputDark : styles.commentInputLight,
170
+ ]}
171
+ value={comment}
172
+ onChangeText={setComment}
173
+ placeholder={i18n.commentPlaceholder}
174
+ placeholderTextColor={isDark ? '#64748b' : '#94a3b8'}
175
+ multiline
176
+ maxLength={500}
177
+ accessibilityLabel={i18n.commentPlaceholder}
178
+ />
179
+ )}
180
+
181
+ {/* Actions */}
182
+ <View style={styles.actions}>
183
+ {onDismiss && (
184
+ <Pressable
185
+ onPress={onDismiss}
186
+ style={styles.dismissButton}
187
+ accessibilityRole="button"
188
+ accessibilityLabel={i18n.dismiss}
189
+ >
190
+ <Text style={[styles.dismissText, isDark && styles.dismissTextDark]}>
191
+ {i18n.dismiss}
192
+ </Text>
193
+ </Pressable>
194
+ )}
195
+
196
+ <Pressable
197
+ onPress={handleSubmit}
198
+ disabled={score === 0 || isSubmitting}
199
+ style={[
200
+ styles.submitButton,
201
+ {
202
+ backgroundColor: score === 0 || isSubmitting ? '#cbd5e1' : accentColor,
203
+ },
204
+ ]}
205
+ accessibilityRole="button"
206
+ accessibilityLabel={i18n.submit}
207
+ accessibilityState={{ disabled: score === 0 || isSubmitting }}
208
+ >
209
+ {isSubmitting ? (
210
+ <ActivityIndicator size="small" color="#ffffff" />
211
+ ) : (
212
+ <Text style={styles.submitText}>{i18n.submit}</Text>
213
+ )}
214
+ </Pressable>
215
+ </View>
216
+ </View>
217
+ </View>
218
+ );
219
+ }
220
+
221
+ // ---------------------------------------------------------------------------
222
+ // Styles
223
+ // ---------------------------------------------------------------------------
224
+
225
+ const styles = StyleSheet.create({
226
+ root: {
227
+ backgroundColor: '#ffffff',
228
+ paddingVertical: 24,
229
+ },
230
+ rootDark: {
231
+ backgroundColor: '#0f172a',
232
+ },
233
+ container: {
234
+ paddingHorizontal: 24,
235
+ alignItems: 'center',
236
+ },
237
+ title: {
238
+ fontSize: 18,
239
+ fontWeight: '700',
240
+ color: '#0f172a',
241
+ marginBottom: 6,
242
+ textAlign: 'center',
243
+ },
244
+ titleDark: {
245
+ color: '#f1f5f9',
246
+ },
247
+ description: {
248
+ fontSize: 14,
249
+ color: '#64748b',
250
+ textAlign: 'center',
251
+ marginBottom: 20,
252
+ },
253
+ descriptionDark: {
254
+ color: '#94a3b8',
255
+ },
256
+ starsRow: {
257
+ flexDirection: 'row',
258
+ gap: 12,
259
+ marginBottom: 8,
260
+ },
261
+ scoreLabel: {
262
+ fontSize: 14,
263
+ fontWeight: '500',
264
+ color: '#475569',
265
+ marginBottom: 16,
266
+ },
267
+ scoreLabelDark: {
268
+ color: '#94a3b8',
269
+ },
270
+ commentInput: {
271
+ width: '100%',
272
+ minHeight: 80,
273
+ maxHeight: 120,
274
+ fontSize: 14,
275
+ paddingHorizontal: 14,
276
+ paddingVertical: 10,
277
+ borderRadius: 10,
278
+ borderWidth: 1,
279
+ textAlignVertical: 'top',
280
+ marginBottom: 16,
281
+ },
282
+ commentInputLight: {
283
+ backgroundColor: '#f8fafc',
284
+ borderColor: '#e2e8f0',
285
+ color: '#0f172a',
286
+ },
287
+ commentInputDark: {
288
+ backgroundColor: '#1e293b',
289
+ borderColor: '#334155',
290
+ color: '#f1f5f9',
291
+ },
292
+ actions: {
293
+ flexDirection: 'row',
294
+ gap: 12,
295
+ alignItems: 'center',
296
+ },
297
+ dismissButton: {
298
+ paddingHorizontal: 20,
299
+ paddingVertical: 12,
300
+ },
301
+ dismissText: {
302
+ fontSize: 14,
303
+ color: '#64748b',
304
+ },
305
+ dismissTextDark: {
306
+ color: '#94a3b8',
307
+ },
308
+ submitButton: {
309
+ flex: 1,
310
+ paddingVertical: 12,
311
+ borderRadius: 10,
312
+ alignItems: 'center',
313
+ },
314
+ submitText: {
315
+ color: '#ffffff',
316
+ fontSize: 15,
317
+ fontWeight: '600',
318
+ },
319
+ checkmark: {
320
+ fontSize: 48,
321
+ color: '#22c55e',
322
+ marginBottom: 12,
323
+ },
324
+ thanksText: {
325
+ fontSize: 16,
326
+ fontWeight: '600',
327
+ color: '#0f172a',
328
+ textAlign: 'center',
329
+ },
330
+ thanksTextDark: {
331
+ color: '#f1f5f9',
332
+ },
333
+ });
@@ -0,0 +1,89 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Parlr React Native SDK - Typing Indicator (animated 3 dots)
3
+ // ---------------------------------------------------------------------------
4
+
5
+ import React, { useEffect } from 'react';
6
+ import { StyleSheet, View, useColorScheme } from 'react-native';
7
+ import Animated, {
8
+ useSharedValue,
9
+ useAnimatedStyle,
10
+ withRepeat,
11
+ withSequence,
12
+ withTiming,
13
+ withDelay,
14
+ Easing,
15
+ } from 'react-native-reanimated';
16
+
17
+ interface TypingIndicatorProps {
18
+ accentColor?: string;
19
+ }
20
+
21
+ function Dot({ index, color }: { index: number; color: string }) {
22
+ const translateY = useSharedValue(0);
23
+
24
+ useEffect(() => {
25
+ translateY.value = withDelay(
26
+ index * 150,
27
+ withRepeat(
28
+ withSequence(
29
+ withTiming(-6, { duration: 300, easing: Easing.out(Easing.ease) }),
30
+ withTiming(0, { duration: 300, easing: Easing.in(Easing.ease) }),
31
+ ),
32
+ -1,
33
+ false,
34
+ ),
35
+ );
36
+ }, [index, translateY]);
37
+
38
+ const animatedStyle = useAnimatedStyle(() => ({
39
+ transform: [{ translateY: translateY.value }],
40
+ }));
41
+
42
+ return (
43
+ <Animated.View
44
+ style={[styles.dot, { backgroundColor: color }, animatedStyle]}
45
+ />
46
+ );
47
+ }
48
+
49
+ export function TypingIndicator({ accentColor }: TypingIndicatorProps) {
50
+ const isDark = useColorScheme() === 'dark';
51
+ const dotColor = accentColor ?? (isDark ? '#94a3b8' : '#64748b');
52
+
53
+ return (
54
+ <View
55
+ style={[styles.container, isDark ? styles.containerDark : styles.containerLight]}
56
+ accessibilityLabel="Agent is typing"
57
+ accessibilityRole="text"
58
+ >
59
+ <Dot index={0} color={dotColor} />
60
+ <Dot index={1} color={dotColor} />
61
+ <Dot index={2} color={dotColor} />
62
+ </View>
63
+ );
64
+ }
65
+
66
+ const styles = StyleSheet.create({
67
+ container: {
68
+ flexDirection: 'row',
69
+ alignItems: 'center',
70
+ alignSelf: 'flex-start',
71
+ paddingHorizontal: 16,
72
+ paddingVertical: 12,
73
+ borderRadius: 18,
74
+ marginLeft: 12,
75
+ marginVertical: 4,
76
+ gap: 4,
77
+ },
78
+ containerLight: {
79
+ backgroundColor: '#f1f5f9',
80
+ },
81
+ containerDark: {
82
+ backgroundColor: '#1e293b',
83
+ },
84
+ dot: {
85
+ width: 7,
86
+ height: 7,
87
+ borderRadius: 3.5,
88
+ },
89
+ });