import { useState, useRef, useEffect, useCallback } from 'react' import { EMOJI_GROUPS, EMOJIS_BY_GROUP, GROUP_SHORT_LABELS, searchEmojis } from '../utils/emoji' interface EmojiPickerProps { onSelect: (emoji: string) => void onClose: () => void } export function EmojiPicker({ onSelect, onClose }: EmojiPickerProps) { const [search, setSearch] = useState('') const inputRef = useRef(null) const containerRef = useRef(null) const scrollRef = useRef(null) useEffect(() => { setTimeout(() => inputRef.current?.focus(), 50) }, []) useEffect(() => { const handler = (e: KeyboardEvent) => { if (e.key === 'Escape') { e.preventDefault() e.stopPropagation() onClose() } } window.addEventListener('keydown', handler, true) return () => window.removeEventListener('keydown', handler, true) }, [onClose]) // Close when clicking outside useEffect(() => { const handler = (e: MouseEvent) => { if (containerRef.current && !containerRef.current.contains(e.target as Node)) { onClose() } } const timer = setTimeout(() => document.addEventListener('mousedown', handler), 0) return () => { clearTimeout(timer); document.removeEventListener('mousedown', handler) } }, [onClose]) const handleSelect = useCallback((emoji: string) => { onSelect(emoji) onClose() }, [onSelect, onClose]) const searchResults = search.trim() ? searchEmojis(search) : null const isSearching = searchResults !== null return (
setSearch(e.target.value)} data-testid="emoji-picker-search" />
{isSearching ? ( searchResults.length > 0 ? (
{searchResults.map(entry => ( ))}
) : (
No emojis found
) ) : ( EMOJI_GROUPS.map(group => { const emojis = EMOJIS_BY_GROUP.get(group) if (!emojis?.length) return null return (
{GROUP_SHORT_LABELS[group]}
{emojis.map(entry => ( ))}
) }) )}
) }