@mapfirst.ai/react 0.0.14 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx","../src/components/SmartFilter.tsx","../src/components/smart-filter/FilterChips.tsx","../src/components/smart-filter/CloseButton.tsx","../src/components/Icons.tsx","../src/components/smart-filter/Chip.tsx","../src/components/smart-filter/MinRatingFilterChip.tsx","../src/hooks/useTranslation.ts","../src/components/smart-filter/utils.tsx","../src/components/smart-filter/PriceRangeFilterChip.tsx","../src/components/smart-filter/RestaurantPriceLevelChip.tsx","../src/components/smart-filter/TransformedQueryChip.tsx","../src/hooks/useFilterScroll.ts","../src/hooks/useIsPortrait.ts"],"sourcesContent":["import React from \"react\";\nimport {\n MapFirstCore,\n type MapFirstOptions,\n type BaseMapFirstOptions,\n type Property,\n type MapLibreNamespace,\n type GoogleMapsNamespace,\n type MapboxNamespace,\n type MapState,\n type PropertyType,\n} from \"@mapfirst.ai/core\";\n\n// Export filter utilities from core\nexport {\n processApiFilters,\n convertToApiFilters,\n type ApiFiltersResponse,\n} from \"@mapfirst.ai/core\";\n\n// Export all components\nexport * from \"./components\";\n\n// Export all hooks\nexport * from \"./hooks\";\n\n// Import additional types for search functionality\ntype InitialRequestBody = {\n initial?: boolean;\n query?: string;\n bounds?: {\n sw: { lat: number; lng: number };\n ne: { lat: number; lng: number };\n };\n filters?: any;\n city?: string;\n country?: string;\n location_id?: number;\n longitude?: number;\n latitude?: number;\n radius?: number;\n};\n\ntype SmartFilter = {\n id: string;\n label: string;\n type:\n | \"amenity\"\n | \"hotelStyle\"\n | \"priceRange\"\n | \"minRating\"\n | \"starRating\"\n | \"primary_type\"\n | \"transformed_query\"\n | \"selected_restaurant_price_levels\";\n value: string;\n numericValue?: number;\n priceRange?: {\n min: number;\n max?: number;\n };\n propertyType?: PropertyType;\n priceLevels?: any[];\n};\n\n/**\n * Hook that creates a MapFirstCore instance that can be initialized before maps are ready.\n * Supports two-phase initialization: create SDK first, attach map later.\n * Returns the instance and reactive state that updates when SDK state changes.\n *\n * @example\n * ```tsx\n * // Phase 1: Create SDK instance with location data\n * const { mapFirst, state } = useMapFirstCore({\n * initialLocationData: {\n * city: \"New York\",\n * country: \"United States\",\n * currency: \"USD\"\n * }\n * });\n *\n * // Access reactive state\n * console.log(state.properties); // Updates when properties change\n * console.log(state.isSearching); // Updates when search state changes\n *\n * // Phase 2: Attach map when ready\n * useEffect(() => {\n * if (mapLibreInstance && mapFirst) {\n * mapFirst.attachMap(mapLibreInstance, {\n * platform: \"maplibre\",\n * maplibregl: maplibregl,\n * onMarkerClick: (marker) => console.log(marker)\n * });\n * }\n * }, [mapLibreInstance, mapFirst]);\n * ```\n */\nexport function useMapFirstCore(options: BaseMapFirstOptions) {\n const instanceRef = React.useRef<MapFirstCore | null>(null);\n const [state, setState] = React.useState<MapState | null>(null);\n\n // Memoize the options to prevent recreation on every render\n const optionsRef = React.useRef(options);\n React.useEffect(() => {\n optionsRef.current = options;\n });\n\n React.useEffect(() => {\n const opts = optionsRef.current;\n\n // Create MapFirstCore instance without map using adapter-driven options\n const coreOptions: MapFirstOptions = {\n adapter: null as any, // Will be set when attachMap is called\n ...opts,\n callbacks: {\n ...opts.callbacks,\n // Add internal callbacks to trigger React re-renders\n onPropertiesChange: (properties) => {\n setState((prev) => (prev ? { ...prev, properties } : null));\n optionsRef.current.callbacks?.onPropertiesChange?.(properties);\n },\n onSelectedPropertyChange: (id) => {\n setState((prev) =>\n prev ? { ...prev, selectedPropertyId: id } : null\n );\n optionsRef.current.callbacks?.onSelectedPropertyChange?.(id);\n },\n onPrimaryTypeChange: (type) => {\n setState((prev) => (prev ? { ...prev, primary: type } : null));\n optionsRef.current.callbacks?.onPrimaryTypeChange?.(type);\n },\n onFiltersChange: (filters) => {\n setState((prev) => (prev ? { ...prev, filters } : null));\n optionsRef.current.callbacks?.onFiltersChange?.(filters);\n },\n onBoundsChange: (bounds) => {\n setState((prev) => (prev ? { ...prev, bounds } : null));\n optionsRef.current.callbacks?.onBoundsChange?.(bounds);\n },\n onPendingBoundsChange: (pendingBounds) => {\n setState((prev) => (prev ? { ...prev, pendingBounds } : null));\n optionsRef.current.callbacks?.onPendingBoundsChange?.(pendingBounds);\n },\n onCenterChange: (center, zoom) => {\n setState((prev) => (prev ? { ...prev, center, zoom } : null));\n optionsRef.current.callbacks?.onCenterChange?.(center, zoom);\n },\n onZoomChange: (zoom) => {\n setState((prev) => (prev ? { ...prev, zoom } : null));\n optionsRef.current.callbacks?.onZoomChange?.(zoom);\n },\n onActiveLocationChange: (location) => {\n setState((prev) =>\n prev ? { ...prev, activeLocation: location } : null\n );\n optionsRef.current.callbacks?.onActiveLocationChange?.(location);\n },\n onLoadingStateChange: (loading) => {\n setState((prev) =>\n prev ? { ...prev, initialLoading: loading } : null\n );\n optionsRef.current.callbacks?.onLoadingStateChange?.(loading);\n },\n onSearchingStateChange: (searching) => {\n setState((prev) =>\n prev ? { ...prev, isSearching: searching } : null\n );\n optionsRef.current.callbacks?.onSearchingStateChange?.(searching);\n },\n },\n };\n\n const instance = new MapFirstCore(coreOptions);\n instanceRef.current = instance;\n\n // Initialize state from SDK\n setState(instance.getState());\n\n return () => {\n instance.destroy();\n instanceRef.current = null;\n setState(null);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return { mapFirst: instanceRef.current, state };\n}\n\n/**\n * Hook to access reactive properties from MapFirst SDK.\n * Returns the current properties array that updates when properties change.\n *\n * @example\n * ```tsx\n * const { mapFirst } = useMapFirstCore({ ... });\n * const properties = useMapFirstProperties(mapFirst);\n *\n * return <div>Found {properties.length} properties</div>;\n * ```\n */\nexport function useMapFirstProperties(\n mapFirst: MapFirstCore | null\n): Property[] {\n const [properties, setProperties] = React.useState<Property[]>([]);\n\n React.useEffect(() => {\n if (!mapFirst) {\n setProperties([]);\n return;\n }\n\n // Initialize with current state\n setProperties(mapFirst.getState().properties);\n }, [mapFirst]);\n\n return properties;\n}\n\n/**\n * Hook to access the selected property ID from MapFirst SDK.\n * Returns the currently selected property ID that updates when selection changes.\n *\n * @example\n * ```tsx\n * const { mapFirst } = useMapFirstCore({ ... });\n * const selectedId = useMapFirstSelectedProperty(mapFirst);\n *\n * return <div>Selected: {selectedId || 'None'}</div>;\n * ```\n */\nexport function useMapFirstSelectedProperty(\n mapFirst: MapFirstCore | null\n): number | null {\n const [selectedId, setSelectedId] = React.useState<number | null>(null);\n\n React.useEffect(() => {\n if (!mapFirst) {\n setSelectedId(null);\n return;\n }\n\n // Initialize with current state\n setSelectedId(mapFirst.getState().selectedPropertyId);\n }, [mapFirst]);\n\n return selectedId;\n}\n\n/**\n * Hook to access and control the primary property type.\n * Returns the current primary type and a setter function.\n *\n * @example\n * ```tsx\n * const { mapFirst } = useMapFirstCore({ ... });\n * const [primaryType, setPrimaryType] = usePrimaryType(mapFirst);\n *\n * return (\n * <select value={primaryType} onChange={(e) => setPrimaryType(e.target.value as PropertyType)}>\n * <option value=\"Accommodation\">Hotels</option>\n * <option value=\"Restaurant\">Restaurants</option>\n * <option value=\"Attraction\">Attractions</option>\n * </select>\n * );\n * ```\n */\nexport function usePrimaryType(\n mapFirst: MapFirstCore | null\n): [PropertyType, (type: PropertyType) => void] {\n const [primaryType, setPrimaryTypeState] =\n React.useState<PropertyType>(\"Accommodation\");\n\n React.useEffect(() => {\n if (!mapFirst) {\n setPrimaryTypeState(\"Accommodation\");\n return;\n }\n\n // Initialize with current state\n setPrimaryTypeState(mapFirst.getState().primary);\n }, [mapFirst]);\n\n const setPrimaryType = React.useCallback(\n (type: PropertyType) => {\n if (mapFirst) {\n mapFirst.setPrimaryType(type);\n setPrimaryTypeState(type);\n }\n },\n [mapFirst]\n );\n\n return [primaryType, setPrimaryType];\n}\n\n/**\n * Hook to access and control the selected marker.\n * Returns the current selected marker ID and a setter function.\n * Note: This hook requires the MapFirstCore instance. For simpler usage with reactive updates,\n * use state.selectedPropertyId from useMapFirstCore instead.\n *\n * @example\n * ```tsx\n * const { mapFirst } = useMapFirstCore({ ... });\n * const [selectedMarker, setSelectedMarker] = useSelectedMarker(mapFirst);\n *\n * return (\n * <div>\n * <p>Selected: {selectedMarker || 'None'}</p>\n * <button onClick={() => setSelectedMarker(null)}>Clear Selection</button>\n * </div>\n * );\n * ```\n */\nexport function useSelectedMarker(\n mapFirst: MapFirstCore | null\n): [number | null, (id: number | null) => void] {\n const [selectedMarker, setSelectedMarkerState] = React.useState<\n number | null\n >(null);\n\n React.useEffect(() => {\n if (!mapFirst) {\n setSelectedMarkerState(null);\n return;\n }\n\n // Initialize with current state\n setSelectedMarkerState(mapFirst.getState().selectedPropertyId);\n }, [mapFirst]);\n\n const setSelectedMarker = React.useCallback(\n (id: number | null) => {\n if (mapFirst) {\n mapFirst.setSelectedMarker(id);\n }\n },\n [mapFirst]\n );\n\n return [selectedMarker, setSelectedMarker];\n}\n\n/**\n * Hook for MapLibre GL JS integration.\n * Automatically attaches the map when both the SDK instance and map are available.\n *\n * @example\n * ```tsx\n * const { mapFirst, state } = useMapFirstCore({ initialLocationData: { city: \"Paris\", country: \"France\" } });\n * const mapRef = useRef<maplibregl.Map | null>(null);\n *\n * useMapLibreAttachment({\n * mapFirst,\n * map: mapRef.current,\n * maplibregl: maplibregl,\n * onMarkerClick: (marker) => console.log(marker)\n * });\n *\n * // Access reactive state\n * console.log(state?.properties);\n * ```\n */\nexport function useMapLibreAttachment({\n mapFirst,\n map,\n maplibregl,\n onMarkerClick,\n}: {\n mapFirst: MapFirstCore | null;\n map: any | null;\n maplibregl: MapLibreNamespace;\n onMarkerClick?: (marker: Property) => void;\n}) {\n const attachedRef = React.useRef(false);\n\n React.useEffect(() => {\n if (!mapFirst || !map || attachedRef.current) {\n return;\n }\n\n mapFirst.attachMap(map, {\n platform: \"maplibre\",\n maplibregl,\n onMarkerClick,\n });\n\n attachedRef.current = true;\n }, [mapFirst, map, maplibregl, onMarkerClick]);\n}\n\n/**\n * Hook for Google Maps integration.\n * Automatically attaches the map when both the SDK instance and map are available.\n *\n * @example\n * ```tsx\n * const { mapFirst, state } = useMapFirstCore({ initialLocationData: { city: \"Tokyo\", country: \"Japan\" } });\n * const mapRef = useRef<google.maps.Map | null>(null);\n *\n * useGoogleMapsAttachment({\n * mapFirst,\n * map: mapRef.current,\n * google: window.google,\n * onMarkerClick: (marker) => console.log(marker)\n * });\n *\n * // Access reactive state\n * console.log(state?.isSearching);\n * ```\n */\nexport function useGoogleMapsAttachment({\n mapFirst,\n map,\n google,\n onMarkerClick,\n}: {\n mapFirst: MapFirstCore | null;\n map: any | null;\n google: GoogleMapsNamespace;\n onMarkerClick?: (marker: Property) => void;\n}) {\n const attachedRef = React.useRef(false);\n\n React.useEffect(() => {\n if (!mapFirst || !map || attachedRef.current) {\n return;\n }\n\n mapFirst.attachMap(map, {\n platform: \"google\",\n google,\n onMarkerClick,\n });\n\n attachedRef.current = true;\n }, [mapFirst, map, google, onMarkerClick]);\n}\n\n/**\n * Hook for Mapbox GL JS integration.\n * Automatically attaches the map when both the SDK instance and map are available.\n *\n * @example\n * ```tsx\n * const { mapFirst, state } = useMapFirstCore({ initialLocationData: { city: \"London\", country: \"United Kingdom\" } });\n * const mapRef = useRef<mapboxgl.Map | null>(null);\n *\n * useMapboxAttachment({\n * mapFirst,\n * map: mapRef.current,\n * mapboxgl: mapboxgl,\n * onMarkerClick: (marker) => console.log(marker)\n * });\n *\n * // Access reactive state\n * console.log(state?.filters);\n * ```\n */\nexport function useMapboxAttachment({\n mapFirst,\n map,\n mapboxgl,\n onMarkerClick,\n}: {\n mapFirst: MapFirstCore | null;\n map: any | null;\n mapboxgl: MapboxNamespace;\n onMarkerClick?: (marker: Property) => void;\n}) {\n const attachedRef = React.useRef(false);\n\n React.useEffect(() => {\n if (!mapFirst || !map || attachedRef.current) {\n return;\n }\n\n mapFirst.attachMap(map, {\n platform: \"mapbox\",\n mapboxgl,\n onMarkerClick,\n });\n\n attachedRef.current = true;\n }, [mapFirst, map, mapboxgl, onMarkerClick]);\n}\n\n/**\n * Legacy hook that creates the MapFirstCore instance with a map immediately.\n * Use useMapFirstCore + useMap*Attachment hooks for better control.\n *\n * @deprecated Use useMapFirstCore and platform-specific attachment hooks instead\n */\nexport function useMapFirst(options: MapFirstOptions | null) {\n const instanceRef = React.useRef<MapFirstCore | null>(null);\n\n React.useEffect(() => {\n if (!options) {\n return undefined;\n }\n const instance = new MapFirstCore(options);\n instanceRef.current = instance;\n\n return () => {\n instance.destroy();\n instanceRef.current = null;\n };\n }, [options]);\n\n return instanceRef;\n}\n\n/**\n * Hook to run properties search with the MapFirst SDK.\n * Returns a function to trigger the search and loading state.\n *\n * @example\n * ```tsx\n * const { mapFirst } = useMapFirstCore({ ... });\n * const { search, isLoading, error } = usePropertiesSearch(mapFirst);\n *\n * const handleSearch = async () => {\n * await search({\n * body: {\n * city: \"Paris\",\n * country: \"France\",\n * filters: {\n * checkIn: new Date(),\n * checkOut: new Date(Date.now() + 86400000),\n * numAdults: 2,\n * numRooms: 1\n * }\n * }\n * });\n * };\n * ```\n */\nexport function usePropertiesSearch(mapFirst: MapFirstCore | null) {\n const [isLoading, setIsLoading] = React.useState(false);\n const [error, setError] = React.useState<Error | null>(null);\n\n const search = React.useCallback(\n async (options: {\n body: InitialRequestBody;\n beforeApplyProperties?: (data: any) => {\n price?: any;\n limit?: number;\n };\n smartFiltersClearable?: boolean;\n }) => {\n if (!mapFirst) {\n const err = new Error(\"MapFirst instance not available\");\n setError(err);\n throw err;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await mapFirst.runPropertiesSearch({\n ...options,\n onError: (err) => {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n },\n });\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n throw error;\n } finally {\n setIsLoading(false);\n }\n },\n [mapFirst]\n );\n\n return { search, isLoading, error };\n}\n\n/**\n * Hook to run smart filter search with the MapFirst SDK.\n * Returns a function to trigger the search and loading state.\n *\n * @example\n * ```tsx\n * const { mapFirst } = useMapFirstCore({ ... });\n * const { search, isLoading, error } = useSmartFilterSearch(mapFirst);\n *\n * const handleSearch = async () => {\n * await search({\n * query: \"hotels near beach with pool\"\n * });\n * };\n *\n * // Or with filters\n * const handleFilterSearch = async () => {\n * await search({\n * filters: [\n * { id: \"pool\", label: \"Pool\", type: \"amenity\", value: \"pool\" },\n * { id: \"4star\", label: \"4 Star\", type: \"starRating\", value: \"4\", numericValue: 4 }\n * ]\n * });\n * };\n * ```\n */\nexport function useSmartFilterSearch(mapFirst: MapFirstCore | null) {\n const [isLoading, setIsLoading] = React.useState(false);\n const [error, setError] = React.useState<Error | null>(null);\n\n const search = React.useCallback(\n async (options: {\n query?: string;\n filters?: SmartFilter[];\n onProcessFilters?: (\n filters: any,\n location_id?: number\n ) => {\n smartFilters?: SmartFilter[];\n price?: any;\n limit?: number;\n language?: string;\n };\n }) => {\n if (!mapFirst) {\n const err = new Error(\"MapFirst instance not available\");\n setError(err);\n throw err;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await mapFirst.runSmartFilterSearch({\n ...options,\n onError: (err) => {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n },\n });\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n throw error;\n } finally {\n setIsLoading(false);\n }\n },\n [mapFirst]\n );\n\n return { search, isLoading, error };\n}\n\n/**\n * Hook to perform a bounds search when the user moves the map\n *\n * @example\n * ```tsx\n * const { mapFirst, state } = useMapFirstCore({ ... });\n * const { performBoundsSearch, isSearching } = useMapFirstBoundsSearch(mapFirst);\n *\n * // When user clicks \"Search this area\" button\n * <button onClick={performBoundsSearch} disabled={!state.pendingBounds || isSearching}>\n * Search this area\n * </button>\n * ```\n */\nexport function useMapFirstBoundsSearch(mapFirst: MapFirstCore | null) {\n const [isSearching, setIsSearching] = React.useState(false);\n const [error, setError] = React.useState<Error | null>(null);\n\n const performBoundsSearch = React.useCallback(async () => {\n if (!mapFirst) {\n return null;\n }\n\n setIsSearching(true);\n setError(null);\n\n try {\n const result = await mapFirst.performBoundsSearch();\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setError(error);\n throw error;\n } finally {\n setIsSearching(false);\n }\n }, [mapFirst]);\n\n return { performBoundsSearch, isSearching, error };\n}\n\n/**\n * Helper component that simply renders the markers it receives so non-React environments\n * can verify data flows before wiring the SDK into a map.\n */\nexport function MarkerDebugList({ markers }: { markers: Property[] }) {\n return (\n <div style={{ fontFamily: \"sans-serif\", fontSize: 14 }}>\n <strong>Markers</strong>\n <ul>\n {markers.map((marker) => (\n <li key={String(marker.tripadvisor_id)}>\n {marker.name} — {marker.location?.lat?.toFixed(3) ?? \"n/a\"},{\" \"}\n {marker.location?.lon?.toFixed(3) ?? \"n/a\"}\n </li>\n ))}\n </ul>\n </div>\n );\n}\n","import React, {\r\n FormEventHandler,\r\n FunctionComponent,\r\n useCallback,\r\n useState,\r\n CSSProperties,\r\n} from \"react\";\r\nimport { FilterChips } from \"./smart-filter/FilterChips\";\r\nimport { useIsPortrait } from \"../hooks/useIsPortrait\";\r\nimport { useTranslation } from \"../hooks/useTranslation\";\r\nimport type { Filter } from \"./smart-filter/types\";\r\nimport type { MapFirstCore } from \"@mapfirst.ai/core\";\r\n\r\nexport interface SmartFilterProps {\r\n mapFirst: MapFirstCore | null;\r\n filters: Filter[];\r\n value?: string;\r\n isSearching?: boolean;\r\n placeholder?: string;\r\n onSearch: (query: string, filters?: Filter[]) => Promise<void> | void;\r\n onFilterChange: (filters: Filter[]) => Promise<void> | void;\r\n onValueChange?: (value: string) => void;\r\n showTypingPrompt?: boolean;\r\n customTranslations?: Record<string, string>;\r\n currency?: string;\r\n style?: CSSProperties;\r\n inputStyle?: CSSProperties;\r\n containerStyle?: CSSProperties;\r\n}\r\n\r\nconst containerStyles: CSSProperties = {\r\n position: \"relative\",\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n gap: \"8px\",\r\n width: \"100%\",\r\n};\r\n\r\nconst formStyles: CSSProperties = {\r\n position: \"relative\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n width: \"100%\",\r\n};\r\n\r\nconst inputContainerStyles: CSSProperties = {\r\n position: \"relative\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n flex: 1,\r\n backgroundColor: \"white\",\r\n borderRadius: \"24px\",\r\n border: \"1px solid #e5e5e5\",\r\n padding: \"0 16px\",\r\n boxShadow: \"0 1px 3px rgba(0,0,0,0.1)\",\r\n};\r\n\r\nconst inputStyles: CSSProperties = {\r\n flex: 1,\r\n border: \"none\",\r\n outline: \"none\",\r\n fontSize: \"16px\",\r\n backgroundColor: \"transparent\",\r\n color: \"#000\",\r\n padding: \"10px\",\r\n};\r\n\r\nconst loaderContainerStyles: CSSProperties = {\r\n position: \"absolute\",\r\n right: \"16px\",\r\n top: \"50%\",\r\n transform: \"translateY(-50%)\",\r\n};\r\n\r\nconst loaderStyles: CSSProperties = {\r\n width: \"20px\",\r\n height: \"20px\",\r\n border: \"2px solid #e5e5e5\",\r\n borderTop: \"2px solid #03852e\",\r\n borderRadius: \"50%\",\r\n animation: \"spin 1s linear infinite\",\r\n};\r\n\r\nconst typingPromptStyles: CSSProperties = {\r\n position: \"absolute\",\r\n padding: \"10px\",\r\n color: \"#737373\",\r\n pointerEvents: \"none\",\r\n fontSize: \"16px\",\r\n};\r\n\r\n/**\r\n * SmartFilter component for AI-powered search with filter chips.\r\n * Provides a search input with smart filtering capabilities.\r\n *\r\n * @example\r\n * ```tsx\r\n * const { mapFirst, state } = useMapFirstCore({ ... });\r\n * const [filters, setFilters] = useState<Filter[]>([]);\r\n * const [searchValue, setSearchValue] = useState(\"\");\r\n *\r\n * const handleSearch = async (query: string, currentFilters?: Filter[]) => {\r\n * // Perform search using mapFirst.runSmartFilterSearch\r\n * const result = await mapFirst.runSmartFilterSearch({\r\n * query,\r\n * filters: currentFilters\r\n * });\r\n * // Update filters based on response\r\n * };\r\n *\r\n * return (\r\n * <SmartFilter\r\n * mapFirst={mapFirst}\r\n * filters={filters}\r\n * value={searchValue}\r\n * isSearching={state?.isSearching}\r\n * onSearch={handleSearch}\r\n * onFilterChange={setFilters}\r\n * onValueChange={setSearchValue}\r\n * />\r\n * );\r\n * ```\r\n */\r\nexport const SmartFilter: FunctionComponent<SmartFilterProps> = ({\r\n mapFirst,\r\n filters,\r\n value: controlledValue,\r\n isSearching = false,\r\n placeholder,\r\n onSearch,\r\n onFilterChange,\r\n onValueChange,\r\n showTypingPrompt = true,\r\n customTranslations,\r\n currency = \"USD\",\r\n style,\r\n inputStyle,\r\n containerStyle,\r\n}) => {\r\n const [internalValue, setInternalValue] = useState(\"\");\r\n const value = controlledValue !== undefined ? controlledValue : internalValue;\r\n const setValue = onValueChange || setInternalValue;\r\n\r\n const isPortrait = useIsPortrait();\r\n const { t, formatCurrency } = useTranslation(customTranslations);\r\n\r\n const minRatingSuffix = t(\"smartFilter.minRating.suffix\");\r\n const typingPrompt = placeholder || t(\"smartFilter.typingPrompt\");\r\n const previousFiltersLabel = t(\"smartFilter.nav.previous\");\r\n const nextFiltersLabel = t(\"smartFilter.nav.next\");\r\n const clearAllLabel = t(\"smartFilter.clearAll\");\r\n\r\n const formSubmit: FormEventHandler<HTMLFormElement> = async (e) => {\r\n e.preventDefault();\r\n const query = value.trim();\r\n if (!query || isSearching) {\r\n return;\r\n }\r\n try {\r\n await onSearch(query);\r\n } catch (error) {\r\n console.error(\"Search error:\", error);\r\n }\r\n };\r\n\r\n const handleFilterChange = useCallback(\r\n async (nextFilters: Filter[], clearAll?: boolean) => {\r\n if (isSearching) {\r\n return;\r\n }\r\n try {\r\n await onFilterChange(nextFilters);\r\n } catch (error) {\r\n console.error(\"Filter change error:\", error);\r\n }\r\n },\r\n [isSearching, onFilterChange]\r\n );\r\n\r\n const resetFilters = useCallback(() => {\r\n void handleFilterChange([]);\r\n }, [handleFilterChange]);\r\n\r\n const clearAllFilters = useCallback(() => {\r\n void handleFilterChange([], true);\r\n setValue(\"\");\r\n }, [handleFilterChange, setValue]);\r\n\r\n return (\r\n <div style={{ ...containerStyles, ...containerStyle }}>\r\n <style>\r\n {`\r\n @keyframes spin {\r\n 0% { transform: rotate(0deg); }\r\n 100% { transform: rotate(360deg); }\r\n }\r\n `}\r\n </style>\r\n <form onSubmit={formSubmit} style={{ ...formStyles, ...style }}>\r\n <div style={inputContainerStyles}>\r\n <input\r\n type=\"text\"\r\n value={value}\r\n onChange={(e) => setValue(e.target.value)}\r\n disabled={isSearching}\r\n style={{ ...inputStyles, ...inputStyle }}\r\n autoComplete=\"off\"\r\n aria-label=\"Smart search\"\r\n />\r\n {showTypingPrompt && value.length === 0 && !isSearching && (\r\n <span style={typingPromptStyles}>{typingPrompt}</span>\r\n )}\r\n {isSearching && (\r\n <div style={loaderContainerStyles}>\r\n <div style={loaderStyles} />\r\n </div>\r\n )}\r\n </div>\r\n </form>\r\n\r\n {filters.length > 0 && (\r\n <FilterChips\r\n filters={filters}\r\n isPortrait={isPortrait}\r\n currency={currency}\r\n minRatingSuffix={minRatingSuffix}\r\n clearAllLabel={clearAllLabel}\r\n previousFiltersLabel={previousFiltersLabel}\r\n nextFiltersLabel={nextFiltersLabel}\r\n formatCurrency={formatCurrency}\r\n onFilterChange={handleFilterChange}\r\n onResetFilters={resetFilters}\r\n onClearAll={clearAllFilters}\r\n />\r\n )}\r\n </div>\r\n );\r\n};\r\n","import React, { FunctionComponent, CSSProperties } from \"react\";\r\nimport { Chip } from \"./Chip\";\r\nimport { MinRatingFilterChip } from \"./MinRatingFilterChip\";\r\nimport { PriceRangeFilterChip } from \"./PriceRangeFilterChip\";\r\nimport { RestaurantPriceLevelChip } from \"./RestaurantPriceLevelChip\";\r\nimport { TransformedQueryChip } from \"./TransformedQueryChip\";\r\nimport { SearchIcon, NextIcon } from \"../Icons\";\r\nimport { useFilterScroll } from \"../../hooks/useFilterScroll\";\r\nimport { useTranslation } from \"../../hooks/useTranslation\";\r\nimport type { Filter } from \"./types\";\r\n\r\nexport interface FilterChipsProps {\r\n filters: Filter[];\r\n isPortrait: boolean;\r\n currency: string;\r\n minRatingSuffix: string;\r\n clearAllLabel: string;\r\n previousFiltersLabel: string;\r\n nextFiltersLabel: string;\r\n formatCurrency: (value: number, currency?: string) => string;\r\n onFilterChange: (\r\n filters: Filter[],\r\n clearAll?: boolean\r\n ) => void | Promise<void>;\r\n onResetFilters: () => void;\r\n onClearAll: () => void;\r\n}\r\n\r\nconst containerStyles: CSSProperties = {\r\n position: \"relative\",\r\n width: \"100%\",\r\n};\r\n\r\nconst scrollContainerBase: CSSProperties = {\r\n display: \"flex\",\r\n gap: \"8px\",\r\n overflowX: \"auto\",\r\n alignItems: \"center\",\r\n width: \"100%\",\r\n scrollbarWidth: \"none\",\r\n msOverflowStyle: \"none\",\r\n};\r\n\r\nconst gradientStyles: CSSProperties = {\r\n pointerEvents: \"none\",\r\n position: \"absolute\",\r\n top: 0,\r\n bottom: 0,\r\n width: \"40px\",\r\n};\r\n\r\nconst navButtonStyles: CSSProperties = {\r\n position: \"absolute\",\r\n top: \"50%\",\r\n transform: \"translateY(-50%)\",\r\n backgroundColor: \"white\",\r\n color: \"#003c30\",\r\n border: \"1px solid #003c30\",\r\n padding: \"4px\",\r\n borderRadius: \"50%\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n boxShadow: \"0 1px 3px rgba(0,0,0,0.1)\",\r\n cursor: \"pointer\",\r\n};\r\n\r\nexport const FilterChips: FunctionComponent<FilterChipsProps> = ({\r\n filters,\r\n isPortrait,\r\n currency,\r\n minRatingSuffix,\r\n clearAllLabel,\r\n previousFiltersLabel,\r\n nextFiltersLabel,\r\n formatCurrency,\r\n onFilterChange,\r\n onResetFilters,\r\n onClearAll,\r\n}) => {\r\n const { scrollerRef, atStart, atEnd, scrollByDir } = useFilterScroll(\r\n filters.length\r\n );\r\n const { t } = useTranslation();\r\n const [navHover, setNavHover] = React.useState<\"prev\" | \"next\" | null>(null);\r\n const [resetHover, setResetHover] = React.useState(false);\r\n const [clearHover, setClearHover] = React.useState(false);\r\n\r\n const scrollContainerStyles: CSSProperties = {\r\n ...scrollContainerBase,\r\n padding: isPortrait ? \"8px 16px\" : \"8px\",\r\n };\r\n\r\n return (\r\n <div style={containerStyles}>\r\n <div\r\n ref={scrollerRef}\r\n style={{\r\n ...scrollContainerStyles,\r\n // Hide scrollbar for webkit browsers\r\n WebkitOverflowScrolling: \"touch\",\r\n }}\r\n >\r\n <style>\r\n {`\r\n div::-webkit-scrollbar {\r\n display: none;\r\n }\r\n `}\r\n </style>\r\n <button\r\n style={{\r\n flexShrink: 0,\r\n backgroundColor: resetHover ? \"#03a03e\" : \"#03852e\",\r\n borderRadius: \"50%\",\r\n padding: \"8px\",\r\n cursor: \"pointer\",\r\n border: \"none\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n transition: \"background-color 0.2s\",\r\n }}\r\n onClick={onResetFilters}\r\n onMouseEnter={() => setResetHover(true)}\r\n onMouseLeave={() => setResetHover(false)}\r\n >\r\n <SearchIcon\r\n style={{ width: \"20px\", height: \"20px\", color: \"white\" }}\r\n />\r\n </button>\r\n {filters.map((filter) => {\r\n const renderStandardChip = () => (\r\n <Chip\r\n key={filter.id}\r\n label={filter.label}\r\n icon={filter.icon}\r\n remove={() => {\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id));\r\n }}\r\n />\r\n );\r\n\r\n if (filter.type === \"minRating\") {\r\n const currentRating = filter.numericValue ?? Number(filter.value);\r\n if (!Number.isFinite(currentRating)) {\r\n return renderStandardChip();\r\n }\r\n\r\n return (\r\n <MinRatingFilterChip\r\n key={filter.id}\r\n rating={currentRating}\r\n onChange={(nextRating) => {\r\n const nextFilters = filters.map((f) =>\r\n f.id === filter.id\r\n ? {\r\n ...f,\r\n numericValue: nextRating,\r\n value: String(nextRating),\r\n }\r\n : f\r\n );\r\n void onFilterChange(nextFilters);\r\n }}\r\n onRemove={() =>\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id))\r\n }\r\n />\r\n );\r\n }\r\n\r\n if (filter.type === \"starRating\") {\r\n const currentRating = filter.numericValue ?? Number(filter.value);\r\n if (!Number.isFinite(currentRating)) {\r\n return renderStandardChip();\r\n }\r\n\r\n return (\r\n <MinRatingFilterChip\r\n star\r\n key={filter.id}\r\n rating={currentRating}\r\n onChange={(nextRating) => {\r\n const nextFilters = filters.map((f) =>\r\n f.id === filter.id\r\n ? {\r\n ...f,\r\n numericValue: nextRating,\r\n value: String(nextRating),\r\n }\r\n : f\r\n );\r\n void onFilterChange(nextFilters);\r\n }}\r\n onRemove={() =>\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id))\r\n }\r\n />\r\n );\r\n }\r\n\r\n if (filter.type === \"priceRange\" && filter.priceRange) {\r\n return (\r\n <PriceRangeFilterChip\r\n key={filter.id}\r\n priceRange={filter.priceRange}\r\n currency={currency}\r\n onChange={(nextRange) => {\r\n const nextFilters = filters.map((f) =>\r\n f.id === filter.id\r\n ? {\r\n ...f,\r\n priceRange: nextRange,\r\n }\r\n : f\r\n );\r\n void onFilterChange(nextFilters);\r\n }}\r\n onRemove={() =>\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id))\r\n }\r\n />\r\n );\r\n }\r\n\r\n if (filter.type === \"transformed_query\") {\r\n return (\r\n <TransformedQueryChip\r\n key={filter.id}\r\n value={filter.value}\r\n onChange={(nextValue) => {\r\n const nextFilters = filters.map((f) =>\r\n f.id === filter.id\r\n ? {\r\n ...f,\r\n value: nextValue,\r\n }\r\n : f\r\n );\r\n void onFilterChange(nextFilters);\r\n }}\r\n onRemove={() =>\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id))\r\n }\r\n />\r\n );\r\n }\r\n\r\n if (filter.type === \"selected_restaurant_price_levels\") {\r\n return (\r\n <RestaurantPriceLevelChip\r\n key={filter.id}\r\n values={filter.priceLevels ?? []}\r\n onChange={(nextLevels) => {\r\n const nextFilters = filters.map((f) =>\r\n f.id === filter.id\r\n ? {\r\n ...f,\r\n priceLevels: nextLevels,\r\n }\r\n : f\r\n );\r\n void onFilterChange(nextFilters);\r\n }}\r\n onRemove={() =>\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id))\r\n }\r\n />\r\n );\r\n }\r\n\r\n return renderStandardChip();\r\n })}\r\n <button\r\n style={{\r\n flexShrink: 0,\r\n padding: \"4px 16px\",\r\n borderRadius: \"9999px\",\r\n cursor: \"pointer\",\r\n fontSize: \"14px\",\r\n userSelect: \"none\",\r\n border: \"none\",\r\n backgroundColor: clearHover ? \"#e5e5e5\" : \"transparent\",\r\n transition: \"background-color 0.2s\",\r\n }}\r\n onClick={onClearAll}\r\n onMouseEnter={() => setClearHover(true)}\r\n onMouseLeave={() => setClearHover(false)}\r\n >\r\n {clearAllLabel}\r\n </button>\r\n </div>\r\n\r\n {!atStart && (\r\n <div\r\n aria-hidden=\"true\"\r\n style={{\r\n ...gradientStyles,\r\n left: 0,\r\n background: \"linear-gradient(to right, white, transparent)\",\r\n }}\r\n />\r\n )}\r\n\r\n {!atEnd && (\r\n <div\r\n aria-hidden=\"true\"\r\n style={{\r\n ...gradientStyles,\r\n right: 0,\r\n background: \"linear-gradient(to left, white, transparent)\",\r\n }}\r\n />\r\n )}\r\n\r\n {!atStart && (\r\n <button\r\n type=\"button\"\r\n aria-label={previousFiltersLabel}\r\n style={{\r\n ...navButtonStyles,\r\n left: \"4px\",\r\n transform: \"translateY(-50%) rotate(180deg)\",\r\n backgroundColor: navHover === \"prev\" ? \"#e5e5e5\" : \"white\",\r\n }}\r\n onClick={() => scrollByDir(\"prev\")}\r\n onMouseEnter={() => setNavHover(\"prev\")}\r\n onMouseLeave={() => setNavHover(null)}\r\n >\r\n <NextIcon style={{ width: \"20px\", height: \"20px\" }} />\r\n </button>\r\n )}\r\n\r\n {!atEnd && (\r\n <button\r\n type=\"button\"\r\n aria-label={nextFiltersLabel}\r\n style={{\r\n ...navButtonStyles,\r\n right: \"4px\",\r\n backgroundColor: navHover === \"next\" ? \"#e5e5e5\" : \"white\",\r\n }}\r\n onClick={() => scrollByDir(\"next\")}\r\n onMouseEnter={() => setNavHover(\"next\")}\r\n onMouseLeave={() => setNavHover(null)}\r\n >\r\n <NextIcon style={{ width: \"20px\", height: \"20px\" }} />\r\n </button>\r\n )}\r\n </div>\r\n );\r\n};\r\n","import React, { CSSProperties } from \"react\";\r\nimport { CloseIcon } from \"../Icons\";\r\n\r\nexport interface CloseButtonProps {\r\n onClick: () => void;\r\n style?: CSSProperties;\r\n}\r\n\r\nconst closeButtonStyles: CSSProperties = {\r\n position: \"absolute\",\r\n top: \"-8px\",\r\n right: \"-8px\",\r\n padding: \"2px\",\r\n borderRadius: \"50%\",\r\n backgroundColor: \"white\",\r\n border: \"1px solid #03852e\",\r\n cursor: \"pointer\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n transition: \"background-color 0.2s\",\r\n};\r\n\r\nconst iconStyles: CSSProperties = {\r\n width: \"17px\",\r\n height: \"17px\",\r\n};\r\n\r\nexport const CloseButton: React.FC<CloseButtonProps> = ({ onClick, style }) => {\r\n const [isHovering, setIsHovering] = React.useState(false);\r\n\r\n return (\r\n <button\r\n style={{\r\n ...closeButtonStyles,\r\n backgroundColor: isHovering ? \"#e5e5e5\" : \"white\",\r\n ...style,\r\n }}\r\n onClick={onClick}\r\n onMouseEnter={() => setIsHovering(true)}\r\n onMouseLeave={() => setIsHovering(false)}\r\n aria-label=\"Remove filter\"\r\n >\r\n <CloseIcon style={iconStyles} />\r\n </button>\r\n );\r\n};\r\n","import React, { CSSProperties } from \"react\";\r\n\r\nexport interface IconProps {\r\n className?: string;\r\n style?: CSSProperties;\r\n}\r\n\r\nexport const SearchIcon: React.FC<IconProps> = ({ className, style }) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n style={{ width: \"1em\", height: \"1em\", ...style }}\r\n >\r\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\r\n <path d=\"m21 21-4.35-4.35\" />\r\n </svg>\r\n);\r\n\r\nexport const CloseIcon: React.FC<IconProps> = ({ className, style }) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n style={{ width: \"1em\", height: \"1em\", ...style }}\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\r\n </svg>\r\n);\r\n\r\nexport const EditIcon: React.FC<IconProps> = ({ className, style }) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n style={{ width: \"1em\", height: \"1em\", ...style }}\r\n >\r\n <path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\r\n <path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\" />\r\n </svg>\r\n);\r\n\r\nexport const NextIcon: React.FC<IconProps> = ({ className, style }) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n style={{ width: \"1em\", height: \"1em\", ...style }}\r\n >\r\n <polyline points=\"9 18 15 12 9 6\" />\r\n </svg>\r\n);\r\n\r\nexport const StarIcon: React.FC<IconProps & { fill?: string }> = ({\r\n className,\r\n style,\r\n fill = \"none\",\r\n}) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill={fill}\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n style={{ width: \"1em\", height: \"1em\", ...style }}\r\n >\r\n <polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\" />\r\n </svg>\r\n);\r\n","import React, { CSSProperties, ReactNode } from \"react\";\r\nimport { CloseButton } from \"./CloseButton\";\r\n\r\nexport interface ChipProps {\r\n label: string | ReactNode;\r\n icon?: ReactNode;\r\n remove: () => void;\r\n style?: CSSProperties;\r\n}\r\n\r\nconst chipStyles: CSSProperties = {\r\n position: \"relative\",\r\n backgroundColor: \"white\",\r\n color: \"black\",\r\n fontSize: \"14px\",\r\n borderRadius: \"9999px\",\r\n padding: \"0 16px\",\r\n paddingRight: \"20px\",\r\n border: \"1px solid #03852e\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n flexShrink: 0,\r\n height: \"34px\",\r\n};\r\n\r\nexport const Chip: React.FC<ChipProps> = ({ label, icon, remove, style }) => {\r\n return (\r\n <div style={{ ...chipStyles, ...style }}>\r\n {icon && (\r\n <span style={{ display: \"flex\", alignItems: \"center\" }}>{icon}</span>\r\n )}\r\n <span style={{ whiteSpace: \"nowrap\" }}>{label}</span>\r\n <CloseButton onClick={remove} />\r\n </div>\r\n );\r\n};\r\n","import React, {\r\n FunctionComponent,\r\n useState,\r\n FocusEvent,\r\n CSSProperties,\r\n} from \"react\";\r\nimport { StarIcon } from \"../Icons\";\r\nimport { CloseButton } from \"./CloseButton\";\r\nimport { useTranslation } from \"../../hooks/useTranslation\";\r\nimport { formatRatingValue } from \"./utils\";\r\n\r\nconst chipContainerStyles: CSSProperties = {\r\n position: \"relative\",\r\n backgroundColor: \"white\",\r\n color: \"black\",\r\n fontSize: \"14px\",\r\n borderRadius: \"9999px\",\r\n padding: \"0 16px\",\r\n paddingRight: \"20px\",\r\n border: \"1px solid #03852e\",\r\n display: \"flex\",\r\n gap: \"8px\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n flexShrink: 0,\r\n height: \"34px\",\r\n};\r\n\r\nconst starContainerStyles: CSSProperties = {\r\n display: \"flex\",\r\n gap: \"1px\",\r\n userSelect: \"none\",\r\n};\r\n\r\nconst circleBaseStyles: CSSProperties = {\r\n display: \"block\",\r\n width: \"12px\",\r\n height: \"12px\",\r\n borderRadius: \"50%\",\r\n border: \"1px solid #03852e\",\r\n pointerEvents: \"none\",\r\n};\r\n\r\nconst buttonBaseStyles: CSSProperties = {\r\n position: \"absolute\",\r\n top: 0,\r\n height: \"100%\",\r\n cursor: \"pointer\",\r\n backgroundColor: \"transparent\",\r\n border: \"none\",\r\n padding: 0,\r\n};\r\n\r\nexport const MinRatingFilterChip: FunctionComponent<{\r\n star?: boolean;\r\n rating: number;\r\n onChange: (rating: number) => void;\r\n onRemove: () => void;\r\n}> = ({ rating, onChange, onRemove, star = false }) => {\r\n const [hoverRating, setHoverRating] = useState<number | null>(null);\r\n const { t } = useTranslation();\r\n\r\n const displayRating = hoverRating ?? rating;\r\n const formatLabel = (value: number) =>\r\n star && value\r\n ? value.toString()\r\n : t(\"smartFilter.minRating.label\", { value: formatRatingValue(value) });\r\n const removeLabel = t(\"smartFilter.minRating.remove\");\r\n const setLabel = (value: number) =>\r\n t(\"smartFilter.minRating.setTo\", { rating: formatRatingValue(value) });\r\n\r\n const getFillForStar = (index: number) => {\r\n const starNumber = index + 1;\r\n if (displayRating >= starNumber) {\r\n return \"full\" as const;\r\n }\r\n if (displayRating >= starNumber - 0.5) {\r\n return \"half\" as const;\r\n }\r\n return \"empty\" as const;\r\n };\r\n\r\n const handleSelect = (nextRating: number) => {\r\n setHoverRating(null);\r\n if (nextRating === rating) {\r\n return;\r\n }\r\n onChange(nextRating);\r\n };\r\n\r\n const handleBlur = (event: FocusEvent<HTMLButtonElement>) => {\r\n const related = event.relatedTarget as HTMLElement | null;\r\n if (\r\n !related ||\r\n !(event.currentTarget as HTMLElement)\r\n .closest(\"[data-min-rating-chip]\")\r\n ?.contains(related)\r\n ) {\r\n setHoverRating(null);\r\n }\r\n };\r\n\r\n return (\r\n <div style={chipContainerStyles} data-min-rating-chip>\r\n <div\r\n style={{ display: \"flex\", alignItems: \"center\", gap: \"4px\" }}\r\n onMouseLeave={() => setHoverRating(null)}\r\n >\r\n <div style={starContainerStyles}>\r\n {Array.from({ length: 5 }).map((_, index) => {\r\n const fillState = getFillForStar(index);\r\n const starNumber = index + 1;\r\n const halfValue = starNumber - 0.5;\r\n\r\n if (star) {\r\n return (\r\n <div\r\n key={index}\r\n style={{\r\n position: \"relative\",\r\n width: \"16px\",\r\n height: \"16px\",\r\n }}\r\n >\r\n <StarIcon\r\n fill={displayRating >= starNumber ? \"#03852e\" : \"none\"}\r\n style={{\r\n width: \"16px\",\r\n height: \"16px\",\r\n pointerEvents: \"none\",\r\n }}\r\n />\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...buttonBaseStyles,\r\n left: 0,\r\n width: \"50%\",\r\n borderRadius: \"50% 0 0 50%\",\r\n }}\r\n onMouseEnter={() => setHoverRating(halfValue)}\r\n onFocus={() => setHoverRating(halfValue)}\r\n onBlur={handleBlur}\r\n onClick={() => handleSelect(halfValue)}\r\n aria-label={setLabel(halfValue)}\r\n title={formatLabel(halfValue)}\r\n />\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...buttonBaseStyles,\r\n left: \"50%\",\r\n width: \"50%\",\r\n borderRadius: \"0 50% 50% 0\",\r\n }}\r\n onMouseEnter={() => setHoverRating(starNumber)}\r\n onFocus={() => setHoverRating(starNumber)}\r\n onBlur={handleBlur}\r\n onClick={() => handleSelect(starNumber)}\r\n aria-label={setLabel(starNumber)}\r\n title={formatLabel(starNumber)}\r\n />\r\n </div>\r\n );\r\n }\r\n\r\n const circleStyles: CSSProperties =\r\n fillState === \"full\"\r\n ? { ...circleBaseStyles, backgroundColor: \"#03852e\" }\r\n : circleBaseStyles;\r\n\r\n const halfCircleStyles: CSSProperties = {\r\n ...circleBaseStyles,\r\n background:\r\n \"linear-gradient(90deg, #03852e 50%, transparent 50%)\",\r\n };\r\n\r\n return (\r\n <div\r\n key={index}\r\n style={{ position: \"relative\", width: \"12px\", height: \"12px\" }}\r\n >\r\n <span\r\n style={fillState === \"half\" ? halfCircleStyles : circleStyles}\r\n />\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...buttonBaseStyles,\r\n left: 0,\r\n width: \"50%\",\r\n borderRadius: \"50% 0 0 50%\",\r\n outline: \"2px solid transparent\",\r\n outlineOffset: \"1px\",\r\n }}\r\n onMouseEnter={() => setHoverRating(halfValue)}\r\n onFocus={() => setHoverRating(halfValue)}\r\n onBlur={handleBlur}\r\n onClick={() => handleSelect(halfValue)}\r\n aria-label={setLabel(halfValue)}\r\n title={formatLabel(halfValue)}\r\n />\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...buttonBaseStyles,\r\n left: \"50%\",\r\n width: \"50%\",\r\n borderRadius: \"0 50% 50% 0\",\r\n outline: \"2px solid transparent\",\r\n outlineOffset: \"1px\",\r\n }}\r\n onMouseEnter={() => setHoverRating(starNumber)}\r\n onFocus={() => setHoverRating(starNumber)}\r\n onBlur={handleBlur}\r\n onClick={() => handleSelect(starNumber)}\r\n aria-label={setLabel(starNumber)}\r\n title={formatLabel(starNumber)}\r\n />\r\n </div>\r\n );\r\n })}\r\n </div>\r\n <span style={{ whiteSpace: \"nowrap\" }}>\r\n {formatLabel(displayRating)}\r\n </span>\r\n </div>\r\n <CloseButton onClick={onRemove} />\r\n </div>\r\n );\r\n};\r\n","import { useCallback, useState } from \"react\";\r\n\r\nexport type Locale = \"en\" | \"es\" | \"de\" | \"fr\" | \"it\" | \"pt\";\r\n\r\ntype TranslationFunction = (\r\n key: string,\r\n params?: Record<string, any>\r\n) => string;\r\ntype FormatCurrencyFunction = (value: number, currency?: string) => string;\r\n\r\nconst defaultTranslations: Record<string, string> = {\r\n \"smartFilter.typingPrompt\":\r\n \"Search for hotels, restaurants, or attractions...\",\r\n \"smartFilter.nav.previous\": \"Previous filters\",\r\n \"smartFilter.nav.next\": \"Next filters\",\r\n \"smartFilter.toast.locationRequired\": \"Please select a location first\",\r\n \"smartFilter.clearAll\": \"Clear all\",\r\n \"smartFilter.minRating.suffix\": \"+\",\r\n \"smartFilter.minRating.label\": \"{{value}}+\",\r\n \"smartFilter.minRating.remove\": \"Remove rating filter\",\r\n \"smartFilter.minRating.setTo\": \"Set rating to {{rating}}\",\r\n \"smartFilter.priceRange.label\": \"Price Range\",\r\n \"smartFilter.priceRange.remove\": \"Remove price filter\",\r\n \"smartFilter.priceRange.edit\": \"Edit price\",\r\n \"smartFilter.transformedQuery.remove\": \"Remove search query\",\r\n \"smartFilter.transformedQuery.edit\": \"Edit search query\",\r\n \"smartFilter.restaurantPriceLevel.label\": \"Price Level\",\r\n \"smartFilter.restaurantPriceLevel.remove\": \"Remove price level filter\",\r\n \"smartFilter.restaurantPriceLevel.none\": \"Any\",\r\n \"smartFilter.restaurantPriceLevel.options.cheapEats\": \"Cheap Eats\",\r\n \"smartFilter.restaurantPriceLevel.options.midRange\": \"Mid Range\",\r\n \"smartFilter.restaurantPriceLevel.options.fineDining\": \"Fine Dining\",\r\n};\r\n\r\nconst formatCurrencyDefault: FormatCurrencyFunction = (\r\n value,\r\n currency = \"USD\"\r\n) => {\r\n return new Intl.NumberFormat(\"en-US\", {\r\n style: \"currency\",\r\n currency: currency,\r\n minimumFractionDigits: 0,\r\n maximumFractionDigits: 0,\r\n }).format(value);\r\n};\r\n\r\n/**\r\n * Simple translation hook with default English translations.\r\n * Can be extended with custom translations and locales.\r\n */\r\nexport const useTranslation = (\r\n customTranslations?: Record<string, string>,\r\n customFormatCurrency?: FormatCurrencyFunction\r\n) => {\r\n const [locale, setLocale] = useState<Locale>(\"en\");\r\n\r\n const t: TranslationFunction = useCallback(\r\n (key: string, params?: Record<string, any>) => {\r\n const translations = { ...defaultTranslations, ...customTranslations };\r\n let translation = translations[key] || key;\r\n\r\n if (params) {\r\n Object.keys(params).forEach((paramKey) => {\r\n translation = translation.replace(\r\n new RegExp(`{{${paramKey}}}`, \"g\"),\r\n String(params[paramKey])\r\n );\r\n });\r\n }\r\n\r\n return translation;\r\n },\r\n [customTranslations]\r\n );\r\n\r\n const formatCurrency = useCallback(\r\n (value: number, currency?: string) => {\r\n if (customFormatCurrency) {\r\n return customFormatCurrency(value, currency);\r\n }\r\n return formatCurrencyDefault(value, currency);\r\n },\r\n [customFormatCurrency]\r\n );\r\n\r\n return {\r\n t,\r\n locale,\r\n setLocale,\r\n formatCurrency,\r\n };\r\n};\r\n","import React, { ReactNode, CSSProperties } from \"react\";\r\n\r\nexport const renderStars = (rating: number): ReactNode[] => {\r\n const stars: ReactNode[] = [];\r\n const fullStars = Math.floor(rating);\r\n const hasHalfStar = rating % 1 !== 0;\r\n\r\n const baseStyles: CSSProperties = {\r\n display: \"block\",\r\n width: \"12px\",\r\n height: \"12px\",\r\n borderRadius: \"50%\",\r\n border: \"1px solid #03852e\",\r\n pointerEvents: \"none\",\r\n };\r\n\r\n const fullStarStyles: CSSProperties = {\r\n ...baseStyles,\r\n backgroundColor: \"#03852e\",\r\n };\r\n\r\n const halfStarStyles: CSSProperties = {\r\n ...baseStyles,\r\n background: \"linear-gradient(90deg, #03852e 50%, transparent 50%)\",\r\n };\r\n\r\n for (let i = 0; i < fullStars; i += 1) {\r\n stars.push(<span key={`full-${i}`} style={fullStarStyles} />);\r\n }\r\n\r\n if (hasHalfStar) {\r\n stars.push(<span key=\"half\" style={halfStarStyles} />);\r\n }\r\n\r\n const remainingStars = Math.max(0, 5 - Math.ceil(rating));\r\n for (let i = 0; i < remainingStars; i += 1) {\r\n stars.push(<span key={`empty-${i}`} style={baseStyles} />);\r\n }\r\n\r\n return stars;\r\n};\r\n\r\nexport const createMinRatingFilterLabel = (\r\n rating: number,\r\n suffix?: string\r\n): ReactNode => (\r\n <span style={{ display: \"flex\", alignItems: \"center\", gap: \"4px\" }}>\r\n <span\r\n style={{\r\n display: \"flex\",\r\n gap: \"1px\",\r\n userSelect: \"none\",\r\n }}\r\n >\r\n {renderStars(rating)}\r\n </span>{\" \"}\r\n {suffix}\r\n </span>\r\n);\r\n\r\nexport const formatRatingValue = (rating: number): string => rating.toFixed(1);\r\n\r\nexport const createPriceRangeFilterLabel = (\r\n min: number,\r\n max: number | undefined,\r\n currency: string | undefined,\r\n formatCurrencyFn: (value: number, currency?: string) => string\r\n): string =>\r\n `${formatCurrencyFn(min, currency)} - ${formatCurrencyFn(\r\n max ?? 0,\r\n currency\r\n )}`;\r\n","import React, {\r\n ChangeEvent,\r\n FunctionComponent,\r\n KeyboardEvent,\r\n useEffect,\r\n useState,\r\n CSSProperties,\r\n} from \"react\";\r\nimport { EditIcon } from \"../Icons\";\r\nimport { CloseButton } from \"./CloseButton\";\r\nimport { useTranslation } from \"../../hooks/useTranslation\";\r\nimport type { PriceRangeValue } from \"./types\";\r\n\r\ntype Boundary = \"min\" | \"max\";\r\n\r\nconst chipStyles: CSSProperties = {\r\n position: \"relative\",\r\n backgroundColor: \"white\",\r\n color: \"black\",\r\n fontSize: \"14px\",\r\n borderRadius: \"9999px\",\r\n padding: \"0 16px\",\r\n border: \"1px solid #03852e\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n flexShrink: 0,\r\n height: \"34px\",\r\n};\r\n\r\nconst inputStyles: CSSProperties = {\r\n outline: \"none\",\r\n fontSize: \"16px\",\r\n backgroundColor: \"transparent\",\r\n borderRadius: \"2px\",\r\n padding: \"2px 8px\",\r\n width: \"64px\",\r\n textAlign: \"center\",\r\n border: \"none\",\r\n};\r\n\r\nconst editButtonStyles: CSSProperties = {\r\n padding: \"4px\",\r\n borderRadius: \"50%\",\r\n cursor: \"pointer\",\r\n transition: \"background-color 0.2s\",\r\n border: \"none\",\r\n backgroundColor: \"transparent\",\r\n color: \"#737373\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n};\r\n\r\ninterface PriceBoundaryChipProps {\r\n boundary: Boundary;\r\n label: string;\r\n value?: number;\r\n placeholder?: string;\r\n currency: string;\r\n isOptional?: boolean;\r\n showRemoveButton?: boolean;\r\n removeLabel?: string;\r\n editLabel?: string;\r\n showAddWhenEmpty?: boolean;\r\n onCommit: (value?: number) => void;\r\n onRemove: () => void;\r\n}\r\n\r\nconst PriceBoundaryChip: FunctionComponent<PriceBoundaryChipProps> = ({\r\n boundary,\r\n label,\r\n value,\r\n placeholder,\r\n currency,\r\n isOptional = false,\r\n showRemoveButton = false,\r\n removeLabel,\r\n editLabel,\r\n showAddWhenEmpty = false,\r\n onCommit,\r\n onRemove,\r\n}) => {\r\n const [draft, setDraft] = useState<string>(\r\n value !== undefined ? String(value) : \"\"\r\n );\r\n const [isEditing, setIsEditing] = useState(false);\r\n const [editHover, setEditHover] = useState(false);\r\n const hasValue = value !== undefined;\r\n\r\n useEffect(() => {\r\n setDraft(value !== undefined ? String(value) : \"\");\r\n setIsEditing(false);\r\n }, [value]);\r\n\r\n const resetDraft = () => {\r\n setDraft(value !== undefined ? String(value) : \"\");\r\n };\r\n\r\n const commitValue = () => {\r\n if (draft.trim() === \"\") {\r\n if (isOptional) {\r\n onCommit(undefined);\r\n setDraft(\"\");\r\n return;\r\n }\r\n resetDraft();\r\n return;\r\n }\r\n\r\n const parsed = Number(draft);\r\n if (!Number.isFinite(parsed)) {\r\n resetDraft();\r\n return;\r\n }\r\n\r\n const normalized = Math.max(0, parsed);\r\n if (normalized === value) {\r\n resetDraft();\r\n return;\r\n }\r\n onCommit(normalized);\r\n };\r\n\r\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\r\n const next = event.target.value.replace(/[^\\d]/g, \"\");\r\n setDraft(next);\r\n };\r\n\r\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\r\n if (event.key === \"Enter\") {\r\n event.preventDefault();\r\n (event.currentTarget as HTMLInputElement).blur();\r\n setIsEditing(false);\r\n return;\r\n }\r\n\r\n if (event.key === \"Escape\") {\r\n event.preventDefault();\r\n resetDraft();\r\n (event.currentTarget as HTMLInputElement).blur();\r\n setIsEditing(false);\r\n return;\r\n }\r\n\r\n const allowed =\r\n (event.key.length === 1 && /[0-9]/.test(event.key)) ||\r\n event.key === \"Backspace\" ||\r\n event.key === \"Delete\" ||\r\n event.key === \"Tab\" ||\r\n event.key === \"ArrowLeft\" ||\r\n event.key === \"ArrowRight\" ||\r\n event.key === \"Home\" ||\r\n event.key === \"End\";\r\n\r\n if (!allowed) {\r\n event.preventDefault();\r\n }\r\n };\r\n\r\n return (\r\n <div style={chipStyles}>\r\n <span\r\n style={{\r\n fontSize: \"10px\",\r\n textTransform: \"uppercase\",\r\n fontWeight: 600,\r\n letterSpacing: \"0.05em\",\r\n }}\r\n >\r\n {label}\r\n </span>\r\n {isEditing ? (\r\n <input\r\n value={draft}\r\n onChange={handleChange}\r\n onBlur={() => {\r\n commitValue();\r\n setIsEditing(false);\r\n }}\r\n onKeyDown={handleKeyDown}\r\n placeholder={placeholder}\r\n inputMode=\"numeric\"\r\n pattern=\"[0-9]*\"\r\n aria-label={label}\r\n style={inputStyles}\r\n autoFocus\r\n />\r\n ) : hasValue ? (\r\n <span style={{ fontSize: \"16px\" }}>\r\n {currency}\r\n {value}\r\n </span>\r\n ) : showAddWhenEmpty ? (\r\n <button\r\n type=\"button\"\r\n style={{\r\n fontSize: \"16px\",\r\n color: \"#737373\",\r\n cursor: \"pointer\",\r\n border: \"none\",\r\n backgroundColor: \"transparent\",\r\n padding: 0,\r\n }}\r\n onClick={() => setIsEditing(true)}\r\n aria-label={editLabel}\r\n >\r\n +\r\n </button>\r\n ) : (\r\n <span style={{ fontSize: \"16px\", color: \"#737373\" }}>-</span>\r\n )}\r\n {(!showAddWhenEmpty || (showAddWhenEmpty && isEditing)) && (\r\n <span style={{ color: \"#737373\", fontSize: \"12px\" }}>{currency}</span>\r\n )}\r\n {!isEditing && (!showAddWhenEmpty || hasValue) && (\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...editButtonStyles,\r\n backgroundColor: editHover ? \"#e5e5e5\" : \"transparent\",\r\n }}\r\n aria-label={editLabel}\r\n title={editLabel}\r\n onClick={() => setIsEditing(true)}\r\n onMouseEnter={() => setEditHover(true)}\r\n onMouseLeave={() => setEditHover(false)}\r\n >\r\n <EditIcon />\r\n </button>\r\n )}\r\n {showRemoveButton && <CloseButton onClick={onRemove} />}\r\n </div>\r\n );\r\n};\r\n\r\nexport const PriceRangeFilterChip: FunctionComponent<{\r\n priceRange: PriceRangeValue;\r\n currency: string;\r\n onChange: (range: PriceRangeValue) => void;\r\n onRemove: () => void;\r\n}> = ({ priceRange, currency, onChange, onRemove }) => {\r\n const { t } = useTranslation();\r\n\r\n const minLabel = \"Min\";\r\n const maxChipLabel = \"Max\";\r\n const removeLabel = t(\"smartFilter.priceRange.remove\");\r\n const editLabel = t(\"smartFilter.priceRange.edit\");\r\n\r\n const handleBoundaryCommit = (boundary: Boundary, nextValue?: number) => {\r\n const nextRange: PriceRangeValue = {\r\n min: priceRange.min,\r\n max: priceRange.max,\r\n };\r\n\r\n if (boundary === \"min\") {\r\n nextRange.min = nextValue;\r\n if (\r\n nextValue !== undefined &&\r\n priceRange.max !== undefined &&\r\n nextValue > priceRange.max\r\n ) {\r\n nextRange.max = nextValue;\r\n }\r\n } else {\r\n nextRange.max = nextValue;\r\n if (\r\n nextValue !== undefined &&\r\n priceRange.min !== undefined &&\r\n nextValue < priceRange.min\r\n ) {\r\n nextRange.min = nextValue;\r\n }\r\n }\r\n\r\n if (nextRange.min !== priceRange.min || nextRange.max !== priceRange.max) {\r\n onChange(nextRange);\r\n }\r\n };\r\n\r\n return (\r\n <>\r\n <PriceBoundaryChip\r\n boundary=\"min\"\r\n label={minLabel}\r\n value={priceRange.min}\r\n currency={currency}\r\n editLabel={editLabel}\r\n showRemoveButton={priceRange.min !== undefined && priceRange.min !== 0}\r\n onCommit={(value) => handleBoundaryCommit(\"min\", value)}\r\n onRemove={onRemove}\r\n />\r\n <PriceBoundaryChip\r\n boundary=\"max\"\r\n label={maxChipLabel}\r\n value={priceRange.max}\r\n currency={currency}\r\n isOptional\r\n showRemoveButton={priceRange.max !== undefined}\r\n removeLabel={removeLabel}\r\n editLabel={editLabel}\r\n showAddWhenEmpty\r\n onCommit={(value) => handleBoundaryCommit(\"max\", value)}\r\n onRemove={onRemove}\r\n />\r\n </>\r\n );\r\n};\r\n","import React, { ChangeEvent, FunctionComponent, CSSProperties } from \"react\";\r\nimport { CloseButton } from \"./CloseButton\";\r\nimport { useTranslation } from \"../../hooks/useTranslation\";\r\nimport type { PriceLevel } from \"@mapfirst.ai/core\";\r\n\r\nconst chipStyles: CSSProperties = {\r\n position: \"relative\",\r\n backgroundColor: \"white\",\r\n color: \"black\",\r\n fontSize: \"14px\",\r\n borderRadius: \"9999px\",\r\n padding: \"0 16px\",\r\n paddingRight: \"20px\",\r\n border: \"1px solid #03852e\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"16px\",\r\n flexShrink: 0,\r\n height: \"34px\",\r\n};\r\n\r\nconst PRICE_LEVEL_OPTIONS = [\r\n { value: \"Cheap Eats\" as PriceLevel, key: \"cheapEats\" },\r\n { value: \"Mid Range\" as PriceLevel, key: \"midRange\" },\r\n { value: \"Fine Dining\" as PriceLevel, key: \"fineDining\" },\r\n] as const;\r\n\r\nexport interface RestaurantPriceLevelChipProps {\r\n values: PriceLevel[];\r\n onChange: (values: PriceLevel[]) => void;\r\n onRemove: () => void;\r\n}\r\n\r\nexport const RestaurantPriceLevelChip: FunctionComponent<\r\n RestaurantPriceLevelChipProps\r\n> = ({ values, onChange, onRemove }) => {\r\n const { t } = useTranslation();\r\n\r\n const label = t(\"smartFilter.restaurantPriceLevel.label\");\r\n const removeLabel = t(\"smartFilter.restaurantPriceLevel.remove\");\r\n const noneSelectedLabel = t(\"smartFilter.restaurantPriceLevel.none\");\r\n\r\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\r\n const { value, checked } = event.target;\r\n const valueAsPriceLevel = value as PriceLevel;\r\n const selection = new Set(values);\r\n if (checked) {\r\n selection.add(valueAsPriceLevel);\r\n } else {\r\n selection.delete(valueAsPriceLevel);\r\n }\r\n const orderedSelection = PRICE_LEVEL_OPTIONS.filter((option) =>\r\n selection.has(option.value)\r\n ).map((option) => option.value);\r\n onChange(orderedSelection);\r\n };\r\n\r\n return (\r\n <div style={chipStyles}>\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n flexWrap: \"wrap\",\r\n }}\r\n >\r\n <span\r\n style={{\r\n fontSize: \"10px\",\r\n textTransform: \"uppercase\",\r\n fontWeight: 600,\r\n letterSpacing: \"0.05em\",\r\n }}\r\n >\r\n {label}\r\n </span>\r\n <div style={{ display: \"flex\", gap: \"12px\" }}>\r\n {PRICE_LEVEL_OPTIONS.map((option) => {\r\n const optionLabel = t(\r\n `smartFilter.restaurantPriceLevel.options.${option.key}`\r\n );\r\n const checkboxId = `price-level-${option.key}`;\r\n return (\r\n <label\r\n key={option.value}\r\n htmlFor={checkboxId}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"4px\",\r\n fontSize: \"12px\",\r\n cursor: \"pointer\",\r\n }}\r\n >\r\n <input\r\n id={checkboxId}\r\n type=\"checkbox\"\r\n value={option.value}\r\n checked={values.includes(option.value)}\r\n onChange={handleChange}\r\n style={{ accentColor: \"#03852e\", cursor: \"pointer\" }}\r\n />\r\n <span>{optionLabel}</span>\r\n </label>\r\n );\r\n })}\r\n {values.length === 0 && (\r\n <span style={{ fontSize: \"12px\", color: \"#737373\" }}>\r\n {noneSelectedLabel}\r\n </span>\r\n )}\r\n </div>\r\n </div>\r\n\r\n <CloseButton onClick={onRemove} />\r\n </div>\r\n );\r\n};\r\n","import React, {\r\n ChangeEvent,\r\n FunctionComponent,\r\n KeyboardEvent,\r\n useEffect,\r\n useRef,\r\n useState,\r\n CSSProperties,\r\n} from \"react\";\r\nimport { EditIcon, SearchIcon } from \"../Icons\";\r\nimport { CloseButton } from \"./CloseButton\";\r\nimport { useTranslation } from \"../../hooks/useTranslation\";\r\n\r\nconst chipStyles: CSSProperties = {\r\n position: \"relative\",\r\n backgroundColor: \"white\",\r\n color: \"black\",\r\n fontSize: \"14px\",\r\n borderRadius: \"9999px\",\r\n padding: \"0 16px\",\r\n paddingRight: \"20px\",\r\n border: \"1px solid #03852e\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n flexShrink: 0,\r\n userSelect: \"none\",\r\n height: \"34px\",\r\n};\r\n\r\nconst inputStyles: CSSProperties = {\r\n backgroundColor: \"#ececec\",\r\n borderRadius: \"2px\",\r\n padding: \"2px 8px\",\r\n outline: \"none\",\r\n fontSize: \"16px\",\r\n minWidth: \"8ch\",\r\n border: \"none\",\r\n};\r\n\r\nconst editButtonStyles: CSSProperties = {\r\n padding: \"4px\",\r\n borderRadius: \"50%\",\r\n cursor: \"pointer\",\r\n transition: \"background-color 0.2s\",\r\n color: \"#737373\",\r\n border: \"none\",\r\n backgroundColor: \"transparent\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n};\r\n\r\nexport interface TransformedQueryChipProps {\r\n value: string;\r\n onChange: (nextValue: string) => void;\r\n onRemove: () => void;\r\n}\r\n\r\nexport const TransformedQueryChip: FunctionComponent<\r\n TransformedQueryChipProps\r\n> = ({ value, onChange, onRemove }) => {\r\n const inputRef = useRef<HTMLInputElement | null>(null);\r\n const [draft, setDraft] = useState(value);\r\n const [isEditing, setIsEditing] = useState(false);\r\n const [editHover, setEditHover] = useState(false);\r\n const { t } = useTranslation();\r\n\r\n const removeLabel = t(\"smartFilter.transformedQuery.remove\");\r\n const editLabel = t(\"smartFilter.transformedQuery.edit\");\r\n\r\n useEffect(() => {\r\n setDraft(value);\r\n setIsEditing(false);\r\n }, [value]);\r\n\r\n const applyChanges = () => {\r\n const nextValue = draft.trim();\r\n if (!nextValue.length) {\r\n setDraft(value);\r\n return;\r\n }\r\n if (nextValue === value) {\r\n return;\r\n }\r\n onChange(nextValue);\r\n };\r\n\r\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\r\n setDraft(event.target.value);\r\n };\r\n\r\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\r\n if (event.key === \"Enter\") {\r\n event.preventDefault();\r\n (event.currentTarget as HTMLInputElement).blur();\r\n return;\r\n }\r\n\r\n if (event.key === \"Escape\") {\r\n event.preventDefault();\r\n setDraft(value);\r\n (event.currentTarget as HTMLInputElement).blur();\r\n return;\r\n }\r\n };\r\n\r\n return (\r\n <div style={chipStyles}>\r\n <SearchIcon style={{ width: \"16px\", height: \"16px\", color: \"#03852e\" }} />\r\n {isEditing ? (\r\n <input\r\n ref={inputRef}\r\n value={draft}\r\n onChange={handleChange}\r\n onBlur={() => {\r\n applyChanges();\r\n setIsEditing(false);\r\n }}\r\n onKeyDown={handleKeyDown}\r\n aria-label={editLabel}\r\n style={inputStyles}\r\n autoFocus\r\n />\r\n ) : (\r\n <span style={{ fontSize: \"16px\" }}>{value}</span>\r\n )}\r\n {!isEditing && (\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...editButtonStyles,\r\n backgroundColor: editHover ? \"#e5e5e5\" : \"transparent\",\r\n }}\r\n aria-label={editLabel}\r\n title={editLabel}\r\n onClick={() => setIsEditing(true)}\r\n onMouseEnter={() => setEditHover(true)}\r\n onMouseLeave={() => setEditHover(false)}\r\n >\r\n <EditIcon />\r\n </button>\r\n )}\r\n <CloseButton onClick={onRemove} />\r\n </div>\r\n );\r\n};\r\n","import { useCallback, useEffect, useRef, useState } from \"react\";\r\n\r\nexport const useFilterScroll = (dependency: number) => {\r\n const scrollerRef = useRef<HTMLDivElement | null>(null);\r\n const [atStart, setAtStart] = useState(true);\r\n const [atEnd, setAtEnd] = useState(true);\r\n\r\n const updateScrollButtons = useCallback(() => {\r\n const el = scrollerRef.current;\r\n if (!el) {\r\n setAtStart(true);\r\n setAtEnd(true);\r\n return;\r\n }\r\n\r\n const { scrollLeft, scrollWidth, clientWidth } = el;\r\n setAtStart(scrollLeft <= 0);\r\n setAtEnd(scrollLeft + clientWidth >= scrollWidth - 1);\r\n }, []);\r\n\r\n useEffect(() => {\r\n const el = scrollerRef.current;\r\n updateScrollButtons();\r\n if (!el) {\r\n return;\r\n }\r\n\r\n const handleScroll = () => updateScrollButtons();\r\n el.addEventListener(\"scroll\", handleScroll, { passive: true });\r\n window.addEventListener(\"resize\", updateScrollButtons);\r\n\r\n return () => {\r\n el.removeEventListener(\"scroll\", handleScroll);\r\n window.removeEventListener(\"resize\", updateScrollButtons);\r\n };\r\n }, [dependency, updateScrollButtons]);\r\n\r\n const scrollByDir = useCallback((dir: \"prev\" | \"next\") => {\r\n const el = scrollerRef.current;\r\n if (!el) {\r\n return;\r\n }\r\n\r\n const delta = el.clientWidth * 0.7;\r\n el.scrollBy({\r\n left: dir === \"next\" ? delta : -delta,\r\n behavior: \"smooth\",\r\n });\r\n }, []);\r\n\r\n return {\r\n scrollerRef,\r\n atStart,\r\n atEnd,\r\n scrollByDir,\r\n };\r\n};\r\n","import { useEffect, useState } from \"react\";\r\n\r\n/**\r\n * Hook to detect if the viewport is in portrait orientation.\r\n * Updates on window resize.\r\n */\r\nexport const useIsPortrait = (): boolean => {\r\n const [isPortrait, setIsPortrait] = useState(\r\n typeof window !== \"undefined\"\r\n ? window.innerHeight > window.innerWidth\r\n : false\r\n );\r\n\r\n useEffect(() => {\r\n if (typeof window === \"undefined\") {\r\n return;\r\n }\r\n\r\n const handleResize = () => {\r\n setIsPortrait(window.innerHeight > window.innerWidth);\r\n };\r\n\r\n window.addEventListener(\"resize\", handleResize);\r\n return () => window.removeEventListener(\"resize\", handleResize);\r\n }, []);\r\n\r\n return isPortrait;\r\n};\r\n"],"mappings":"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","names":["index_exports","__export","Chip","CloseIcon","EditIcon","FilterChips","MarkerDebugList","MinRatingFilterChip","NextIcon","PriceRangeFilterChip","RestaurantPriceLevelChip","SearchIcon","SmartFilter","StarIcon","TransformedQueryChip","createMinRatingFilterLabel","createPriceRangeFilterLabel","formatRatingValue","renderStars","useFilterScroll","useGoogleMapsAttachment","useIsPortrait","useMapFirst","useMapFirstBoundsSearch","useMapFirstCore","useMapFirstProperties","useMapFirstSelectedProperty","useMapLibreAttachment","useMapboxAttachment","usePrimaryType","usePropertiesSearch","useSelectedMarker","useSmartFilterSearch","useTranslation","__toCommonJS","import_react","import_core","import_react","import_react","import_react","import_jsx_runtime","SearchIcon","className","style","CloseIcon","EditIcon","NextIcon","StarIcon","fill","import_jsx_runtime","closeButtonStyles","iconStyles","CloseButton","onClick","style","isHovering","setIsHovering","React","CloseIcon","import_jsx_runtime","chipStyles","Chip","label","icon","remove","style","CloseButton","import_react","import_react","defaultTranslations","formatCurrencyDefault","value","currency","useTranslation","customTranslations","customFormatCurrency","locale","setLocale","t","key","params","translation","paramKey","formatCurrency","import_jsx_runtime","renderStars","rating","stars","fullStars","hasHalfStar","baseStyles","fullStarStyles","halfStarStyles","i","remainingStars","createMinRatingFilterLabel","suffix","formatRatingValue","createPriceRangeFilterLabel","min","max","currency","formatCurrencyFn","import_jsx_runtime","chipContainerStyles","starContainerStyles","circleBaseStyles","buttonBaseStyles","MinRatingFilterChip","rating","onChange","onRemove","star","hoverRating","setHoverRating","t","useTranslation","displayRating","formatLabel","value","formatRatingValue","removeLabel","setLabel","getFillForStar","index","starNumber","handleSelect","nextRating","handleBlur","event","_a","related","_","fillState","halfValue","StarIcon","circleStyles","halfCircleStyles","CloseButton","import_react","import_jsx_runtime","chipStyles","inputStyles","editButtonStyles","PriceBoundaryChip","boundary","label","value","placeholder","currency","isOptional","showRemoveButton","removeLabel","editLabel","showAddWhenEmpty","onCommit","onRemove","draft","setDraft","isEditing","setIsEditing","editHover","setEditHover","hasValue","resetDraft","commitValue","parsed","normalized","event","next","EditIcon","CloseButton","PriceRangeFilterChip","priceRange","onChange","t","useTranslation","minLabel","maxChipLabel","handleBoundaryCommit","nextValue","nextRange","import_jsx_runtime","chipStyles","PRICE_LEVEL_OPTIONS","RestaurantPriceLevelChip","values","onChange","onRemove","t","useTranslation","label","removeLabel","noneSelectedLabel","handleChange","event","value","checked","valueAsPriceLevel","selection","orderedSelection","option","optionLabel","checkboxId","CloseButton","import_react","import_jsx_runtime","chipStyles","inputStyles","editButtonStyles","TransformedQueryChip","value","onChange","onRemove","inputRef","draft","setDraft","isEditing","setIsEditing","editHover","setEditHover","t","useTranslation","removeLabel","editLabel","applyChanges","nextValue","SearchIcon","event","EditIcon","CloseButton","import_react","useFilterScroll","dependency","scrollerRef","atStart","setAtStart","atEnd","setAtEnd","updateScrollButtons","el","scrollLeft","scrollWidth","clientWidth","handleScroll","scrollByDir","dir","delta","import_jsx_runtime","containerStyles","scrollContainerBase","gradientStyles","navButtonStyles","FilterChips","filters","isPortrait","currency","minRatingSuffix","clearAllLabel","previousFiltersLabel","nextFiltersLabel","formatCurrency","onFilterChange","onResetFilters","onClearAll","scrollerRef","atStart","atEnd","scrollByDir","useFilterScroll","t","useTranslation","navHover","setNavHover","React","resetHover","setResetHover","clearHover","setClearHover","scrollContainerStyles","SearchIcon","filter","_a","_b","_c","renderStandardChip","Chip","f","currentRating","MinRatingFilterChip","nextRating","nextFilters","PriceRangeFilterChip","nextRange","TransformedQueryChip","nextValue","RestaurantPriceLevelChip","nextLevels","NextIcon","import_react","useIsPortrait","isPortrait","setIsPortrait","handleResize","import_jsx_runtime","containerStyles","formStyles","inputContainerStyles","inputStyles","loaderContainerStyles","loaderStyles","typingPromptStyles","SmartFilter","mapFirst","filters","controlledValue","isSearching","placeholder","onSearch","onFilterChange","onValueChange","showTypingPrompt","customTranslations","currency","style","inputStyle","containerStyle","internalValue","setInternalValue","value","setValue","isPortrait","useIsPortrait","t","formatCurrency","useTranslation","minRatingSuffix","typingPrompt","previousFiltersLabel","nextFiltersLabel","clearAllLabel","formSubmit","e","query","error","handleFilterChange","nextFilters","clearAll","resetFilters","clearAllFilters","FilterChips","import_jsx_runtime","useMapFirstCore","options","instanceRef","React","state","setState","optionsRef","opts","coreOptions","properties","_a","_b","prev","id","type","filters","bounds","pendingBounds","center","zoom","location","loading","searching","instance","useMapFirstProperties","mapFirst","setProperties","useMapFirstSelectedProperty","selectedId","setSelectedId","usePrimaryType","primaryType","setPrimaryTypeState","setPrimaryType","useSelectedMarker","selectedMarker","setSelectedMarkerState","setSelectedMarker","useMapLibreAttachment","map","maplibregl","onMarkerClick","attachedRef","useGoogleMapsAttachment","google","useMapboxAttachment","mapboxgl","useMapFirst","usePropertiesSearch","isLoading","setIsLoading","error","setError","err","useSmartFilterSearch","useMapFirstBoundsSearch","isSearching","setIsSearching","MarkerDebugList","markers","marker","_c","_d","_e","_f"]}
1
+ {"version":3,"sources":["../src/index.tsx","../src/components/SmartFilter.tsx","../src/components/smart-filter/FilterChips.tsx","../src/components/smart-filter/CloseButton.tsx","../src/components/Icons.tsx","../src/components/smart-filter/Chip.tsx","../src/components/smart-filter/MinRatingFilterChip.tsx","../src/hooks/useTranslation.ts","../src/components/smart-filter/utils.tsx","../src/components/smart-filter/PriceRangeFilterChip.tsx","../src/components/smart-filter/RestaurantPriceLevelChip.tsx","../src/components/smart-filter/TransformedQueryChip.tsx","../src/hooks/useFilterScroll.ts"],"sourcesContent":["import React from \"react\";\nimport {\n MapFirstCore,\n type MapFirstOptions,\n type BaseMapFirstOptions,\n type Property,\n type MapLibreNamespace,\n type GoogleMapsNamespace,\n type MapboxNamespace,\n type MapState,\n type PropertyType,\n} from \"@mapfirst.ai/core\";\n\n// Export filter utilities from core\nexport {\n processApiFilters,\n convertToApiFilters,\n type ApiFiltersResponse,\n} from \"@mapfirst.ai/core\";\n\n// Export all components\nexport * from \"./components\";\n\n// Export all hooks\nexport * from \"./hooks\";\n\n// Import additional types for search functionality\ntype InitialRequestBody = {\n initial?: boolean;\n query?: string;\n bounds?: {\n sw: { lat: number; lng: number };\n ne: { lat: number; lng: number };\n };\n filters?: any;\n city?: string;\n country?: string;\n location_id?: number;\n longitude?: number;\n latitude?: number;\n radius?: number;\n};\n\ntype SmartFilter = {\n id: string;\n label: string;\n type:\n | \"amenity\"\n | \"hotelStyle\"\n | \"priceRange\"\n | \"minRating\"\n | \"starRating\"\n | \"primary_type\"\n | \"transformed_query\"\n | \"selected_restaurant_price_levels\";\n value: string;\n numericValue?: number;\n priceRange?: {\n min: number;\n max?: number;\n };\n propertyType?: PropertyType;\n priceLevels?: any[];\n};\n\n/**\n * Comprehensive hook for MapFirst SDK with all functionality in one place.\n * Creates a MapFirstCore instance with reactive state and provides all necessary methods.\n *\n * @example\n * ```tsx\n * // Initialize with location data\n * const {\n * instance,\n * state,\n * setPrimaryType,\n * setSelectedMarker,\n * propertiesSearch,\n * smartFilterSearch,\n * boundsSearch,\n * attachMapLibre,\n * attachGoogle,\n * attachMapbox\n * } = useMapFirst({\n * initialLocationData: {\n * city: \"New York\",\n * country: \"United States\",\n * currency: \"USD\"\n * }\n * });\n *\n * // Access reactive state\n * console.log(state?.properties);\n * console.log(state?.isSearching);\n * console.log(state?.selectedPropertyId);\n *\n * // Attach map when ready\n * useEffect(() => {\n * if (mapLibreInstance) {\n * attachMapLibre(mapLibreInstance, maplibregl, {\n * onMarkerClick: (marker) => console.log(marker)\n * });\n * }\n * }, [mapLibreInstance]);\n *\n * // Use search methods\n * await propertiesSearch.search({\n * body: { city: \"Paris\", country: \"France\" }\n * });\n *\n * await smartFilterSearch.search({\n * query: \"hotels near beach with pool\"\n * });\n *\n * await boundsSearch.perform();\n * ```\n */\nexport function useMapFirst(options: BaseMapFirstOptions) {\n const instanceRef = React.useRef<MapFirstCore | null>(null);\n const [state, setState] = React.useState<MapState | null>(null);\n\n // Memoize the options to prevent recreation on every render\n const optionsRef = React.useRef(options);\n React.useEffect(() => {\n optionsRef.current = options;\n });\n\n React.useEffect(() => {\n const opts = optionsRef.current;\n\n // Create MapFirstCore instance without map using adapter-driven options\n const coreOptions: MapFirstOptions = {\n adapter: null as any, // Will be set when attachMap is called\n ...opts,\n callbacks: {\n ...opts.callbacks,\n // Add internal callbacks to trigger React re-renders\n onPropertiesChange: (properties) => {\n setState((prev) => (prev ? { ...prev, properties } : null));\n optionsRef.current.callbacks?.onPropertiesChange?.(properties);\n },\n onSelectedPropertyChange: (id) => {\n setState((prev) =>\n prev ? { ...prev, selectedPropertyId: id } : null\n );\n optionsRef.current.callbacks?.onSelectedPropertyChange?.(id);\n },\n onPrimaryTypeChange: (type) => {\n setState((prev) => (prev ? { ...prev, primary: type } : null));\n optionsRef.current.callbacks?.onPrimaryTypeChange?.(type);\n },\n onFiltersChange: (filters) => {\n setState((prev) => (prev ? { ...prev, filters } : null));\n optionsRef.current.callbacks?.onFiltersChange?.(filters);\n },\n onBoundsChange: (bounds) => {\n setState((prev) => (prev ? { ...prev, bounds } : null));\n optionsRef.current.callbacks?.onBoundsChange?.(bounds);\n },\n onPendingBoundsChange: (pendingBounds) => {\n setState((prev) => (prev ? { ...prev, pendingBounds } : null));\n optionsRef.current.callbacks?.onPendingBoundsChange?.(pendingBounds);\n },\n onCenterChange: (center, zoom) => {\n setState((prev) => (prev ? { ...prev, center, zoom } : null));\n optionsRef.current.callbacks?.onCenterChange?.(center, zoom);\n },\n onZoomChange: (zoom) => {\n setState((prev) => (prev ? { ...prev, zoom } : null));\n optionsRef.current.callbacks?.onZoomChange?.(zoom);\n },\n onActiveLocationChange: (location) => {\n setState((prev) =>\n prev ? { ...prev, activeLocation: location } : null\n );\n optionsRef.current.callbacks?.onActiveLocationChange?.(location);\n },\n onLoadingStateChange: (loading) => {\n setState((prev) =>\n prev ? { ...prev, initialLoading: loading } : null\n );\n optionsRef.current.callbacks?.onLoadingStateChange?.(loading);\n },\n onSearchingStateChange: (searching) => {\n setState((prev) =>\n prev ? { ...prev, isSearching: searching } : null\n );\n optionsRef.current.callbacks?.onSearchingStateChange?.(searching);\n },\n },\n };\n\n const instance = new MapFirstCore(coreOptions);\n instanceRef.current = instance;\n\n // Initialize state from SDK\n setState(instance.getState());\n\n return () => {\n instance.destroy();\n instanceRef.current = null;\n setState(null);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Primary type control\n const setPrimaryType = React.useCallback((type: PropertyType) => {\n if (instanceRef.current) {\n instanceRef.current.setPrimaryType(type);\n }\n }, []);\n\n // Selected marker control\n const setSelectedMarker = React.useCallback((id: number | null) => {\n if (instanceRef.current) {\n instanceRef.current.setSelectedMarker(id);\n }\n }, []);\n\n // Properties search\n const [propertiesSearchLoading, setPropertiesSearchLoading] =\n React.useState(false);\n const [propertiesSearchError, setPropertiesSearchError] =\n React.useState<Error | null>(null);\n\n const propertiesSearch = React.useMemo(\n () => ({\n search: async (options: {\n body: InitialRequestBody;\n beforeApplyProperties?: (data: any) => {\n price?: any;\n limit?: number;\n };\n smartFiltersClearable?: boolean;\n }) => {\n if (!instanceRef.current) {\n const err = new Error(\"MapFirst instance not available\");\n setPropertiesSearchError(err);\n throw err;\n }\n\n setPropertiesSearchLoading(true);\n setPropertiesSearchError(null);\n\n try {\n const result = await instanceRef.current.runPropertiesSearch({\n ...options,\n onError: (err) => {\n const error = err instanceof Error ? err : new Error(String(err));\n setPropertiesSearchError(error);\n },\n });\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setPropertiesSearchError(error);\n throw error;\n } finally {\n setPropertiesSearchLoading(false);\n }\n },\n isLoading: propertiesSearchLoading,\n error: propertiesSearchError,\n }),\n [propertiesSearchLoading, propertiesSearchError]\n );\n\n // Smart filter search\n const [smartFilterSearchLoading, setSmartFilterSearchLoading] =\n React.useState(false);\n const [smartFilterSearchError, setSmartFilterSearchError] =\n React.useState<Error | null>(null);\n\n const smartFilterSearch = React.useMemo(\n () => ({\n search: async (options: {\n query?: string;\n filters?: SmartFilter[];\n onProcessFilters?: (\n filters: any,\n location_id?: number\n ) => {\n smartFilters?: SmartFilter[];\n price?: any;\n limit?: number;\n language?: string;\n };\n }) => {\n if (!instanceRef.current) {\n const err = new Error(\"MapFirst instance not available\");\n setSmartFilterSearchError(err);\n throw err;\n }\n\n setSmartFilterSearchLoading(true);\n setSmartFilterSearchError(null);\n\n try {\n const result = await instanceRef.current.runSmartFilterSearch({\n ...options,\n onError: (err) => {\n const error = err instanceof Error ? err : new Error(String(err));\n setSmartFilterSearchError(error);\n },\n });\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setSmartFilterSearchError(error);\n throw error;\n } finally {\n setSmartFilterSearchLoading(false);\n }\n },\n isLoading: smartFilterSearchLoading,\n error: smartFilterSearchError,\n }),\n [smartFilterSearchLoading, smartFilterSearchError]\n );\n\n // Bounds search\n const [boundsSearchLoading, setBoundsSearchLoading] = React.useState(false);\n const [boundsSearchError, setBoundsSearchError] =\n React.useState<Error | null>(null);\n\n const boundsSearch = React.useMemo(\n () => ({\n perform: async () => {\n if (!instanceRef.current) {\n return null;\n }\n\n setBoundsSearchLoading(true);\n setBoundsSearchError(null);\n\n try {\n const result = await instanceRef.current.performBoundsSearch();\n return result;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n setBoundsSearchError(error);\n throw error;\n } finally {\n setBoundsSearchLoading(false);\n }\n },\n isSearching: boundsSearchLoading,\n error: boundsSearchError,\n }),\n [boundsSearchLoading, boundsSearchError]\n );\n\n // Map attachment helpers\n const mapLibreAttachedRef = React.useRef(false);\n const attachMapLibre = React.useCallback(\n (\n map: any,\n maplibregl: MapLibreNamespace,\n options?: { onMarkerClick?: (marker: Property) => void }\n ) => {\n if (instanceRef.current && map && !mapLibreAttachedRef.current) {\n instanceRef.current.attachMap(map, {\n platform: \"maplibre\",\n maplibregl,\n onMarkerClick: options?.onMarkerClick,\n });\n mapLibreAttachedRef.current = true;\n }\n },\n []\n );\n\n const googleMapsAttachedRef = React.useRef(false);\n const attachGoogle = React.useCallback(\n (\n map: any,\n google: GoogleMapsNamespace,\n options?: { onMarkerClick?: (marker: Property) => void }\n ) => {\n if (instanceRef.current && map && !googleMapsAttachedRef.current) {\n instanceRef.current.attachMap(map, {\n platform: \"google\",\n google,\n onMarkerClick: options?.onMarkerClick,\n });\n googleMapsAttachedRef.current = true;\n }\n },\n []\n );\n\n const mapboxAttachedRef = React.useRef(false);\n const attachMapbox = React.useCallback(\n (\n map: any,\n mapboxgl: MapboxNamespace,\n options?: { onMarkerClick?: (marker: Property) => void }\n ) => {\n if (instanceRef.current && map && !mapboxAttachedRef.current) {\n instanceRef.current.attachMap(map, {\n platform: \"mapbox\",\n mapboxgl,\n onMarkerClick: options?.onMarkerClick,\n });\n mapboxAttachedRef.current = true;\n }\n },\n []\n );\n\n return {\n instance: instanceRef.current,\n state,\n setPrimaryType,\n setSelectedMarker,\n propertiesSearch,\n smartFilterSearch,\n boundsSearch,\n attachMapLibre,\n attachGoogle,\n attachMapbox,\n };\n}\n","import React, {\r\n FormEventHandler,\r\n FunctionComponent,\r\n useCallback,\r\n useState,\r\n CSSProperties,\r\n} from \"react\";\r\nimport { FilterChips } from \"./smart-filter/FilterChips\";\r\nimport { useTranslation } from \"../hooks/useTranslation\";\r\nimport type { Filter } from \"./smart-filter/types\";\r\nimport type { MapFirstCore } from \"@mapfirst.ai/core\";\r\n\r\nexport interface SmartFilterProps {\r\n mapFirst: MapFirstCore | null;\r\n filters: Filter[];\r\n value?: string;\r\n isSearching?: boolean;\r\n placeholder?: string;\r\n onSearch: (query: string, filters?: Filter[]) => Promise<void> | void;\r\n onFilterChange: (filters: Filter[]) => Promise<void> | void;\r\n onValueChange?: (value: string) => void;\r\n showTypingPrompt?: boolean;\r\n customTranslations?: Record<string, string>;\r\n currency?: string;\r\n style?: CSSProperties;\r\n inputStyle?: CSSProperties;\r\n containerStyle?: CSSProperties;\r\n}\r\n\r\nconst containerStyles: CSSProperties = {\r\n position: \"relative\",\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n gap: \"8px\",\r\n width: \"100%\",\r\n};\r\n\r\nconst formStyles: CSSProperties = {\r\n position: \"relative\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n width: \"100%\",\r\n};\r\n\r\nconst inputContainerStyles: CSSProperties = {\r\n position: \"relative\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n flex: 1,\r\n backgroundColor: \"white\",\r\n borderRadius: \"24px\",\r\n border: \"1px solid #e5e5e5\",\r\n padding: \"0 16px\",\r\n boxShadow: \"0 1px 3px rgba(0,0,0,0.1)\",\r\n};\r\n\r\nconst inputStyles: CSSProperties = {\r\n flex: 1,\r\n border: \"none\",\r\n outline: \"none\",\r\n fontSize: \"16px\",\r\n backgroundColor: \"transparent\",\r\n color: \"#000\",\r\n padding: \"10px\",\r\n};\r\n\r\nconst loaderContainerStyles: CSSProperties = {\r\n position: \"absolute\",\r\n right: \"16px\",\r\n top: \"50%\",\r\n transform: \"translateY(-50%)\",\r\n};\r\n\r\nconst loaderStyles: CSSProperties = {\r\n width: \"20px\",\r\n height: \"20px\",\r\n border: \"2px solid #e5e5e5\",\r\n borderTop: \"2px solid #03852e\",\r\n borderRadius: \"50%\",\r\n animation: \"spin 1s linear infinite\",\r\n};\r\n\r\nconst typingPromptStyles: CSSProperties = {\r\n position: \"absolute\",\r\n padding: \"10px\",\r\n color: \"#737373\",\r\n pointerEvents: \"none\",\r\n fontSize: \"16px\",\r\n};\r\n\r\n/**\r\n * SmartFilter component for AI-powered search with filter chips.\r\n * Provides a search input with smart filtering capabilities.\r\n *\r\n * @example\r\n * ```tsx\r\n * const { mapFirst, state } = useMapFirstCore({ ... });\r\n * const [filters, setFilters] = useState<Filter[]>([]);\r\n * const [searchValue, setSearchValue] = useState(\"\");\r\n *\r\n * const handleSearch = async (query: string, currentFilters?: Filter[]) => {\r\n * // Perform search using mapFirst.runSmartFilterSearch\r\n * const result = await mapFirst.runSmartFilterSearch({\r\n * query,\r\n * filters: currentFilters\r\n * });\r\n * // Update filters based on response\r\n * };\r\n *\r\n * return (\r\n * <SmartFilter\r\n * mapFirst={mapFirst}\r\n * filters={filters}\r\n * value={searchValue}\r\n * isSearching={state?.isSearching}\r\n * onSearch={handleSearch}\r\n * onFilterChange={setFilters}\r\n * onValueChange={setSearchValue}\r\n * />\r\n * );\r\n * ```\r\n */\r\nexport const SmartFilter: FunctionComponent<SmartFilterProps> = ({\r\n mapFirst,\r\n filters,\r\n value: controlledValue,\r\n isSearching = false,\r\n placeholder,\r\n onSearch,\r\n onFilterChange,\r\n onValueChange,\r\n showTypingPrompt = true,\r\n customTranslations,\r\n currency = \"USD\",\r\n style,\r\n inputStyle,\r\n containerStyle,\r\n}) => {\r\n const [internalValue, setInternalValue] = useState(\"\");\r\n const value = controlledValue !== undefined ? controlledValue : internalValue;\r\n const setValue = onValueChange || setInternalValue;\r\n\r\n const { t, formatCurrency } = useTranslation(customTranslations);\r\n\r\n const minRatingSuffix = t(\"smartFilter.minRating.suffix\");\r\n const typingPrompt = placeholder || t(\"smartFilter.typingPrompt\");\r\n const previousFiltersLabel = t(\"smartFilter.nav.previous\");\r\n const nextFiltersLabel = t(\"smartFilter.nav.next\");\r\n const clearAllLabel = t(\"smartFilter.clearAll\");\r\n\r\n const formSubmit: FormEventHandler<HTMLFormElement> = async (e) => {\r\n e.preventDefault();\r\n const query = value.trim();\r\n if (!query || isSearching) {\r\n return;\r\n }\r\n try {\r\n await onSearch(query);\r\n } catch (error) {\r\n console.error(\"Search error:\", error);\r\n }\r\n };\r\n\r\n const handleFilterChange = useCallback(\r\n async (nextFilters: Filter[], clearAll?: boolean) => {\r\n if (isSearching) {\r\n return;\r\n }\r\n try {\r\n await onFilterChange(nextFilters);\r\n } catch (error) {\r\n console.error(\"Filter change error:\", error);\r\n }\r\n },\r\n [isSearching, onFilterChange]\r\n );\r\n\r\n const resetFilters = useCallback(() => {\r\n void handleFilterChange([]);\r\n }, [handleFilterChange]);\r\n\r\n const clearAllFilters = useCallback(() => {\r\n void handleFilterChange([], true);\r\n setValue(\"\");\r\n }, [handleFilterChange, setValue]);\r\n\r\n return (\r\n <div style={{ ...containerStyles, ...containerStyle }}>\r\n <style>\r\n {`\r\n @keyframes spin {\r\n 0% { transform: rotate(0deg); }\r\n 100% { transform: rotate(360deg); }\r\n }\r\n `}\r\n </style>\r\n {filters.length === 0 && (\r\n <form onSubmit={formSubmit} style={{ ...formStyles, ...style }}>\r\n <div style={inputContainerStyles}>\r\n <input\r\n type=\"text\"\r\n value={value}\r\n onChange={(e) => setValue(e.target.value)}\r\n disabled={isSearching}\r\n style={{ ...inputStyles, ...inputStyle }}\r\n autoComplete=\"off\"\r\n aria-label=\"Smart search\"\r\n />\r\n {showTypingPrompt && value.length === 0 && !isSearching && (\r\n <span style={typingPromptStyles}>{typingPrompt}</span>\r\n )}\r\n {isSearching && (\r\n <div style={loaderContainerStyles}>\r\n <div style={loaderStyles} />\r\n </div>\r\n )}\r\n </div>\r\n </form>\r\n )}\r\n\r\n {filters.length > 0 && (\r\n <FilterChips\r\n filters={filters}\r\n currency={currency}\r\n minRatingSuffix={minRatingSuffix}\r\n clearAllLabel={clearAllLabel}\r\n previousFiltersLabel={previousFiltersLabel}\r\n nextFiltersLabel={nextFiltersLabel}\r\n formatCurrency={formatCurrency}\r\n onFilterChange={handleFilterChange}\r\n onResetFilters={resetFilters}\r\n onClearAll={clearAllFilters}\r\n />\r\n )}\r\n </div>\r\n );\r\n};\r\n","import React, { FunctionComponent, CSSProperties } from \"react\";\r\nimport { Chip } from \"./Chip\";\r\nimport { MinRatingFilterChip } from \"./MinRatingFilterChip\";\r\nimport { PriceRangeFilterChip } from \"./PriceRangeFilterChip\";\r\nimport { RestaurantPriceLevelChip } from \"./RestaurantPriceLevelChip\";\r\nimport { TransformedQueryChip } from \"./TransformedQueryChip\";\r\nimport { SearchIcon, NextIcon } from \"../Icons\";\r\nimport { useFilterScroll } from \"../../hooks/useFilterScroll\";\r\nimport type { Filter } from \"./types\";\r\n\r\nexport interface FilterChipsProps {\r\n filters: Filter[];\r\n currency: string;\r\n minRatingSuffix: string;\r\n clearAllLabel: string;\r\n previousFiltersLabel: string;\r\n nextFiltersLabel: string;\r\n formatCurrency: (value: number, currency?: string) => string;\r\n onFilterChange: (\r\n filters: Filter[],\r\n clearAll?: boolean\r\n ) => void | Promise<void>;\r\n onResetFilters: () => void;\r\n onClearAll: () => void;\r\n}\r\n\r\nconst containerStyles: CSSProperties = {\r\n position: \"relative\",\r\n width: \"100%\",\r\n};\r\n\r\nconst scrollContainerBase: CSSProperties = {\r\n display: \"flex\",\r\n gap: \"8px\",\r\n overflowX: \"auto\",\r\n alignItems: \"center\",\r\n width: \"100%\",\r\n scrollbarWidth: \"none\",\r\n msOverflowStyle: \"none\",\r\n};\r\n\r\nconst gradientStyles: CSSProperties = {\r\n pointerEvents: \"none\",\r\n position: \"absolute\",\r\n top: 0,\r\n bottom: 0,\r\n width: \"40px\",\r\n};\r\n\r\nconst navButtonStyles: CSSProperties = {\r\n position: \"absolute\",\r\n top: \"50%\",\r\n transform: \"translateY(-50%)\",\r\n backgroundColor: \"white\",\r\n color: \"#003c30\",\r\n border: \"1px solid #003c30\",\r\n padding: \"4px\",\r\n borderRadius: \"50%\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n boxShadow: \"0 1px 3px rgba(0,0,0,0.1)\",\r\n cursor: \"pointer\",\r\n};\r\n\r\nexport const FilterChips: FunctionComponent<FilterChipsProps> = ({\r\n filters,\r\n currency,\r\n minRatingSuffix,\r\n clearAllLabel,\r\n previousFiltersLabel,\r\n nextFiltersLabel,\r\n formatCurrency,\r\n onFilterChange,\r\n onResetFilters,\r\n onClearAll,\r\n}) => {\r\n const { scrollerRef, atStart, atEnd, scrollByDir } = useFilterScroll(\r\n filters.length\r\n );\r\n const [navHover, setNavHover] = React.useState<\"prev\" | \"next\" | null>(null);\r\n const [clearHover, setClearHover] = React.useState(false);\r\n\r\n return (\r\n <div style={containerStyles}>\r\n <div\r\n ref={scrollerRef}\r\n style={{\r\n ...scrollContainerBase,\r\n padding: \"8px\",\r\n // Hide scrollbar for webkit browsers\r\n WebkitOverflowScrolling: \"touch\",\r\n }}\r\n >\r\n <style>\r\n {`\r\n div::-webkit-scrollbar {\r\n display: none;\r\n }\r\n `}\r\n </style>\r\n {filters.map((filter) => {\r\n const renderStandardChip = () => (\r\n <Chip\r\n key={filter.id}\r\n label={filter.label}\r\n icon={filter.icon}\r\n remove={() => {\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id));\r\n }}\r\n />\r\n );\r\n\r\n if (filter.type === \"minRating\") {\r\n const currentRating = filter.numericValue ?? Number(filter.value);\r\n if (!Number.isFinite(currentRating)) {\r\n return renderStandardChip();\r\n }\r\n\r\n return (\r\n <MinRatingFilterChip\r\n key={filter.id}\r\n rating={currentRating}\r\n onChange={(nextRating) => {\r\n const nextFilters = filters.map((f) =>\r\n f.id === filter.id\r\n ? {\r\n ...f,\r\n numericValue: nextRating,\r\n value: String(nextRating),\r\n }\r\n : f\r\n );\r\n void onFilterChange(nextFilters);\r\n }}\r\n onRemove={() =>\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id))\r\n }\r\n />\r\n );\r\n }\r\n\r\n if (filter.type === \"starRating\") {\r\n const currentRating = filter.numericValue ?? Number(filter.value);\r\n if (!Number.isFinite(currentRating)) {\r\n return renderStandardChip();\r\n }\r\n\r\n return (\r\n <MinRatingFilterChip\r\n star\r\n key={filter.id}\r\n rating={currentRating}\r\n onChange={(nextRating) => {\r\n const nextFilters = filters.map((f) =>\r\n f.id === filter.id\r\n ? {\r\n ...f,\r\n numericValue: nextRating,\r\n value: String(nextRating),\r\n }\r\n : f\r\n );\r\n void onFilterChange(nextFilters);\r\n }}\r\n onRemove={() =>\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id))\r\n }\r\n />\r\n );\r\n }\r\n\r\n if (filter.type === \"priceRange\" && filter.priceRange) {\r\n return (\r\n <PriceRangeFilterChip\r\n key={filter.id}\r\n priceRange={filter.priceRange}\r\n currency={currency}\r\n onChange={(nextRange) => {\r\n const nextFilters = filters.map((f) =>\r\n f.id === filter.id\r\n ? {\r\n ...f,\r\n priceRange: nextRange,\r\n }\r\n : f\r\n );\r\n void onFilterChange(nextFilters);\r\n }}\r\n onRemove={() =>\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id))\r\n }\r\n />\r\n );\r\n }\r\n\r\n if (filter.type === \"transformed_query\") {\r\n return (\r\n <TransformedQueryChip\r\n key={filter.id}\r\n value={filter.value}\r\n onChange={(nextValue) => {\r\n const nextFilters = filters.map((f) =>\r\n f.id === filter.id\r\n ? {\r\n ...f,\r\n value: nextValue,\r\n }\r\n : f\r\n );\r\n void onFilterChange(nextFilters);\r\n }}\r\n onRemove={() =>\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id))\r\n }\r\n />\r\n );\r\n }\r\n\r\n if (filter.type === \"selected_restaurant_price_levels\") {\r\n return (\r\n <RestaurantPriceLevelChip\r\n key={filter.id}\r\n values={filter.priceLevels ?? []}\r\n onChange={(nextLevels) => {\r\n const nextFilters = filters.map((f) =>\r\n f.id === filter.id\r\n ? {\r\n ...f,\r\n priceLevels: nextLevels,\r\n }\r\n : f\r\n );\r\n void onFilterChange(nextFilters);\r\n }}\r\n onRemove={() =>\r\n void onFilterChange(filters.filter((f) => f.id !== filter.id))\r\n }\r\n />\r\n );\r\n }\r\n\r\n return renderStandardChip();\r\n })}\r\n <button\r\n style={{\r\n flexShrink: 0,\r\n padding: \"4px 16px\",\r\n borderRadius: \"9999px\",\r\n cursor: \"pointer\",\r\n fontSize: \"14px\",\r\n userSelect: \"none\",\r\n backgroundColor: clearHover ? \"#eee\" : \"white\",\r\n color: \"black\",\r\n border: \"1px solid #03852e\",\r\n }}\r\n onClick={onClearAll}\r\n onMouseEnter={() => setClearHover(true)}\r\n onMouseLeave={() => setClearHover(false)}\r\n >\r\n {clearAllLabel}\r\n </button>\r\n </div>\r\n\r\n {!atStart && (\r\n <div\r\n aria-hidden=\"true\"\r\n style={{\r\n ...gradientStyles,\r\n left: 0,\r\n background: \"linear-gradient(to right, white, transparent)\",\r\n }}\r\n />\r\n )}\r\n\r\n {!atEnd && (\r\n <div\r\n aria-hidden=\"true\"\r\n style={{\r\n ...gradientStyles,\r\n right: 0,\r\n background: \"linear-gradient(to left, white, transparent)\",\r\n }}\r\n />\r\n )}\r\n\r\n {!atStart && (\r\n <button\r\n type=\"button\"\r\n aria-label={previousFiltersLabel}\r\n style={{\r\n ...navButtonStyles,\r\n left: \"4px\",\r\n transform: \"translateY(-50%) rotate(180deg)\",\r\n backgroundColor: navHover === \"prev\" ? \"#e5e5e5\" : \"white\",\r\n }}\r\n onClick={() => scrollByDir(\"prev\")}\r\n onMouseEnter={() => setNavHover(\"prev\")}\r\n onMouseLeave={() => setNavHover(null)}\r\n >\r\n <NextIcon style={{ width: \"20px\", height: \"20px\" }} />\r\n </button>\r\n )}\r\n\r\n {!atEnd && (\r\n <button\r\n type=\"button\"\r\n aria-label={nextFiltersLabel}\r\n style={{\r\n ...navButtonStyles,\r\n right: \"4px\",\r\n backgroundColor: navHover === \"next\" ? \"#e5e5e5\" : \"white\",\r\n }}\r\n onClick={() => scrollByDir(\"next\")}\r\n onMouseEnter={() => setNavHover(\"next\")}\r\n onMouseLeave={() => setNavHover(null)}\r\n >\r\n <NextIcon style={{ width: \"20px\", height: \"20px\" }} />\r\n </button>\r\n )}\r\n </div>\r\n );\r\n};\r\n","import React, { CSSProperties } from \"react\";\r\nimport { CloseIcon } from \"../Icons\";\r\n\r\nexport interface CloseButtonProps {\r\n onClick: () => void;\r\n style?: CSSProperties;\r\n}\r\n\r\nconst closeButtonStyles: CSSProperties = {\r\n position: \"absolute\",\r\n top: \"-8px\",\r\n right: \"-8px\",\r\n padding: \"2px\",\r\n borderRadius: \"50%\",\r\n backgroundColor: \"white\",\r\n border: \"1px solid #03852e\",\r\n cursor: \"pointer\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n transition: \"background-color 0.2s\",\r\n};\r\n\r\nconst iconStyles: CSSProperties = {\r\n width: \"17px\",\r\n height: \"17px\",\r\n};\r\n\r\nexport const CloseButton: React.FC<CloseButtonProps> = ({ onClick, style }) => {\r\n const [isHovering, setIsHovering] = React.useState(false);\r\n\r\n return (\r\n <button\r\n style={{\r\n ...closeButtonStyles,\r\n backgroundColor: isHovering ? \"#e5e5e5\" : \"white\",\r\n ...style,\r\n }}\r\n onClick={onClick}\r\n onMouseEnter={() => setIsHovering(true)}\r\n onMouseLeave={() => setIsHovering(false)}\r\n aria-label=\"Remove filter\"\r\n >\r\n <CloseIcon style={iconStyles} />\r\n </button>\r\n );\r\n};\r\n","import React, { CSSProperties } from \"react\";\r\n\r\nexport interface IconProps {\r\n className?: string;\r\n style?: CSSProperties;\r\n}\r\n\r\nexport const SearchIcon: React.FC<IconProps> = ({ className, style }) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n style={{ width: \"1em\", height: \"1em\", ...style }}\r\n >\r\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\r\n <path d=\"m21 21-4.35-4.35\" />\r\n </svg>\r\n);\r\n\r\nexport const CloseIcon: React.FC<IconProps> = ({ className, style }) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n style={{ width: \"1em\", height: \"1em\", ...style }}\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\r\n </svg>\r\n);\r\n\r\nexport const EditIcon: React.FC<IconProps> = ({ className, style }) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n style={{ width: \"1em\", height: \"1em\", ...style }}\r\n >\r\n <path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\r\n <path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\" />\r\n </svg>\r\n);\r\n\r\nexport const NextIcon: React.FC<IconProps> = ({ className, style }) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n style={{ width: \"1em\", height: \"1em\", ...style }}\r\n >\r\n <polyline points=\"9 18 15 12 9 6\" />\r\n </svg>\r\n);\r\n\r\nexport const StarIcon: React.FC<IconProps & { fill?: string }> = ({\r\n className,\r\n style,\r\n fill = \"none\",\r\n}) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill={fill}\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n className={className}\r\n style={{ width: \"1em\", height: \"1em\", ...style }}\r\n >\r\n <polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\" />\r\n </svg>\r\n);\r\n","import React, { CSSProperties, ReactNode } from \"react\";\r\nimport { CloseButton } from \"./CloseButton\";\r\n\r\nexport interface ChipProps {\r\n label: string | ReactNode;\r\n icon?: ReactNode;\r\n remove: () => void;\r\n style?: CSSProperties;\r\n}\r\n\r\nconst chipStyles: CSSProperties = {\r\n position: \"relative\",\r\n backgroundColor: \"white\",\r\n color: \"black\",\r\n fontSize: \"14px\",\r\n borderRadius: \"9999px\",\r\n padding: \"0 16px\",\r\n paddingRight: \"20px\",\r\n border: \"1px solid #03852e\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n flexShrink: 0,\r\n height: \"34px\",\r\n};\r\n\r\nexport const Chip: React.FC<ChipProps> = ({ label, icon, remove, style }) => {\r\n return (\r\n <div style={{ ...chipStyles, ...style }}>\r\n {icon && (\r\n <span style={{ display: \"flex\", alignItems: \"center\" }}>{icon}</span>\r\n )}\r\n <span style={{ whiteSpace: \"nowrap\" }}>{label}</span>\r\n <CloseButton onClick={remove} />\r\n </div>\r\n );\r\n};\r\n","import React, {\r\n FunctionComponent,\r\n useState,\r\n FocusEvent,\r\n CSSProperties,\r\n} from \"react\";\r\nimport { StarIcon } from \"../Icons\";\r\nimport { CloseButton } from \"./CloseButton\";\r\nimport { useTranslation } from \"../../hooks/useTranslation\";\r\nimport { formatRatingValue } from \"./utils\";\r\n\r\nconst chipContainerStyles: CSSProperties = {\r\n position: \"relative\",\r\n backgroundColor: \"white\",\r\n color: \"black\",\r\n fontSize: \"14px\",\r\n borderRadius: \"9999px\",\r\n padding: \"0 16px\",\r\n paddingRight: \"20px\",\r\n border: \"1px solid #03852e\",\r\n display: \"flex\",\r\n gap: \"8px\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n flexShrink: 0,\r\n height: \"34px\",\r\n};\r\n\r\nconst starContainerStyles: CSSProperties = {\r\n display: \"flex\",\r\n gap: \"1px\",\r\n userSelect: \"none\",\r\n};\r\n\r\nconst circleBaseStyles: CSSProperties = {\r\n display: \"block\",\r\n width: \"12px\",\r\n height: \"12px\",\r\n borderRadius: \"50%\",\r\n border: \"1px solid #03852e\",\r\n pointerEvents: \"none\",\r\n};\r\n\r\nconst buttonBaseStyles: CSSProperties = {\r\n position: \"absolute\",\r\n top: 0,\r\n height: \"100%\",\r\n cursor: \"pointer\",\r\n backgroundColor: \"transparent\",\r\n border: \"none\",\r\n padding: 0,\r\n};\r\n\r\nexport const MinRatingFilterChip: FunctionComponent<{\r\n star?: boolean;\r\n rating: number;\r\n onChange: (rating: number) => void;\r\n onRemove: () => void;\r\n}> = ({ rating, onChange, onRemove, star = false }) => {\r\n const [hoverRating, setHoverRating] = useState<number | null>(null);\r\n const { t } = useTranslation();\r\n\r\n const displayRating = hoverRating ?? rating;\r\n const formatLabel = (value: number) =>\r\n star && value\r\n ? value.toString()\r\n : t(\"smartFilter.minRating.label\", { value: formatRatingValue(value) });\r\n const removeLabel = t(\"smartFilter.minRating.remove\");\r\n const setLabel = (value: number) =>\r\n t(\"smartFilter.minRating.setTo\", { rating: formatRatingValue(value) });\r\n\r\n const getFillForStar = (index: number) => {\r\n const starNumber = index + 1;\r\n if (displayRating >= starNumber) {\r\n return \"full\" as const;\r\n }\r\n if (displayRating >= starNumber - 0.5) {\r\n return \"half\" as const;\r\n }\r\n return \"empty\" as const;\r\n };\r\n\r\n const handleSelect = (nextRating: number) => {\r\n setHoverRating(null);\r\n if (nextRating === rating) {\r\n return;\r\n }\r\n onChange(nextRating);\r\n };\r\n\r\n const handleBlur = (event: FocusEvent<HTMLButtonElement>) => {\r\n const related = event.relatedTarget as HTMLElement | null;\r\n if (\r\n !related ||\r\n !(event.currentTarget as HTMLElement)\r\n .closest(\"[data-min-rating-chip]\")\r\n ?.contains(related)\r\n ) {\r\n setHoverRating(null);\r\n }\r\n };\r\n\r\n return (\r\n <div style={chipContainerStyles} data-min-rating-chip>\r\n <div\r\n style={{ display: \"flex\", alignItems: \"center\", gap: \"4px\" }}\r\n onMouseLeave={() => setHoverRating(null)}\r\n >\r\n <div style={starContainerStyles}>\r\n {Array.from({ length: 5 }).map((_, index) => {\r\n const fillState = getFillForStar(index);\r\n const starNumber = index + 1;\r\n const halfValue = starNumber - 0.5;\r\n\r\n if (star) {\r\n return (\r\n <div\r\n key={index}\r\n style={{\r\n position: \"relative\",\r\n width: \"16px\",\r\n height: \"16px\",\r\n }}\r\n >\r\n <StarIcon\r\n fill={displayRating >= starNumber ? \"#03852e\" : \"none\"}\r\n style={{\r\n width: \"16px\",\r\n height: \"16px\",\r\n pointerEvents: \"none\",\r\n }}\r\n />\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...buttonBaseStyles,\r\n left: 0,\r\n width: \"50%\",\r\n borderRadius: \"50% 0 0 50%\",\r\n }}\r\n onMouseEnter={() => setHoverRating(halfValue)}\r\n onFocus={() => setHoverRating(halfValue)}\r\n onBlur={handleBlur}\r\n onClick={() => handleSelect(halfValue)}\r\n aria-label={setLabel(halfValue)}\r\n title={formatLabel(halfValue)}\r\n />\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...buttonBaseStyles,\r\n left: \"50%\",\r\n width: \"50%\",\r\n borderRadius: \"0 50% 50% 0\",\r\n }}\r\n onMouseEnter={() => setHoverRating(starNumber)}\r\n onFocus={() => setHoverRating(starNumber)}\r\n onBlur={handleBlur}\r\n onClick={() => handleSelect(starNumber)}\r\n aria-label={setLabel(starNumber)}\r\n title={formatLabel(starNumber)}\r\n />\r\n </div>\r\n );\r\n }\r\n\r\n const circleStyles: CSSProperties =\r\n fillState === \"full\"\r\n ? { ...circleBaseStyles, backgroundColor: \"#03852e\" }\r\n : circleBaseStyles;\r\n\r\n const halfCircleStyles: CSSProperties = {\r\n ...circleBaseStyles,\r\n background:\r\n \"linear-gradient(90deg, #03852e 50%, transparent 50%)\",\r\n };\r\n\r\n return (\r\n <div\r\n key={index}\r\n style={{ position: \"relative\", width: \"12px\", height: \"12px\" }}\r\n >\r\n <span\r\n style={fillState === \"half\" ? halfCircleStyles : circleStyles}\r\n />\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...buttonBaseStyles,\r\n left: 0,\r\n width: \"50%\",\r\n borderRadius: \"50% 0 0 50%\",\r\n outline: \"2px solid transparent\",\r\n outlineOffset: \"1px\",\r\n }}\r\n onMouseEnter={() => setHoverRating(halfValue)}\r\n onFocus={() => setHoverRating(halfValue)}\r\n onBlur={handleBlur}\r\n onClick={() => handleSelect(halfValue)}\r\n aria-label={setLabel(halfValue)}\r\n title={formatLabel(halfValue)}\r\n />\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...buttonBaseStyles,\r\n left: \"50%\",\r\n width: \"50%\",\r\n borderRadius: \"0 50% 50% 0\",\r\n outline: \"2px solid transparent\",\r\n outlineOffset: \"1px\",\r\n }}\r\n onMouseEnter={() => setHoverRating(starNumber)}\r\n onFocus={() => setHoverRating(starNumber)}\r\n onBlur={handleBlur}\r\n onClick={() => handleSelect(starNumber)}\r\n aria-label={setLabel(starNumber)}\r\n title={formatLabel(starNumber)}\r\n />\r\n </div>\r\n );\r\n })}\r\n </div>\r\n <span style={{ whiteSpace: \"nowrap\" }}>\r\n {formatLabel(displayRating)}\r\n </span>\r\n </div>\r\n <CloseButton onClick={onRemove} />\r\n </div>\r\n );\r\n};\r\n","import { useCallback, useState } from \"react\";\r\n\r\nexport type Locale = \"en\" | \"es\" | \"de\" | \"fr\" | \"it\" | \"pt\";\r\n\r\ntype TranslationFunction = (\r\n key: string,\r\n params?: Record<string, any>\r\n) => string;\r\ntype FormatCurrencyFunction = (value: number, currency?: string) => string;\r\n\r\nconst defaultTranslations: Record<string, string> = {\r\n \"smartFilter.typingPrompt\":\r\n \"Search for hotels, restaurants, or attractions...\",\r\n \"smartFilter.nav.previous\": \"Previous filters\",\r\n \"smartFilter.nav.next\": \"Next filters\",\r\n \"smartFilter.toast.locationRequired\": \"Please select a location first\",\r\n \"smartFilter.clearAll\": \"Clear all\",\r\n \"smartFilter.minRating.suffix\": \"+\",\r\n \"smartFilter.minRating.label\": \"{{value}}+\",\r\n \"smartFilter.minRating.remove\": \"Remove rating filter\",\r\n \"smartFilter.minRating.setTo\": \"Set rating to {{rating}}\",\r\n \"smartFilter.priceRange.label\": \"Price Range\",\r\n \"smartFilter.priceRange.remove\": \"Remove price filter\",\r\n \"smartFilter.priceRange.edit\": \"Edit price\",\r\n \"smartFilter.transformedQuery.remove\": \"Remove search query\",\r\n \"smartFilter.transformedQuery.edit\": \"Edit search query\",\r\n \"smartFilter.restaurantPriceLevel.label\": \"Price Level\",\r\n \"smartFilter.restaurantPriceLevel.remove\": \"Remove price level filter\",\r\n \"smartFilter.restaurantPriceLevel.none\": \"Any\",\r\n \"smartFilter.restaurantPriceLevel.options.cheapEats\": \"Cheap Eats\",\r\n \"smartFilter.restaurantPriceLevel.options.midRange\": \"Mid Range\",\r\n \"smartFilter.restaurantPriceLevel.options.fineDining\": \"Fine Dining\",\r\n};\r\n\r\nconst formatCurrencyDefault: FormatCurrencyFunction = (\r\n value,\r\n currency = \"USD\"\r\n) => {\r\n return new Intl.NumberFormat(\"en-US\", {\r\n style: \"currency\",\r\n currency: currency,\r\n minimumFractionDigits: 0,\r\n maximumFractionDigits: 0,\r\n }).format(value);\r\n};\r\n\r\n/**\r\n * Simple translation hook with default English translations.\r\n * Can be extended with custom translations and locales.\r\n */\r\nexport const useTranslation = (\r\n customTranslations?: Record<string, string>,\r\n customFormatCurrency?: FormatCurrencyFunction\r\n) => {\r\n const [locale, setLocale] = useState<Locale>(\"en\");\r\n\r\n const t: TranslationFunction = useCallback(\r\n (key: string, params?: Record<string, any>) => {\r\n const translations = { ...defaultTranslations, ...customTranslations };\r\n let translation = translations[key] || key;\r\n\r\n if (params) {\r\n Object.keys(params).forEach((paramKey) => {\r\n translation = translation.replace(\r\n new RegExp(`{{${paramKey}}}`, \"g\"),\r\n String(params[paramKey])\r\n );\r\n });\r\n }\r\n\r\n return translation;\r\n },\r\n [customTranslations]\r\n );\r\n\r\n const formatCurrency = useCallback(\r\n (value: number, currency?: string) => {\r\n if (customFormatCurrency) {\r\n return customFormatCurrency(value, currency);\r\n }\r\n return formatCurrencyDefault(value, currency);\r\n },\r\n [customFormatCurrency]\r\n );\r\n\r\n return {\r\n t,\r\n locale,\r\n setLocale,\r\n formatCurrency,\r\n };\r\n};\r\n","import React, { ReactNode, CSSProperties } from \"react\";\r\n\r\nexport const renderStars = (rating: number): ReactNode[] => {\r\n const stars: ReactNode[] = [];\r\n const fullStars = Math.floor(rating);\r\n const hasHalfStar = rating % 1 !== 0;\r\n\r\n const baseStyles: CSSProperties = {\r\n display: \"block\",\r\n width: \"12px\",\r\n height: \"12px\",\r\n borderRadius: \"50%\",\r\n border: \"1px solid #03852e\",\r\n pointerEvents: \"none\",\r\n };\r\n\r\n const fullStarStyles: CSSProperties = {\r\n ...baseStyles,\r\n backgroundColor: \"#03852e\",\r\n };\r\n\r\n const halfStarStyles: CSSProperties = {\r\n ...baseStyles,\r\n background: \"linear-gradient(90deg, #03852e 50%, transparent 50%)\",\r\n };\r\n\r\n for (let i = 0; i < fullStars; i += 1) {\r\n stars.push(<span key={`full-${i}`} style={fullStarStyles} />);\r\n }\r\n\r\n if (hasHalfStar) {\r\n stars.push(<span key=\"half\" style={halfStarStyles} />);\r\n }\r\n\r\n const remainingStars = Math.max(0, 5 - Math.ceil(rating));\r\n for (let i = 0; i < remainingStars; i += 1) {\r\n stars.push(<span key={`empty-${i}`} style={baseStyles} />);\r\n }\r\n\r\n return stars;\r\n};\r\n\r\nexport const createMinRatingFilterLabel = (\r\n rating: number,\r\n suffix?: string\r\n): ReactNode => (\r\n <span style={{ display: \"flex\", alignItems: \"center\", gap: \"4px\" }}>\r\n <span\r\n style={{\r\n display: \"flex\",\r\n gap: \"1px\",\r\n userSelect: \"none\",\r\n }}\r\n >\r\n {renderStars(rating)}\r\n </span>{\" \"}\r\n {suffix}\r\n </span>\r\n);\r\n\r\nexport const formatRatingValue = (rating: number): string => rating.toFixed(1);\r\n\r\nexport const createPriceRangeFilterLabel = (\r\n min: number,\r\n max: number | undefined,\r\n currency: string | undefined,\r\n formatCurrencyFn: (value: number, currency?: string) => string\r\n): string =>\r\n `${formatCurrencyFn(min, currency)} - ${formatCurrencyFn(\r\n max ?? 0,\r\n currency\r\n )}`;\r\n","import React, {\r\n ChangeEvent,\r\n FunctionComponent,\r\n KeyboardEvent,\r\n useEffect,\r\n useState,\r\n CSSProperties,\r\n} from \"react\";\r\nimport { EditIcon } from \"../Icons\";\r\nimport { CloseButton } from \"./CloseButton\";\r\nimport { useTranslation } from \"../../hooks/useTranslation\";\r\nimport type { PriceRangeValue } from \"./types\";\r\n\r\ntype Boundary = \"min\" | \"max\";\r\n\r\nconst chipStyles: CSSProperties = {\r\n position: \"relative\",\r\n backgroundColor: \"white\",\r\n color: \"black\",\r\n fontSize: \"14px\",\r\n borderRadius: \"9999px\",\r\n padding: \"0 16px\",\r\n border: \"1px solid #03852e\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n flexShrink: 0,\r\n height: \"34px\",\r\n};\r\n\r\nconst inputStyles: CSSProperties = {\r\n outline: \"none\",\r\n fontSize: \"16px\",\r\n backgroundColor: \"transparent\",\r\n borderRadius: \"2px\",\r\n padding: \"2px 8px\",\r\n width: \"64px\",\r\n textAlign: \"center\",\r\n border: \"none\",\r\n};\r\n\r\nconst editButtonStyles: CSSProperties = {\r\n padding: \"4px\",\r\n borderRadius: \"50%\",\r\n cursor: \"pointer\",\r\n transition: \"background-color 0.2s\",\r\n border: \"none\",\r\n backgroundColor: \"transparent\",\r\n color: \"#737373\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n};\r\n\r\ninterface PriceBoundaryChipProps {\r\n boundary: Boundary;\r\n label: string;\r\n value?: number;\r\n placeholder?: string;\r\n currency: string;\r\n isOptional?: boolean;\r\n showRemoveButton?: boolean;\r\n removeLabel?: string;\r\n editLabel?: string;\r\n showAddWhenEmpty?: boolean;\r\n onCommit: (value?: number) => void;\r\n onRemove: () => void;\r\n}\r\n\r\nconst PriceBoundaryChip: FunctionComponent<PriceBoundaryChipProps> = ({\r\n boundary,\r\n label,\r\n value,\r\n placeholder,\r\n currency,\r\n isOptional = false,\r\n showRemoveButton = false,\r\n removeLabel,\r\n editLabel,\r\n showAddWhenEmpty = false,\r\n onCommit,\r\n onRemove,\r\n}) => {\r\n const [draft, setDraft] = useState<string>(\r\n value !== undefined ? String(value) : \"\"\r\n );\r\n const [isEditing, setIsEditing] = useState(false);\r\n const [editHover, setEditHover] = useState(false);\r\n const hasValue = value !== undefined;\r\n\r\n useEffect(() => {\r\n setDraft(value !== undefined ? String(value) : \"\");\r\n setIsEditing(false);\r\n }, [value]);\r\n\r\n const resetDraft = () => {\r\n setDraft(value !== undefined ? String(value) : \"\");\r\n };\r\n\r\n const commitValue = () => {\r\n if (draft.trim() === \"\") {\r\n if (isOptional) {\r\n onCommit(undefined);\r\n setDraft(\"\");\r\n return;\r\n }\r\n resetDraft();\r\n return;\r\n }\r\n\r\n const parsed = Number(draft);\r\n if (!Number.isFinite(parsed)) {\r\n resetDraft();\r\n return;\r\n }\r\n\r\n const normalized = Math.max(0, parsed);\r\n if (normalized === value) {\r\n resetDraft();\r\n return;\r\n }\r\n onCommit(normalized);\r\n };\r\n\r\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\r\n const next = event.target.value.replace(/[^\\d]/g, \"\");\r\n setDraft(next);\r\n };\r\n\r\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\r\n if (event.key === \"Enter\") {\r\n event.preventDefault();\r\n (event.currentTarget as HTMLInputElement).blur();\r\n setIsEditing(false);\r\n return;\r\n }\r\n\r\n if (event.key === \"Escape\") {\r\n event.preventDefault();\r\n resetDraft();\r\n (event.currentTarget as HTMLInputElement).blur();\r\n setIsEditing(false);\r\n return;\r\n }\r\n\r\n const allowed =\r\n (event.key.length === 1 && /[0-9]/.test(event.key)) ||\r\n event.key === \"Backspace\" ||\r\n event.key === \"Delete\" ||\r\n event.key === \"Tab\" ||\r\n event.key === \"ArrowLeft\" ||\r\n event.key === \"ArrowRight\" ||\r\n event.key === \"Home\" ||\r\n event.key === \"End\";\r\n\r\n if (!allowed) {\r\n event.preventDefault();\r\n }\r\n };\r\n\r\n return (\r\n <div style={chipStyles}>\r\n <span\r\n style={{\r\n fontSize: \"10px\",\r\n textTransform: \"uppercase\",\r\n fontWeight: 600,\r\n letterSpacing: \"0.05em\",\r\n }}\r\n >\r\n {label}\r\n </span>\r\n {isEditing ? (\r\n <input\r\n value={draft}\r\n onChange={handleChange}\r\n onBlur={() => {\r\n commitValue();\r\n setIsEditing(false);\r\n }}\r\n onKeyDown={handleKeyDown}\r\n placeholder={placeholder}\r\n inputMode=\"numeric\"\r\n pattern=\"[0-9]*\"\r\n aria-label={label}\r\n style={inputStyles}\r\n autoFocus\r\n />\r\n ) : hasValue ? (\r\n <span style={{ fontSize: \"16px\" }}>\r\n {currency}\r\n {value}\r\n </span>\r\n ) : showAddWhenEmpty ? (\r\n <button\r\n type=\"button\"\r\n style={{\r\n fontSize: \"16px\",\r\n color: \"#737373\",\r\n cursor: \"pointer\",\r\n border: \"none\",\r\n backgroundColor: \"transparent\",\r\n padding: 0,\r\n }}\r\n onClick={() => setIsEditing(true)}\r\n aria-label={editLabel}\r\n >\r\n +\r\n </button>\r\n ) : (\r\n <span style={{ fontSize: \"16px\", color: \"#737373\" }}>-</span>\r\n )}\r\n {(!showAddWhenEmpty || (showAddWhenEmpty && isEditing)) && (\r\n <span style={{ color: \"#737373\", fontSize: \"12px\" }}>{currency}</span>\r\n )}\r\n {!isEditing && (!showAddWhenEmpty || hasValue) && (\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...editButtonStyles,\r\n backgroundColor: editHover ? \"#e5e5e5\" : \"transparent\",\r\n }}\r\n aria-label={editLabel}\r\n title={editLabel}\r\n onClick={() => setIsEditing(true)}\r\n onMouseEnter={() => setEditHover(true)}\r\n onMouseLeave={() => setEditHover(false)}\r\n >\r\n <EditIcon />\r\n </button>\r\n )}\r\n {showRemoveButton && <CloseButton onClick={onRemove} />}\r\n </div>\r\n );\r\n};\r\n\r\nexport const PriceRangeFilterChip: FunctionComponent<{\r\n priceRange: PriceRangeValue;\r\n currency: string;\r\n onChange: (range: PriceRangeValue) => void;\r\n onRemove: () => void;\r\n}> = ({ priceRange, currency, onChange, onRemove }) => {\r\n const { t } = useTranslation();\r\n\r\n const minLabel = \"Min\";\r\n const maxChipLabel = \"Max\";\r\n const removeLabel = t(\"smartFilter.priceRange.remove\");\r\n const editLabel = t(\"smartFilter.priceRange.edit\");\r\n\r\n const handleBoundaryCommit = (boundary: Boundary, nextValue?: number) => {\r\n const nextRange: PriceRangeValue = {\r\n min: priceRange.min,\r\n max: priceRange.max,\r\n };\r\n\r\n if (boundary === \"min\") {\r\n nextRange.min = nextValue;\r\n if (\r\n nextValue !== undefined &&\r\n priceRange.max !== undefined &&\r\n nextValue > priceRange.max\r\n ) {\r\n nextRange.max = nextValue;\r\n }\r\n } else {\r\n nextRange.max = nextValue;\r\n if (\r\n nextValue !== undefined &&\r\n priceRange.min !== undefined &&\r\n nextValue < priceRange.min\r\n ) {\r\n nextRange.min = nextValue;\r\n }\r\n }\r\n\r\n if (nextRange.min !== priceRange.min || nextRange.max !== priceRange.max) {\r\n onChange(nextRange);\r\n }\r\n };\r\n\r\n return (\r\n <>\r\n <PriceBoundaryChip\r\n boundary=\"min\"\r\n label={minLabel}\r\n value={priceRange.min}\r\n currency={currency}\r\n editLabel={editLabel}\r\n showRemoveButton={priceRange.min !== undefined && priceRange.min !== 0}\r\n onCommit={(value) => handleBoundaryCommit(\"min\", value)}\r\n onRemove={onRemove}\r\n />\r\n <PriceBoundaryChip\r\n boundary=\"max\"\r\n label={maxChipLabel}\r\n value={priceRange.max}\r\n currency={currency}\r\n isOptional\r\n showRemoveButton={priceRange.max !== undefined}\r\n removeLabel={removeLabel}\r\n editLabel={editLabel}\r\n showAddWhenEmpty\r\n onCommit={(value) => handleBoundaryCommit(\"max\", value)}\r\n onRemove={onRemove}\r\n />\r\n </>\r\n );\r\n};\r\n","import React, { ChangeEvent, FunctionComponent, CSSProperties } from \"react\";\r\nimport { CloseButton } from \"./CloseButton\";\r\nimport { useTranslation } from \"../../hooks/useTranslation\";\r\nimport type { PriceLevel } from \"@mapfirst.ai/core\";\r\n\r\nconst chipStyles: CSSProperties = {\r\n position: \"relative\",\r\n backgroundColor: \"white\",\r\n color: \"black\",\r\n fontSize: \"14px\",\r\n borderRadius: \"9999px\",\r\n padding: \"0 16px\",\r\n paddingRight: \"20px\",\r\n border: \"1px solid #03852e\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"16px\",\r\n flexShrink: 0,\r\n height: \"34px\",\r\n};\r\n\r\nconst PRICE_LEVEL_OPTIONS = [\r\n { value: \"Cheap Eats\" as PriceLevel, key: \"cheapEats\" },\r\n { value: \"Mid Range\" as PriceLevel, key: \"midRange\" },\r\n { value: \"Fine Dining\" as PriceLevel, key: \"fineDining\" },\r\n] as const;\r\n\r\nexport interface RestaurantPriceLevelChipProps {\r\n values: PriceLevel[];\r\n onChange: (values: PriceLevel[]) => void;\r\n onRemove: () => void;\r\n}\r\n\r\nexport const RestaurantPriceLevelChip: FunctionComponent<\r\n RestaurantPriceLevelChipProps\r\n> = ({ values, onChange, onRemove }) => {\r\n const { t } = useTranslation();\r\n\r\n const label = t(\"smartFilter.restaurantPriceLevel.label\");\r\n const removeLabel = t(\"smartFilter.restaurantPriceLevel.remove\");\r\n const noneSelectedLabel = t(\"smartFilter.restaurantPriceLevel.none\");\r\n\r\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\r\n const { value, checked } = event.target;\r\n const valueAsPriceLevel = value as PriceLevel;\r\n const selection = new Set(values);\r\n if (checked) {\r\n selection.add(valueAsPriceLevel);\r\n } else {\r\n selection.delete(valueAsPriceLevel);\r\n }\r\n const orderedSelection = PRICE_LEVEL_OPTIONS.filter((option) =>\r\n selection.has(option.value)\r\n ).map((option) => option.value);\r\n onChange(orderedSelection);\r\n };\r\n\r\n return (\r\n <div style={chipStyles}>\r\n <div\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n flexWrap: \"wrap\",\r\n }}\r\n >\r\n <span\r\n style={{\r\n fontSize: \"10px\",\r\n textTransform: \"uppercase\",\r\n fontWeight: 600,\r\n letterSpacing: \"0.05em\",\r\n }}\r\n >\r\n {label}\r\n </span>\r\n <div style={{ display: \"flex\", gap: \"12px\" }}>\r\n {PRICE_LEVEL_OPTIONS.map((option) => {\r\n const optionLabel = t(\r\n `smartFilter.restaurantPriceLevel.options.${option.key}`\r\n );\r\n const checkboxId = `price-level-${option.key}`;\r\n return (\r\n <label\r\n key={option.value}\r\n htmlFor={checkboxId}\r\n style={{\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"4px\",\r\n fontSize: \"12px\",\r\n cursor: \"pointer\",\r\n }}\r\n >\r\n <input\r\n id={checkboxId}\r\n type=\"checkbox\"\r\n value={option.value}\r\n checked={values.includes(option.value)}\r\n onChange={handleChange}\r\n style={{ accentColor: \"#03852e\", cursor: \"pointer\" }}\r\n />\r\n <span>{optionLabel}</span>\r\n </label>\r\n );\r\n })}\r\n {values.length === 0 && (\r\n <span style={{ fontSize: \"12px\", color: \"#737373\" }}>\r\n {noneSelectedLabel}\r\n </span>\r\n )}\r\n </div>\r\n </div>\r\n\r\n <CloseButton onClick={onRemove} />\r\n </div>\r\n );\r\n};\r\n","import React, {\r\n ChangeEvent,\r\n FunctionComponent,\r\n KeyboardEvent,\r\n useEffect,\r\n useRef,\r\n useState,\r\n CSSProperties,\r\n} from \"react\";\r\nimport { EditIcon, SearchIcon } from \"../Icons\";\r\nimport { CloseButton } from \"./CloseButton\";\r\nimport { useTranslation } from \"../../hooks/useTranslation\";\r\n\r\nconst chipStyles: CSSProperties = {\r\n position: \"relative\",\r\n backgroundColor: \"white\",\r\n color: \"black\",\r\n fontSize: \"14px\",\r\n borderRadius: \"9999px\",\r\n padding: \"0 16px\",\r\n paddingRight: \"20px\",\r\n border: \"1px solid #03852e\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n flexShrink: 0,\r\n userSelect: \"none\",\r\n height: \"34px\",\r\n};\r\n\r\nconst inputStyles: CSSProperties = {\r\n backgroundColor: \"#ececec\",\r\n borderRadius: \"2px\",\r\n padding: \"2px 8px\",\r\n outline: \"none\",\r\n fontSize: \"16px\",\r\n minWidth: \"8ch\",\r\n border: \"none\",\r\n};\r\n\r\nconst editButtonStyles: CSSProperties = {\r\n padding: \"4px\",\r\n borderRadius: \"50%\",\r\n cursor: \"pointer\",\r\n transition: \"background-color 0.2s\",\r\n color: \"#737373\",\r\n border: \"none\",\r\n backgroundColor: \"transparent\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n};\r\n\r\nexport interface TransformedQueryChipProps {\r\n value: string;\r\n onChange: (nextValue: string) => void;\r\n onRemove: () => void;\r\n}\r\n\r\nexport const TransformedQueryChip: FunctionComponent<\r\n TransformedQueryChipProps\r\n> = ({ value, onChange, onRemove }) => {\r\n const inputRef = useRef<HTMLInputElement | null>(null);\r\n const [draft, setDraft] = useState(value);\r\n const [isEditing, setIsEditing] = useState(false);\r\n const [editHover, setEditHover] = useState(false);\r\n const { t } = useTranslation();\r\n\r\n const removeLabel = t(\"smartFilter.transformedQuery.remove\");\r\n const editLabel = t(\"smartFilter.transformedQuery.edit\");\r\n\r\n useEffect(() => {\r\n setDraft(value);\r\n setIsEditing(false);\r\n }, [value]);\r\n\r\n const applyChanges = () => {\r\n const nextValue = draft.trim();\r\n if (!nextValue.length) {\r\n setDraft(value);\r\n return;\r\n }\r\n if (nextValue === value) {\r\n return;\r\n }\r\n onChange(nextValue);\r\n };\r\n\r\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\r\n setDraft(event.target.value);\r\n };\r\n\r\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\r\n if (event.key === \"Enter\") {\r\n event.preventDefault();\r\n (event.currentTarget as HTMLInputElement).blur();\r\n return;\r\n }\r\n\r\n if (event.key === \"Escape\") {\r\n event.preventDefault();\r\n setDraft(value);\r\n (event.currentTarget as HTMLInputElement).blur();\r\n return;\r\n }\r\n };\r\n\r\n return (\r\n <div style={chipStyles}>\r\n <SearchIcon style={{ width: \"16px\", height: \"16px\", color: \"#03852e\" }} />\r\n {isEditing ? (\r\n <input\r\n ref={inputRef}\r\n value={draft}\r\n onChange={handleChange}\r\n onBlur={() => {\r\n applyChanges();\r\n setIsEditing(false);\r\n }}\r\n onKeyDown={handleKeyDown}\r\n aria-label={editLabel}\r\n style={inputStyles}\r\n autoFocus\r\n />\r\n ) : (\r\n <span style={{ fontSize: \"16px\" }}>{value}</span>\r\n )}\r\n {!isEditing && (\r\n <button\r\n type=\"button\"\r\n style={{\r\n ...editButtonStyles,\r\n backgroundColor: editHover ? \"#e5e5e5\" : \"transparent\",\r\n }}\r\n aria-label={editLabel}\r\n title={editLabel}\r\n onClick={() => setIsEditing(true)}\r\n onMouseEnter={() => setEditHover(true)}\r\n onMouseLeave={() => setEditHover(false)}\r\n >\r\n <EditIcon />\r\n </button>\r\n )}\r\n <CloseButton onClick={onRemove} />\r\n </div>\r\n );\r\n};\r\n","import { useCallback, useEffect, useRef, useState } from \"react\";\r\n\r\nexport const useFilterScroll = (dependency: number) => {\r\n const scrollerRef = useRef<HTMLDivElement | null>(null);\r\n const [atStart, setAtStart] = useState(true);\r\n const [atEnd, setAtEnd] = useState(true);\r\n\r\n const updateScrollButtons = useCallback(() => {\r\n const el = scrollerRef.current;\r\n if (!el) {\r\n setAtStart(true);\r\n setAtEnd(true);\r\n return;\r\n }\r\n\r\n const { scrollLeft, scrollWidth, clientWidth } = el;\r\n setAtStart(scrollLeft <= 0);\r\n setAtEnd(scrollLeft + clientWidth >= scrollWidth - 1);\r\n }, []);\r\n\r\n useEffect(() => {\r\n const el = scrollerRef.current;\r\n updateScrollButtons();\r\n if (!el) {\r\n return;\r\n }\r\n\r\n const handleScroll = () => updateScrollButtons();\r\n el.addEventListener(\"scroll\", handleScroll, { passive: true });\r\n window.addEventListener(\"resize\", updateScrollButtons);\r\n\r\n return () => {\r\n el.removeEventListener(\"scroll\", handleScroll);\r\n window.removeEventListener(\"resize\", updateScrollButtons);\r\n };\r\n }, [dependency, updateScrollButtons]);\r\n\r\n const scrollByDir = useCallback((dir: \"prev\" | \"next\") => {\r\n const el = scrollerRef.current;\r\n if (!el) {\r\n return;\r\n }\r\n\r\n const delta = el.clientWidth * 0.7;\r\n el.scrollBy({\r\n left: dir === \"next\" ? delta : -delta,\r\n behavior: \"smooth\",\r\n });\r\n }, []);\r\n\r\n return {\r\n scrollerRef,\r\n atStart,\r\n atEnd,\r\n scrollByDir,\r\n };\r\n};\r\n"],"mappings":"0kBAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,UAAAE,GAAA,cAAAC,GAAA,aAAAC,EAAA,gBAAAC,GAAA,wBAAAC,EAAA,aAAAC,GAAA,yBAAAC,GAAA,6BAAAC,GAAA,eAAAC,GAAA,gBAAAC,GAAA,aAAAC,GAAA,yBAAAC,GAAA,8EAAAC,GAAA,gCAAAC,GAAA,sBAAAC,GAAA,2DAAAC,GAAA,oBAAAC,GAAA,gBAAAC,GAAA,mBAAAC,IAAA,eAAAC,GAAArB,IAAA,IAAAsB,EAAkB,qBAClBC,GAUO,6BAGPA,GAIO,6BClBP,IAAAC,EAMO,iBCNP,IAAAC,GAAwD,qBCAxD,IAAAC,GAAqC,qBCQnC,IAAAC,EAAA,6BADWC,GAAkC,CAAC,CAAE,UAAAC,EAAW,MAAAC,CAAM,OACjE,QAAC,OACC,MAAM,6BACN,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,UAAWD,EACX,MAAO,CAAE,MAAO,MAAO,OAAQ,MAAO,GAAGC,CAAM,EAE/C,oBAAC,UAAO,GAAG,KAAK,GAAG,KAAK,EAAE,IAAI,KAC9B,OAAC,QAAK,EAAE,mBAAmB,GAC7B,EAGWC,GAAiC,CAAC,CAAE,UAAAF,EAAW,MAAAC,CAAM,OAChE,QAAC,OACC,MAAM,6BACN,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,UAAWD,EACX,MAAO,CAAE,MAAO,MAAO,OAAQ,MAAO,GAAGC,CAAM,EAE/C,oBAAC,QAAK,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,KACpC,OAAC,QAAK,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GACtC,EAGWE,EAAgC,CAAC,CAAE,UAAAH,EAAW,MAAAC,CAAM,OAC/D,QAAC,OACC,MAAM,6BACN,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,UAAWD,EACX,MAAO,CAAE,MAAO,MAAO,OAAQ,MAAO,GAAGC,CAAM,EAE/C,oBAAC,QAAK,EAAE,6DAA6D,KACrE,OAAC,QAAK,EAAE,0DAA0D,GACpE,EAGWG,GAAgC,CAAC,CAAE,UAAAJ,EAAW,MAAAC,CAAM,OAC/D,OAAC,OACC,MAAM,6BACN,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,UAAWD,EACX,MAAO,CAAE,MAAO,MAAO,OAAQ,MAAO,GAAGC,CAAM,EAE/C,mBAAC,YAAS,OAAO,iBAAiB,EACpC,EAGWI,GAAoD,CAAC,CAChE,UAAAL,EACA,MAAAC,EACA,KAAAK,EAAO,MACT,OACE,OAAC,OACC,MAAM,6BACN,QAAQ,YACR,KAAMA,EACN,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACf,UAAWN,EACX,MAAO,CAAE,MAAO,MAAO,OAAQ,MAAO,GAAGC,CAAM,EAE/C,mBAAC,WAAQ,OAAO,iGAAiG,EACnH,EDhDI,IAAAM,GAAA,6BAnCAC,GAAmC,CACvC,SAAU,WACV,IAAK,OACL,MAAO,OACP,QAAS,MACT,aAAc,MACd,gBAAiB,QACjB,OAAQ,oBACR,OAAQ,UACR,QAAS,OACT,WAAY,SACZ,eAAgB,SAChB,WAAY,uBACd,EAEMC,GAA4B,CAChC,MAAO,OACP,OAAQ,MACV,EAEaC,EAA0C,CAAC,CAAE,QAAAC,EAAS,MAAAC,CAAM,IAAM,CAC7E,GAAM,CAACC,EAAYC,CAAa,EAAI,GAAAC,QAAM,SAAS,EAAK,EAExD,SACE,QAAC,UACC,MAAO,CACL,GAAGP,GACH,gBAAiBK,EAAa,UAAY,QAC1C,GAAGD,CACL,EACA,QAASD,EACT,aAAc,IAAMG,EAAc,EAAI,EACtC,aAAc,IAAMA,EAAc,EAAK,EACvC,aAAW,gBAEX,oBAACE,GAAA,CAAU,MAAOP,GAAY,EAChC,CAEJ,EElBI,IAAAQ,EAAA,6BAlBEC,GAA4B,CAChC,SAAU,WACV,gBAAiB,QACjB,MAAO,QACP,SAAU,OACV,aAAc,SACd,QAAS,SACT,aAAc,OACd,OAAQ,oBACR,QAAS,OACT,WAAY,SACZ,IAAK,MACL,WAAY,EACZ,OAAQ,MACV,EAEaC,GAA4B,CAAC,CAAE,MAAAC,EAAO,KAAAC,EAAM,OAAAC,EAAQ,MAAAC,CAAM,OAEnE,QAAC,OAAI,MAAO,CAAE,GAAGL,GAAY,GAAGK,CAAM,EACnC,UAAAF,MACC,OAAC,QAAK,MAAO,CAAE,QAAS,OAAQ,WAAY,QAAS,EAAI,SAAAA,EAAK,KAEhE,OAAC,QAAK,MAAO,CAAE,WAAY,QAAS,EAAI,SAAAD,EAAM,KAC9C,OAACI,EAAA,CAAY,QAASF,EAAQ,GAChC,EClCJ,IAAAG,GAKO,iBCLP,IAAAC,EAAsC,iBAUhCC,GAA8C,CAClD,2BACE,oDACF,2BAA4B,mBAC5B,uBAAwB,eACxB,qCAAsC,iCACtC,uBAAwB,YACxB,+BAAgC,IAChC,8BAA+B,aAC/B,+BAAgC,uBAChC,8BAA+B,2BAC/B,+BAAgC,cAChC,gCAAiC,sBACjC,8BAA+B,aAC/B,sCAAuC,sBACvC,oCAAqC,oBACrC,yCAA0C,cAC1C,0CAA2C,4BAC3C,wCAAyC,MACzC,qDAAsD,aACtD,oDAAqD,YACrD,sDAAuD,aACzD,EAEMC,GAAgD,CACpDC,EACAC,EAAW,QAEJ,IAAI,KAAK,aAAa,QAAS,CACpC,MAAO,WACP,SAAUA,EACV,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,EAAE,OAAOD,CAAK,EAOJE,EAAiB,CAC5BC,EACAC,IACG,CACH,GAAM,CAACC,EAAQC,CAAS,KAAI,YAAiB,IAAI,EAE3CC,KAAyB,eAC7B,CAACC,EAAaC,IAAiC,CAE7C,IAAIC,EADiB,CAAE,GAAGZ,GAAqB,GAAGK,CAAmB,EACtCK,CAAG,GAAKA,EAEvC,OAAIC,GACF,OAAO,KAAKA,CAAM,EAAE,QAASE,GAAa,CACxCD,EAAcA,EAAY,QACxB,IAAI,OAAO,KAAKC,CAAQ,KAAM,GAAG,EACjC,OAAOF,EAAOE,CAAQ,CAAC,CACzB,CACF,CAAC,EAGID,CACT,EACA,CAACP,CAAkB,CACrB,EAEMS,KAAiB,eACrB,CAACZ,EAAeC,IACVG,EACKA,EAAqBJ,EAAOC,CAAQ,EAEtCF,GAAsBC,EAAOC,CAAQ,EAE9C,CAACG,CAAoB,CACvB,EAEA,MAAO,CACL,EAAAG,EACA,OAAAF,EACA,UAAAC,EACA,eAAAM,CACF,CACF,EChEe,IAAAC,EAAA,6BAzBFC,GAAeC,GAAgC,CAC1D,IAAMC,EAAqB,CAAC,EACtBC,EAAY,KAAK,MAAMF,CAAM,EAC7BG,EAAcH,EAAS,IAAM,EAE7BI,EAA4B,CAChC,QAAS,QACT,MAAO,OACP,OAAQ,OACR,aAAc,MACd,OAAQ,oBACR,cAAe,MACjB,EAEMC,EAAgC,CACpC,GAAGD,EACH,gBAAiB,SACnB,EAEME,EAAgC,CACpC,GAAGF,EACH,WAAY,sDACd,EAEA,QAASG,EAAI,EAAGA,EAAIL,EAAWK,GAAK,EAClCN,EAAM,QAAK,OAAC,QAAuB,MAAOI,GAApB,QAAQE,CAAC,EAA2B,CAAE,EAG1DJ,GACFF,EAAM,QAAK,OAAC,QAAgB,MAAOK,GAAd,MAA8B,CAAE,EAGvD,IAAME,EAAiB,KAAK,IAAI,EAAG,EAAI,KAAK,KAAKR,CAAM,CAAC,EACxD,QAASO,EAAI,EAAGA,EAAIC,EAAgBD,GAAK,EACvCN,EAAM,QAAK,OAAC,QAAwB,MAAOG,GAArB,SAASG,CAAC,EAAuB,CAAE,EAG3D,OAAON,CACT,EAEaQ,GAA6B,CACxCT,EACAU,OAEA,QAAC,QAAK,MAAO,CAAE,QAAS,OAAQ,WAAY,SAAU,IAAK,KAAM,EAC/D,oBAAC,QACC,MAAO,CACL,QAAS,OACT,IAAK,MACL,WAAY,MACd,EAEC,SAAAX,GAAYC,CAAM,EACrB,EAAQ,IACPU,GACH,EAGWC,GAAqBX,GAA2BA,EAAO,QAAQ,CAAC,EAEhEY,GAA8B,CACzCC,EACAC,EACAC,EACAC,IAEA,GAAGA,EAAiBH,EAAKE,CAAQ,CAAC,MAAMC,EACtCF,GAAA,KAAAA,EAAO,EACPC,CACF,CAAC,GF6Ca,IAAAE,EAAA,6BAzGVC,GAAqC,CACzC,SAAU,WACV,gBAAiB,QACjB,MAAO,QACP,SAAU,OACV,aAAc,SACd,QAAS,SACT,aAAc,OACd,OAAQ,oBACR,QAAS,OACT,IAAK,MACL,WAAY,SACZ,eAAgB,SAChB,WAAY,EACZ,OAAQ,MACV,EAEMC,GAAqC,CACzC,QAAS,OACT,IAAK,MACL,WAAY,MACd,EAEMC,GAAkC,CACtC,QAAS,QACT,MAAO,OACP,OAAQ,OACR,aAAc,MACd,OAAQ,oBACR,cAAe,MACjB,EAEMC,GAAkC,CACtC,SAAU,WACV,IAAK,EACL,OAAQ,OACR,OAAQ,UACR,gBAAiB,cACjB,OAAQ,OACR,QAAS,CACX,EAEaC,EAKR,CAAC,CAAE,OAAAC,EAAQ,SAAAC,EAAU,SAAAC,EAAU,KAAAC,EAAO,EAAM,IAAM,CACrD,GAAM,CAACC,EAAaC,CAAc,KAAI,aAAwB,IAAI,EAC5D,CAAE,EAAAC,CAAE,EAAIC,EAAe,EAEvBC,EAAgBJ,GAAA,KAAAA,EAAeJ,EAC/BS,EAAeC,GACnBP,GAAQO,EACJA,EAAM,SAAS,EACfJ,EAAE,8BAA+B,CAAE,MAAOK,GAAkBD,CAAK,CAAE,CAAC,EACpEE,EAAcN,EAAE,8BAA8B,EAC9CO,EAAYH,GAChBJ,EAAE,8BAA+B,CAAE,OAAQK,GAAkBD,CAAK,CAAE,CAAC,EAEjEI,EAAkBC,GAAkB,CACxC,IAAMC,EAAaD,EAAQ,EAC3B,OAAIP,GAAiBQ,EACZ,OAELR,GAAiBQ,EAAa,GACzB,OAEF,OACT,EAEMC,EAAgBC,GAAuB,CAC3Cb,EAAe,IAAI,EACfa,IAAelB,GAGnBC,EAASiB,CAAU,CACrB,EAEMC,EAAcC,GAAyC,CA1F/D,IAAAC,EA2FI,IAAMC,EAAUF,EAAM,eAEpB,CAACE,GACD,GAAED,EAAAD,EAAM,cACL,QAAQ,wBAAwB,IADjC,MAAAC,EAEE,SAASC,MAEbjB,EAAe,IAAI,CAEvB,EAEA,SACE,QAAC,OAAI,MAAOV,GAAqB,uBAAoB,GACnD,qBAAC,OACC,MAAO,CAAE,QAAS,OAAQ,WAAY,SAAU,IAAK,KAAM,EAC3D,aAAc,IAAMU,EAAe,IAAI,EAEvC,oBAAC,OAAI,MAAOT,GACT,eAAM,KAAK,CAAE,OAAQ,CAAE,CAAC,EAAE,IAAI,CAAC2B,EAAGR,IAAU,CAC3C,IAAMS,EAAYV,EAAeC,CAAK,EAChCC,EAAaD,EAAQ,EACrBU,EAAYT,EAAa,GAE/B,GAAIb,EACF,SACE,QAAC,OAEC,MAAO,CACL,SAAU,WACV,MAAO,OACP,OAAQ,MACV,EAEA,oBAACuB,GAAA,CACC,KAAMlB,GAAiBQ,EAAa,UAAY,OAChD,MAAO,CACL,MAAO,OACP,OAAQ,OACR,cAAe,MACjB,EACF,KACA,OAAC,UACC,KAAK,SACL,MAAO,CACL,GAAGlB,GACH,KAAM,EACN,MAAO,MACP,aAAc,aAChB,EACA,aAAc,IAAMO,EAAeoB,CAAS,EAC5C,QAAS,IAAMpB,EAAeoB,CAAS,EACvC,OAAQN,EACR,QAAS,IAAMF,EAAaQ,CAAS,EACrC,aAAYZ,EAASY,CAAS,EAC9B,MAAOhB,EAAYgB,CAAS,EAC9B,KACA,OAAC,UACC,KAAK,SACL,MAAO,CACL,GAAG3B,GACH,KAAM,MACN,MAAO,MACP,aAAc,aAChB,EACA,aAAc,IAAMO,EAAeW,CAAU,EAC7C,QAAS,IAAMX,EAAeW,CAAU,EACxC,OAAQG,EACR,QAAS,IAAMF,EAAaD,CAAU,EACtC,aAAYH,EAASG,CAAU,EAC/B,MAAOP,EAAYO,CAAU,EAC/B,IA5CKD,CA6CP,EAIJ,IAAMY,EACJH,IAAc,OACV,CAAE,GAAG3B,GAAkB,gBAAiB,SAAU,EAClDA,GAEA+B,EAAkC,CACtC,GAAG/B,GACH,WACE,sDACJ,EAEA,SACE,QAAC,OAEC,MAAO,CAAE,SAAU,WAAY,MAAO,OAAQ,OAAQ,MAAO,EAE7D,oBAAC,QACC,MAAO2B,IAAc,OAASI,EAAmBD,EACnD,KACA,OAAC,UACC,KAAK,SACL,MAAO,CACL,GAAG7B,GACH,KAAM,EACN,MAAO,MACP,aAAc,cACd,QAAS,wBACT,cAAe,KACjB,EACA,aAAc,IAAMO,EAAeoB,CAAS,EAC5C,QAAS,IAAMpB,EAAeoB,CAAS,EACvC,OAAQN,EACR,QAAS,IAAMF,EAAaQ,CAAS,EACrC,aAAYZ,EAASY,CAAS,EAC9B,MAAOhB,EAAYgB,CAAS,EAC9B,KACA,OAAC,UACC,KAAK,SACL,MAAO,CACL,GAAG3B,GACH,KAAM,MACN,MAAO,MACP,aAAc,cACd,QAAS,wBACT,cAAe,KACjB,EACA,aAAc,IAAMO,EAAeW,CAAU,EAC7C,QAAS,IAAMX,EAAeW,CAAU,EACxC,OAAQG,EACR,QAAS,IAAMF,EAAaD,CAAU,EACtC,aAAYH,EAASG,CAAU,EAC/B,MAAOP,EAAYO,CAAU,EAC/B,IAvCKD,CAwCP,CAEJ,CAAC,EACH,KACA,OAAC,QAAK,MAAO,CAAE,WAAY,QAAS,EACjC,SAAAN,EAAYD,CAAa,EAC5B,GACF,KACA,OAACqB,EAAA,CAAY,QAAS3B,EAAU,GAClC,CAEJ,EGtOA,IAAA4B,EAOO,iBA2JD,IAAAC,EAAA,6BAnJAC,GAA4B,CAChC,SAAU,WACV,gBAAiB,QACjB,MAAO,QACP,SAAU,OACV,aAAc,SACd,QAAS,SACT,OAAQ,oBACR,QAAS,OACT,WAAY,SACZ,IAAK,MACL,WAAY,EACZ,OAAQ,MACV,EAEMC,GAA6B,CACjC,QAAS,OACT,SAAU,OACV,gBAAiB,cACjB,aAAc,MACd,QAAS,UACT,MAAO,OACP,UAAW,SACX,OAAQ,MACV,EAEMC,GAAkC,CACtC,QAAS,MACT,aAAc,MACd,OAAQ,UACR,WAAY,wBACZ,OAAQ,OACR,gBAAiB,cACjB,MAAO,UACP,QAAS,OACT,WAAY,SACZ,eAAgB,QAClB,EAiBMC,GAA+D,CAAC,CACpE,SAAAC,EACA,MAAAC,EACA,MAAAC,EACA,YAAAC,EACA,SAAAC,EACA,WAAAC,EAAa,GACb,iBAAAC,EAAmB,GACnB,YAAAC,EACA,UAAAC,EACA,iBAAAC,EAAmB,GACnB,SAAAC,EACA,SAAAC,CACF,IAAM,CACJ,GAAM,CAACC,EAAOC,CAAQ,KAAI,YACxBX,IAAU,OAAY,OAAOA,CAAK,EAAI,EACxC,EACM,CAACY,EAAWC,CAAY,KAAI,YAAS,EAAK,EAC1C,CAACC,EAAWC,CAAY,KAAI,YAAS,EAAK,EAC1CC,EAAWhB,IAAU,UAE3B,aAAU,IAAM,CACdW,EAASX,IAAU,OAAY,OAAOA,CAAK,EAAI,EAAE,EACjDa,EAAa,EAAK,CACpB,EAAG,CAACb,CAAK,CAAC,EAEV,IAAMiB,EAAa,IAAM,CACvBN,EAASX,IAAU,OAAY,OAAOA,CAAK,EAAI,EAAE,CACnD,EAEMkB,EAAc,IAAM,CACxB,GAAIR,EAAM,KAAK,IAAM,GAAI,CACvB,GAAIP,EAAY,CACdK,EAAS,MAAS,EAClBG,EAAS,EAAE,EACX,MACF,CACAM,EAAW,EACX,MACF,CAEA,IAAME,EAAS,OAAOT,CAAK,EAC3B,GAAI,CAAC,OAAO,SAASS,CAAM,EAAG,CAC5BF,EAAW,EACX,MACF,CAEA,IAAMG,EAAa,KAAK,IAAI,EAAGD,CAAM,EACrC,GAAIC,IAAepB,EAAO,CACxBiB,EAAW,EACX,MACF,CACAT,EAASY,CAAU,CACrB,EAsCA,SACE,QAAC,OAAI,MAAO1B,GACV,oBAAC,QACC,MAAO,CACL,SAAU,OACV,cAAe,YACf,WAAY,IACZ,cAAe,QACjB,EAEC,SAAAK,EACH,EACCa,KACC,OAAC,SACC,MAAOF,EACP,SAnDcW,GAAyC,CAC7D,IAAMC,EAAOD,EAAM,OAAO,MAAM,QAAQ,SAAU,EAAE,EACpDV,EAASW,CAAI,CACf,EAiDQ,OAAQ,IAAM,CACZJ,EAAY,EACZL,EAAa,EAAK,CACpB,EACA,UAnDeQ,GAA2C,CAChE,GAAIA,EAAM,MAAQ,QAAS,CACzBA,EAAM,eAAe,EACpBA,EAAM,cAAmC,KAAK,EAC/CR,EAAa,EAAK,EAClB,MACF,CAEA,GAAIQ,EAAM,MAAQ,SAAU,CAC1BA,EAAM,eAAe,EACrBJ,EAAW,EACVI,EAAM,cAAmC,KAAK,EAC/CR,EAAa,EAAK,EAClB,MACF,CAGGQ,EAAM,IAAI,SAAW,GAAK,QAAQ,KAAKA,EAAM,GAAG,GACjDA,EAAM,MAAQ,aACdA,EAAM,MAAQ,UACdA,EAAM,MAAQ,OACdA,EAAM,MAAQ,aACdA,EAAM,MAAQ,cACdA,EAAM,MAAQ,QACdA,EAAM,MAAQ,OAGdA,EAAM,eAAe,CAEzB,EAuBQ,YAAapB,EACb,UAAU,UACV,QAAQ,SACR,aAAYF,EACZ,MAAOJ,GACP,UAAS,GACX,EACEqB,KACF,QAAC,QAAK,MAAO,CAAE,SAAU,MAAO,EAC7B,UAAAd,EACAF,GACH,EACEO,KACF,OAAC,UACC,KAAK,SACL,MAAO,CACL,SAAU,OACV,MAAO,UACP,OAAQ,UACR,OAAQ,OACR,gBAAiB,cACjB,QAAS,CACX,EACA,QAAS,IAAMM,EAAa,EAAI,EAChC,aAAYP,EACb,aAED,KAEA,OAAC,QAAK,MAAO,CAAE,SAAU,OAAQ,MAAO,SAAU,EAAG,aAAC,GAEtD,CAACC,GAAqBA,GAAoBK,OAC1C,OAAC,QAAK,MAAO,CAAE,MAAO,UAAW,SAAU,MAAO,EAAI,SAAAV,EAAS,EAEhE,CAACU,IAAc,CAACL,GAAoBS,OACnC,OAAC,UACC,KAAK,SACL,MAAO,CACL,GAAGpB,GACH,gBAAiBkB,EAAY,UAAY,aAC3C,EACA,aAAYR,EACZ,MAAOA,EACP,QAAS,IAAMO,EAAa,EAAI,EAChC,aAAc,IAAME,EAAa,EAAI,EACrC,aAAc,IAAMA,EAAa,EAAK,EAEtC,mBAACQ,EAAA,EAAS,EACZ,EAEDnB,MAAoB,OAACoB,EAAA,CAAY,QAASf,EAAU,GACvD,CAEJ,EAEagB,GAKR,CAAC,CAAE,WAAAC,EAAY,SAAAxB,EAAU,SAAAyB,EAAU,SAAAlB,CAAS,IAAM,CACrD,GAAM,CAAE,EAAAmB,CAAE,EAAIC,EAAe,EAEvBC,EAAW,MACXC,EAAe,MACf1B,EAAcuB,EAAE,+BAA+B,EAC/CtB,EAAYsB,EAAE,6BAA6B,EAE3CI,EAAuB,CAAClC,EAAoBmC,IAAuB,CACvE,IAAMC,EAA6B,CACjC,IAAKR,EAAW,IAChB,IAAKA,EAAW,GAClB,EAEI5B,IAAa,OACfoC,EAAU,IAAMD,EAEdA,IAAc,QACdP,EAAW,MAAQ,QACnBO,EAAYP,EAAW,MAEvBQ,EAAU,IAAMD,KAGlBC,EAAU,IAAMD,EAEdA,IAAc,QACdP,EAAW,MAAQ,QACnBO,EAAYP,EAAW,MAEvBQ,EAAU,IAAMD,KAIhBC,EAAU,MAAQR,EAAW,KAAOQ,EAAU,MAAQR,EAAW,MACnEC,EAASO,CAAS,CAEtB,EAEA,SACE,oBACE,oBAACrC,GAAA,CACC,SAAS,MACT,MAAOiC,EACP,MAAOJ,EAAW,IAClB,SAAUxB,EACV,UAAWI,EACX,iBAAkBoB,EAAW,MAAQ,QAAaA,EAAW,MAAQ,EACrE,SAAW1B,GAAUgC,EAAqB,MAAOhC,CAAK,EACtD,SAAUS,EACZ,KACA,OAACZ,GAAA,CACC,SAAS,MACT,MAAOkC,EACP,MAAOL,EAAW,IAClB,SAAUxB,EACV,WAAU,GACV,iBAAkBwB,EAAW,MAAQ,OACrC,YAAarB,EACb,UAAWC,EACX,iBAAgB,GAChB,SAAWN,GAAUgC,EAAqB,MAAOhC,CAAK,EACtD,SAAUS,EACZ,GACF,CAEJ,EChPQ,IAAA0B,EAAA,6BA9DFC,GAA4B,CAChC,SAAU,WACV,gBAAiB,QACjB,MAAO,QACP,SAAU,OACV,aAAc,SACd,QAAS,SACT,aAAc,OACd,OAAQ,oBACR,QAAS,OACT,WAAY,SACZ,IAAK,OACL,WAAY,EACZ,OAAQ,MACV,EAEMC,GAAsB,CAC1B,CAAE,MAAO,aAA4B,IAAK,WAAY,EACtD,CAAE,MAAO,YAA2B,IAAK,UAAW,EACpD,CAAE,MAAO,cAA6B,IAAK,YAAa,CAC1D,EAQaC,GAET,CAAC,CAAE,OAAAC,EAAQ,SAAAC,EAAU,SAAAC,CAAS,IAAM,CACtC,GAAM,CAAE,EAAAC,CAAE,EAAIC,EAAe,EAEvBC,EAAQF,EAAE,wCAAwC,EAClDG,EAAcH,EAAE,yCAAyC,EACzDI,EAAoBJ,EAAE,uCAAuC,EAE7DK,EAAgBC,GAAyC,CAC7D,GAAM,CAAE,MAAAC,EAAO,QAAAC,CAAQ,EAAIF,EAAM,OAC3BG,EAAoBF,EACpBG,EAAY,IAAI,IAAIb,CAAM,EAC5BW,EACFE,EAAU,IAAID,CAAiB,EAE/BC,EAAU,OAAOD,CAAiB,EAEpC,IAAME,EAAmBhB,GAAoB,OAAQiB,GACnDF,EAAU,IAAIE,EAAO,KAAK,CAC5B,EAAE,IAAKA,GAAWA,EAAO,KAAK,EAC9Bd,EAASa,CAAgB,CAC3B,EAEA,SACE,QAAC,OAAI,MAAOjB,GACV,qBAAC,OACC,MAAO,CACL,QAAS,OACT,WAAY,SACZ,IAAK,MACL,SAAU,MACZ,EAEA,oBAAC,QACC,MAAO,CACL,SAAU,OACV,cAAe,YACf,WAAY,IACZ,cAAe,QACjB,EAEC,SAAAQ,EACH,KACA,QAAC,OAAI,MAAO,CAAE,QAAS,OAAQ,IAAK,MAAO,EACxC,UAAAP,GAAoB,IAAKiB,GAAW,CACnC,IAAMC,EAAcb,EAClB,4CAA4CY,EAAO,GAAG,EACxD,EACME,EAAa,eAAeF,EAAO,GAAG,GAC5C,SACE,QAAC,SAEC,QAASE,EACT,MAAO,CACL,QAAS,OACT,WAAY,SACZ,IAAK,MACL,SAAU,OACV,OAAQ,SACV,EAEA,oBAAC,SACC,GAAIA,EACJ,KAAK,WACL,MAAOF,EAAO,MACd,QAASf,EAAO,SAASe,EAAO,KAAK,EACrC,SAAUP,EACV,MAAO,CAAE,YAAa,UAAW,OAAQ,SAAU,EACrD,KACA,OAAC,QAAM,SAAAQ,EAAY,IAlBdD,EAAO,KAmBd,CAEJ,CAAC,EACAf,EAAO,SAAW,MACjB,OAAC,QAAK,MAAO,CAAE,SAAU,OAAQ,MAAO,SAAU,EAC/C,SAAAO,EACH,GAEJ,GACF,KAEA,OAACW,EAAA,CAAY,QAAShB,EAAU,GAClC,CAEJ,ECtHA,IAAAiB,EAQO,iBAoGH,IAAAC,EAAA,6BA/FEC,GAA4B,CAChC,SAAU,WACV,gBAAiB,QACjB,MAAO,QACP,SAAU,OACV,aAAc,SACd,QAAS,SACT,aAAc,OACd,OAAQ,oBACR,QAAS,OACT,WAAY,SACZ,IAAK,MACL,WAAY,EACZ,WAAY,OACZ,OAAQ,MACV,EAEMC,GAA6B,CACjC,gBAAiB,UACjB,aAAc,MACd,QAAS,UACT,QAAS,OACT,SAAU,OACV,SAAU,MACV,OAAQ,MACV,EAEMC,GAAkC,CACtC,QAAS,MACT,aAAc,MACd,OAAQ,UACR,WAAY,wBACZ,MAAO,UACP,OAAQ,OACR,gBAAiB,cACjB,QAAS,OACT,WAAY,SACZ,eAAgB,QAClB,EAQaC,GAET,CAAC,CAAE,MAAAC,EAAO,SAAAC,EAAU,SAAAC,CAAS,IAAM,CACrC,IAAMC,KAAW,UAAgC,IAAI,EAC/C,CAACC,EAAOC,CAAQ,KAAI,YAASL,CAAK,EAClC,CAACM,EAAWC,CAAY,KAAI,YAAS,EAAK,EAC1C,CAACC,EAAWC,CAAY,KAAI,YAAS,EAAK,EAC1C,CAAE,EAAAC,CAAE,EAAIC,EAAe,EAEvBC,EAAcF,EAAE,qCAAqC,EACrDG,EAAYH,EAAE,mCAAmC,KAEvD,aAAU,IAAM,CACdL,EAASL,CAAK,EACdO,EAAa,EAAK,CACpB,EAAG,CAACP,CAAK,CAAC,EAEV,IAAMc,EAAe,IAAM,CACzB,IAAMC,EAAYX,EAAM,KAAK,EAC7B,GAAI,CAACW,EAAU,OAAQ,CACrBV,EAASL,CAAK,EACd,MACF,CACIe,IAAcf,GAGlBC,EAASc,CAAS,CACpB,EAqBA,SACE,QAAC,OAAI,MAAOnB,GACV,oBAACoB,GAAA,CAAW,MAAO,CAAE,MAAO,OAAQ,OAAQ,OAAQ,MAAO,SAAU,EAAG,EACvEV,KACC,OAAC,SACC,IAAKH,EACL,MAAOC,EACP,SA1Bca,GAAyC,CAC7DZ,EAASY,EAAM,OAAO,KAAK,CAC7B,EAyBQ,OAAQ,IAAM,CACZH,EAAa,EACbP,EAAa,EAAK,CACpB,EACA,UA3BeU,GAA2C,CAChE,GAAIA,EAAM,MAAQ,QAAS,CACzBA,EAAM,eAAe,EACpBA,EAAM,cAAmC,KAAK,EAC/C,MACF,CAEA,GAAIA,EAAM,MAAQ,SAAU,CAC1BA,EAAM,eAAe,EACrBZ,EAASL,CAAK,EACbiB,EAAM,cAAmC,KAAK,EAC/C,MACF,CACF,EAeQ,aAAYJ,EACZ,MAAOhB,GACP,UAAS,GACX,KAEA,OAAC,QAAK,MAAO,CAAE,SAAU,MAAO,EAAI,SAAAG,EAAM,EAE3C,CAACM,MACA,OAAC,UACC,KAAK,SACL,MAAO,CACL,GAAGR,GACH,gBAAiBU,EAAY,UAAY,aAC3C,EACA,aAAYK,EACZ,MAAOA,EACP,QAAS,IAAMN,EAAa,EAAI,EAChC,aAAc,IAAME,EAAa,EAAI,EACrC,aAAc,IAAMA,EAAa,EAAK,EAEtC,mBAACS,EAAA,EAAS,EACZ,KAEF,OAACC,EAAA,CAAY,QAASjB,EAAU,GAClC,CAEJ,EClJA,IAAAkB,EAAyD,iBAE5CC,GAAmBC,GAAuB,CACrD,IAAMC,KAAc,UAA8B,IAAI,EAChD,CAACC,EAASC,CAAU,KAAI,YAAS,EAAI,EACrC,CAACC,EAAOC,CAAQ,KAAI,YAAS,EAAI,EAEjCC,KAAsB,eAAY,IAAM,CAC5C,IAAMC,EAAKN,EAAY,QACvB,GAAI,CAACM,EAAI,CACPJ,EAAW,EAAI,EACfE,EAAS,EAAI,EACb,MACF,CAEA,GAAM,CAAE,WAAAG,EAAY,YAAAC,EAAa,YAAAC,CAAY,EAAIH,EACjDJ,EAAWK,GAAc,CAAC,EAC1BH,EAASG,EAAaE,GAAeD,EAAc,CAAC,CACtD,EAAG,CAAC,CAAC,KAEL,aAAU,IAAM,CACd,IAAMF,EAAKN,EAAY,QAEvB,GADAK,EAAoB,EAChB,CAACC,EACH,OAGF,IAAMI,EAAe,IAAML,EAAoB,EAC/C,OAAAC,EAAG,iBAAiB,SAAUI,EAAc,CAAE,QAAS,EAAK,CAAC,EAC7D,OAAO,iBAAiB,SAAUL,CAAmB,EAE9C,IAAM,CACXC,EAAG,oBAAoB,SAAUI,CAAY,EAC7C,OAAO,oBAAoB,SAAUL,CAAmB,CAC1D,CACF,EAAG,CAACN,EAAYM,CAAmB,CAAC,EAEpC,IAAMM,KAAc,eAAaC,GAAyB,CACxD,IAAMN,EAAKN,EAAY,QACvB,GAAI,CAACM,EACH,OAGF,IAAMO,EAAQP,EAAG,YAAc,GAC/BA,EAAG,SAAS,CACV,KAAMM,IAAQ,OAASC,EAAQ,CAACA,EAChC,SAAU,QACZ,CAAC,CACH,EAAG,CAAC,CAAC,EAEL,MAAO,CACL,YAAAb,EACA,QAAAC,EACA,MAAAE,EACA,YAAAQ,CACF,CACF,EV6BM,IAAAG,EAAA,6BA3DAC,GAAiC,CACrC,SAAU,WACV,MAAO,MACT,EAEMC,GAAqC,CACzC,QAAS,OACT,IAAK,MACL,UAAW,OACX,WAAY,SACZ,MAAO,OACP,eAAgB,OAChB,gBAAiB,MACnB,EAEMC,GAAgC,CACpC,cAAe,OACf,SAAU,WACV,IAAK,EACL,OAAQ,EACR,MAAO,MACT,EAEMC,GAAiC,CACrC,SAAU,WACV,IAAK,MACL,UAAW,mBACX,gBAAiB,QACjB,MAAO,UACP,OAAQ,oBACR,QAAS,MACT,aAAc,MACd,QAAS,OACT,WAAY,SACZ,eAAgB,SAChB,UAAW,4BACX,OAAQ,SACV,EAEaC,GAAmD,CAAC,CAC/D,QAAAC,EACA,SAAAC,EACA,gBAAAC,EACA,cAAAC,EACA,qBAAAC,EACA,iBAAAC,EACA,eAAAC,EACA,eAAAC,EACA,eAAAC,EACA,WAAAC,CACF,IAAM,CACJ,GAAM,CAAE,YAAAC,EAAa,QAAAC,EAAS,MAAAC,EAAO,YAAAC,CAAY,EAAIC,GACnDd,EAAQ,MACV,EACM,CAACe,EAAUC,CAAW,EAAI,GAAAC,QAAM,SAAiC,IAAI,EACrE,CAACC,EAAYC,CAAa,EAAI,GAAAF,QAAM,SAAS,EAAK,EAExD,SACE,QAAC,OAAI,MAAOtB,GACV,qBAAC,OACC,IAAKe,EACL,MAAO,CACL,GAAGd,GACH,QAAS,MAET,wBAAyB,OAC3B,EAEA,oBAAC,SACE;AAAA;AAAA;AAAA;AAAA,YAKH,EACCI,EAAQ,IAAKoB,GAAW,CArGjC,IAAAC,EAAAC,EAAAC,EAsGU,IAAMC,EAAqB,OACzB,OAACC,GAAA,CAEC,MAAOL,EAAO,MACd,KAAMA,EAAO,KACb,OAAQ,IAAM,CACPb,EAAeP,EAAQ,OAAQ0B,GAAMA,EAAE,KAAON,EAAO,EAAE,CAAC,CAC/D,GALKA,EAAO,EAMd,EAGF,GAAIA,EAAO,OAAS,YAAa,CAC/B,IAAMO,GAAgBN,EAAAD,EAAO,eAAP,KAAAC,EAAuB,OAAOD,EAAO,KAAK,EAChE,OAAK,OAAO,SAASO,CAAa,KAKhC,OAACC,EAAA,CAEC,OAAQD,EACR,SAAWE,GAAe,CACxB,IAAMC,EAAc9B,EAAQ,IAAK0B,GAC/BA,EAAE,KAAON,EAAO,GACZ,CACE,GAAGM,EACH,aAAcG,EACd,MAAO,OAAOA,CAAU,CAC1B,EACAH,CACN,EACKnB,EAAeuB,CAAW,CACjC,EACA,SAAU,IACR,KAAKvB,EAAeP,EAAQ,OAAQ0B,GAAMA,EAAE,KAAON,EAAO,EAAE,CAAC,GAf1DA,EAAO,EAiBd,EAtBOI,EAAmB,CAwB9B,CAEA,GAAIJ,EAAO,OAAS,aAAc,CAChC,IAAMO,GAAgBL,EAAAF,EAAO,eAAP,KAAAE,EAAuB,OAAOF,EAAO,KAAK,EAChE,OAAK,OAAO,SAASO,CAAa,KAKhC,OAACC,EAAA,CACC,KAAI,GAEJ,OAAQD,EACR,SAAWE,GAAe,CACxB,IAAMC,EAAc9B,EAAQ,IAAK0B,GAC/BA,EAAE,KAAON,EAAO,GACZ,CACE,GAAGM,EACH,aAAcG,EACd,MAAO,OAAOA,CAAU,CAC1B,EACAH,CACN,EACKnB,EAAeuB,CAAW,CACjC,EACA,SAAU,IACR,KAAKvB,EAAeP,EAAQ,OAAQ0B,GAAMA,EAAE,KAAON,EAAO,EAAE,CAAC,GAf1DA,EAAO,EAiBd,EAvBOI,EAAmB,CAyB9B,CAEA,OAAIJ,EAAO,OAAS,cAAgBA,EAAO,cAEvC,OAACW,GAAA,CAEC,WAAYX,EAAO,WACnB,SAAUnB,EACV,SAAW+B,GAAc,CACvB,IAAMF,EAAc9B,EAAQ,IAAK0B,GAC/BA,EAAE,KAAON,EAAO,GACZ,CACE,GAAGM,EACH,WAAYM,CACd,EACAN,CACN,EACKnB,EAAeuB,CAAW,CACjC,EACA,SAAU,IACR,KAAKvB,EAAeP,EAAQ,OAAQ0B,GAAMA,EAAE,KAAON,EAAO,EAAE,CAAC,GAf1DA,EAAO,EAiBd,EAIAA,EAAO,OAAS,uBAEhB,OAACa,GAAA,CAEC,MAAOb,EAAO,MACd,SAAWc,GAAc,CACvB,IAAMJ,EAAc9B,EAAQ,IAAK0B,GAC/BA,EAAE,KAAON,EAAO,GACZ,CACE,GAAGM,EACH,MAAOQ,CACT,EACAR,CACN,EACKnB,EAAeuB,CAAW,CACjC,EACA,SAAU,IACR,KAAKvB,EAAeP,EAAQ,OAAQ0B,GAAMA,EAAE,KAAON,EAAO,EAAE,CAAC,GAd1DA,EAAO,EAgBd,EAIAA,EAAO,OAAS,sCAEhB,OAACe,GAAA,CAEC,QAAQZ,EAAAH,EAAO,cAAP,KAAAG,EAAsB,CAAC,EAC/B,SAAWa,GAAe,CACxB,IAAMN,EAAc9B,EAAQ,IAAK0B,GAC/BA,EAAE,KAAON,EAAO,GACZ,CACE,GAAGM,EACH,YAAaU,CACf,EACAV,CACN,EACKnB,EAAeuB,CAAW,CACjC,EACA,SAAU,IACR,KAAKvB,EAAeP,EAAQ,OAAQ0B,GAAMA,EAAE,KAAON,EAAO,EAAE,CAAC,GAd1DA,EAAO,EAgBd,EAIGI,EAAmB,CAC5B,CAAC,KACD,OAAC,UACC,MAAO,CACL,WAAY,EACZ,QAAS,WACT,aAAc,SACd,OAAQ,UACR,SAAU,OACV,WAAY,OACZ,gBAAiBN,EAAa,OAAS,QACvC,MAAO,QACP,OAAQ,mBACV,EACA,QAAST,EACT,aAAc,IAAMU,EAAc,EAAI,EACtC,aAAc,IAAMA,EAAc,EAAK,EAEtC,SAAAhB,EACH,GACF,EAEC,CAACQ,MACA,OAAC,OACC,cAAY,OACZ,MAAO,CACL,GAAGd,GACH,KAAM,EACN,WAAY,+CACd,EACF,EAGD,CAACe,MACA,OAAC,OACC,cAAY,OACZ,MAAO,CACL,GAAGf,GACH,MAAO,EACP,WAAY,8CACd,EACF,EAGD,CAACc,MACA,OAAC,UACC,KAAK,SACL,aAAYP,EACZ,MAAO,CACL,GAAGN,GACH,KAAM,MACN,UAAW,kCACX,gBAAiBiB,IAAa,OAAS,UAAY,OACrD,EACA,QAAS,IAAMF,EAAY,MAAM,EACjC,aAAc,IAAMG,EAAY,MAAM,EACtC,aAAc,IAAMA,EAAY,IAAI,EAEpC,mBAACqB,GAAA,CAAS,MAAO,CAAE,MAAO,OAAQ,OAAQ,MAAO,EAAG,EACtD,EAGD,CAACzB,MACA,OAAC,UACC,KAAK,SACL,aAAYP,EACZ,MAAO,CACL,GAAGP,GACH,MAAO,MACP,gBAAiBiB,IAAa,OAAS,UAAY,OACrD,EACA,QAAS,IAAMF,EAAY,MAAM,EACjC,aAAc,IAAMG,EAAY,MAAM,EACtC,aAAc,IAAMA,EAAY,IAAI,EAEpC,mBAACqB,GAAA,CAAS,MAAO,CAAE,MAAO,OAAQ,OAAQ,MAAO,EAAG,EACtD,GAEJ,CAEJ,EDrIM,IAAAC,EAAA,6BAhKAC,GAAiC,CACrC,SAAU,WACV,QAAS,OACT,cAAe,SACf,IAAK,MACL,MAAO,MACT,EAEMC,GAA4B,CAChC,SAAU,WACV,QAAS,OACT,WAAY,SACZ,IAAK,MACL,MAAO,MACT,EAEMC,GAAsC,CAC1C,SAAU,WACV,QAAS,OACT,WAAY,SACZ,KAAM,EACN,gBAAiB,QACjB,aAAc,OACd,OAAQ,oBACR,QAAS,SACT,UAAW,2BACb,EAEMC,GAA6B,CACjC,KAAM,EACN,OAAQ,OACR,QAAS,OACT,SAAU,OACV,gBAAiB,cACjB,MAAO,OACP,QAAS,MACX,EAEMC,GAAuC,CAC3C,SAAU,WACV,MAAO,OACP,IAAK,MACL,UAAW,kBACb,EAEMC,GAA8B,CAClC,MAAO,OACP,OAAQ,OACR,OAAQ,oBACR,UAAW,oBACX,aAAc,MACd,UAAW,yBACb,EAEMC,GAAoC,CACxC,SAAU,WACV,QAAS,OACT,MAAO,UACP,cAAe,OACf,SAAU,MACZ,EAkCaC,GAAmD,CAAC,CAC/D,SAAAC,EACA,QAAAC,EACA,MAAOC,EACP,YAAAC,EAAc,GACd,YAAAC,EACA,SAAAC,EACA,eAAAC,EACA,cAAAC,EACA,iBAAAC,EAAmB,GACnB,mBAAAC,EACA,SAAAC,EAAW,MACX,MAAAC,EACA,WAAAC,EACA,eAAAC,CACF,IAAM,CACJ,GAAM,CAACC,EAAeC,CAAgB,KAAI,YAAS,EAAE,EAC/CC,EAAQd,IAAoB,OAAYA,EAAkBY,EAC1DG,EAAWV,GAAiBQ,EAE5B,CAAE,EAAAG,EAAG,eAAAC,CAAe,EAAIC,EAAeX,CAAkB,EAEzDY,EAAkBH,EAAE,8BAA8B,EAClDI,EAAelB,GAAec,EAAE,0BAA0B,EAC1DK,EAAuBL,EAAE,0BAA0B,EACnDM,EAAmBN,EAAE,sBAAsB,EAC3CO,EAAgBP,EAAE,sBAAsB,EAExCQ,EAAgD,MAAOC,GAAM,CACjEA,EAAE,eAAe,EACjB,IAAMC,EAAQZ,EAAM,KAAK,EACzB,GAAI,GAACY,GAASzB,GAGd,GAAI,CACF,MAAME,EAASuB,CAAK,CACtB,OAASC,EAAO,CACd,QAAQ,MAAM,gBAAiBA,CAAK,CACtC,CACF,EAEMC,KAAqB,eACzB,MAAOC,EAAuBC,IAAuB,CACnD,GAAI,CAAA7B,EAGJ,GAAI,CACF,MAAMG,EAAeyB,CAAW,CAClC,OAASF,EAAO,CACd,QAAQ,MAAM,uBAAwBA,CAAK,CAC7C,CACF,EACA,CAAC1B,EAAaG,CAAc,CAC9B,EAEM2B,MAAe,eAAY,IAAM,CAChCH,EAAmB,CAAC,CAAC,CAC5B,EAAG,CAACA,CAAkB,CAAC,EAEjBI,KAAkB,eAAY,IAAM,CACnCJ,EAAmB,CAAC,EAAG,EAAI,EAChCb,EAAS,EAAE,CACb,EAAG,CAACa,EAAoBb,CAAQ,CAAC,EAEjC,SACE,QAAC,OAAI,MAAO,CAAE,GAAGzB,GAAiB,GAAGqB,CAAe,EAClD,oBAAC,SACE;AAAA;AAAA;AAAA;AAAA;AAAA,UAMH,EACCZ,EAAQ,SAAW,MAClB,OAAC,QAAK,SAAUyB,EAAY,MAAO,CAAE,GAAGjC,GAAY,GAAGkB,CAAM,EAC3D,oBAAC,OAAI,MAAOjB,GACV,oBAAC,SACC,KAAK,OACL,MAAOsB,EACP,SAAWW,GAAMV,EAASU,EAAE,OAAO,KAAK,EACxC,SAAUxB,EACV,MAAO,CAAE,GAAGR,GAAa,GAAGiB,CAAW,EACvC,aAAa,MACb,aAAW,eACb,EACCJ,GAAoBQ,EAAM,SAAW,GAAK,CAACb,MAC1C,OAAC,QAAK,MAAOL,GAAqB,SAAAwB,EAAa,EAEhDnB,MACC,OAAC,OAAI,MAAOP,GACV,mBAAC,OAAI,MAAOC,GAAc,EAC5B,GAEJ,EACF,EAGDI,EAAQ,OAAS,MAChB,OAACkC,GAAA,CACC,QAASlC,EACT,SAAUS,EACV,gBAAiBW,EACjB,cAAeI,EACf,qBAAsBF,EACtB,iBAAkBC,EAClB,eAAgBL,EAChB,eAAgBW,EAChB,eAAgBG,GAChB,WAAYC,EACd,GAEJ,CAEJ,EDxHO,SAASE,GAAYC,EAA8B,CACxD,IAAMC,EAAc,EAAAC,QAAM,OAA4B,IAAI,EACpD,CAACC,EAAOC,CAAQ,EAAI,EAAAF,QAAM,SAA0B,IAAI,EAGxDG,EAAa,EAAAH,QAAM,OAAOF,CAAO,EACvC,EAAAE,QAAM,UAAU,IAAM,CACpBG,EAAW,QAAUL,CACvB,CAAC,EAED,EAAAE,QAAM,UAAU,IAAM,CACpB,IAAMI,EAAOD,EAAW,QAGlBE,EAA+B,CACnC,QAAS,KACT,GAAGD,EACH,UAAW,CACT,GAAGA,EAAK,UAER,mBAAqBE,GAAe,CAzI5C,IAAAC,EAAAC,EA0IUN,EAAUO,GAAUA,EAAO,CAAE,GAAGA,EAAM,WAAAH,CAAW,EAAI,IAAK,GAC1DE,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,qBAA9B,MAAAC,EAAA,KAAAD,EAAmDD,EACrD,EACA,yBAA2BI,GAAO,CA7I1C,IAAAH,EAAAC,EA8IUN,EAAUO,GACRA,EAAO,CAAE,GAAGA,EAAM,mBAAoBC,CAAG,EAAI,IAC/C,GACAF,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,2BAA9B,MAAAC,EAAA,KAAAD,EAAyDG,EAC3D,EACA,oBAAsBC,GAAS,CAnJvC,IAAAJ,EAAAC,EAoJUN,EAAUO,GAAUA,EAAO,CAAE,GAAGA,EAAM,QAASE,CAAK,EAAI,IAAK,GAC7DH,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,sBAA9B,MAAAC,EAAA,KAAAD,EAAoDI,EACtD,EACA,gBAAkBC,GAAY,CAvJtC,IAAAL,EAAAC,EAwJUN,EAAUO,GAAUA,EAAO,CAAE,GAAGA,EAAM,QAAAG,CAAQ,EAAI,IAAK,GACvDJ,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,kBAA9B,MAAAC,EAAA,KAAAD,EAAgDK,EAClD,EACA,eAAiBC,GAAW,CA3JpC,IAAAN,EAAAC,EA4JUN,EAAUO,GAAUA,EAAO,CAAE,GAAGA,EAAM,OAAAI,CAAO,EAAI,IAAK,GACtDL,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,iBAA9B,MAAAC,EAAA,KAAAD,EAA+CM,EACjD,EACA,sBAAwBC,GAAkB,CA/JlD,IAAAP,EAAAC,EAgKUN,EAAUO,GAAUA,EAAO,CAAE,GAAGA,EAAM,cAAAK,CAAc,EAAI,IAAK,GAC7DN,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,wBAA9B,MAAAC,EAAA,KAAAD,EAAsDO,EACxD,EACA,eAAgB,CAACC,EAAQC,IAAS,CAnK1C,IAAAT,EAAAC,EAoKUN,EAAUO,IAAUA,GAAO,CAAE,GAAGA,GAAM,OAAAM,EAAQ,KAAAC,CAAK,EAAI,IAAK,GAC5DR,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,iBAA9B,MAAAC,EAAA,KAAAD,EAA+CQ,EAAQC,EACzD,EACA,aAAeA,GAAS,CAvKhC,IAAAT,EAAAC,EAwKUN,EAAUO,GAAUA,EAAO,CAAE,GAAGA,EAAM,KAAAO,CAAK,EAAI,IAAK,GACpDR,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,eAA9B,MAAAC,EAAA,KAAAD,EAA6CS,EAC/C,EACA,uBAAyBC,GAAa,CA3K9C,IAAAV,EAAAC,EA4KUN,EAAUO,GACRA,EAAO,CAAE,GAAGA,EAAM,eAAgBQ,CAAS,EAAI,IACjD,GACAT,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,yBAA9B,MAAAC,EAAA,KAAAD,EAAuDU,EACzD,EACA,qBAAuBC,GAAY,CAjL3C,IAAAX,EAAAC,EAkLUN,EAAUO,GACRA,EAAO,CAAE,GAAGA,EAAM,eAAgBS,CAAQ,EAAI,IAChD,GACAV,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,uBAA9B,MAAAC,EAAA,KAAAD,EAAqDW,EACvD,EACA,uBAAyBC,GAAc,CAvL/C,IAAAZ,EAAAC,EAwLUN,EAAUO,GACRA,EAAO,CAAE,GAAGA,EAAM,YAAaU,CAAU,EAAI,IAC/C,GACAX,GAAAD,EAAAJ,EAAW,QAAQ,YAAnB,YAAAI,EAA8B,yBAA9B,MAAAC,EAAA,KAAAD,EAAuDY,EACzD,CACF,CACF,EAEMC,EAAW,IAAI,gBAAaf,CAAW,EAC7C,OAAAN,EAAY,QAAUqB,EAGtBlB,EAASkB,EAAS,SAAS,CAAC,EAErB,IAAM,CACXA,EAAS,QAAQ,EACjBrB,EAAY,QAAU,KACtBG,EAAS,IAAI,CACf,CAEF,EAAG,CAAC,CAAC,EAGL,IAAMmB,EAAiB,EAAArB,QAAM,YAAaW,GAAuB,CAC3DZ,EAAY,SACdA,EAAY,QAAQ,eAAeY,CAAI,CAE3C,EAAG,CAAC,CAAC,EAGCW,EAAoB,EAAAtB,QAAM,YAAaU,GAAsB,CAC7DX,EAAY,SACdA,EAAY,QAAQ,kBAAkBW,CAAE,CAE5C,EAAG,CAAC,CAAC,EAGC,CAACa,EAAyBC,CAA0B,EACxD,EAAAxB,QAAM,SAAS,EAAK,EAChB,CAACyB,EAAuBC,CAAwB,EACpD,EAAA1B,QAAM,SAAuB,IAAI,EAE7B2B,EAAmB,EAAA3B,QAAM,QAC7B,KAAO,CACL,OAAQ,MAAOF,GAOT,CACJ,GAAI,CAACC,EAAY,QAAS,CACxB,IAAM6B,EAAM,IAAI,MAAM,iCAAiC,EACvD,MAAAF,EAAyBE,CAAG,EACtBA,CACR,CAEAJ,EAA2B,EAAI,EAC/BE,EAAyB,IAAI,EAE7B,GAAI,CAQF,OAPe,MAAM3B,EAAY,QAAQ,oBAAoB,CAC3D,GAAGD,EACH,QAAU8B,GAAQ,CAChB,IAAMC,EAAQD,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,EAChEF,EAAyBG,CAAK,CAChC,CACF,CAAC,CAEH,OAASD,EAAK,CACZ,IAAMC,EAAQD,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,EAChE,MAAAF,EAAyBG,CAAK,EACxBA,CACR,QAAE,CACAL,EAA2B,EAAK,CAClC,CACF,EACA,UAAWD,EACX,MAAOE,CACT,GACA,CAACF,EAAyBE,CAAqB,CACjD,EAGM,CAACK,EAA0BC,CAA2B,EAC1D,EAAA/B,QAAM,SAAS,EAAK,EAChB,CAACgC,EAAwBC,CAAyB,EACtD,EAAAjC,QAAM,SAAuB,IAAI,EAE7BkC,EAAoB,EAAAlC,QAAM,QAC9B,KAAO,CACL,OAAQ,MAAOF,GAYT,CACJ,GAAI,CAACC,EAAY,QAAS,CACxB,IAAM6B,EAAM,IAAI,MAAM,iCAAiC,EACvD,MAAAK,EAA0BL,CAAG,EACvBA,CACR,CAEAG,EAA4B,EAAI,EAChCE,EAA0B,IAAI,EAE9B,GAAI,CAQF,OAPe,MAAMlC,EAAY,QAAQ,qBAAqB,CAC5D,GAAGD,EACH,QAAU8B,GAAQ,CAChB,IAAMC,EAAQD,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,EAChEK,EAA0BJ,CAAK,CACjC,CACF,CAAC,CAEH,OAASD,EAAK,CACZ,IAAMC,EAAQD,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,EAChE,MAAAK,EAA0BJ,CAAK,EACzBA,CACR,QAAE,CACAE,EAA4B,EAAK,CACnC,CACF,EACA,UAAWD,EACX,MAAOE,CACT,GACA,CAACF,EAA0BE,CAAsB,CACnD,EAGM,CAACG,EAAqBC,CAAsB,EAAI,EAAApC,QAAM,SAAS,EAAK,EACpE,CAACqC,EAAmBC,CAAoB,EAC5C,EAAAtC,QAAM,SAAuB,IAAI,EAE7BuC,EAAe,EAAAvC,QAAM,QACzB,KAAO,CACL,QAAS,SAAY,CACnB,GAAI,CAACD,EAAY,QACf,OAAO,KAGTqC,EAAuB,EAAI,EAC3BE,EAAqB,IAAI,EAEzB,GAAI,CAEF,OADe,MAAMvC,EAAY,QAAQ,oBAAoB,CAE/D,OAAS6B,EAAK,CACZ,IAAMC,EAAQD,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,EAChE,MAAAU,EAAqBT,CAAK,EACpBA,CACR,QAAE,CACAO,EAAuB,EAAK,CAC9B,CACF,EACA,YAAaD,EACb,MAAOE,CACT,GACA,CAACF,EAAqBE,CAAiB,CACzC,EAGMG,EAAsB,EAAAxC,QAAM,OAAO,EAAK,EACxCyC,EAAiB,EAAAzC,QAAM,YAC3B,CACE0C,EACAC,EACA7C,IACG,CACCC,EAAY,SAAW2C,GAAO,CAACF,EAAoB,UACrDzC,EAAY,QAAQ,UAAU2C,EAAK,CACjC,SAAU,WACV,WAAAC,EACA,cAAe7C,GAAA,YAAAA,EAAS,aAC1B,CAAC,EACD0C,EAAoB,QAAU,GAElC,EACA,CAAC,CACH,EAEMI,EAAwB,EAAA5C,QAAM,OAAO,EAAK,EAC1C6C,EAAe,EAAA7C,QAAM,YACzB,CACE0C,EACAI,EACAhD,IACG,CACCC,EAAY,SAAW2C,GAAO,CAACE,EAAsB,UACvD7C,EAAY,QAAQ,UAAU2C,EAAK,CACjC,SAAU,SACV,OAAAI,EACA,cAAehD,GAAA,YAAAA,EAAS,aAC1B,CAAC,EACD8C,EAAsB,QAAU,GAEpC,EACA,CAAC,CACH,EAEMG,EAAoB,EAAA/C,QAAM,OAAO,EAAK,EACtCgD,GAAe,EAAAhD,QAAM,YACzB,CACE0C,EACAO,EACAnD,IACG,CACCC,EAAY,SAAW2C,GAAO,CAACK,EAAkB,UACnDhD,EAAY,QAAQ,UAAU2C,EAAK,CACjC,SAAU,SACV,SAAAO,EACA,cAAenD,GAAA,YAAAA,EAAS,aAC1B,CAAC,EACDiD,EAAkB,QAAU,GAEhC,EACA,CAAC,CACH,EAEA,MAAO,CACL,SAAUhD,EAAY,QACtB,MAAAE,EACA,eAAAoB,EACA,kBAAAC,EACA,iBAAAK,EACA,kBAAAO,EACA,aAAAK,EACA,eAAAE,EACA,aAAAI,EACA,aAAAG,EACF,CACF","names":["index_exports","__export","Chip","CloseIcon","EditIcon","FilterChips","MinRatingFilterChip","NextIcon","PriceRangeFilterChip","RestaurantPriceLevelChip","SearchIcon","SmartFilter","StarIcon","TransformedQueryChip","createMinRatingFilterLabel","createPriceRangeFilterLabel","formatRatingValue","renderStars","useFilterScroll","useMapFirst","useTranslation","__toCommonJS","import_react","import_core","import_react","import_react","import_react","import_jsx_runtime","SearchIcon","className","style","CloseIcon","EditIcon","NextIcon","StarIcon","fill","import_jsx_runtime","closeButtonStyles","iconStyles","CloseButton","onClick","style","isHovering","setIsHovering","React","CloseIcon","import_jsx_runtime","chipStyles","Chip","label","icon","remove","style","CloseButton","import_react","import_react","defaultTranslations","formatCurrencyDefault","value","currency","useTranslation","customTranslations","customFormatCurrency","locale","setLocale","t","key","params","translation","paramKey","formatCurrency","import_jsx_runtime","renderStars","rating","stars","fullStars","hasHalfStar","baseStyles","fullStarStyles","halfStarStyles","i","remainingStars","createMinRatingFilterLabel","suffix","formatRatingValue","createPriceRangeFilterLabel","min","max","currency","formatCurrencyFn","import_jsx_runtime","chipContainerStyles","starContainerStyles","circleBaseStyles","buttonBaseStyles","MinRatingFilterChip","rating","onChange","onRemove","star","hoverRating","setHoverRating","t","useTranslation","displayRating","formatLabel","value","formatRatingValue","removeLabel","setLabel","getFillForStar","index","starNumber","handleSelect","nextRating","handleBlur","event","_a","related","_","fillState","halfValue","StarIcon","circleStyles","halfCircleStyles","CloseButton","import_react","import_jsx_runtime","chipStyles","inputStyles","editButtonStyles","PriceBoundaryChip","boundary","label","value","placeholder","currency","isOptional","showRemoveButton","removeLabel","editLabel","showAddWhenEmpty","onCommit","onRemove","draft","setDraft","isEditing","setIsEditing","editHover","setEditHover","hasValue","resetDraft","commitValue","parsed","normalized","event","next","EditIcon","CloseButton","PriceRangeFilterChip","priceRange","onChange","t","useTranslation","minLabel","maxChipLabel","handleBoundaryCommit","nextValue","nextRange","import_jsx_runtime","chipStyles","PRICE_LEVEL_OPTIONS","RestaurantPriceLevelChip","values","onChange","onRemove","t","useTranslation","label","removeLabel","noneSelectedLabel","handleChange","event","value","checked","valueAsPriceLevel","selection","orderedSelection","option","optionLabel","checkboxId","CloseButton","import_react","import_jsx_runtime","chipStyles","inputStyles","editButtonStyles","TransformedQueryChip","value","onChange","onRemove","inputRef","draft","setDraft","isEditing","setIsEditing","editHover","setEditHover","t","useTranslation","removeLabel","editLabel","applyChanges","nextValue","SearchIcon","event","EditIcon","CloseButton","import_react","useFilterScroll","dependency","scrollerRef","atStart","setAtStart","atEnd","setAtEnd","updateScrollButtons","el","scrollLeft","scrollWidth","clientWidth","handleScroll","scrollByDir","dir","delta","import_jsx_runtime","containerStyles","scrollContainerBase","gradientStyles","navButtonStyles","FilterChips","filters","currency","minRatingSuffix","clearAllLabel","previousFiltersLabel","nextFiltersLabel","formatCurrency","onFilterChange","onResetFilters","onClearAll","scrollerRef","atStart","atEnd","scrollByDir","useFilterScroll","navHover","setNavHover","React","clearHover","setClearHover","filter","_a","_b","_c","renderStandardChip","Chip","f","currentRating","MinRatingFilterChip","nextRating","nextFilters","PriceRangeFilterChip","nextRange","TransformedQueryChip","nextValue","RestaurantPriceLevelChip","nextLevels","NextIcon","import_jsx_runtime","containerStyles","formStyles","inputContainerStyles","inputStyles","loaderContainerStyles","loaderStyles","typingPromptStyles","SmartFilter","mapFirst","filters","controlledValue","isSearching","placeholder","onSearch","onFilterChange","onValueChange","showTypingPrompt","customTranslations","currency","style","inputStyle","containerStyle","internalValue","setInternalValue","value","setValue","t","formatCurrency","useTranslation","minRatingSuffix","typingPrompt","previousFiltersLabel","nextFiltersLabel","clearAllLabel","formSubmit","e","query","error","handleFilterChange","nextFilters","clearAll","resetFilters","clearAllFilters","FilterChips","useMapFirst","options","instanceRef","React","state","setState","optionsRef","opts","coreOptions","properties","_a","_b","prev","id","type","filters","bounds","pendingBounds","center","zoom","location","loading","searching","instance","setPrimaryType","setSelectedMarker","propertiesSearchLoading","setPropertiesSearchLoading","propertiesSearchError","setPropertiesSearchError","propertiesSearch","err","error","smartFilterSearchLoading","setSmartFilterSearchLoading","smartFilterSearchError","setSmartFilterSearchError","smartFilterSearch","boundsSearchLoading","setBoundsSearchLoading","boundsSearchError","setBoundsSearchError","boundsSearch","mapLibreAttachedRef","attachMapLibre","map","maplibregl","googleMapsAttachedRef","attachGoogle","google","mapboxAttachedRef","attachMapbox","mapboxgl"]}