Skip to content
This repository was archived by the owner on Nov 13, 2024. It is now read-only.

Commit a53b9ce

Browse files
authored
feat(lib): add additional options for TextInput and TextArea (#121)
1 parent 218247d commit a53b9ce

3 files changed

Lines changed: 61 additions & 15 deletions

File tree

packages/common/src/message-input/message-input.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ export interface CommonMessageInputProps {
4242
* Allows users to compose messages using text and emojis
4343
* and automatically publish them on PubNub channels upon sending.
4444
*/
45-
export const useMessageInputCore = (props: CommonMessageInputProps) => {
45+
export const useMessageInputCore = <T extends CommonMessageInputProps>(props: T) => {
4646
const pubnub = usePubNub();
4747

48-
const [text, setText] = useState(props.draftMessage || "");
48+
const { draftMessage, senderInfo, onSend, onBeforeSend, typingIndicator, ...inputProps } = props;
49+
50+
const [text, setText] = useState(draftMessage || "");
4951
const [file, setFile] = useState<File | UriFileInput>(null);
5052
const [typingIndicatorSent, setTypingIndicatorSent] = useState(false);
5153
const [loader, setLoader] = useState(false);
@@ -75,21 +77,21 @@ export const useMessageInputCore = (props: CommonMessageInputProps) => {
7577
id: uuid.v4(),
7678
text: file ? "" : text,
7779
type: file ? "" : "default",
78-
...(props.senderInfo && { sender: users.find((u) => u.id === pubnub.getUUID()) }),
80+
...(senderInfo && { sender: users.find((u) => u.id === pubnub.getUUID()) }),
7981
createdAt: new Date().toISOString(),
8082
} as MessagePayload;
8183
setLoader(true);
8284

8385
if (file) {
8486
await pubnub.sendFile({ channel, file, message });
85-
props.onSend && props.onSend(file);
87+
onSend && onSend(file);
8688
} else if (text) {
87-
if (props.onBeforeSend) message = props.onBeforeSend(message) || message;
89+
if (onBeforeSend) message = onBeforeSend(message) || message;
8890
await pubnub.publish({ channel, message });
89-
props.onSend && props.onSend(message);
91+
onSend && onSend(message);
9092
}
9193

92-
if (props.typingIndicator) stopTypingIndicator();
94+
if (typingIndicator) stopTypingIndicator();
9395
clearInput();
9496
} catch (e) {
9597
onError(e);
@@ -153,5 +155,6 @@ export const useMessageInputCore = (props: CommonMessageInputProps) => {
153155
theme,
154156
startTypingIndicator,
155157
stopTypingIndicator,
158+
...inputProps,
156159
};
157160
};

packages/react-native/src/message-input/message-input.tsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { FC, useState } from "react";
2-
import { View, Image, TouchableOpacity, TextInput, Animated } from "react-native";
2+
import { View, Image, TouchableOpacity, TextInput, Animated, TextInputProps } from "react-native";
33
import { CommonMessageInputProps, useMessageInputCore } from "@pubnub/common-chat-components";
44
import { getDocumentAsync } from "expo-document-picker";
55
import { useStyle, useRotation } from "../helpers";
@@ -12,6 +12,8 @@ import ImageIcon from "../icons/image.png";
1212
import XCircleIcon from "../icons/x-circle.png";
1313
import * as ImagePicker from "expo-image-picker";
1414
import { FileModal } from "./file-modal";
15+
import { NativeSyntheticEvent } from "react-native/Libraries/Types/CoreEventTypes";
16+
import { TextInputKeyPressEventData } from "react-native/Libraries/Components/TextInput/TextInput";
1517

1618
export type MessageInputProps = CommonMessageInputProps & {
1719
/** Options to provide custom StyleSheet for the component. It will be merged with the default styles. */
@@ -23,7 +25,19 @@ export type MessageInputProps = CommonMessageInputProps & {
2325
setModalVisible: React.Dispatch<React.SetStateAction<boolean>>;
2426
}) => JSX.Element;
2527
onChange?: (newText: string) => void;
26-
};
28+
sendMessageOnSubmitEditing?: boolean;
29+
} & Omit<
30+
TextInputProps,
31+
| "testID"
32+
| "autoComplete"
33+
| "multiline"
34+
| "onChangeText"
35+
| "placeholder"
36+
| "style"
37+
| "placeholderTextColor"
38+
| "editable"
39+
| "value"
40+
>;
2741

2842
/**
2943
* Allows users to compose messages using text and emojis
@@ -42,6 +56,7 @@ export const MessageInput: FC<MessageInputProps> = (props: MessageInputProps) =>
4256
file,
4357
setText,
4458
onError,
59+
...otherTextInputProps
4560
} = useMessageInputCore(props);
4661
const style = useStyle<MessageInputStyle>({
4762
theme,
@@ -120,6 +135,14 @@ export const MessageInput: FC<MessageInputProps> = (props: MessageInputProps) =>
120135
}
121136
};
122137

138+
const handleKeyPress = (e: NativeSyntheticEvent<TextInputKeyPressEventData>) => {
139+
props.onKeyPress && props.onKeyPress(e);
140+
141+
if (e.nativeEvent.key == "Enter" && props.sendMessageOnSubmitEditing) {
142+
sendMessage();
143+
}
144+
};
145+
123146
/*
124147
/* Renderers
125148
*/
@@ -202,6 +225,7 @@ export const MessageInput: FC<MessageInputProps> = (props: MessageInputProps) =>
202225
{renderFileModal()}
203226
{!props.actionsAfterInput && renderActions()}
204227
<TextInput
228+
{...otherTextInputProps}
205229
testID="message-input"
206230
autoComplete="off"
207231
multiline={true}
@@ -211,6 +235,7 @@ export const MessageInput: FC<MessageInputProps> = (props: MessageInputProps) =>
211235
placeholderTextColor={style.messageInputPlaceholder.color}
212236
editable={!props.disabled && file == null}
213237
value={text}
238+
onKeyPress={handleKeyPress}
214239
/>
215240
{props.actionsAfterInput && renderActions()}
216241
{!props.disabled && (

packages/react/src/message-input/message-input.tsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import React, {
77
useEffect,
88
useRef,
99
useState,
10+
DetailedHTMLProps,
11+
TextareaHTMLAttributes,
1012
} from "react";
1113
import { CommonMessageInputProps, useMessageInputCore } from "@pubnub/common-chat-components";
1214
import { EmojiPickerElementProps } from "../types";
@@ -28,7 +30,18 @@ export type MessageInputProps = CommonMessageInputProps & {
2830
onChange?: (event: ChangeEvent<HTMLTextAreaElement>) => void;
2931
/** Callback to handle an event when the key is pressed in textarea. */
3032
onKeyPress?: (event: KeyboardEvent<HTMLTextAreaElement>) => void;
31-
};
33+
} & Omit<
34+
DetailedHTMLProps<TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>,
35+
| "className"
36+
| "data-testid"
37+
| "disabled"
38+
| "onChange"
39+
| "onKeyPress"
40+
| "placeholder"
41+
| "ref"
42+
| "rows"
43+
| "value"
44+
>;
3245

3346
/**
3447
* Allows users to compose messages using text and emojis
@@ -48,6 +61,10 @@ export const MessageInput: FC<MessageInputProps> = (props: MessageInputProps) =>
4861
theme,
4962
startTypingIndicator,
5063
stopTypingIndicator,
64+
fileUpload,
65+
sendButton,
66+
hideSendButton,
67+
...otherTextAreaProps
5168
} = useMessageInputCore(props);
5269

5370
const [emojiPickerShown, setEmojiPickerShown] = useState(false);
@@ -158,10 +175,10 @@ export const MessageInput: FC<MessageInputProps> = (props: MessageInputProps) =>
158175
) : (
159176
<>
160177
<button aria-label={addTitle} title={addTitle} onClick={() => fileRef.current.click()}>
161-
{props.fileUpload === "image" ? <ImageIcon /> : <FileIcon />}
178+
{fileUpload === "image" ? <ImageIcon /> : <FileIcon />}
162179
</button>
163180
<input
164-
accept={props.fileUpload === "image" ? "image/*" : "*"}
181+
accept={fileUpload === "image" ? "image/*" : "*"}
165182
className="pn-msg-input__fileInput"
166183
data-testid="file-upload"
167184
id="file-upload"
@@ -201,7 +218,7 @@ export const MessageInput: FC<MessageInputProps> = (props: MessageInputProps) =>
201218
<div className="pn-msg-input__emoji-toggle">
202219
{!props.disabled && props.emojiPicker && renderEmojiPicker()}
203220
</div>
204-
{!props.disabled && props.fileUpload && renderFileUpload()}
221+
{!props.disabled && fileUpload && renderFileUpload()}
205222
{props.extraActionsRenderer && props.extraActionsRenderer()}
206223
</div>
207224
);
@@ -215,6 +232,7 @@ export const MessageInput: FC<MessageInputProps> = (props: MessageInputProps) =>
215232
<div className="pn-msg-input__wrapper">
216233
{!props.actionsAfterInput && renderActions()}
217234
<textarea
235+
{...otherTextAreaProps}
218236
className="pn-msg-input__textarea"
219237
data-testid="message-input"
220238
disabled={props.disabled || !!file}
@@ -226,15 +244,15 @@ export const MessageInput: FC<MessageInputProps> = (props: MessageInputProps) =>
226244
value={text}
227245
/>
228246
{props.actionsAfterInput && renderActions()}
229-
{!props.hideSendButton && !props.disabled && (
247+
{!hideSendButton && !props.disabled && (
230248
<button
231249
className={`pn-msg-input__send ${isValidInputText() && "pn-msg-input__send--active"}`}
232250
disabled={loader || props.disabled}
233251
onClick={handleSendClick}
234252
aria-label="Send"
235253
title="Send"
236254
>
237-
{loader ? <SpinnerIcon /> : props.sendButton}
255+
{loader ? <SpinnerIcon /> : sendButton}
238256
</button>
239257
)}
240258
</div>

0 commit comments

Comments
 (0)