A React Native app for the ultimate thinking partner.
1import React, { useState, useEffect, useRef } from 'react';
2import { TextInput, StyleSheet, Platform } from 'react-native';
3
4interface MessageInputProps {
5 onTextChange: (text: string) => void;
6 onSendMessage: () => void;
7 isSendingMessage: boolean;
8 colorScheme: 'light' | 'dark';
9 onFocusChange: (focused: boolean) => void;
10 clearTrigger: number;
11}
12
13const MessageInput: React.FC<MessageInputProps> = ({
14 onTextChange,
15 onSendMessage,
16 isSendingMessage,
17 colorScheme,
18 onFocusChange,
19 clearTrigger,
20}) => {
21 const [inputText, setInputText] = useState('');
22 const inputRef = useRef<any>(null);
23
24 useEffect(() => {
25 if (clearTrigger > 0) {
26 setInputText('');
27 }
28 }, [clearTrigger]);
29
30 const handleTextChange = React.useCallback((text: string) => {
31 setInputText(text);
32 onTextChange(text);
33 }, [onTextChange]);
34
35 const handleSubmit = React.useCallback(() => {
36 if (inputText.trim() && !isSendingMessage) {
37 onSendMessage();
38 }
39 }, [inputText, isSendingMessage, onSendMessage]);
40
41 const inputStyle = React.useMemo(() => [
42 styles.textInput,
43 {
44 color: colorScheme === 'dark' ? '#FFFFFF' : '#000000',
45 backgroundColor: colorScheme === 'dark' ? '#242424' : '#FFFFFF',
46 fontFamily: 'Lexend_400Regular',
47 }
48 ], [colorScheme]);
49
50 const handleContentSizeChange = React.useCallback((event: any) => {
51 if (Platform.OS !== 'web') {
52 // Native platforms can use onContentSizeChange
53 const contentHeight = event.nativeEvent.contentSize.height;
54 const newHeight = Math.min(Math.max(contentHeight, 40), 120);
55 if (inputRef.current) {
56 inputRef.current.setNativeProps({ style: { height: newHeight } });
57 }
58 }
59 }, []);
60
61 const handleFocus = React.useCallback(() => onFocusChange(true), [onFocusChange]);
62 const handleBlur = React.useCallback(() => onFocusChange(false), [onFocusChange]);
63
64 return (
65 <TextInput
66 ref={inputRef}
67 style={inputStyle}
68 placeholder="What's on your mind?"
69 placeholderTextColor={colorScheme === 'dark' ? '#666666' : '#999999'}
70 value={inputText}
71 onChangeText={handleTextChange}
72 onFocus={handleFocus}
73 onBlur={handleBlur}
74 multiline
75 maxLength={4000}
76 editable={!isSendingMessage}
77 autoFocus
78 onSubmitEditing={handleSubmit}
79 onContentSizeChange={handleContentSizeChange}
80 />
81 );
82};
83
84const styles = StyleSheet.create({
85 textInput: {
86 width: '100%',
87 minHeight: 40,
88 maxHeight: 120,
89 paddingLeft: 18,
90 paddingRight: 130,
91 paddingTop: 8,
92 paddingBottom: 8,
93 borderRadius: 24,
94 fontSize: 16,
95 lineHeight: 24,
96 borderWidth: 0,
97 ...(Platform.OS === 'web' && {
98 // @ts-ignore
99 outline: 'none',
100 WebkitAppearance: 'none',
101 MozAppearance: 'none',
102 resize: 'none',
103 overflowY: 'auto',
104 }),
105 },
106});
107
108export default React.memo(MessageInput);