{"version":3,"file":"MunicipalitySearch.cjs","names":[],"sources":["../../src/br/MunicipalitySearch.tsx"],"sourcesContent":["import { useEffect, useId, useRef, useState, type ReactElement } from \"react\";\nimport { Input } from \"@/components/Input\";\nimport { useDebounce } from \"@/hooks\";\nimport { searchMunicipalities, type MunicipalityCentroid } from \"./geocode\";\nimport type { UF } from \"./locations\";\nimport styles from \"./MunicipalitySearch.module.css\";\n\nexport interface MunicipalitySearchProps {\n    /** Restrict the search to a single UF. */\n    uf?: UF;\n    /** Fired when a municipality is picked from the results. */\n    onSelect: (municipality: MunicipalityCentroid) => void;\n    /** Field label. */\n    label?: string;\n    /** Input placeholder. Default: `\"Buscar município…\"`. */\n    placeholder?: string;\n    /** Max results shown. Default: `8`. */\n    limit?: number;\n    /** Debounce in ms before searching. Default: `250`. */\n    debounceMs?: number;\n    /** Disable the field. */\n    disabled?: boolean;\n}\n\n/**\n * Debounced municipality autocomplete backed by the offline\n * {@link searchMunicipalities} index — no network. Type a partial name, pick a\n * result, and `onSelect` fires with its `{ id, name, uf, latitude, longitude }`.\n * Wire `onSelect` to a `BrazilStateMap` `selected` to highlight it on the map.\n *\n * @example\n * const [uf, setUf] = useState<UF>(\"SP\");\n * const [city, setCity] = useState<string | null>(null);\n * <MunicipalitySearch uf={uf} onSelect={(m) => setCity(m.name)} />\n * <BrazilStateMap uf={uf} selected={city} />\n */\nexport function MunicipalitySearch({\n    uf,\n    onSelect,\n    label,\n    placeholder = \"Buscar município…\",\n    limit = 8,\n    debounceMs = 250,\n    disabled = false,\n}: MunicipalitySearchProps): ReactElement {\n    const [query, setQuery] = useState<string>(\"\");\n    const [results, setResults] = useState<MunicipalityCentroid[]>([]);\n    const [open, setOpen] = useState<boolean>(false);\n    const debounced = useDebounce(query, debounceMs);\n    const listId = useId();\n    const blurTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n    useEffect(() => {\n        let active = true;\n        if (!debounced.trim()) {\n            setResults([]);\n            return;\n        }\n        void searchMunicipalities(debounced, { uf, limit }).then((hits) => {\n            if (active) setResults(hits);\n        });\n        return () => {\n            active = false;\n        };\n    }, [debounced, uf, limit]);\n\n    function choose(municipality: MunicipalityCentroid): void {\n        onSelect(municipality);\n        setQuery(municipality.name);\n        setOpen(false);\n    }\n\n    return (\n        <div className={styles.search}>\n            <Input\n                label={label}\n                value={query}\n                placeholder={placeholder}\n                disabled={disabled}\n                role=\"combobox\"\n                aria-expanded={open && results.length > 0}\n                aria-controls={listId}\n                autoComplete=\"off\"\n                onChange={(e) => {\n                    setQuery(e.target.value);\n                    setOpen(true);\n                }}\n                onFocus={() => setOpen(true)}\n                onBlur={() => {\n                    // Delay so a result click registers before the list closes.\n                    blurTimer.current = setTimeout(() => setOpen(false), 120);\n                }}\n            />\n            {open && results.length > 0 && (\n                <ul id={listId} className={styles.results} role=\"listbox\">\n                    {results.map((m) => (\n                        <li key={m.id}>\n                            <button\n                                type=\"button\"\n                                role=\"option\"\n                                aria-selected={false}\n                                className={styles.result}\n                                onMouseDown={(e) => e.preventDefault()}\n                                onClick={() => {\n                                    if (blurTimer.current) clearTimeout(blurTimer.current);\n                                    choose(m);\n                                }}\n                            >\n                                <span>{m.name}</span>\n                                <span className={styles.uf}>{m.uf}</span>\n                            </button>\n                        </li>\n                    ))}\n                </ul>\n            )}\n        </div>\n    );\n}\n"],"mappings":"sNAoCA,SAAgB,EAAmB,CAC/B,KACA,WACA,QACA,cAAc,oBACd,QAAQ,EACR,aAAa,IACb,WAAW,IAC2B,CACtC,GAAM,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAiB,EAAE,EACvC,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAAiC,CAAC,CAAC,EAC3D,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAkB,EAAK,EACzC,EAAY,EAAA,YAAY,EAAO,CAAU,EACzC,GAAA,EAAS,EAAA,MAAA,CAAM,EACf,GAAA,EAAY,EAAA,OAAA,CAA6C,IAAI,GAEnE,EAAA,EAAA,UAAA,KAAgB,CACZ,IAAI,EAAS,GACb,GAAI,CAAC,EAAU,KAAK,EAAG,CACnB,EAAW,CAAC,CAAC,EACb,MACJ,CAIA,OAHA,EAAK,qBAAqB,EAAW,CAAE,KAAI,OAAM,CAAC,CAAC,CAAC,KAAM,GAAS,CAC3D,GAAQ,EAAW,CAAI,CAC/B,CAAC,MACY,CACT,EAAS,EACb,CACJ,EAAG,CAAC,EAAW,EAAI,CAAK,CAAC,EAEzB,SAAS,EAAO,EAA0C,CACtD,EAAS,CAAY,EACrB,EAAS,EAAa,IAAI,EAC1B,EAAQ,EAAK,CACjB,CAEA,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,OAAvB,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,EAAA,MAAD,CACW,QACP,MAAO,EACM,cACH,WACV,KAAK,WACL,gBAAe,GAAQ,EAAQ,OAAS,EACxC,gBAAe,EACf,aAAa,MACb,SAAW,GAAM,CACb,EAAS,EAAE,OAAO,KAAK,EACvB,EAAQ,EAAI,CAChB,EACA,YAAe,EAAQ,EAAI,EAC3B,WAAc,CAEV,EAAU,QAAU,eAAiB,EAAQ,EAAK,EAAG,GAAG,CAC5D,CACH,CAAA,EACA,GAAQ,EAAQ,OAAS,IACtB,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,GAAI,EAAQ,UAAW,EAAA,QAAO,QAAS,KAAK,UAC3C,SAAA,EAAQ,IAAK,IACV,EAAA,EAAA,IAAA,CAAC,KAAD,CAAA,UACI,EAAA,EAAA,KAAA,CAAC,SAAD,CACI,KAAK,SACL,KAAK,SACL,gBAAe,GACf,UAAW,EAAA,QAAO,OAClB,YAAc,GAAM,EAAE,eAAe,EACrC,YAAe,CACP,EAAU,SAAS,aAAa,EAAU,OAAO,EACrD,EAAO,CAAC,CACZ,EATJ,SAAA,EAWI,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,SAAO,EAAE,IAAW,CAAA,GACpB,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAA,QAAO,GAAK,SAAA,EAAE,EAAS,CAAA,CACpC,CACR,CAAA,CAAA,EAfK,EAAE,EAeP,CACP,CACD,CAAA,CAEP,GAEb"}