import React, { ChangeEvent, KeyboardEvent, FormEvent, useCallback, useRef, useMemo, useState, } from "react"; import { useChat, useDrawer, useEmojis } from "../../hooks"; import { EmojiDrawer, QuickEmojis } from "../emoji"; import "./UserInput.css"; export function UserInput() { const { draft, sendMessage, updateDraft } = useChat(); const { reveal, hide, open } = useDrawer(); 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); 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") { handleSendMessage(); } }, [handleSendMessage] ); const handleOpenEmojiDrawer = useCallback( () => reveal({ title: "Select an emoji", content: ( builtChatInput.current?.focus()} /> ), }), [] ); const handleCloseEmojiDrawer = useCallback(() => { builtChatInput.current?.focus(); hide(); }, [hide]); const handleSelectEmoji = useCallback((emoji: string) => { updateDraft((prev) => `${prev} :${emoji}: `); }, []); 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] ); return (
{quickEmojis.length > 0 && (
)}