/**
* Map — a themed vector map.
*
* Everything visible is built from theme tokens rather than shipped as a
* finished style, so the map belongs to whatever theme is active instead of
* being the one rectangle on the screen that stayed grey. See `basemap.ts` for
* how the style is assembled; the short version is that the tiles are bought
* and the colours are ours.
*
* ```tsx
*
* ```
*
* The renderer is native and optional, so `Map` has a state no other component
* here does: it may be unable to draw at all. It says so in place rather than
* throwing, because the usual way to reach that state is running in a client
* that cannot load native modules, and a screen explaining the build you need
* is more use than a stack trace.
*
* `Map.Popup` reads its position from the marker it sits inside, the way a
* frame's title reads its weight from its slot. Given a `lngLat` of its own it
* anchors to that coordinate instead, so the same name covers both the popup
* attached to a pin and the one floating over a place with no pin at all.
*/
import { type ReactNode } from 'react';
import { type PressableProps, type ViewProps } from 'react-native';
import { CARTO_SOURCE, type BasemapSource, type BasemapTokens } from './basemap.js';
import { hasMapLibre, type CameraRef, type LngLat, type LngLatBounds, type MapRef, type PixelPoint, type StyleSpecification, type ViewState } from './maplibre.js';
import { type MapFeatureAccessibility } from './map-accessibility.js';
export { hasMapLibre, CARTO_SOURCE };
export type { BasemapSource, BasemapTokens, LngLat, LngLatBounds, PixelPoint, ViewState };
export type { MapFeatureAccessibility } from './map-accessibility.js';
export type MapControlsPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
interface MapContextValue {
mapRef: React.RefObject;
cameraRef: React.RefObject;
/** The style has loaded and the map is drawing. */
ready: boolean;
}
/**
* The map's camera and view state, from inside it.
*
* For a control, an overlay, or anything that has to move the map in response
* to something that is not a gesture on it.
*/
export declare function useMap(): MapContextValue;
export interface MapHandle {
/** Move the camera, animating unless `duration` is 0. */
flyTo(options: {
center: LngLat;
zoom?: number;
duration?: number;
}): void;
/** Frame a bounding box, leaving `padding` points around it. */
fitBounds(bounds: LngLatBounds, padding?: number): void;
/** Where the map is looking right now. */
getViewState(): Promise;
}
export interface MapProps extends Omit {
children?: ReactNode;
/** Initial centre, `[longitude, latitude]`. */
center?: LngLat;
/** Initial zoom. 0 is the whole world; 18 is a building. */
zoom?: number;
/** Initial bearing in degrees, clockwise from north. */
bearing?: number;
/** Initial tilt in degrees. 0 looks straight down. */
pitch?: number;
/**
* Frame these bounds instead of centring — `[west, south, east, north]`.
* Wins over `center` and `zoom` when both are given.
*/
bounds?: LngLatBounds;
/**
* Drop the basemap and keep only the ground colour. For data that carries
* its own geography — a choropleth, an arc diagram — where streets
* underneath are noise rather than context.
*/
blank?: boolean;
/**
* Where the vector tiles come from. Defaults to CARTO, which is free for
* non-commercial use and licensed for everything else.
*/
source?: BasemapSource;
/**
* Use this style wholesale instead of building one from tokens. The escape
* hatch for a map that has to match something outside the app.
*/
mapStyle?: string | StyleSpecification;
/** Let the map rotate and tilt. Off by default — most maps only pan and zoom. */
rotatable?: boolean;
/** Turn off panning and zooming, for a map that is an illustration. */
interactive?: boolean;
/** Fires continuously while the map moves. */
onViewStateChange?: (state: ViewState) => void;
/**
* Fires when the map is pressed somewhere that is not a feature. The second
* argument is the same press in screen coordinates, for anchoring something
* of your own to where the finger landed.
*/
onPress?: (lngLat: LngLat, point: PixelPoint) => void;
/** Fires once the style has loaded and the first frame is drawn. */
onReady?: () => void;
}
export interface MapMarkerProps extends Omit {
/** Where the marker sits, `[longitude, latitude]`. */
lngLat: LngLat;
/**
* Which part of the marker sits on the coordinate. A pin drawn above its
* point wants `bottom`; a dot centred on it wants the default.
*/
anchor?: 'center' | 'top' | 'bottom' | 'left' | 'right';
/** Pressing the marker. Adds a button role when given. */
onPress?: () => void;
/** Explicit spoken name. Other React Native accessibility props pass through too. */
accessibilityLabel?: string;
className?: string;
/** Defaults to a dot. Anything else replaces it. */
children?: ReactNode;
}
/**
* A point on the map, drawn as React views rather than as a style layer — so
* it can be anything the rest of the library can draw. For hundreds of points
* use `Map.Cluster` instead: a view per marker stops being affordable long
* before the map stops being readable.
*/
declare function MapMarker({ lngLat, anchor, onPress, className, children, accessibilityState, ...props }: MapMarkerProps): import("react").JSX.Element | null;
declare namespace MapMarker {
var displayName: string;
}
export interface MapLabelProps {
children?: ReactNode;
className?: string;
/** Which side of the marker the label sits on. */
side?: 'top' | 'bottom';
/** `sm` for a map carrying a lot of them, where the pills start to collide. */
size?: 'sm' | 'md';
/**
* How loud the label is. `muted` for codes and counts that support the map
* without being its subject; `primary` for the one place being pointed at.
*/
tone?: 'default' | 'muted' | 'primary';
}
/**
* A caption pinned to a marker. Always visible, unlike a popup — for the
* handful of places whose names are the point of the map.
*
* It is taken out of the marker's layout flow, which matters more than it
* sounds: a marker sits on its coordinate by the centre of its box, so a label
* in flow underneath the pin would pull that centre down and lift every pin
* off the place it marks. Absolute keeps the box the size of the pin.
*
* The overhang on each side is what lets a long name stay centred on the pin
* without widening the marker — a name is usually far wider than the dot it
* belongs to, and a box sized to the name would be anchored by the name.
*/
declare function MapLabel({ children, className, side, size, tone, }: MapLabelProps): import("react").JSX.Element;
declare namespace MapLabel {
var displayName: string;
}
export interface MapPopupProps {
children?: ReactNode;
className?: string;
/** Heading above the content. Strings are wrapped for you. */
title?: string;
/**
* Anchor to this coordinate instead of to an enclosing marker. Required when
* the popup is not inside one.
*/
lngLat?: LngLat;
}
/**
* A card anchored to a point.
*
* Inside a `Map.Marker` it takes that marker's coordinate and opens when the
* marker is pressed. Given a `lngLat` it stands alone at that coordinate — the
* same component either way, because the difference is where it is anchored
* rather than what it is.
*
* Either way it is its own annotation rather than something drawn inside the
* marker, which is what keeps a card from dragging the pin off its coordinate.
* Anchored by its bottom edge, so it floats above the point it describes
* instead of covering it.
*/
declare function MapPopup({ children, className, title, lngLat }: MapPopupProps): import("react").JSX.Element | null;
declare namespace MapPopup {
var displayName: string;
}
export interface MapControlsProps {
/** Which corner the stack sits in. */
position?: MapControlsPosition;
/** Zoom in and out. On by default — it is the one control a map always needs. */
zoom?: boolean;
/** Recentre on the device's location. Needs a location permission. */
locate?: boolean;
/** Reset bearing and pitch to north and flat. */
compass?: boolean;
className?: string;
/** Called with the located coordinate, so a caller can react to it. */
onLocate?: (lngLat: LngLat) => void;
}
/**
* The map's own chrome, as themed views.
*
* The renderer draws its own zoom and compass ornaments, but in its style
* rather than the app's, and they cannot be recoloured — so they are turned
* off in `Map` and replaced here by buttons built from the same tokens as
* every other control in the library.
*/
declare function MapControls({ position, zoom, locate, compass, className, onLocate, }: MapControlsProps): import("react").JSX.Element;
declare namespace MapControls {
var displayName: string;
}
export interface MapRouteProps {
/** The path, in order. */
coordinates: LngLat[];
/** Defaults to the primary token. */
color?: string;
/** Line thickness in points. */
width?: number;
/** Draw it dashed — for a leg that is planned rather than travelled. */
dashed?: boolean;
/** 0 is invisible, 1 is solid. */
opacity?: number;
id?: string;
}
/**
* A path across the map, drawn as a style layer rather than as views — so its
* cost does not grow with the number of points in it.
*/
declare function MapRoute({ coordinates, color, width, dashed, opacity, id, }: MapRouteProps): import("react").JSX.Element | null;
declare namespace MapRoute {
var displayName: string;
}
export interface MapArcProps {
/** Where the arc starts. */
from: LngLat;
/** Where it ends. */
to: LngLat;
/** How far it bows. 0 is a straight line; 0.2 is the default lift. */
curvature?: number;
color?: string;
width?: number;
opacity?: number;
id?: string;
}
/**
* A curved connection between two points.
*
* The curve is not geography — a great circle between two cities is not bowed
* on a flat projection. It is there so that two arcs sharing an endpoint stay
* tellable apart, which a bundle of straight lines through one city does not.
*/
declare function MapArc({ from, to, curvature, color, width, opacity, id, }: MapArcProps): import("react").JSX.Element | null;
declare namespace MapArc {
var displayName: string;
}
export interface MapGeoJSONProps {
/** A Feature, FeatureCollection, or the URL of one. */
data: unknown;
/** Fill colour for polygons. A style expression works here too. */
fill?: string | unknown[];
/** Outline colour. Defaults to the border token. */
stroke?: string | unknown[];
/** Outline thickness. */
strokeWidth?: number;
/** 0 is invisible, 1 is solid. */
fillOpacity?: number;
/** Fires with the pressed feature. */
onPress?: (feature: unknown) => void;
/** Describes each inline GeoJSON feature for the synchronized nonvisual list. */
accessibility?: (feature: unknown, index: number) => MapFeatureAccessibility;
id?: string;
}
/**
* Arbitrary geography as a themed layer — the component behind a choropleth,
* a coverage area, or any other shape that comes from data rather than from
* the basemap.
*
* `fill` takes a style expression as well as a colour, which is what makes a
* choropleth one layer instead of one layer per bucket.
*/
declare function MapGeoJSON({ data, fill, stroke, strokeWidth, fillOpacity, onPress, accessibility, id, }: MapGeoJSONProps): import("react").JSX.Element | null;
declare namespace MapGeoJSON {
var displayName: string;
}
export interface MapClusterProps {
/** Point features to cluster. */
data: unknown;
/** Defaults to the primary token. */
color?: string;
/** Text colour inside a cluster bubble. */
textColor?: string;
/** How close two points have to be, in points, to merge. */
radius?: number;
/** Above this zoom every point stands alone. */
maxZoom?: number;
/** Fires with the pressed cluster or point. */
onPress?: (feature: unknown) => void;
/** Describes each source point for the synchronized nonvisual list. */
accessibility?: (feature: unknown, index: number) => MapFeatureAccessibility;
id?: string;
}
/**
* Dense points, merged as they get too close to tell apart.
*
* This is the layer to reach for past a few dozen points: `Map.Marker` mounts
* a React view each, which a thousand points cannot afford, and a thousand
* overlapping pins would be unreadable even if it could.
*/
declare function MapCluster({ data, color, textColor, radius, maxZoom, onPress, accessibility, id, }: MapClusterProps): import("react").JSX.Element | null;
declare namespace MapCluster {
var displayName: string;
}
export interface MapHeatmapProps {
/** Point features to spread. */
data: unknown;
/** Feature property to weight each point by. Unweighted when omitted. */
weight?: string;
/**
* Base colour of the field — a theme token by name, or a literal. The ramp
* is this colour at rising opacity, so density reads as *more of the same
* thing* rather than as a change of subject.
*
* Defaults to `--color-chart-2`, which is a saturated accent in every theme.
* It is deliberately not `--color-chart-1`: that is the series colour a chart
* is about, and every theme starts it on something close to the foreground —
* near-black in a light theme, near-white in a dark one — which over a
* basemap is a smudge rather than a measurement.
*/
color?: string;
/**
* Replace the derived ramp outright, coolest first. For the conventional
* heat ramp, where the hue carries the reading as well as the opacity —
* worth it when the field sits over varied terrain and one hue at five
* opacities stops being separable from what is underneath it.
*
* The first stop is drawn at the lowest density, the last at the highest.
* Density zero stays fully transparent either way.
*/
colors?: string[];
/**
* Spread of a single point, in points, at street zoom. Larger blurs more.
* The drawn radius shrinks as the map zooms out, so a point keeps covering
* roughly the same ground rather than the same screen area.
*/
radius?: number;
/** Overall strength. Raise it when the data is sparse. */
intensity?: number;
/** 0 is invisible, 1 is solid. */
opacity?: number;
/** Above this zoom the layer fades out — see the note on the component. */
maxZoom?: number;
/**
* Draw the points themselves as the field fades out, coloured from the same
* ramp by weight. Without them, zooming past `maxZoom` leaves an empty map:
* the layer gets out of the way, and nothing takes its place.
*/
points?: boolean;
id?: string;
}
/**
* Point density as a continuous field.
*
* The opposite trade to `Map.Cluster`: a cluster keeps every point countable
* and tells you nothing about the space between them, while a heatmap shows
* the shape of the distribution and no longer lets you count anything. Reach
* for it when the question is *where* rather than *how many*.
*
* It fades out past `maxZoom` on purpose. Zoomed far enough in, every point is
* its own island and the blur says less than the points would — so the layer
* gets out of the way rather than smearing five records across a street. Set
* `points` and the records themselves fade in as it goes, which is the whole
* handover: a field while the question is where, marks once it is which.
*
* The radius is tied to zoom for the mirror-image reason. Left as a fixed
* number of screen points it would mean a different distance at every zoom:
* a blur that reads as a city at street level covers half a continent once
* the map is pulled out, and a field measured over land ends up sitting in
* the sea. Scaling it with the projection keeps the claim the same one.
*
* Intensity is tied to zoom too, and in the other direction. The same points
* are packed into fewer pixels the further out the map goes, so a constant
* intensity saturates the whole field at world zoom and shows nothing but its
* own ceiling.
*/
declare function MapHeatmap({ data, weight, color, colors, radius, intensity, opacity, maxZoom, points, id, }: MapHeatmapProps): import("react").JSX.Element | null;
declare namespace MapHeatmap {
var displayName: string;
}
export interface MapUserLocationProps {
/** Show which way the device is facing, not just where it is. */
heading?: boolean;
/** Draw the ring showing how confident the fix is. */
accuracy?: boolean;
}
/** The device's own position, drawn by the renderer. */
declare function MapUserLocation({ heading, accuracy, }: MapUserLocationProps): import("react").JSX.Element | null;
declare namespace MapUserLocation {
var displayName: string;
}
export declare const Map: import("react").ForwardRefExoticComponent> & {
Marker: typeof MapMarker;
Label: typeof MapLabel;
Popup: typeof MapPopup;
Controls: typeof MapControls;
Route: typeof MapRoute;
Arc: typeof MapArc;
GeoJSON: typeof MapGeoJSON;
Cluster: typeof MapCluster;
Heatmap: typeof MapHeatmap;
UserLocation: typeof MapUserLocation;
};
//# sourceMappingURL=index.d.ts.map