import { useState, useId, useMemo, useEffect } from 'react' import { ChevronDown, ChevronUp } from 'lucide-react' import { haystackForEmoji, matchesEmojiSearch } from './emojiIconPickerKeywords.js' /** * Kuratierte Emoji-Gruppen (viele Einzel-Glyphen für breite OS-Unterstützung). * Erste Sport-Gruppe: typische Vereins-/Breitensportarten in Deutschland (DOSB/Nischensport mit abgedeckt). * Erweiterbar: prop `extraGroups` an EmojiIconPicker, oder diese Konstante editieren. */ export const EMOJI_ICON_GROUPS = [ { label: 'Sportarten (typisch Deutschland)', emojis: [ // Vereins- & Breitensport (Reihenfolge: Fußball, Handball, Kampfsport Gi = Karate/Judo/…, …) '⚽', '🤾', '🤾‍♂️', '🤾‍♀️', '🥋', '🏐', '🏀', '🎾', '🏓', '🏸', '🏒', '🏑', '🥍', '🏈', '🏉', '⚾', '🥎', '⛹️', '⛹️‍♂️', '⛹️‍♀️', '🥅', '⛷️', '🎿', '🏂', '🛷', '⛸️', '🥌', '🚴', '🚴‍♂️', '🚴‍♀️', '🚵', '🚵‍♂️', '🚵‍♀️', '🏃', '🏃‍♂️', '🏃‍♀️', '🏃‍➡️', '🚶', '🥾', '🏊', '🏊‍♂️', '🏊‍♀️', '🤽', '🤽‍♂️', '🤽‍♀️', '🤿', '🏄', '🏄‍♂️', '🏄‍♀️', '🚣', '🚣‍♂️', '🚣‍♀️', '⛵', '🧗', '🧗‍♂️', '🧗‍♀️', '🏋️', '🏋️‍♂️', '🏋️‍♀️', '🤸', '🤸‍♂️', '🤸‍♀️', '🥊', '🤼', '🤺', '🏇', '⛳', '🏌️', '🏌️‍♂️', '🏌️‍♀️', '💃', '🕺', '🧘', '🧘‍♂️', '🧘‍♀️', '🛼', '🛹', '🎯', '🎳', '🏟️', '🏆', '🥇', '🥈', '🥉' ] }, { label: 'Weitere Sportarten & Hobbysport', emojis: [ '🎱', '🎣', '🤹', '🪁', '🥏', '🛶', '🏹', '🌊', '🏖️', '🛣️', '🧭', '🏕️', '⛺' ] }, { label: 'Yoga, Geist, Balance', emojis: [ '🧘', '🧘‍♂️', '🧘‍♀️', '🪷', '☯️', '🕉️', '🙏', '🧎', '🧍', '💭', '📿', '🎼', '🎹', '🥁', '🎸', '🎺', '🔔', '✨', '🌟', '💫', '🔮' ] }, { label: 'Outdoor & Natur', emojis: [ '⛰️', '🏔️', '🗻', '🌋', '🏕️', '⛺', '🧭', '🗺️', '🌲', '🌳', '🌴', '🍃', '🍂', '🌿', '☘️', '🪨', '🏞️', '🏜️', '🏖️', '🌅', '🌄', '🌈', '⛅', '🌤️', '☀️', '🌙', '⭐', '🌠', '❄️', '☃️', '⛄' ] }, { label: 'Körper & Medizin', emojis: [ '💪', '🦾', '🦵', '🦶', '🖐️', '✋', '👣', '❤️', '🩷', '💙', '💚', '🫀', '🫁', '🧠', '👁️', '👂', '🦷', '🦴', '🧬', '⚕️', '🩺', '🩹', '🩼', '💊', '🌡️', '🔬', '🧪', '🧫', '♿', '⚖️', '📏', '📐' ] }, { label: 'Ernährung & Getränke', emojis: [ '🍎', '🍐', '🍊', '🍋', '🍌', '🍉', '🍇', '🍓', '🫐', '🍒', '🍑', '🥭', '🍍', '🥝', '🍅', '🥑', '🥦', '🥬', '🥒', '🌶️', '🫑', '🌽', '🥕', '🫒', '🧄', '🧅', '🥔', '🍠', '🥐', '🍞', '🥖', '🥨', '🧀', '🥚', '🍳', '🧈', '🥞', '🧇', '🥓', '🥩', '🍗', '🍖', '🌭', '🍔', '🍟', '🍕', '🫓', '🥙', '🌮', '🌯', '🥗', '🍝', '🍜', '🍲', '🍛', '🍣', '🍱', '🥟', '🦪', '🍤', '🍙', '🍚', '🍘', '🍥', '🥠', '🥮', '🍢', '🍡', '🍧', '🍨', '🍦', '🥧', '🧁', '🍰', '🎂', '🍮', '🍭', '🍬', '🍫', '🍿', '🍩', '🍪', '🌰', '🥜', '🍯', '🥛', '🍼', '🫖', '☕', '🍵', '🧃', '🥤', '🧋', '🍶', '🍺', '🍻', '🥂', '🍷', '🥃', '🍸', '🍹', '🧉', '🍾', '💧', '🧊' ] }, { label: 'Schlaf & Erholung', emojis: [ '😴', '🛌', '🛏️', '💤', '🌙', '🌛', '🌜', '💆', '💆‍♂️', '💆‍♀️', '🧖', '🧖‍♂️', '🧖‍♀️', '🧴', '🛁', '🚿', '🪥', '🩴', '🧘', '🕯️' ] }, { label: 'Stimmung & Motivation Smileys', emojis: [ '😊', '🙂', '😌', '😎', '🤩', '🥳', '😤', '💯', '🙌', '👏', '🤝', '👍', '👎', '✊', '🤛', '🤜', '💪', '🦵', '🧗', '🔥', '💥', '⚡', '🎉', '🏆', '🥇', '🥈', '🥉', '🎖️', '🏅', '😅', '🤔', '🧐', '😇' ] }, { label: 'Tiere (Maskottchen)', emojis: [ '🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐨', '🐯', '🦁', '🐮', '🐷', '🐸', '🐵', '🐔', '🐧', '🐦', '🐤', '🦆', '🦅', '🦉', '🦇', '🐺', '🐗', '🐴', '🦄', '🐝', '🐛', '🦋', '🐌', '🐞', '🐜', '🦗', '🕷️', '🦂', '🐢', '🐍', '🦎', '🦖', '🦕', '🐙', '🦑', '🦐', '🦞', '🐠', '🐟', '🐬', '🐳', '🐋', '🦈', '🐊' ] }, { label: 'Symbole & Pointers', emojis: [ '🎯', '📊', '📈', '📉', '🧮', '📋', '📌', '📍', '🔖', '🏷️', '✏️', '✒️', '🖊️', '📎', '🔗', '⛓️', '🔒', '🔓', '🔑', '🗝️', '🔨', '🛠️', '⚙️', '🧰', '💡', '🔦', '🏮', '🪔', '📣', '📢', '🔔', '🔕', '⏱️', '⏰', '🕐', '📅', '🗓️', '✅', '☑️', '✔️', '❌', '⭕', '❗', '❓', '💬', '🗨️', '📝', '📖', '🪄', '🎪', '🎭', '🎬', '🎨', '🖼️', '🧩', '♟️', '🎲', '🧸' ] }, { label: 'Fahrzeuge & Weg', emojis: [ '🚗', '🚕', '🚙', '🚌', '🚎', '🏎️', '🚓', '🚑', '🚒', '🚐', '🛻', '🚚', '🚛', '🚜', '🛵', '🏍️', '🛺', '🚲', '🛴', '🛹', '🚁', '✈️', '🛫', '🛬', '🪂', '🚀', '🛶', '⛵', '🚤', '🛥️', '🛳️', '⛴️', '🚢', '⚓', '🗼', '🏟️' ] } ] /** * Wiederverwendbare Emoji-/Icon-Auswahl: Vorschau, Freitext (inkl. System-Emoji-Picker), * optional ausklappbare Vorschläge. * * @param {string} value – aktueller Icon-String (meist ein Emoji) * @param {(next: string) => void} onChange * @param {string} [placeholder] * @param {number} [maxLength=10] * @param {boolean} [disabled] * @param {string} [id] – optionale ID für das Textfeld (Label for=) * @param {boolean} [defaultExpanded=false] – Vorschlags-Bereich initial offen * @param {{ label: string, emojis: string[] }[]} [extraGroups=[]] – eigene Gruppe(n) anhängen (z. B. Projekt-Favoriten) */ export default function EmojiIconPicker({ value, onChange, placeholder = '📝', maxLength = 10, disabled = false, id: idProp, defaultExpanded = false, extraGroups = [] }) { const uid = useId() const inputId = idProp || `emoji-icon-${uid}` const searchInputId = `${inputId}-picker-search` const [open, setOpen] = useState(defaultExpanded) const [pickerSearch, setPickerSearch] = useState('') const groups = extraGroups.length > 0 ? [...EMOJI_ICON_GROUPS, ...extraGroups] : EMOJI_ICON_GROUPS useEffect(() => { if (!open) setPickerSearch('') }, [open]) const filteredGroups = useMemo(() => { const q = pickerSearch if (!q.trim()) { return groups } return groups .map((g) => ({ ...g, emojis: g.emojis.filter((em) => matchesEmojiSearch(haystackForEmoji(em, g.label), q)) })) .filter((g) => g.emojis.length > 0) }, [groups, pickerSearch]) const handleInput = (e) => { onChange(e.target.value.slice(0, maxLength)) } const pick = (em) => { onChange(em.slice(0, maxLength)) } return (
{value || '·'} {!!value && !disabled && ( )}
{open && (
setPickerSearch(e.target.value)} placeholder="z. B. rollschuh, karate, apfel…" disabled={disabled} autoComplete="off" spellCheck={false} inputMode="search" style={{ width: '100%', marginBottom: 12, boxSizing: 'border-box' }} /> {filteredGroups.length === 0 && pickerSearch.trim() && (

Keine Treffer für „{pickerSearch.trim()}“. Andere Begriffe probieren oder oben ein Emoji einfügen (z. B. Win + .).

)} {filteredGroups.map((group, gi) => (
{group.label}
{group.emojis.map((em, ei) => ( ))}
))}

Du kannst auch direkt in das Feld tippen oder das Betriebssystem-Emoji-Menü nutzen (z. B. Win + . unter Windows). Mehrere Wörter verfeinern die Suche: jedes muss in den Stichwörtern vorkommen.{' '} Inline Skating: Es gibt kein separates Inliner-Emoji; 🛼 (Rollschuh) wird dafür oft genutzt – Suchbegriffe: rollschuh, inline, inliner.{' '} Karate / Kampfsport mit Gi: 🥋 (gemeinsames Unicode-Symbol für u. a. Karate, Judo, Ju-Jitsu).

)}
) }