import React from 'react'; import { MapLayersConfig } from '../map-layers'; import { type MapMarkerData } from './map-marker'; import { type MapCircleShape, type MapPolygonShape, type MapPolylineShape, type MapSectorShape } from './use-map-geometry'; import { type MapDrawingConfig } from './use-map-drawing'; import { type MapBasemap, type MapBasemapStyles } from './map-basemap'; import { type MapScaleUnits } from '../map-scale-bar'; import { type MapHeatmapConfig } from './use-map-heatmap'; import { type MapChoroplethBand, type MapChoroplethConfig } from './use-map-choropleth'; import { type MapClusterConfig } from './map-cluster'; import { type MapDataLayer } from './map-layers-model'; import type { MapControl } from './map-control'; import type { GeoJsonFeatureCollection } from './map-geojson'; import type { GeoJsonInput } from './map-geojson'; import { type MapBounds, type MapFitTarget, type MapView } from './use-map-fit'; import type { ColorToken, LatLng, MapFeatureRef, MapOverlayPosition } from './map.types'; /** A pin authored by the user, distinct from the data markers. */ export interface MapAnnotation { id: string; position: LatLng; text: string; author?: string; createdAt?: string; } declare global { namespace JSX { interface IntrinsicElements { 'gmp-map': React.DetailedHTMLProps, HTMLElement> & { 'map-id'?: string; center?: string | google.maps.LatLng | google.maps.LatLngLiteral; zoom?: number; }; 'gmp-advanced-marker': React.DetailedHTMLProps, HTMLElement> & { title?: string; position?: string | google.maps.LatLng | google.maps.LatLngLiteral; }; } } } export interface MapProps extends React.HTMLAttributes { center?: { lat: number; lng: number; }; zoom?: number; mapTypeId?: string; mapId?: string; markers?: MapMarkerData[]; circle?: { center: { lat: number; lng: number; }; radius: number; /** Literal color. Prefer `circleColorToken`. */ fillColor?: string; /** Literal color. Prefer `circleColorToken`. */ strokeColor?: string; }; /** Semantic token for the single `circle`. Wins over its literal colors. */ circleColorToken?: ColorToken; polygon?: { paths: Array<{ lat: number; lng: number; }>[]; /** Literal color. Prefer `polygonColorToken`. */ fillColor?: string; /** Literal color. Prefer `polygonColorToken`. */ strokeColor?: string; }; /** Semantic token for the single `polygon`. Wins over its literal colors. */ polygonColorToken?: ColorToken; layers?: MapLayersConfig; height?: string; apiKey?: string; mapContainerClassName?: string; disableDefaultUI?: boolean; zoomControl?: boolean; streetViewControl?: boolean; mapTypeControl?: boolean; fullscreenControl?: boolean; gestureHandling?: 'cooperative' | 'greedy' | 'none' | 'auto'; onMapLoad?: (map: google.maps.Map) => void; /** Title shown when the Google Maps script fails to load. @default "Failed to load Google Maps" */ loadErrorTitle?: string; /** Hint shown below `loadErrorTitle`. @default "Check API key in Settings" */ loadErrorHint?: string; /** Id of the currently selected feature. Requires `markers[].id`. */ selectedId?: string | null; /** Fires with `null` when the user clicks the map outside every feature. */ onFeatureSelect?: (id: string | null, feature: MapFeatureRef | null) => void; /** Fires with `null` when the pointer or focus leaves a feature. */ onFeatureHover?: (id: string | null, feature: MapFeatureRef | null) => void; /** Every click on the map surface, feature or not. */ onMapClick?: (position: LatLng) => void; /** Accessible name for the map region. @default "Map" */ ariaLabel?: string; /** Explicit frame. Takes precedence over `fitTo`. */ bounds?: MapBounds; /** What to frame the camera around. @default "none" */ fitTo?: MapFitTarget; /** Padding around fitted content, in pixels. @default 34 */ fitPadding?: number; /** Upper zoom bound applied after fitting. */ maxZoomOnFit?: number; /** Named camera positions. Pair with `` to expose them. */ views?: MapView[]; /** Active entry of `views`. An active view wins over automatic fitting. */ activeViewId?: string; /** * Not consumed by `` itself — `` renders the buttons that * call it. Accepted here so the view triple can be spread onto both: * `` and ``. */ onViewChange?: (id: string) => void; /** Forces the loading skeleton regardless of script state. */ loading?: boolean; /** The filter returned nothing. A normal outcome, not an error. */ isEmpty?: boolean; /** Replaces the built-in empty state. */ emptyState?: React.ReactNode; /** Rendering it signals a data error. Outranks every state but `deniedState`. */ errorState?: React.ReactNode; /** Rendering it signals the viewer may not see this data. Outranks all states. */ deniedState?: React.ReactNode; /** @default "No results for the current filters" */ emptyTitle?: string; /** @default "Adjust the filters to see data on the map" */ emptyHint?: string; /** @default "Configure Google Maps API Key in Settings" */ missingKeyTitle?: string; /** Any number of polygons. The singular `polygon` keeps working alongside. */ polygons?: MapPolygonShape[]; /** Any number of circles. The singular `circle` keeps working alongside. */ circles?: MapCircleShape[]; /** Antenna coverage wedges: vertex on the site, opening around an azimuth. */ sectors?: MapSectorShape[]; /** Lines through arbitrary coordinates. Not Directions routes — see `RouteMap`. */ polylines?: MapPolylineShape[]; /** * Named, toggleable layers. Markers and geometries join one through `layerId`. * * Named `dataLayers` and not `layers` on purpose — `layers` already means * Google's native traffic / transit / bicycling overlays and could not change * meaning without breaking working code. */ dataLayers?: MapDataLayer[]; /** Territorial mesh painted by value. Requires `choropleth`. */ geojson?: GeoJsonFeatureCollection | null; choropleth?: MapChoroplethConfig; /** Density surface. Needs the Maps `visualization` library, which ships by default. */ heatmap?: MapHeatmapConfig; /** Collapses co-located records into markers carrying a count. */ cluster?: MapClusterConfig; /** * Privacy floor: groups holding fewer than this many records are merged * instead of plotted individually. Display anonymization only — it changes * what is drawn, never what the payload contains. */ minAggregation?: number; /** Hides cartographic captions that overlap. @default 'hide' */ captionCollision?: 'hide' | 'none'; /** Fired by controls rendered inside a marker's `popup`. */ onPopupAction?: (featureId: string, action: string) => void; /** * Receives the classes the choropleth actually painted, so a `MapLegend` can * be built from them instead of a second, independently computed set. */ onChoroplethBands?: (bands: MapChoroplethBand[]) => void; /** * Imperative handle. Separate from `ref`, which stays the container element. */ controlRef?: React.Ref; /** User-authored pins, distinct from data markers: they have authorship and can be removed. */ annotations?: MapAnnotation[]; /** Arms annotation placement — the next map click creates one. */ annotationMode?: boolean; onAnnotationAdd?: (position: LatLng) => void; onAnnotationRemove?: (id: string) => void; /** Free-hand geofence drawing. Pair the result with `pointsInShape`. */ drawing?: MapDrawingConfig; /** The device's own position, with its accuracy halo. */ deviceLocation?: { position: LatLng; accuracyMeters?: number; /** Renders in a destructive state — a simulated coordinate must be visible, not just logged. */ mocked?: boolean; } | null; /** Field on `markers[].data` holding the timestamp used by `timeWindow`. */ timeField?: string; /** Inclusive `[from, to]`. Markers outside it are not drawn. */ timeWindow?: [number, number]; /** Graphic scale bar. Required reading for anything printed. */ scaleBar?: { units?: MapScaleUnits; position?: MapOverlayPosition; } | boolean; /** Cloud-styled or filtered base maps. `'none'` draws no basemap at all. */ basemapStyles?: MapBasemapStyles; /** * `'none'` draws the data with no Google basemap at all — markers, tooltips, * selection and keyboard navigation on a neutral surface. Use it for print, * for deployments that may not call Google, or to cut tile cost on a panel * where the map is secondary. */ basemap?: MapBasemap; /** * Reference outline drawn behind the markers when there is no basemap, in the * same projection. Without it the view answers "how many" but not "where", so * pass boundaries whenever the geography matters. */ baseGeojson?: GeoJsonInput | null; /** * When the Maps script cannot load — no API key, exhausted quota, a network * that blocks `maps.googleapis.com` — fall back to drawing the data without a * basemap instead of replacing the panel with a setup prompt. * @default true */ basemapFallback?: boolean; /** @default "Base cartográfica indisponível" */ noBasemapLabel?: string; /** Cartographic attribution, required by most tile licenses. */ attribution?: React.ReactNode; } /** * Primary Google Maps component. * * @description * Supports Advanced Markers with proportional symbology, per-feature selection * and hover, theme-aware colors through semantic tokens, content-driven framing, * and explicit empty/error/denied container states. Automatically loads the * Google Maps JavaScript API via `useGoogleMapsLoader`. * * @ai-rules * 1. REQUIRED: provide a valid `apiKey` via prop, ``, or storage. * 2. Color new surfaces with `colorToken` (e.g. `'--chart-1'`), never a hex literal — a token * follows the theme, a literal does not. * 3. Give every marker an `id` when using `selectedId` / `onFeatureSelect`. * 4. Use `shape: 'circle'` with `scale` to encode a quantity, and pair it with a * `` so the sizes are readable. * 5. Always set `height` explicitly (default is 400px) so the map is visible. */ export declare const Map: React.ForwardRefExoticComponent>; export type { MapMarkerData } from './map-marker';