import { Check, Loader2, Search, X } from "lucide-react";
import { useEffect, useState } from "react";
import { api, errorMessage } from "../api";
import type { EmojiRow } from "../types";
import { StaticLottie } from "./StaticLottie";
function isAnimated(mime: string): boolean {
const m = mime.toLowerCase();
return m.includes("tgsticker") || m.includes("lottie") || m.includes("json");
}
function EmojiThumb({ row }: { row: EmojiRow }) {
const [failed, setFailed] = useState(!isAnimated(row.MimeType));
useEffect(() => {
setFailed(!isAnimated(row.MimeType));
}, [row.DocumentID, row.MimeType]);
if (failed) {
return
{row.Alt || "🙂"}
;
}
return (
api.emojiAnimation(row.DocumentID)}
onError={() => setFailed(true)}
/>
);
}
// EmojiPicker searches every custom-emoji document already on this
// deployment -- unlike the Emoji admin page's per-pack browsing, this is a
// flat document search with no system/non-system distinction, so a bundled
// icon from a default pack (e.g. Topics' ✅) is just as findable as a
// hand-uploaded one. Lets the caller select a document id by clicking it
// instead of typing one from memory; used wherever a raw document id field
// otherwise has nothing else in the panel to pick from (e.g. a
// bot-verification icon).
export function EmojiPicker({
label,
value,
onChange
}: {
label: string;
value: string;
onChange: (documentID: string) => void;
}) {
const [query, setQuery] = useState("");
const [rows, setRows] = useState([]);
const [busy, setBusy] = useState(false);
const [error, setError] = useState("");
const selected = rows.find((row) => row.DocumentID === value) ?? null;
async function search() {
setBusy(true);
setError("");
const params = new URLSearchParams({ limit: "24" });
if (query.trim()) params.set("q", query.trim());
try {
const result = await api.emoji(params);
setRows(result.rows ?? []);
} catch (err) {
setError(errorMessage(err));
} finally {
setBusy(false);
}
}
useEffect(() => {
void search();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
{label}
{value ? (
) : null}
{value ? (
{selected?.Alt || "—"}{value}
{selected?.SetTitle || "-"}
) : null}
setQuery(event.target.value)}
onKeyDown={(event) => {
if (event.key === "Enter") {
event.preventDefault();
void search();
}
}}
placeholder={"Search document ID or emoji"}
/>