import type { FocusEventHandler } from "react"; import { startTransition, useState } from "react"; import { Box, Card, Combobox, Flex, Image, Indicator, InputBase, Paper, Skeleton, Stack, Text, UnstyledButton, useCombobox, } from "@mantine/core"; import { clientApi } from "@homarr/api/client"; import { useScopedI18n } from "@homarr/translation/client"; interface IconPickerProps { initialValue?: string; onChange: (iconUrl: string) => void; error?: string | null; onFocus?: FocusEventHandler; onBlur?: FocusEventHandler; } export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: IconPickerProps) => { const [value, setValue] = useState(initialValue ?? ""); const [search, setSearch] = useState(initialValue ?? ""); const [previewUrl, setPreviewUrl] = useState(initialValue ?? null); const tCommon = useScopedI18n("common"); const [data] = clientApi.icon.findIcons.useSuspenseQuery({ searchText: search, }); const combobox = useCombobox({ onDropdownClose: () => combobox.resetSelectedOption(), }); const totalOptions = data.icons.reduce((acc, group) => acc + group.icons.length, 0); const groups = data.icons.map((group) => { const options = group.icons.map((item) => ( { const value = item.url; startTransition(() => { setValue(value); setPreviewUrl(value); setSearch(value); onChange(value); combobox.closeDropdown(); }); }} key={item.id} > )); return ( {group.slug} {options} ); }); return ( } // eslint-disable-next-line @next/next/no-img-element leftSection={previewUrl ? : null} value={search} onChange={(event) => { combobox.openDropdown(); combobox.updateSelectedOptionIndex(); setSearch(event.currentTarget.value); setValue(event.currentTarget.value); setPreviewUrl(null); onChange(event.currentTarget.value); }} onClick={() => combobox.openDropdown()} onFocus={(event) => { onFocus?.(event); combobox.openDropdown(); }} onBlur={(event) => { onBlur?.(event); combobox.closeDropdown(); setPreviewUrl(value); setSearch(value || ""); }} rightSectionPointerEvents="none" withAsterisk error={error} label={tCommon("iconPicker.label")} placeholder={tCommon("iconPicker.header", { countIcons: data.countIcons })} /> {totalOptions > 0 ? ( {groups} ) : ( Array(15) .fill(0) .map((_, index: number) => ( )) )} ); };