import React, { ChangeEvent, KeyboardEvent, FormEvent, useCallback, useRef, useMemo, useState, useEffect, } from "react"; import cx from "classnames"; import { useChat, useEmojis } from "../../hooks"; import { QuickEmojis } from "../emoji"; import "./UserInput.css"; interface Props { large?: boolean; onFocus(): void; onBlur(): void; } export function UserInput({ large = false, onFocus, onBlur }: Props) { const { draft, userToDm, sendMessage, updateDraft } = useChat(); const builtChatInput = useRef(null); const { visible, addQuery } = useEmojis(); const form = useRef(null); const [typingOffset, setTypingOffset] = useState(0); const quickEmojis = useMemo( () => visible.slice(0, process.env.QUICK_EMOJIS_MAX_COUNT), [visible] ); const handleChange = useCallback( (event: ChangeEvent) => { const input = event.target.value; const [openEmojiToken, closeEmojiToken] = locateEmojiTokens(input); const emojiSegment = input.slice(openEmojiToken + 1, closeEmojiToken + 1); updateDraft(input); addQuery( openEmojiToken === -1 || emojiSegment.includes(" ") ? "" : emojiSegment ); setTypingOffset( emojiSegment.length * process.env.APPROXIMATE_CHARACTER_WIDTH ); }, [] ); const handleSendMessage = useCallback( (event?: FormEvent) => { event?.preventDefault(); sendMessage(); }, [sendMessage] ); const handleKeyUp = useCallback( (event: KeyboardEvent) => { if (event.key === "Enter" && !event.shiftKey) { handleSendMessage(); } }, [handleSendMessage] ); const handleInsertQuickEmoji = useCallback( (emoji: string) => { const [openEmojiToken, closeEmojiToken] = locateEmojiTokens(draft); const toReplace = draft.slice(openEmojiToken, closeEmojiToken + 1); updateDraft((prev) => prev.replace(toReplace, `:${emoji}: `)); addQuery(""); builtChatInput.current?.focus(); }, [draft] ); const handleFocus = useCallback(() => { builtChatInput.current?.scrollIntoView({ behavior: "smooth" }); onFocus(); }, [onFocus]); // Listen for changes from the Emoji Modal and reflect them in draft useEffect(() => { const handleEmojiInsert = (event: CustomEvent<{ emoji: string }>) => updateDraft((prev) => `${prev} ${event.detail.emoji} `); document.addEventListener("emojiInserted", handleEmojiInsert); return () => { document.removeEventListener("emojiInserted", handleEmojiInsert); } }, []); useEffect(() => { if (userToDm) { builtChatInput.current?.focus(); } }, [userToDm]) return (
{quickEmojis.length > 0 && (
)}