react-native-srschat 0.1.58 → 0.1.60

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 (51) hide show
  1. package/lib/commonjs/components/input.js +33 -3
  2. package/lib/commonjs/components/input.js.map +1 -1
  3. package/lib/commonjs/components/productCard.js +26 -8
  4. package/lib/commonjs/components/productCard.js.map +1 -1
  5. package/lib/commonjs/components/testing.js +8 -35
  6. package/lib/commonjs/components/testing.js.map +1 -1
  7. package/lib/commonjs/components/voice.js +23 -3
  8. package/lib/commonjs/components/voice.js.map +1 -1
  9. package/lib/commonjs/components/welcomeInput.js +29 -2
  10. package/lib/commonjs/components/welcomeInput.js.map +1 -1
  11. package/lib/commonjs/layout/window.js +101 -93
  12. package/lib/commonjs/layout/window.js.map +1 -1
  13. package/lib/commonjs/utils/audioRecorder.js +129 -38
  14. package/lib/commonjs/utils/audioRecorder.js.map +1 -1
  15. package/lib/module/components/input.js +33 -3
  16. package/lib/module/components/input.js.map +1 -1
  17. package/lib/module/components/productCard.js +26 -8
  18. package/lib/module/components/productCard.js.map +1 -1
  19. package/lib/module/components/testing.js +9 -36
  20. package/lib/module/components/testing.js.map +1 -1
  21. package/lib/module/components/voice.js +23 -3
  22. package/lib/module/components/voice.js.map +1 -1
  23. package/lib/module/components/welcomeInput.js +29 -2
  24. package/lib/module/components/welcomeInput.js.map +1 -1
  25. package/lib/module/layout/window.js +101 -93
  26. package/lib/module/layout/window.js.map +1 -1
  27. package/lib/module/utils/audioRecorder.js +129 -38
  28. package/lib/module/utils/audioRecorder.js.map +1 -1
  29. package/lib/typescript/components/input.d.ts.map +1 -1
  30. package/lib/typescript/components/testing.d.ts.map +1 -1
  31. package/lib/typescript/components/voice.d.ts +3 -1
  32. package/lib/typescript/components/voice.d.ts.map +1 -1
  33. package/lib/typescript/components/welcomeInput.d.ts.map +1 -1
  34. package/lib/typescript/layout/window.d.ts.map +1 -1
  35. package/lib/typescript/utils/audioRecorder.d.ts +1 -1
  36. package/lib/typescript/utils/audioRecorder.d.ts.map +1 -1
  37. package/package.json +1 -1
  38. package/src/components/input.js +30 -3
  39. package/src/components/productCard.js +19 -4
  40. package/src/components/testing.js +14 -45
  41. package/src/components/voice.js +33 -14
  42. package/src/components/welcomeInput.js +26 -1
  43. package/src/layout/window.js +16 -6
  44. package/src/utils/audioRecorder.js +131 -35
  45. package/lib/commonjs/components/testProductCard.js +0 -60
  46. package/lib/commonjs/components/testProductCard.js.map +0 -1
  47. package/lib/module/components/testProductCard.js +0 -52
  48. package/lib/module/components/testProductCard.js.map +0 -1
  49. package/lib/typescript/components/testProductCard.d.ts +0 -3
  50. package/lib/typescript/components/testProductCard.d.ts.map +0 -1
  51. package/src/components/testProductCard.js +0 -55
@@ -1 +1 @@
1
- {"version":3,"file":"welcomeInput.d.ts","sourceRoot":"","sources":["../../../src/components/welcomeInput.js"],"names":[],"mappings":"AAgBO;;;sBA+CN;kBA/D8D,OAAO"}
1
+ {"version":3,"file":"welcomeInput.d.ts","sourceRoot":"","sources":["../../../src/components/welcomeInput.js"],"names":[],"mappings":"AAgBO;;;sBAwEN;kBAxF8D,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../../../src/layout/window.js"],"names":[],"mappings":"AAeO;;sBAiLN;kBAhM8D,OAAO"}
1
+ {"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../../../src/layout/window.js"],"names":[],"mappings":"AAeO;;sBAuLN;kBAtM8D,OAAO"}
@@ -1,5 +1,5 @@
1
1
  export function setPermissionStatusHandlers(getter: any, setter: any): void;
2
- export function initVoice(onResult: any): Promise<boolean>;
2
+ export function initVoice(onResult: any, onPartialResult?: null): Promise<boolean>;
3
3
  export function startRecording(): Promise<boolean>;
4
4
  export function stopRecording(): Promise<void>;
5
5
  export function cancelRecording(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"audioRecorder.d.ts","sourceRoot":"","sources":["../../../src/utils/audioRecorder.js"],"names":[],"mappings":"AAqBA,4EAGC;AAGD,2DA4GC;AA+ED,mDAyBC;AAED,+CAoCC;AAED,iDASC;AAED,2DA2BC;AAiDD,iDAMC;AAED,gCAgBC"}
1
+ {"version":3,"file":"audioRecorder.d.ts","sourceRoot":"","sources":["../../../src/utils/audioRecorder.js"],"names":[],"mappings":"AAwBA,4EAGC;AAGD,mFAkJC;AA4FD,mDA4BC;AAED,+CA2EC;AAED,iDASC;AAED,2DA2BC;AAiDD,iDAMC;AAED,gCAgBC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-srschat",
3
- "version": "0.1.58",
3
+ "version": "0.1.60",
4
4
  "private": false,
5
5
  "description": "A modern, sophisticated chat interface for React Native",
6
6
  "main": "lib/commonjs/index",
@@ -16,6 +16,7 @@ import { VoiceButton } from './voice';
16
16
 
17
17
  export const ChatInput = ({ onProductCardClick, onAddToCartClick }) => {
18
18
  const { handleSend, input, setInput, showModal, data } = useContext(AppContext);
19
+ const inputRef = useRef(null);
19
20
 
20
21
  const handleKeyPress = ({ nativeEvent }) => {
21
22
  if (nativeEvent.key === 'return' && !nativeEvent.shiftKey) {
@@ -33,10 +34,11 @@ export const ChatInput = ({ onProductCardClick, onAddToCartClick }) => {
33
34
 
34
35
  return (
35
36
  <>
36
- <Text style={styles.textBeta}>Beta version. AI Assistant is still learning!</Text>
37
+ <Text style={styles.textBeta} allowFontScaling={false}>Beta version. AI Assistant is still learning!</Text>
37
38
  <View style={styles.inputWrapper}>
38
39
  <View style={styles.inputContainer}>
39
40
  <TextInput
41
+ ref={inputRef}
40
42
  style={styles.input}
41
43
  value={input}
42
44
  onChangeText={setInput}
@@ -47,9 +49,32 @@ export const ChatInput = ({ onProductCardClick, onAddToCartClick }) => {
47
49
  enablesReturnKeyAutomatically={true}
48
50
  onKeyPress={handleKeyPress}
49
51
  onSubmitEditing={onSubmitEditing}
52
+ selection={undefined}
50
53
  blurOnSubmit={false}
51
54
  />
52
- <VoiceButton/>
55
+ <VoiceButton setInput={(text) => {
56
+ setInput(text);
57
+ // Auto-scroll to end
58
+ if (inputRef.current) {
59
+ // For iOS and Android, blur and refocus to ensure scroll
60
+ inputRef.current.blur();
61
+ setTimeout(() => {
62
+ if (inputRef.current) {
63
+ inputRef.current.focus();
64
+ // Set selection to end - Android sometimes needs a slight delay
65
+ if (Platform.OS === 'android') {
66
+ setTimeout(() => {
67
+ if (inputRef.current) {
68
+ inputRef.current.setSelection(text.length, text.length);
69
+ }
70
+ }, 10);
71
+ } else {
72
+ inputRef.current.setSelection(text.length, text.length);
73
+ }
74
+ }
75
+ }, 50);
76
+ }
77
+ }}/>
53
78
  <TouchableOpacity style={styles.sendButton} onPress={() => handleSend(input)} >
54
79
  <Ionicons name="paper-plane-outline" size={24} color='#8E8E93' />
55
80
  </TouchableOpacity>
@@ -107,6 +132,8 @@ const styles = StyleSheet.create({
107
132
  color: '#808080',
108
133
  fontWeight: '400',
109
134
  marginTop: 5,
110
- marginBottom: 2
135
+ marginBottom: 2,
136
+ textBreakStrategy: "simple",
137
+ lineHeight: 16,
111
138
  },
112
139
  });
@@ -352,11 +352,11 @@ export const ProductCard = ({ prod, onFocusQuantityInput, messageId }) => {
352
352
  <View style={styles.priceContainer}>
353
353
  {isOnSale ? (
354
354
  <>
355
- <Text style={styles.originalPrice}>${Number(grossPrice).toFixed(2)}</Text>
356
- <Text style={styles.salePrice}>${Number(netPrice).toFixed(2)}</Text>
355
+ <Text style={styles.originalPrice} allowFontScaling={false}>${Number(grossPrice).toFixed(2)}</Text>
356
+ <Text style={styles.salePrice} allowFontScaling={false}>${Number(netPrice).toFixed(2)}</Text>
357
357
  </>
358
358
  ) : (
359
- <Text style={styles.price}>${Number(grossPrice).toFixed(2)}</Text>
359
+ <Text style={styles.price} allowFontScaling={false}>${Number(grossPrice).toFixed(2)}</Text>
360
360
  )}
361
361
  <Text style={styles.perUnit}> / {selectedUom}</Text>
362
362
  </View>
@@ -520,24 +520,39 @@ const styles = StyleSheet.create({
520
520
  price: {
521
521
  fontSize: 14,
522
522
  fontWeight: "bold",
523
+ color: "#161616",
523
524
  textAlign: "center",
525
+ textBreakStrategy: "simple",
526
+ alignSelf: "stretch",
527
+ lineHeight: 20,
528
+ includeFontPadding: false,
529
+ textAlignVertical: 'center',
524
530
  },
525
531
  priceContainer: {
526
532
  flexDirection: "row",
527
533
  alignItems: "center",
528
- flexWrap: "wrap",
534
+ flexWrap: "nowrap",
529
535
  justifyContent: "center",
536
+ paddingHorizontal: 2,
530
537
  },
531
538
  originalPrice: {
532
539
  fontSize: 14,
533
540
  textDecorationLine: "line-through",
534
541
  color: "gray",
535
542
  marginRight: 5,
543
+ textBreakStrategy: "simple",
544
+ lineHeight: 20,
545
+ includeFontPadding: false,
546
+ textAlignVertical: 'center',
536
547
  },
537
548
  salePrice: {
538
549
  fontSize: 16,
539
550
  fontWeight: "bold",
540
551
  color: "red",
552
+ textBreakStrategy: "simple",
553
+ lineHeight: 22,
554
+ includeFontPadding: false,
555
+ textAlignVertical: 'center',
541
556
  },
542
557
  perUnit: {
543
558
  fontSize: 12,
@@ -1,6 +1,5 @@
1
1
  import React from 'react';
2
- import { View, Button, StyleSheet, TouchableOpacity, Text, ScrollView } from 'react-native';
3
- import { ProductCard } from './productCard';
2
+ import { View, Button, StyleSheet, TouchableOpacity, Text } from 'react-native';
4
3
 
5
4
  export const Testing = ({ onProductCardClick, onAddToCartClick }) => {
6
5
 
@@ -15,8 +14,7 @@ export const Testing = ({ onProductCardClick, onAddToCartClick }) => {
15
14
  "net_price": 7.83,
16
15
  "is_on_sale": false,
17
16
  "quantity_available": 0,
18
- "discounts": null,
19
- "min_pack_qty": 1.5
17
+ "discounts": null
20
18
  }
21
19
  }
22
20
  },
@@ -30,52 +28,25 @@ export const Testing = ({ onProductCardClick, onAddToCartClick }) => {
30
28
  }
31
29
 
32
30
  return (
33
- <ScrollView style={styles.container}>
34
- <Text style={styles.title}>Test Product Card</Text>
35
-
36
- {/* Display the actual product card */}
37
- <View style={styles.productCardContainer}>
38
- <ProductCard
39
- prod={product}
40
- onFocusQuantityInput={(partNumber) => console.log('Focus on:', partNumber)}
41
- messageId="test-message-123"
42
- />
43
- </View>
44
-
45
- {/* Test buttons */}
46
- <View style={styles.buttonContainer}>
47
- <TouchableOpacity style={styles.button} onPress={() => onProductCardClick(product)}>
48
- <Text style={styles.buttonText}>Product Card Click</Text>
49
- </TouchableOpacity>
50
- <TouchableOpacity style={styles.button} onPress={() => onAddToCartClick({"quantity":1,"product":product})}>
51
- <Text style={styles.buttonText}>Add to Cart</Text>
52
- </TouchableOpacity>
53
- </View>
54
- </ScrollView>
31
+ <View style={styles.container}>
32
+ <TouchableOpacity style={styles.button} onPress={() => onProductCardClick(product)}>
33
+ <Text style={styles.buttonText}>Product Card Click</Text>
34
+ </TouchableOpacity>
35
+ <TouchableOpacity style={styles.button} onPress={() => onAddToCartClick({"quantity":1,"product":product})}>
36
+ <Text style={styles.buttonText}>Add to Cart</Text>
37
+ </TouchableOpacity>
38
+ </View>
55
39
  );
56
40
  };
57
41
 
58
42
  const styles = StyleSheet.create({
59
43
  container: {
60
- backgroundColor: '#f6f6f6',
61
- borderTopWidth: 1,
62
- borderTopColor: '#DDD',
63
- },
64
- title: {
65
- fontSize: 18,
66
- fontWeight: 'bold',
67
- textAlign: 'center',
68
- padding: 16,
69
- },
70
- productCardContainer: {
71
- paddingHorizontal: 16,
72
- },
73
- buttonContainer: {
74
44
  flexDirection: 'row',
75
45
  alignItems: 'center',
76
46
  justifyContent: 'space-evenly',
77
47
  paddingHorizontal: 16,
78
- paddingVertical: 20,
48
+ borderTopWidth: 1,
49
+ borderTopColor: '#DDD',
79
50
  },
80
51
  button: {
81
52
  backgroundColor: "#d4d4d4",
@@ -83,9 +54,7 @@ const styles = StyleSheet.create({
83
54
  paddingHorizontal: 12,
84
55
  borderRadius: 5,
85
56
  alignItems: "center",
86
- },
87
- buttonText: {
88
- fontSize: 14,
89
- fontWeight: 'bold',
57
+ marginBottom: 10,
58
+ marginTop: 10,
90
59
  },
91
60
  });
@@ -19,7 +19,7 @@ import { AppContext } from '../contexts/AppContext';
19
19
 
20
20
  const PERMISSION_STORAGE_KEY = '@voice_permission_status';
21
21
 
22
- export const VoiceButton = () => {
22
+ export const VoiceButton = ({ setInput }) => {
23
23
  const { handleVoiceSend } = useContext(AppContext);
24
24
  const [isListening, setIsListening] = useState(false);
25
25
  const [loading, setLoading] = useState(false);
@@ -48,23 +48,42 @@ export const VoiceButton = () => {
48
48
  setHasPermission(permissionResult);
49
49
 
50
50
  if (permissionResult) {
51
- const initialized = await initVoice((result, error) => {
52
- if (error) {
53
- // Don't show alert for permission errors since we handle that elsewhere
54
- if (!error.includes('permission')) {
55
- Alert.alert('Error', error);
51
+ const initialized = await initVoice(
52
+ // Final result callback - just update input, don't send
53
+ (result, error) => {
54
+ console.log('Voice final result:', result, 'Error:', error);
55
+ if (error) {
56
+ // Don't show alert for permission errors since we handle that elsewhere
57
+ if (!error.includes('permission')) {
58
+ Alert.alert('Error', error);
59
+ }
60
+ setIsListening(false);
61
+ setLoading(false);
62
+ return;
63
+ }
64
+ if (result) {
65
+ if (setInput) {
66
+ // Just update the input field, don't send
67
+ setInput(result);
68
+ } else {
69
+ console.warn('VoiceButton: setInput prop is not provided');
70
+ }
56
71
  }
72
+ // Always reset states when the recognition ends
57
73
  setIsListening(false);
58
74
  setLoading(false);
59
- return;
60
- }
61
- if (result) {
62
- handleVoiceSend(null, result);
75
+ },
76
+ // Partial result callback for live transcription
77
+ (partialResult) => {
78
+ if (partialResult) {
79
+ if (setInput) {
80
+ setInput(partialResult);
81
+ } else {
82
+ console.warn('VoiceButton: setInput prop is not provided for partial results');
83
+ }
84
+ }
63
85
  }
64
- // Always reset states when the recognition ends
65
- setIsListening(false);
66
- setLoading(false);
67
- });
86
+ );
68
87
 
69
88
  if (!initialized) {
70
89
  // Only show this alert once per session
@@ -17,6 +17,7 @@ import { VoiceButton } from './voice';
17
17
  export const WelcomeInput = ({ onProductCardClick, onAddToCartClick }) => {
18
18
 
19
19
  const { data, handleSend, input, setInput, showModal, theme } = useContext(AppContext);
20
+ const inputRef = useRef(null);
20
21
 
21
22
  const handleKeyPress = ({ nativeEvent }) => {
22
23
  if (nativeEvent.key === 'return' && !nativeEvent.shiftKey) {
@@ -35,6 +36,7 @@ export const WelcomeInput = ({ onProductCardClick, onAddToCartClick }) => {
35
36
  return (
36
37
  <View style={styles.inputContainer}>
37
38
  <TextInput
39
+ ref={inputRef}
38
40
  style={styles.input}
39
41
  value={input}
40
42
  onChangeText={setInput}
@@ -45,9 +47,32 @@ export const WelcomeInput = ({ onProductCardClick, onAddToCartClick }) => {
45
47
  enablesReturnKeyAutomatically={true}
46
48
  onKeyPress={handleKeyPress}
47
49
  onSubmitEditing={onSubmitEditing}
50
+ selection={undefined}
48
51
  // blurOnSubmit={false}
49
52
  />
50
- <VoiceButton/>
53
+ <VoiceButton setInput={(text) => {
54
+ setInput(text);
55
+ // Auto-scroll to end
56
+ if (inputRef.current) {
57
+ // For iOS and Android, blur and refocus to ensure scroll
58
+ inputRef.current.blur();
59
+ setTimeout(() => {
60
+ if (inputRef.current) {
61
+ inputRef.current.focus();
62
+ // Set selection to end - Android sometimes needs a slight delay
63
+ if (Platform.OS === 'android') {
64
+ setTimeout(() => {
65
+ if (inputRef.current) {
66
+ inputRef.current.setSelection(text.length, text.length);
67
+ }
68
+ }, 10);
69
+ } else {
70
+ inputRef.current.setSelection(text.length, text.length);
71
+ }
72
+ }
73
+ }, 50);
74
+ }
75
+ }}/>
51
76
  <TouchableOpacity
52
77
  style={styles.sendButton}
53
78
  onPress={() => handleSend(input)}
@@ -104,11 +104,13 @@ export const ChatWindow = ({ panHandlers }) => {
104
104
  >
105
105
  {messages.map((msg, i) => (
106
106
 
107
- <View key={i} style={styles.messageWrapper}>
107
+ <View key={msg.id || msg.message_id || i} style={styles.messageWrapper}>
108
108
  {msg.type !== "middle" && (
109
109
  <View style={[ styles.messageBubble, msg.type === "user" ? styles.userMessage : styles.aiMessage,]}>
110
- <Markdown style={{ body: { color: msg.type === "user" ? "#ffffff" : "#161616",fontSize: 16, lineHeight: 22 }}}>
111
- {msg.text && typeof msg.text === 'string' ? msg.text : (msg.text?.toString() || '')}
110
+
111
+ <Markdown style={{ body: { color: msg.type === "user" ? "#ffffff" : "#161616",fontSize: 16, lineHeight: 22, includeFontPadding: false, textAlignVertical: 'center' }}}>
112
+ {typeof msg.text === 'string' ? msg.text : String(msg.text || '')}
113
+
112
114
  </Markdown>
113
115
  {(msg.type == 'ai' && i != 0 && msg.message_id ) &&
114
116
  <Feedback message={msg} messageId={msg.message_id}/>
@@ -118,10 +120,14 @@ export const ChatWindow = ({ panHandlers }) => {
118
120
 
119
121
  {msg.type == "middle" && (
120
122
  <View style={[styles.middleMessageBubble, styles.middleMessage]}>
121
- <Ionicons name="sparkles-outline" size={16} style={{marginRight: 10, marginTop: 10}}/>
123
+ <Text style={{marginRight: 10, marginTop: 10}} allowFontScaling={false}>
124
+ <Ionicons name="sparkles-outline" size={16} color="#161616"/>
125
+ </Text>
122
126
  <View style={styles.middleMessageText}>
123
- <Markdown style={{ body: { color: msg.type === "user" ? "#ffffff" : "#161616",fontSize: 16, lineHeight: 22 }}}>
124
- {msg.text && typeof msg.text === 'string' ? msg.text : (msg.text?.toString() || '')}
127
+
128
+ <Markdown style={{ body: { color: msg.type === "user" ? "#ffffff" : "#161616",fontSize: 16, lineHeight: 22, includeFontPadding: false, textAlignVertical: 'center' }}}>
129
+ {typeof msg.text === 'string' ? msg.text : String(msg.text || '')}
130
+
125
131
  </Markdown>
126
132
  </View>
127
133
  </View>
@@ -238,6 +244,8 @@ const styles = StyleSheet.create({
238
244
  color: "#004687",
239
245
  fontSize: 13,
240
246
  textAlign: "left",
247
+ includeFontPadding: false,
248
+ textAlignVertical: "center",
241
249
  },
242
250
  ghostMessageContainer: {
243
251
  alignSelf: 'flex-start',
@@ -297,6 +305,8 @@ const styles = StyleSheet.create({
297
305
  color: 'white',
298
306
  fontSize: 16,
299
307
  marginRight: 8,
308
+ includeFontPadding: false,
309
+ textAlignVertical: "center",
300
310
  },
301
311
  middleMessageBubble:{
302
312
  padding: 6,