import { Dispatch } from 'react';
import { FeatureCollection } from 'geojson';
import { GeoJSON as GeoJSON_2 } from 'geojson';
import { IControl } from 'maplibre-gl';
import { Map as Map_2 } from 'maplibre-gl';
import { PropertyValueSpecification } from 'maplibre-gl';
import { Ref } from 'react';
import { SetStateAction } from 'react';
/**
* Thresholds that trip `'auto'` render mode from GeoJSON to dynamic tiles.
*/
export declare interface AutoThreshold {
/**
* Maximum feature count rendered as GeoJSON
* @default 50000
*/
featureCount?: number;
/**
* Maximum source size in bytes rendered as GeoJSON
* @default 26214400 (25 MB)
*/
byteSize?: number;
}
/**
* Broad geometry category of a layer, used to pick map layer types.
*/
export declare type GeometryCategory = 'point' | 'line' | 'polygon' | 'mixed' | 'unknown';
/**
* How a dataset is ingested into DuckDB.
*
* - `'table'` - Materialize into an in-memory table with an EPSG:3857
* column and R-Tree index (fast tiles; memory ~= dataset size)
* - `'stream'` - GeoParquet only: query the file in place through a
* view. Remote files are read with HTTP range requests per tile,
* using the GeoParquet bbox covering column for row-group pruning
* when present. Nothing is copied into the database.
*/
declare type IngestMode = 'table' | 'stream';
/**
* How point features are rendered (geojson render mode only).
*
* - `'circle'` - One circle per point (the default)
* - `'heatmap'` - A density heatmap surface
* - `'cluster'` - Nearby points grouped into counted bubbles
*/
declare type PointMode = 'circle' | 'heatmap' | 'cluster';
/**
* Rendering mode for a vector layer.
*
* - `'auto'` - Decide based on dataset size thresholds
* - `'geojson'` - Convert to GeoJSON and render with a geojson source
* - `'tiles'` - Generate dynamic MVT tiles with DuckDB per z/x/y
*/
export declare type RenderMode = 'auto' | 'geojson' | 'tiles';
/**
* Custom hook for managing vector control state in React applications.
*
* This hook provides a simple way to track and update the state
* of a VectorControl from React components.
*
* @example
* ```tsx
* function MyComponent() {
* const { state, setState, setCollapsed } = useVectorState();
*
* return (
*
*
* setState(newState)}
* />
*
* );
* }
* ```
*
* @param initialState - Optional initial state values
* @returns Object containing state and update functions
*/
export declare function useVectorState(initialState?: Partial): {
state: VectorState;
setState: Dispatch>;
setCollapsed: (collapsed: boolean) => void;
setPanelWidth: (panelWidth: number) => void;
setData: (data: Record) => void;
reset: () => void;
toggle: () => void;
};
/**
* A MapLibre GL control for visualizing vector data in many formats
* (GeoJSON, GeoPackage, Shapefile, GeoParquet, FlatGeobuf, CSV/WKT).
*
* Small datasets are converted to GeoJSON; large datasets are rendered
* as dynamic MVT tiles generated client-side by DuckDB-WASM and served
* through a `duckdb://` protocol handler. DuckDB is lazy-loaded from a
* CDN only when a non-GeoJSON format (or tile rendering) is requested.
*
* @example
* ```typescript
* const control = new VectorControl({ collapsed: false });
* map.addControl(control, 'top-right');
* await control.addData('https://example.com/data.geojson');
* await control.addData('https://example.com/buildings.parquet');
* ```
*/
declare class VectorControl implements IControl {
private _map?;
private _mapContainer?;
private _container?;
private _panel?;
private _content?;
private _options;
private _state;
private _eventHandlers;
private _layerManager?;
private _enginePromise?;
private _disposePanelUI?;
private _styleLoadHandler;
private _styleRestorePromise;
private _removed;
private _resizeHandler;
private _mapResizeHandler;
private _clickOutsideHandler;
private _userWidth;
private _userHeight;
private _resizeDragCleanup;
/**
* Creates a new VectorControl instance.
*
* @param options - Configuration options for the control
*/
constructor(options?: Partial);
/**
* Called when the control is added to the map.
* Implements the IControl interface.
*
* @param map - The MapLibre GL map instance
* @returns The control's container element
*/
onAdd(map: Map_2): HTMLElement;
/**
* Called when the control is removed from the map.
* Implements the IControl interface.
*/
onRemove(): void;
/**
* Loads a vector data source and adds it to the map.
*
* @param source - URL string, File/Blob, or GeoJSON object
* @param options - Layer options
* @returns Metadata of the added layer
*/
addData(source: VectorDataSource, options?: VectorLayerOptions): Promise;
/**
* Removes a layer added with {@link addData}.
*
* @param id - The layer id
*/
removeLayer(id: string): void;
/**
* Removes all layers added with {@link addData}.
*/
removeAll(): void;
/**
* Returns metadata for all loaded layers.
*/
getLayers(): VectorLayerInfo[];
/**
* Returns metadata for a single layer.
*
* @param id - The layer id
*/
getLayer(id: string): VectorLayerInfo | undefined;
/**
* Materializes a layer's features as a GeoJSON FeatureCollection, so a host
* can persist the data of a layer loaded from a local file (which a saved
* project cannot otherwise recreate). Returns null for an unknown id, or a
* layer whose data is not held locally (e.g. a streamed GeoParquet).
*
* @param id - The layer id.
* @returns The features as a FeatureCollection, or null when unavailable.
*/
getLayerGeoJSON(id: string): Promise;
/**
* Reads the non-null values of one layer attribute without materializing
* engine-backed geometry.
*
* @param id - The layer id.
* @param property - An attribute field name.
* @returns The values, or null when the layer or field is unavailable.
*/
getLayerPropertyValues(id: string, property: string): Promise;
/**
* Shows or hides a layer.
*
* @param id - The layer id
* @param visible - Whether the layer should be visible
*/
setLayerVisibility(id: string, visible: boolean): void;
/**
* Zooms the map to a layer's extent.
*
* @param id - The layer id
*/
zoomToLayer(id: string): void;
/**
* Applies a style patch to a layer.
*
* @param id - The layer id
* @param style - Partial style update
*/
setLayerStyle(id: string, style: Partial): void;
/**
* Sets a layer's master opacity, multiplied into every style opacity
* (fill, circle, and line layers alike).
*
* @param id - The layer id
* @param opacity - The new opacity (0-1)
*/
setLayerOpacity(id: string, opacity: number): void;
/**
* Enables or disables the attribute popup for a layer.
*
* @param id - The layer id
* @param enabled - Whether clicking a feature opens a popup
*/
setLayerPicker(id: string, enabled: boolean): void;
/**
* Moves a layer's map layers before another map layer (or to the top
* when omitted).
*
* @param id - The layer id
* @param beforeId - Target map layer id, or undefined for the top
*/
setLayerBeforeId(id: string, beforeId?: string): void;
/**
* Switches a layer between GeoJSON and dynamic tile rendering.
*
* @param id - The layer id
* @param mode - The requested render mode
*/
setRenderMode(id: string, mode: RenderMode): Promise;
/**
* Re-fetches a URL-backed layer's data and re-renders it in place,
* keeping the same layer id, source, style, render mode, and position.
* In-memory GeoJSON and File sources are static, so reloading them is a
* no-op that returns the current layer info.
*
* @param id - The layer id
* @returns The refreshed layer info, or undefined when no such layer exists
*/
reloadLayer(id: string): Promise;
/**
* Gets the current state of the control.
*
* @returns The current control state
*/
getState(): VectorState;
/**
* Updates the control state.
*
* @param newState - Partial state to merge with current state
*/
setState(newState: Partial): void;
/**
* Toggles the collapsed state of the control panel.
*/
toggle(): void;
/**
* Expands the control panel.
*/
expand(): void;
/**
* Collapses the control panel.
*/
collapse(): void;
/**
* Registers an event handler.
*
* @param event - The event type to listen for
* @param handler - The callback function
*/
on(event: VectorControlEvent, handler: VectorControlEventHandler): void;
/**
* Removes an event handler.
*
* @param event - The event type
* @param handler - The callback function to remove
*/
off(event: VectorControlEvent, handler: VectorControlEventHandler): void;
/**
* Gets the map instance.
*
* @returns The MapLibre GL map instance or undefined if not added to a map
*/
getMap(): Map_2 | undefined;
/**
* Gets the control container element.
*
* @returns The container element or undefined if not added to a map
*/
getContainer(): HTMLElement | undefined;
/**
* Gets the panel content element that hosts the control UI.
*
* @returns The content element or undefined if not added to a map
*/
getContentElement(): HTMLElement | undefined;
/**
* Returns the layer manager, throwing when the control has not been
* added to a map yet.
*/
private _manager;
/**
* Lazily creates the shared DuckDB engine on first use.
*/
private _getEngine;
/**
* Emits an event to all registered handlers.
*
* @param event - The event type to emit
* @param extra - Optional layer/error/message context
*/
private _emit;
/**
* Creates the main container element for the control.
* Contains a toggle button (29x29) matching navigation control size.
*
* @returns The container element
*/
private _createContainer;
/**
* Creates the panel element with header and content areas.
* Panel is positioned as a dropdown below the toggle button.
*
* @returns The panel element
*/
private _createPanel;
/**
* Adds drag handles in the panel's bottom-left and bottom-right
* corners. Pointer drags resize the panel and the chosen size is kept
* (in {@link _userWidth}/{@link _userHeight}) so repositioning does not
* reset it.
*
* @param panel - The panel element to attach handles to
*/
private _addResizeHandles;
/**
* Starts a pointer-driven resize from one of the corner handles.
*
* The panel is first frozen to explicit left/top pixels (clearing any
* right/bottom anchor) so the opposite edge stays put no matter which
* corner the control sits in. The right handle then grows the panel
* rightward, the left handle leftward; both grow it downward. Sizes are
* clamped to a sensible minimum and to the map container.
*
* @param event - The pointerdown event
* @param side - Which corner handle started the drag
* @param panel - The panel element being resized
* @param handle - The handle element (for pointer capture)
*/
private _beginResize;
/**
* Setup event listeners for panel positioning and click-outside behavior.
*/
private _setupEventListeners;
/**
* Detect which corner the control is positioned in.
*
* @returns The position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
*/
private _getControlPosition;
/**
* Update the panel position based on button location and control corner.
* Positions the panel next to the button, expanding in the appropriate direction.
*/
private _updatePanelPosition;
}
/**
* Event types emitted by the vector control
*/
export declare type VectorControlEvent = 'collapse' | 'expand' | 'statechange' | 'layeradded' | 'layerremoved' | 'layerupdated' | 'loading' | 'error';
/**
* Event handler function type
*/
export declare type VectorControlEventHandler = (event: VectorEventPayload) => void;
/**
* Options for configuring the VectorControl
*/
export declare interface VectorControlOptions {
/**
* Host-supplied loader for remote HTTP(S) datasets.
*
* When set, URL sources are downloaded through this callback and handed to
* the control as a Blob/File. Desktop hosts can use a native HTTP client to
* load servers that do not permit browser CORS while the public layer source
* remains the original URL for persistence and refresh.
*/
urlLoader?: (url: string) => Promise;
/**
* Whether the control panel should start collapsed (showing only the toggle button)
* @default true
*/
collapsed?: boolean;
/**
* Position of the control on the map
* @default 'top-right'
*/
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
/**
* Title displayed in the control header
* @default 'Vector Data'
*/
title?: string;
/**
* Width of the control panel in pixels
* @default 320
*/
panelWidth?: number;
/**
* Custom CSS class name for the control container
*/
className?: string;
/**
* Thresholds used by `'auto'` render mode
*/
autoThreshold?: AutoThreshold;
/**
* Default render mode for layers that do not specify one
* @default 'auto'
*/
defaultRenderMode?: RenderMode;
/**
* Maximum zoom level for dynamic tile generation
* @default 16
*/
maxTileZoom?: number;
/**
* Attribution string attached to created sources
*/
attribution?: string;
/**
* Existing map layer id that new vector layers are inserted before
* (e.g. a label layer), so loaded data renders underneath it.
* Per-layer `beforeId` overrides this.
*/
beforeId?: string;
/**
* Whether clicking a feature opens a popup with its attributes.
* Per-layer `picker` overrides this.
* @default true
*/
enablePicker?: boolean;
/**
* Default ingest mode for new layers (per-layer `ingestMode` wins)
* @default 'table'
*/
defaultIngestMode?: IngestMode;
/**
* Placeholder text shown in the panel's URL input
* @default 'https://example.com/data.parquet'
*/
urlPlaceholder?: string;
/**
* Initial value of the panel's URL input, so a host can offer a
* ready-to-load sample dataset (the input clears after a successful
* load)
*/
defaultUrl?: string;
/**
* Automatically load `defaultUrl` when the control is added to the
* map, as if the user had pressed Load (no-op without `defaultUrl`)
* @default false
*/
autoLoad?: boolean;
/**
* Collapse the panel when the user clicks outside it (e.g. on the map).
* Set to `false` to keep the panel open until the user closes it with
* the header's close button.
* @default true
*/
closeOnOutsideClick?: boolean;
/**
* Show drag handles in the panel's bottom-left and bottom-right
* corners so the user can resize it. The bottom-right handle grows the
* panel rightward, the bottom-left handle leftward (keeping the
* opposite edge fixed); both grow it downward. The chosen size is kept
* for the session.
* @default false
*/
resizable?: boolean;
/**
* Optional sample datasets offered as one-click "Load sample data"
* links below the URL input. Clicking a link fills the URL input; the
* user must click Load to fetch the dataset. Omit or leave empty to
* hide the row entirely, keeping the URL input clean for the user's own
* links.
*/
sampleData?: VectorSampleDataset[];
/**
* Placeholder shown in the sample-data dropdown before a selection
* (e.g. 'Load sample data...'). Ignored when {@link sampleData} is
* empty.
* @default 'Load sample data...'
*/
sampleDataLabel?: string;
/**
* Base URL to load DuckDB-WASM from instead of the default jsDelivr CDN.
*
* Use this to self-host (or mirror) the assets and avoid the CDN request
* (and the `script-src https://cdn.jsdelivr.net` CSP allowance it needs).
* The base must mirror jsDelivr's layout for the pinned duckdb-wasm
* version: an `/+esm` ES-module bundle plus the `/dist/*` wasm and worker
* files. For example, `'/vendor/duckdb-wasm-1.31.0'` served from the host's
* own origin. Defaults to jsDelivr when unset.
*/
duckdbWasmBaseUrl?: string;
/**
* Base URL to load sql.js from instead of the default jsDelivr CDN.
*
* sql.js is loaded on demand only when a GeoPackage is added, to repair
* files missing the `gpkg_ogr_contents` feature-count table (without it,
* GDAL crashes single-threaded DuckDB-WASM with a thread-constructor error).
* The base must mirror jsDelivr's layout for the pinned sql.js version: a
* `/dist/sql-wasm.js` UMD script plus the matching `/dist/sql-wasm.wasm`.
* Set this alongside {@link duckdbWasmBaseUrl} to fully self-host and avoid
* the `script-src https://cdn.jsdelivr.net` CSP allowance. Defaults to
* jsDelivr when unset.
*/
sqlJsBaseUrl?: string;
/**
* Path or URL to a prebuilt DuckDB spatial extension.
*
* When set, the engine loads the extension with `LOAD ''` and skips
* the remote `INSTALL spatial` step. Use this in sandboxed or firewalled
* environments where DuckDB's extension repository is unreachable: without
* it, loading a non-GeoJSON source (or any source routed through the engine)
* hangs indefinitely on the blocked `INSTALL spatial`. The path must point at
* an extension built for the pinned duckdb-wasm version's DuckDB core.
* Defaults to a remote `INSTALL spatial; LOAD spatial;` when unset.
*/
spatialExtensionPath?: string;
/**
* Replaces the panel's built-in file browse with a host-supplied picker.
*
* When set, clicking the panel's drop zone calls this instead of opening
* the native `` dialog, and each returned
* {@link VectorFileSelection} is loaded through {@link VectorControl.addData}
* with its `sourcePath` recorded on the layer's source descriptor. Use it on
* a desktop host to open a native dialog that yields real filesystem paths,
* so local-file layers can be persisted and re-read when a project reopens.
* Drag-and-drop onto the zone still uses the browser's dropped files.
*/
fileOpener?: VectorFileOpener;
/**
* How the layers of a multi-layer container (a GeoPackage with several
* feature tables, a multi-layer GDAL source, ...) are chosen.
*
* Unset, the control opens its built-in modal picker over the map with every
* layer preselected, so the user can uncheck the ones they do not want
* instead of having the whole container added to the map. Supply a
* {@link VectorLayerSelector} to replace it with a host dialog, or set
* `false` to skip the prompt and load every layer (the behavior before the
* picker existed). A per-load {@link VectorLayerOptions.sourceLayers} wins
* over this.
*/
selectLayers?: VectorLayerSelector | false;
}
/**
* React wrapper component for VectorControl.
*
* This component manages the lifecycle of a VectorControl instance,
* adding it to the map on mount and removing it on unmount.
*
* @example
* ```tsx
* import { VectorControlReact } from 'maplibre-gl-vector/react';
*
* function MyMap() {
* const [map, setMap] = useState