fix(chat): keep mobile send from losing focus
This commit is contained in:
@@ -10,6 +10,7 @@ import { ChatSendButton } from "./chat-send-button";
|
||||
import styles from "./chat-input-bar.module.css";
|
||||
|
||||
const log = new Logger("AppChatComponentsChatInputBar");
|
||||
const POINTER_SEND_CLICK_DEDUPE_MS = 500;
|
||||
|
||||
export interface ChatInputBarProps {
|
||||
disabled?: boolean;
|
||||
@@ -19,12 +20,15 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
const dispatch = useChatDispatch();
|
||||
const [input, setInput] = useState("");
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const barRef = useRef<HTMLDivElement>(null);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const lastPointerSendAtRef = useRef(0);
|
||||
|
||||
const hasContent = input.trim().length > 0;
|
||||
|
||||
useKeyboardHeight({
|
||||
targetRef: textareaRef,
|
||||
containerRef: barRef,
|
||||
active: isFocused,
|
||||
onKeyboardDismiss: () => {
|
||||
log.important("info", "[chat-input-bar] keyboard dismissed", {
|
||||
@@ -51,9 +55,23 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
setIsFocused(focused);
|
||||
};
|
||||
|
||||
const handleSend = () => {
|
||||
if (!hasContent) return;
|
||||
const handleSend = (source: "click" | "keyboard" | "pointerdown") => {
|
||||
if (source === "click") {
|
||||
const elapsed = Date.now() - lastPointerSendAtRef.current;
|
||||
if (elapsed >= 0 && elapsed < POINTER_SEND_CLICK_DEDUPE_MS) {
|
||||
log.important("info", "[chat-input-bar] suppress duplicate click", {
|
||||
elapsed,
|
||||
contentLength: input.length,
|
||||
hasContent,
|
||||
disabled,
|
||||
isFocused,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (disabled || !hasContent) return;
|
||||
log.debug("[chat-input-bar] handleSend", {
|
||||
source,
|
||||
contentLength: input.length,
|
||||
contentPreview: input.slice(0, 50),
|
||||
hasContent,
|
||||
@@ -61,6 +79,7 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
isFocused,
|
||||
});
|
||||
log.important("info", "[chat-input-bar] send", {
|
||||
source,
|
||||
contentLength: input.length,
|
||||
hasContent,
|
||||
disabled,
|
||||
@@ -71,21 +90,30 @@ export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
|
||||
textareaRef.current?.focus();
|
||||
};
|
||||
|
||||
const handlePointerDownSend = () => {
|
||||
lastPointerSendAtRef.current = Date.now();
|
||||
handleSend("pointerdown");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${styles.bar} ${isFocused ? styles.barFocused : ""}`}>
|
||||
<div
|
||||
ref={barRef}
|
||||
className={`${styles.bar} ${isFocused ? styles.barFocused : ""}`}
|
||||
>
|
||||
<div className={`${styles.row} ${isFocused ? styles.rowFocused : ""}`}>
|
||||
<ChatInputTextField
|
||||
ref={textareaRef}
|
||||
value={input}
|
||||
onChange={handleInputChange}
|
||||
onSubmit={handleSend}
|
||||
onSubmit={() => handleSend("keyboard")}
|
||||
onFocusChange={handleFocusChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<ChatSendButton
|
||||
disabled={disabled}
|
||||
hasContent={hasContent}
|
||||
onClick={handleSend}
|
||||
onClick={() => handleSend("click")}
|
||||
onPointerDownSend={handlePointerDownSend}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user