"use client"; import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; import { EMOJIS, FREQUENT, searchEmojis, type EmojiCategory } from "@/lib/emoji"; import { Search } from "lucide-react"; const CATS: EmojiCategory[] = ["Smileys", "Gestures", "Activity", "Animals", "Food", "Travel", "Objects", "Symbols"]; export function EmojiPicker({ onPick, onClose, align = "left", }: { onPick: (emoji: string) => void; onClose: () => void; align?: "left" | "right"; }) { const ref = useRef(null); const [q, setQ] = useState(""); const [pos, setPos] = useState<{ v: "up" | "down"; h: "left" | "right" }>({ v: "up", h: align }); // auto-place: flip up/down + left/right based on available space (tooltip-style) useLayoutEffect(() => { const wrap = (ref.current?.offsetParent as HTMLElement | null) ?? ref.current; const r = wrap?.getBoundingClientRect(); if (!r) return; const H = 300, W = 300; const v = r.top < H + 12 && window.innerHeight - r.bottom > r.top ? "down" : "up"; const h = window.innerWidth - r.left < W ? "right" : "left"; setPos({ v, h }); }, []); useEffect(() => { const onDoc = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) onClose(); }; const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") { e.stopPropagation(); onClose(); } }; const t = setTimeout(() => document.addEventListener("mousedown", onDoc), 0); document.addEventListener("keydown", onKey); return () => { clearTimeout(t); document.removeEventListener("mousedown", onDoc); document.removeEventListener("keydown", onKey); }; }, [onClose]); const results = useMemo(() => (q ? searchEmojis(q, 64) : null), [q]); return (
setQ(e.target.value)} placeholder="Search emoji…" className="w-full bg-transparent py-1.5 text-[13px] outline-none placeholder:text-dim" />
{results ? ( e.e)} onPick={onPick} /> ) : ( <> Frequently used {CATS.map((c) => (
{c} e.c === c).map((e) => e.e)} onPick={onPick} />
))} )} {results && results.length === 0 &&
No emoji found
}
Tip: type :tick: in a message for ✅
); } function CatLabel({ children }: { children: React.ReactNode }) { return
{children}
; } function Grid({ list, onPick }: { list: string[]; onPick: (e: string) => void }) { return (
{list.map((e, i) => ( ))}
); }