maplibre-gl-components 0.3.0 → 0.5.0

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.
Files changed (60) hide show
  1. package/README.md +453 -6
  2. package/dist/InspectControl-BLalXkaR.cjs +5055 -0
  3. package/dist/InspectControl-BLalXkaR.cjs.map +1 -0
  4. package/dist/InspectControl-DXc8bOjy.js +5035 -0
  5. package/dist/InspectControl-DXc8bOjy.js.map +1 -0
  6. package/dist/index.cjs +48 -35
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.mjs +40 -27
  9. package/dist/maplibre-gl-components.css +774 -0
  10. package/dist/react.cjs +806 -13
  11. package/dist/react.cjs.map +1 -1
  12. package/dist/react.mjs +804 -11
  13. package/dist/react.mjs.map +1 -1
  14. package/dist/types/index.d.ts +7 -1
  15. package/dist/types/index.d.ts.map +1 -1
  16. package/dist/types/lib/core/Basemap.d.ts +206 -0
  17. package/dist/types/lib/core/Basemap.d.ts.map +1 -0
  18. package/dist/types/lib/core/BasemapReact.d.ts +32 -0
  19. package/dist/types/lib/core/BasemapReact.d.ts.map +1 -0
  20. package/dist/types/lib/core/InspectControl.d.ts +202 -0
  21. package/dist/types/lib/core/InspectControl.d.ts.map +1 -0
  22. package/dist/types/lib/core/InspectControlReact.d.ts +32 -0
  23. package/dist/types/lib/core/InspectControlReact.d.ts.map +1 -0
  24. package/dist/types/lib/core/SearchControl.d.ts +172 -0
  25. package/dist/types/lib/core/SearchControl.d.ts.map +1 -0
  26. package/dist/types/lib/core/SearchControlReact.d.ts +32 -0
  27. package/dist/types/lib/core/SearchControlReact.d.ts.map +1 -0
  28. package/dist/types/lib/core/Terrain.d.ts +165 -0
  29. package/dist/types/lib/core/Terrain.d.ts.map +1 -0
  30. package/dist/types/lib/core/TerrainReact.d.ts +32 -0
  31. package/dist/types/lib/core/TerrainReact.d.ts.map +1 -0
  32. package/dist/types/lib/core/VectorDataset.d.ts +197 -0
  33. package/dist/types/lib/core/VectorDataset.d.ts.map +1 -0
  34. package/dist/types/lib/core/VectorDatasetReact.d.ts +31 -0
  35. package/dist/types/lib/core/VectorDatasetReact.d.ts.map +1 -0
  36. package/dist/types/lib/core/types.d.ts +557 -0
  37. package/dist/types/lib/core/types.d.ts.map +1 -1
  38. package/dist/types/lib/hooks/index.d.ts +5 -0
  39. package/dist/types/lib/hooks/index.d.ts.map +1 -1
  40. package/dist/types/lib/hooks/useBasemap.d.ts +43 -0
  41. package/dist/types/lib/hooks/useBasemap.d.ts.map +1 -0
  42. package/dist/types/lib/hooks/useInspectControl.d.ts +49 -0
  43. package/dist/types/lib/hooks/useInspectControl.d.ts.map +1 -0
  44. package/dist/types/lib/hooks/useSearchControl.d.ts +43 -0
  45. package/dist/types/lib/hooks/useSearchControl.d.ts.map +1 -0
  46. package/dist/types/lib/hooks/useTerrain.d.ts +43 -0
  47. package/dist/types/lib/hooks/useTerrain.d.ts.map +1 -0
  48. package/dist/types/lib/hooks/useVectorDataset.d.ts +35 -0
  49. package/dist/types/lib/hooks/useVectorDataset.d.ts.map +1 -0
  50. package/dist/types/lib/utils/index.d.ts +1 -0
  51. package/dist/types/lib/utils/index.d.ts.map +1 -1
  52. package/dist/types/lib/utils/providers.d.ts +46 -0
  53. package/dist/types/lib/utils/providers.d.ts.map +1 -0
  54. package/dist/types/react.d.ts +7 -2
  55. package/dist/types/react.d.ts.map +1 -1
  56. package/package.json +4 -1
  57. package/dist/HtmlControl-CxD6T9bG.js +0 -1380
  58. package/dist/HtmlControl-CxD6T9bG.js.map +0 -1
  59. package/dist/HtmlControl-CzXIBk1H.cjs +0 -1379
  60. package/dist/HtmlControl-CzXIBk1H.cjs.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # maplibre-gl-components
2
2
 
3
- Legend, colorbar, and HTML control components for MapLibre GL JS maps.
3
+ Legend, colorbar, basemap switcher, terrain toggle, search, vector data loader, feature inspector, and HTML control components for MapLibre GL JS maps.
4
4
 
5
5
  [![npm version](https://badge.fury.io/js/maplibre-gl-components.svg)](https://badge.fury.io/js/maplibre-gl-components)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
@@ -9,6 +9,11 @@ Legend, colorbar, and HTML control components for MapLibre GL JS maps.
9
9
 
10
10
  - **Colorbar** - Continuous gradient legends with built-in matplotlib colormaps
11
11
  - **Legend** - Categorical legends with color swatches and labels
12
+ - **BasemapControl** - Interactive basemap switcher with 100+ providers from xyzservices
13
+ - **TerrainControl** - Toggle 3D terrain on/off using free AWS Terrarium elevation tiles
14
+ - **SearchControl** - Collapsible place search with geocoding and fly-to functionality
15
+ - **VectorDatasetControl** - Load GeoJSON files via file upload or drag-and-drop
16
+ - **InspectControl** - Click on features to view their properties/attributes
12
17
  - **HtmlControl** - Flexible HTML content control for custom info panels
13
18
  - **Zoom-based Visibility** - Show/hide components at specific zoom levels with `minzoom`/`maxzoom`
14
19
  - **React Support** - First-class React components and hooks
@@ -27,7 +32,7 @@ npm install maplibre-gl-components
27
32
 
28
33
  ```typescript
29
34
  import maplibregl from 'maplibre-gl';
30
- import { Colorbar, Legend, HtmlControl } from 'maplibre-gl-components';
35
+ import { Colorbar, Legend, HtmlControl, BasemapControl, TerrainControl, SearchControl, VectorDatasetControl } from 'maplibre-gl-components';
31
36
  import 'maplibre-gl-components/style.css';
32
37
 
33
38
  const map = new maplibregl.Map({
@@ -37,6 +42,39 @@ const map = new maplibregl.Map({
37
42
  zoom: 4,
38
43
  });
39
44
 
45
+ // Add a terrain toggle control
46
+ const terrainControl = new TerrainControl({
47
+ exaggeration: 1.5,
48
+ hillshade: true,
49
+ });
50
+ map.addControl(terrainControl, 'top-right');
51
+
52
+ // Add a search control
53
+ const searchControl = new SearchControl({
54
+ placeholder: 'Search for a place...',
55
+ flyToZoom: 14,
56
+ showMarker: true,
57
+ });
58
+ map.addControl(searchControl, 'top-right');
59
+
60
+ // Add a vector dataset loader (file upload and drag-drop)
61
+ const vectorControl = new VectorDatasetControl({
62
+ fitBounds: true,
63
+ });
64
+ map.addControl(vectorControl, 'top-left');
65
+
66
+ vectorControl.on('load', (event) => {
67
+ console.log('Loaded:', event.dataset?.filename);
68
+ });
69
+
70
+ // Add a basemap switcher
71
+ const basemapControl = new BasemapControl({
72
+ defaultBasemap: 'OpenStreetMap.Mapnik',
73
+ showSearch: true,
74
+ filterGroups: ['OpenStreetMap', 'CartoDB', 'Stadia', 'Esri'],
75
+ });
76
+ map.addControl(basemapControl, 'top-left');
77
+
40
78
  // Add a colorbar
41
79
  const colorbar = new Colorbar({
42
80
  colormap: 'viridis',
@@ -75,7 +113,7 @@ htmlControl.setHtml('<div><strong>Stats:</strong> 5,678 features</div>');
75
113
  ```tsx
76
114
  import { useState, useEffect, useRef } from 'react';
77
115
  import maplibregl from 'maplibre-gl';
78
- import { ColorbarReact, LegendReact, HtmlControlReact } from 'maplibre-gl-components/react';
116
+ import { ColorbarReact, LegendReact, HtmlControlReact, BasemapReact, TerrainReact, SearchControlReact, VectorDatasetReact } from 'maplibre-gl-components/react';
79
117
  import 'maplibre-gl-components/style.css';
80
118
 
81
119
  function MyMap() {
@@ -104,6 +142,38 @@ function MyMap() {
104
142
 
105
143
  {map && (
106
144
  <>
145
+ <VectorDatasetReact
146
+ map={map}
147
+ fitBounds
148
+ position="top-left"
149
+ onDatasetLoad={(dataset) => console.log('Loaded:', dataset.filename)}
150
+ />
151
+
152
+ <SearchControlReact
153
+ map={map}
154
+ placeholder="Search for a place..."
155
+ flyToZoom={14}
156
+ showMarker
157
+ position="top-right"
158
+ onResultSelect={(result) => console.log('Selected:', result.name)}
159
+ />
160
+
161
+ <TerrainReact
162
+ map={map}
163
+ exaggeration={1.5}
164
+ hillshade
165
+ position="top-right"
166
+ onTerrainChange={(enabled) => console.log('Terrain:', enabled)}
167
+ />
168
+
169
+ <BasemapReact
170
+ map={map}
171
+ defaultBasemap="OpenStreetMap.Mapnik"
172
+ showSearch
173
+ filterGroups={['OpenStreetMap', 'CartoDB', 'Stadia']}
174
+ position="top-left"
175
+ />
176
+
107
177
  <ColorbarReact
108
178
  map={map}
109
179
  colormap="viridis"
@@ -248,6 +318,326 @@ htmlControl.update(options)
248
318
  htmlControl.getState()
249
319
  ```
250
320
 
321
+ ### BasemapControl
322
+
323
+ An interactive basemap switcher that loads providers from [xyzservices](https://github.com/geopandas/xyzservices).
324
+
325
+ ```typescript
326
+ interface BasemapControlOptions {
327
+ basemaps?: BasemapItem[]; // Custom basemaps array
328
+ providersUrl?: string; // URL to fetch providers.json (defaults to xyzservices)
329
+ defaultBasemap?: string; // Initial basemap ID (e.g., 'OpenStreetMap.Mapnik')
330
+ position?: ControlPosition;
331
+ visible?: boolean;
332
+ collapsible?: boolean; // Whether control is collapsible (default: true)
333
+ collapsed?: boolean; // Whether control starts collapsed (default: true)
334
+ displayMode?: 'dropdown' | 'gallery' | 'list'; // UI mode (default: 'dropdown')
335
+ showSearch?: boolean; // Show search input (default: true)
336
+ filterGroups?: string[]; // Only include these provider groups
337
+ excludeGroups?: string[]; // Exclude these provider groups
338
+ excludeBroken?: boolean; // Exclude broken providers (default: true)
339
+ backgroundColor?: string;
340
+ maxWidth?: number;
341
+ maxHeight?: number;
342
+ fontSize?: number;
343
+ fontColor?: string;
344
+ minzoom?: number;
345
+ maxzoom?: number;
346
+ }
347
+
348
+ interface BasemapItem {
349
+ id: string; // Unique identifier
350
+ name: string; // Display name
351
+ group?: string; // Provider group (e.g., 'OpenStreetMap')
352
+ url?: string; // XYZ tile URL template
353
+ style?: string; // MapLibre style URL
354
+ attribution?: string;
355
+ thumbnail?: string; // Preview image URL
356
+ maxZoom?: number;
357
+ minZoom?: number;
358
+ requiresApiKey?: boolean;
359
+ apiKey?: string;
360
+ }
361
+
362
+ // Methods
363
+ basemapControl.show()
364
+ basemapControl.hide()
365
+ basemapControl.expand()
366
+ basemapControl.collapse()
367
+ basemapControl.toggle()
368
+ basemapControl.setBasemap(basemapId) // Switch to a basemap
369
+ basemapControl.getBasemaps() // Get available basemaps
370
+ basemapControl.addBasemap(basemap) // Add a custom basemap
371
+ basemapControl.removeBasemap(id) // Remove a basemap
372
+ basemapControl.setApiKey(id, key) // Set API key for a basemap
373
+ basemapControl.getSelectedBasemap() // Get currently selected basemap
374
+ basemapControl.update(options)
375
+ basemapControl.getState()
376
+ basemapControl.on('basemapchange', handler) // Listen for basemap changes
377
+ ```
378
+
379
+ **Available Provider Groups:**
380
+ - OpenStreetMap, CartoDB, Stadia, Esri, OpenTopoMap
381
+ - Thunderforest, MapBox, MapTiler (require API keys)
382
+ - NASAGIBS, OpenSeaMap, and 20+ more
383
+
384
+ ### SearchControl
385
+
386
+ A collapsible place search control with geocoding support.
387
+
388
+ ```typescript
389
+ interface SearchControlOptions {
390
+ position?: ControlPosition;
391
+ visible?: boolean; // Default: true
392
+ collapsed?: boolean; // Start collapsed (icon only). Default: true
393
+ placeholder?: string; // Search input placeholder. Default: 'Search places...'
394
+ geocoderUrl?: string; // Geocoding API URL. Default: Nominatim
395
+ maxResults?: number; // Max results to show. Default: 5
396
+ debounceMs?: number; // Debounce delay in ms. Default: 300
397
+ flyToZoom?: number; // Zoom level when selecting result. Default: 14
398
+ showMarker?: boolean; // Show marker at selected location. Default: true
399
+ markerColor?: string; // Marker color. Default: '#4264fb'
400
+ collapseOnSelect?: boolean; // Collapse after selecting. Default: true
401
+ clearOnSelect?: boolean; // Clear results after selecting. Default: true
402
+ geocoder?: (query: string) => Promise<SearchResult[]>; // Custom geocoder function
403
+ backgroundColor?: string;
404
+ borderRadius?: number;
405
+ opacity?: number;
406
+ width?: number; // Expanded width in pixels. Default: 280
407
+ fontSize?: number;
408
+ fontColor?: string;
409
+ minzoom?: number;
410
+ maxzoom?: number;
411
+ }
412
+
413
+ interface SearchResult {
414
+ id: string; // Unique identifier
415
+ name: string; // Place name
416
+ displayName: string; // Full display name with address
417
+ lng: number; // Longitude
418
+ lat: number; // Latitude
419
+ bbox?: [number, number, number, number]; // Bounding box [west, south, east, north]
420
+ type?: string; // Place type (city, street, etc.)
421
+ importance?: number; // Relevance score
422
+ }
423
+
424
+ // Methods
425
+ searchControl.show()
426
+ searchControl.hide()
427
+ searchControl.expand() // Expand to show input
428
+ searchControl.collapse() // Collapse to icon only
429
+ searchControl.toggle() // Toggle expanded/collapsed
430
+ searchControl.search(query) // Perform a search
431
+ searchControl.selectResult(result) // Select a result and fly to it
432
+ searchControl.clear() // Clear search and marker
433
+ searchControl.update(options)
434
+ searchControl.getState()
435
+ searchControl.on('resultselect', handler) // Listen for result selection
436
+ searchControl.on('search', handler) // Listen for search completion
437
+ searchControl.on('clear', handler) // Listen for clear events
438
+ ```
439
+
440
+ **Geocoding:**
441
+ By default, SearchControl uses [Nominatim](https://nominatim.openstreetmap.org/) (OpenStreetMap) for geocoding, which is free and requires no API key. You can also provide a custom geocoder function for other services.
442
+
443
+ ```typescript
444
+ // Using custom geocoder
445
+ const searchControl = new SearchControl({
446
+ geocoder: async (query) => {
447
+ const response = await fetch(`https://my-geocoder.com/search?q=${query}`);
448
+ const data = await response.json();
449
+ return data.map(item => ({
450
+ id: item.id,
451
+ name: item.name,
452
+ displayName: item.address,
453
+ lng: item.longitude,
454
+ lat: item.latitude,
455
+ }));
456
+ },
457
+ });
458
+ ```
459
+
460
+ ### VectorDatasetControl
461
+
462
+ A control for loading GeoJSON files via file upload button or drag-and-drop.
463
+
464
+ ```typescript
465
+ interface VectorDatasetControlOptions {
466
+ position?: ControlPosition;
467
+ visible?: boolean; // Default: true
468
+ showDropZone?: boolean; // Show overlay when dragging. Default: true
469
+ acceptedExtensions?: string[]; // File extensions. Default: ['.geojson', '.json']
470
+ multiple?: boolean; // Allow multiple files. Default: true
471
+ defaultStyle?: VectorLayerStyle; // Default styling for loaded layers
472
+ fitBounds?: boolean; // Fit map to loaded data. Default: true
473
+ fitBoundsPadding?: number; // Padding for fitBounds. Default: 50
474
+ maxFileSize?: number; // Max file size in bytes. Default: 50MB
475
+ backgroundColor?: string;
476
+ borderRadius?: number;
477
+ opacity?: number;
478
+ minzoom?: number;
479
+ maxzoom?: number;
480
+ }
481
+
482
+ interface VectorLayerStyle {
483
+ fillColor?: string; // Polygon fill. Default: '#3388ff'
484
+ fillOpacity?: number; // Polygon fill opacity. Default: 0.3
485
+ strokeColor?: string; // Line/outline color. Default: '#3388ff'
486
+ strokeWidth?: number; // Line width. Default: 2
487
+ strokeOpacity?: number; // Line opacity. Default: 1
488
+ circleRadius?: number; // Point radius. Default: 6
489
+ circleColor?: string; // Point color. Default: '#3388ff'
490
+ circleStrokeColor?: string; // Point outline. Default: '#ffffff'
491
+ circleStrokeWidth?: number; // Point outline width. Default: 2
492
+ }
493
+
494
+ interface LoadedDataset {
495
+ id: string; // Unique ID
496
+ filename: string; // Original filename
497
+ sourceId: string; // MapLibre source ID
498
+ layerIds: string[]; // MapLibre layer IDs
499
+ featureCount: number; // Number of features
500
+ geometryTypes: string[]; // Geometry types present
501
+ loadedAt: Date; // When loaded
502
+ }
503
+
504
+ // Methods
505
+ vectorControl.show()
506
+ vectorControl.hide()
507
+ vectorControl.getLoadedDatasets() // Get all loaded datasets
508
+ vectorControl.removeDataset(id) // Remove a dataset by ID
509
+ vectorControl.removeAllDatasets() // Remove all datasets
510
+ vectorControl.loadGeoJSON(geojson, filename) // Programmatically load GeoJSON
511
+ vectorControl.update(options)
512
+ vectorControl.getState()
513
+ vectorControl.on('load', handler) // Fired when a dataset is loaded
514
+ vectorControl.on('error', handler) // Fired when an error occurs
515
+ ```
516
+
517
+ **Loading Methods:**
518
+ - Click the upload button to open a file picker
519
+ - Drag and drop GeoJSON files directly onto the map
520
+
521
+ **Supported Formats:**
522
+ - GeoJSON (.geojson, .json)
523
+ - FeatureCollection, Feature, or raw Geometry objects
524
+
525
+ ### TerrainControl
526
+
527
+ A toggle control for 3D terrain rendering using free AWS Terrarium elevation tiles.
528
+
529
+ ```typescript
530
+ interface TerrainControlOptions {
531
+ sourceUrl?: string; // Terrain tile URL (default: AWS Terrarium)
532
+ encoding?: 'terrarium' | 'mapbox'; // Terrain encoding (default: 'terrarium')
533
+ exaggeration?: number; // Vertical scale factor (default: 1.0)
534
+ enabled?: boolean; // Initial terrain state (default: false)
535
+ hillshade?: boolean; // Add hillshade layer (default: true)
536
+ hillshadeExaggeration?: number; // Hillshade intensity (default: 0.5)
537
+ position?: ControlPosition;
538
+ visible?: boolean;
539
+ backgroundColor?: string;
540
+ borderRadius?: number;
541
+ opacity?: number;
542
+ minzoom?: number; // Min zoom level to show (default: 0)
543
+ maxzoom?: number; // Max zoom level to show (default: 24)
544
+ }
545
+
546
+ // Methods
547
+ terrainControl.show()
548
+ terrainControl.hide()
549
+ terrainControl.enable() // Enable terrain
550
+ terrainControl.disable() // Disable terrain
551
+ terrainControl.toggle() // Toggle terrain on/off
552
+ terrainControl.isEnabled() // Check if terrain is enabled
553
+ terrainControl.setExaggeration(value) // Set vertical exaggeration (0.1 - 10.0)
554
+ terrainControl.getExaggeration() // Get current exaggeration
555
+ terrainControl.enableHillshade() // Enable hillshade layer
556
+ terrainControl.disableHillshade() // Disable hillshade layer
557
+ terrainControl.toggleHillshade() // Toggle hillshade layer
558
+ terrainControl.update(options)
559
+ terrainControl.getState()
560
+ terrainControl.on('terrainchange', handler) // Listen for terrain toggle
561
+ ```
562
+
563
+ **Terrain Source:**
564
+ The control uses free terrain tiles from AWS:
565
+ - URL: `https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png`
566
+ - Encoding: Terrarium RGB-encoded elevation data
567
+ - No API key required
568
+
569
+ ### InspectControl
570
+
571
+ A control for inspecting vector features on the map. Click on features to view their properties/attributes in a popup.
572
+
573
+ ```typescript
574
+ interface InspectControlOptions {
575
+ position?: ControlPosition;
576
+ visible?: boolean; // Default: true
577
+ enabled?: boolean; // Start with inspect mode on. Default: false
578
+ maxFeatures?: number; // Max features at click point. Default: 10
579
+ includeLayers?: string[]; // Only inspect these layers
580
+ excludeLayers?: string[]; // Skip these layers
581
+ highlightStyle?: InspectHighlightStyle; // Style for selected feature
582
+ excludeProperties?: string[]; // Properties to hide (e.g., internal IDs)
583
+ showGeometryType?: boolean; // Show geometry type badge. Default: true
584
+ showLayerName?: boolean; // Show layer name. Default: true
585
+ maxWidth?: number; // Popup max width. Default: 320
586
+ maxHeight?: number; // Popup content max height. Default: 300
587
+ backgroundColor?: string;
588
+ borderRadius?: number;
589
+ opacity?: number;
590
+ fontSize?: number;
591
+ fontColor?: string;
592
+ minzoom?: number;
593
+ maxzoom?: number;
594
+ }
595
+
596
+ interface InspectHighlightStyle {
597
+ fillColor?: string; // Polygon fill. Default: '#ffff00'
598
+ fillOpacity?: number; // Polygon fill opacity. Default: 0.3
599
+ strokeColor?: string; // Line/outline color. Default: '#ffff00'
600
+ strokeWidth?: number; // Line width. Default: 3
601
+ circleRadius?: number; // Point radius. Default: 10
602
+ circleStrokeWidth?: number; // Point outline. Default: 3
603
+ }
604
+
605
+ interface InspectedFeature {
606
+ id: string; // Unique inspection ID
607
+ feature: GeoJSON.Feature; // The GeoJSON feature
608
+ layerId: string; // MapLibre layer ID
609
+ sourceId: string; // MapLibre source ID
610
+ lngLat: [number, number]; // Click coordinates
611
+ }
612
+
613
+ // Methods
614
+ inspectControl.show()
615
+ inspectControl.hide()
616
+ inspectControl.enable() // Enable inspect mode
617
+ inspectControl.disable() // Disable inspect mode
618
+ inspectControl.toggle() // Toggle inspect mode on/off
619
+ inspectControl.isEnabled() // Check if inspect mode is enabled
620
+ inspectControl.clear() // Clear current inspection
621
+ inspectControl.getInspectedFeatures() // Get all features at click point
622
+ inspectControl.getSelectedFeature() // Get currently selected feature
623
+ inspectControl.selectFeature(index) // Select feature by index
624
+ inspectControl.nextFeature() // Navigate to next feature
625
+ inspectControl.previousFeature() // Navigate to previous feature
626
+ inspectControl.update(options)
627
+ inspectControl.getState()
628
+ inspectControl.on('enable', handler) // Fired when inspect mode is enabled
629
+ inspectControl.on('disable', handler) // Fired when inspect mode is disabled
630
+ inspectControl.on('featureselect', handler) // Fired when a feature is selected
631
+ inspectControl.on('clear', handler) // Fired when inspection is cleared
632
+ ```
633
+
634
+ **Usage:**
635
+ 1. Click the info button to enable inspect mode
636
+ 2. Click on any vector feature on the map
637
+ 3. View properties in the popup
638
+ 4. Use < > buttons to navigate when multiple features are at the same location
639
+ 5. Click elsewhere or the button again to disable
640
+
251
641
  ## Built-in Colormaps
252
642
 
253
643
  ### Sequential
@@ -353,12 +743,16 @@ const colorbar = new Colorbar({
353
743
  ## React Hooks
354
744
 
355
745
  ```typescript
356
- import { useColorbar, useLegend, useHtmlControl } from 'maplibre-gl-components/react';
746
+ import { useColorbar, useLegend, useHtmlControl, useBasemap, useTerrain, useSearchControl, useVectorDataset } from 'maplibre-gl-components/react';
357
747
 
358
748
  function MyComponent() {
359
749
  const colorbar = useColorbar({ colormap: 'viridis', vmin: 0, vmax: 100 });
360
750
  const legend = useLegend({ items: [...] });
361
751
  const htmlControl = useHtmlControl({ html: '...' });
752
+ const basemap = useBasemap({ selectedBasemap: 'OpenStreetMap.Mapnik' });
753
+ const terrain = useTerrain({ enabled: false, exaggeration: 1.5 });
754
+ const search = useSearchControl({ collapsed: true });
755
+ const vectorDataset = useVectorDataset();
362
756
 
363
757
  return (
364
758
  <>
@@ -368,10 +762,35 @@ function MyComponent() {
368
762
  <button onClick={() => legend.toggle()}>
369
763
  Toggle Legend
370
764
  </button>
371
- <button onClick={() => htmlControl.setHtml('<div>Updated!</div>')}>
372
- Update HTML
765
+ <button onClick={() => basemap.setBasemap('CartoDB.Positron')}>
766
+ Change Basemap
767
+ </button>
768
+ <button onClick={() => terrain.toggle()}>
769
+ Toggle Terrain
770
+ </button>
771
+ <button onClick={() => search.toggle()}>
772
+ Toggle Search
373
773
  </button>
374
774
 
775
+ <SearchControlReact
776
+ map={map}
777
+ collapsed={search.state.collapsed}
778
+ onResultSelect={(result) => search.selectResult(result)}
779
+ />
780
+
781
+ <TerrainReact
782
+ map={map}
783
+ enabled={terrain.state.enabled}
784
+ exaggeration={terrain.state.exaggeration}
785
+ onTerrainChange={(enabled) => terrain.setEnabled(enabled)}
786
+ />
787
+
788
+ <BasemapReact
789
+ map={map}
790
+ defaultBasemap={basemap.state.selectedBasemap}
791
+ onBasemapChange={(b) => basemap.setBasemap(b.id)}
792
+ />
793
+
375
794
  <ColorbarReact
376
795
  map={map}
377
796
  {...colorbar.state}
@@ -404,6 +823,34 @@ The default styles can be customized using CSS:
404
823
  .maplibre-gl-html-control {
405
824
  max-width: 400px;
406
825
  }
826
+
827
+ /* Override basemap control styles */
828
+ .maplibre-gl-basemap {
829
+ max-width: 300px;
830
+ }
831
+
832
+ /* Override terrain control styles */
833
+ .maplibre-gl-terrain-button {
834
+ color: #0078d7;
835
+ }
836
+
837
+ /* Override search control styles */
838
+ .maplibre-gl-search {
839
+ background: rgba(255, 255, 255, 0.95);
840
+ }
841
+
842
+ .maplibre-gl-search-toggle:hover {
843
+ color: #0078d7;
844
+ }
845
+
846
+ /* Override vector dataset control styles */
847
+ .maplibre-gl-vector-dataset-button:hover {
848
+ color: #0078d7;
849
+ }
850
+
851
+ .maplibre-gl-vector-dataset-dropzone {
852
+ background: rgba(0, 120, 215, 0.2);
853
+ }
407
854
  ```
408
855
 
409
856
  ## Examples