@mapfirst.ai/react 0.0.4

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/README.md ADDED
@@ -0,0 +1,519 @@
1
+ # @mapfirst/react
2
+
3
+ React hooks for the MapFirst SDK supporting MapLibre, Google Maps, and Mapbox.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @mapfirst/react @mapfirst/core
9
+ # or
10
+ pnpm add @mapfirst/react @mapfirst/core
11
+ # or
12
+ yarn add @mapfirst/react @mapfirst/core
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ The React SDK supports a two-phase initialization pattern:
18
+
19
+ 1. Create the MapFirst SDK instance (optionally with location data)
20
+ 2. Attach your map when it's ready
21
+
22
+ ### MapLibre GL JS
23
+
24
+ ```tsx
25
+ import React, { useEffect, useRef, useState } from "react";
26
+ import maplibregl from "maplibre-gl";
27
+ import { useMapFirstCore, useMapLibreAttachment } from "@mapfirst/react";
28
+ import "maplibre-gl/dist/maplibre-gl.css";
29
+
30
+ function MapLibreExample() {
31
+ const mapContainerRef = useRef<HTMLDivElement>(null);
32
+ const [map, setMap] = useState<maplibregl.Map | null>(null);
33
+
34
+ // Phase 1: Create SDK instance with location data
35
+ const { mapFirst, state } = useMapFirstCore({
36
+ initialLocationData: {
37
+ city: "Paris",
38
+ country: "France",
39
+ currency: "EUR",
40
+ },
41
+ environment: "prod",
42
+ mfid: "your-mfid",
43
+ });
44
+
45
+ // Access reactive state
46
+ const properties = state?.properties || [];
47
+ const isSearching = state?.isSearching || false;
48
+
49
+ // Initialize MapLibre map
50
+ useEffect(() => {
51
+ if (!mapContainerRef.current) return;
52
+
53
+ const mapInstance = new maplibregl.Map({
54
+ container: mapContainerRef.current,
55
+ style: "https://demotiles.maplibre.org/style.json",
56
+ center: [2.3522, 48.8566], // Paris
57
+ zoom: 12,
58
+ });
59
+
60
+ mapInstance.on("load", () => {
61
+ setMap(mapInstance);
62
+ });
63
+
64
+ return () => {
65
+ mapInstance.remove();
66
+ };
67
+ }, []);
68
+
69
+ // Phase 2: Attach map to SDK
70
+ useMapLibreAttachment({
71
+ mapFirst,
72
+ map,
73
+ maplibregl,
74
+ onMarkerClick: (marker) => {
75
+ console.log("Marker clicked:", marker);
76
+ },
77
+ });
78
+
79
+ return (
80
+ <div ref={mapContainerRef} style={{ width: "100%", height: "600px" }} />
81
+ );
82
+ }
83
+ ```
84
+
85
+ ### Google Maps
86
+
87
+ ```tsx
88
+ import React, { useEffect, useRef, useState } from "react";
89
+ import { useMapFirstCore, useGoogleMapsAttachment } from "@mapfirst/react";
90
+
91
+ function GoogleMapsExample() {
92
+ const mapContainerRef = useRef<HTMLDivElement>(null);
93
+ const [map, setMap] = useState<google.maps.Map | null>(null);
94
+
95
+ // Phase 1: Create SDK instance
96
+ const { mapFirst, state } = useMapFirstCore({
97
+ initialLocationData: {
98
+ city: "Tokyo",
99
+ country: "Japan",
100
+ currency: "JPY",
101
+ },
102
+ });
103
+
104
+ // Initialize Google Maps
105
+ useEffect(() => {
106
+ if (!mapContainerRef.current || !window.google) return;
107
+
108
+ const mapInstance = new google.maps.Map(mapContainerRef.current, {
109
+ center: { lat: 35.6762, lng: 139.6503 }, // Tokyo
110
+ zoom: 12,
111
+ mapId: "your-map-id", // Required for Advanced Markers
112
+ });
113
+
114
+ setMap(mapInstance);
115
+ }, []);
116
+
117
+ // Phase 2: Attach map to SDK
118
+ useGoogleMapsAttachment({
119
+ mapFirst,
120
+ map,
121
+ google: window.google,
122
+ onMarkerClick: (marker) => {
123
+ console.log("Marker clicked:", marker);
124
+ },
125
+ });
126
+
127
+ return (
128
+ <div ref={mapContainerRef} style={{ width: "100%", height: "600px" }} />
129
+ );
130
+ }
131
+ ```
132
+
133
+ ### Mapbox GL JS
134
+
135
+ ```tsx
136
+ import React, { useEffect, useRef, useState } from "react";
137
+ import mapboxgl from "mapbox-gl";
138
+ import { useMapFirstCore, useMapboxAttachment } from "@mapfirst/react";
139
+ import "mapbox-gl/dist/mapbox-gl.css";
140
+
141
+ function MapboxExample() {
142
+ const mapContainerRef = useRef<HTMLDivElement>(null);
143
+ const [map, setMap] = useState<mapboxgl.Map | null>(null);
144
+
145
+ // Phase 1: Create SDK instance
146
+ const { mapFirst, state } = useMapFirstCore({
147
+ initialLocationData: {
148
+ city: "London",
149
+ country: "United Kingdom",
150
+ currency: "GBP",
151
+ },
152
+ });
153
+
154
+ // Initialize Mapbox map
155
+ useEffect(() => {
156
+ if (!mapContainerRef.current) return;
157
+
158
+ mapboxgl.accessToken = "your-mapbox-token";
159
+
160
+ const mapInstance = new mapboxgl.Map({
161
+ container: mapContainerRef.current,
162
+ style: "mapbox://styles/mapbox/streets-v12",
163
+ center: [-0.1276, 51.5074], // London
164
+ zoom: 12,
165
+ });
166
+
167
+ mapInstance.on("load", () => {
168
+ setMap(mapInstance);
169
+ });
170
+
171
+ return () => {
172
+ mapInstance.remove();
173
+ };
174
+ }, []);
175
+
176
+ // Phase 2: Attach map to SDK
177
+ useMapboxAttachment({
178
+ mapFirst,
179
+ map,
180
+ mapboxgl,
181
+ onMarkerClick: (marker) => {
182
+ console.log("Marker clicked:", marker);
183
+ },
184
+ });
185
+
186
+ return (
187
+ <div ref={mapContainerRef} style={{ width: "100%", height: "600px" }} />
188
+ );
189
+ }
190
+ ```
191
+
192
+ ## Advanced Usage
193
+
194
+ ### Accessing SDK Methods and Reactive State
195
+
196
+ All SDK methods are available through the `mapFirst` instance, and state updates automatically trigger React re-renders:
197
+
198
+ ```tsx
199
+ const { mapFirst, state } = useMapFirstCore({
200
+ /* ... */
201
+ });
202
+
203
+ // Access reactive state (automatically updates)
204
+ const properties = state?.properties || [];
205
+ const isSearching = state?.isSearching || false;
206
+ const selectedId = state?.selectedPropertyId;
207
+ const filters = state?.filters;
208
+
209
+ // Fly to location
210
+ useEffect(() => {
211
+ if (mapFirst) {
212
+ mapFirst.flyMapTo(2.3522, 48.8566, 14); // lng, lat, zoom
213
+ }
214
+ }, [mapFirst]);
215
+
216
+ // Run search
217
+ const handleSearch = async () => {
218
+ if (!mapFirst) return;
219
+
220
+ await mapFirst.runPropertiesSearch({
221
+ body: {
222
+ city: "Paris",
223
+ country: "France",
224
+ filters: {
225
+ checkIn: "2024-06-01",
226
+ checkOut: "2024-06-07",
227
+ numAdults: 2,
228
+ currency: "EUR",
229
+ },
230
+ },
231
+ });
232
+ };
233
+
234
+ // Set filters
235
+ mapFirst?.setFilters({
236
+ checkIn: new Date("2024-06-01"),
237
+ checkOut: new Date("2024-06-07"),
238
+ numAdults: 2,
239
+ currency: "EUR",
240
+ });
241
+ ```
242
+
243
+ ### Alternative: Using Dedicated Hooks
244
+
245
+ For more granular control, use the dedicated hooks that only update when specific state changes:
246
+
247
+ ```tsx
248
+ const { mapFirst } = useMapFirstCore({
249
+ /* ... */
250
+ });
251
+
252
+ // Only re-renders when properties change
253
+ const properties = useMapFirstProperties(mapFirst);
254
+
255
+ // Only re-renders when selection changes
256
+ const selectedId = useMapFirstSelectedProperty(mapFirst);
257
+
258
+ // Get and set primary type with a single hook
259
+ const [primaryType, setPrimaryType] = usePrimaryType(mapFirst);
260
+
261
+ // Get and set selected marker with a single hook
262
+ const [selectedMarker, setSelectedMarker] = useSelectedMarker(mapFirst);
263
+
264
+ return (
265
+ <div>
266
+ <h2>Properties ({properties.length})</h2>
267
+
268
+ {/* Type selector */}
269
+ <select
270
+ value={primaryType}
271
+ onChange={(e) => setPrimaryType(e.target.value as PropertyType)}
272
+ >
273
+ <option value="Accommodation">Hotels</option>
274
+ <option value="Restaurant">Restaurants</option>
275
+ <option value="Attraction">Attractions</option>
276
+ </select>
277
+
278
+ {/* Selection controls */}
279
+ {selectedMarker && (
280
+ <div>
281
+ <p>Selected: {selectedMarker}</p>
282
+ <button onClick={() => setSelectedMarker(null)}>Clear Selection</button>
283
+ </div>
284
+ )}
285
+ </div>
286
+ );
287
+ ```
288
+
289
+ ### State Management with Callbacks
290
+
291
+ ```tsx
292
+ const mapFirst = useMapFirstCore({
293
+ initialLocationData: {
294
+ city: "Paris",
295
+ country: "France",
296
+ },
297
+ callbacks: {
298
+ onPropertiesChange: (properties) => {
299
+ console.log("Properties updated:", properties.length);
300
+ },
301
+ onSelectedPropertyChange: (id) => {
302
+ console.log("Selected property:", id);
303
+ },
304
+ onError: (error, context) => {
305
+ console.error(`Error in ${context}:`, error);
306
+ },
307
+ onLoadingStateChange: (loading) => {
308
+ console.log("Loading:", loading);
309
+ },
310
+ },
311
+ });
312
+ ```
313
+
314
+ ### Configuring Map Behavior
315
+
316
+ ```tsx
317
+ const mapFirst = useMapFirstCore({
318
+ initialLocationData: {
319
+ city: "New York",
320
+ country: "United States",
321
+ },
322
+ fitBoundsPadding: {
323
+ top: 100,
324
+ bottom: 200,
325
+ left: 50,
326
+ right: 50,
327
+ },
328
+ properties: [], // Initial properties
329
+ primaryType: "Accommodation", // or 'Restaurant', 'Attraction'
330
+ autoSelectOnClick: true, // Auto-select marker on click
331
+ environment: "prod", // or 'test'
332
+ });
333
+ ```
334
+
335
+ ## API Reference
336
+
337
+ ### `useMapFirstCore(options)`
338
+
339
+ Creates a MapFirst SDK instance and returns reactive state.
340
+
341
+ **Returns:** `{ mapFirst: MapFirstCore | null, state: MapState | null }`
342
+
343
+ - `mapFirst` - The SDK instance for calling methods
344
+ - `state` - Reactive state that updates when SDK state changes
345
+ - `properties` - Array of properties
346
+ - `selectedPropertyId` - Currently selected property ID
347
+ - `primary` - Primary property type
348
+ - `filters` - Current filter state
349
+ - `isSearching` - Whether a search is in progress
350
+ - `initialLoading` - Whether initial data is loading
351
+ - `bounds` - Current map bounds
352
+ - `center` - Map center coordinates
353
+ - `zoom` - Current zoom level
354
+ - `activeLocation` - Active location data
355
+
356
+ **Options:**
357
+
358
+ - `initialLocationData?` - Location data for geo-lookup
359
+ - `city?` - City name
360
+ - `country?` - Country name
361
+ - `query?` - Search query
362
+ - `currency?` - Currency code
363
+ - `environment?` - API environment ('prod' | 'test')
364
+ - `mfid?` - MapFirst ID
365
+ - `state?` - Initial map state
366
+ - `callbacks?` - State change callbacks
367
+ - `fitBoundsPadding?` - Padding for fitBounds operations
368
+ - `properties?` - Initial properties
369
+ - `primaryType?` - Primary property type
370
+ - `autoSelectOnClick?` - Auto-select markers on click
371
+
372
+ ### `useMapLibreAttachment(options)`
373
+
374
+ Attaches MapLibre map to SDK instance.
375
+
376
+ **Options:**
377
+
378
+ - `mapFirst` - SDK instance
379
+ - `map` - MapLibre map instance
380
+ - `maplibregl` - MapLibre GL namespace
381
+ - `onMarkerClick?` - Marker click handler
382
+
383
+ ### `useGoogleMapsAttachment(options)`
384
+
385
+ Attaches Google Maps to SDK instance.
386
+
387
+ **Options:**
388
+
389
+ - `mapFirst` - SDK instance
390
+ - `map` - Google Maps instance
391
+ - `google` - Google Maps namespace
392
+ - `onMarkerClick?` - Marker click handler
393
+
394
+ ### `useMapboxAttachment(options)`
395
+
396
+ Attaches Mapbox map to SDK instance.
397
+
398
+ **Options:**
399
+
400
+ - `mapFirst` - SDK instance
401
+ - `map` - Mapbox map instance
402
+ - `mapboxgl` - Mapbox GL namespace
403
+ - `onMarkerClick?` - Marker click handler
404
+
405
+ ### `useMapFirstProperties(mapFirst)`
406
+
407
+ Returns the current properties array. Only triggers re-renders when properties change.
408
+
409
+ **Parameters:**
410
+
411
+ - `mapFirst` - SDK instance from `useMapFirstCore`
412
+
413
+ **Returns:** `Property[]`
414
+
415
+ **Example:**
416
+
417
+ ```tsx
418
+ const { mapFirst } = useMapFirstCore({ ... });
419
+ const properties = useMapFirstProperties(mapFirst);
420
+
421
+ return <div>Found {properties.length} properties</div>;
422
+ ```
423
+
424
+ ### `useMapFirstSelectedProperty(mapFirst)`
425
+
426
+ Returns the currently selected property ID. Only triggers re-renders when selection changes.
427
+
428
+ **Parameters:**
429
+
430
+ - `mapFirst` - SDK instance from `useMapFirstCore`
431
+
432
+ **Returns:** `number | null`
433
+
434
+ **Example:**
435
+
436
+ ```tsx
437
+ const { mapFirst } = useMapFirstCore({ ... });
438
+ const selectedId = useMapFirstSelectedProperty(mapFirst);
439
+
440
+ return <div>Selected: {selectedId || 'None'}</div>;
441
+ ```
442
+
443
+ ### `usePrimaryType(mapFirst)`
444
+
445
+ Returns the current primary property type and a setter function. Re-renders when primary type changes.
446
+
447
+ **Parameters:**
448
+
449
+ - `mapFirst` - SDK instance from `useMapFirstCore`
450
+
451
+ **Returns:** `[PropertyType, (type: PropertyType) => void]`
452
+
453
+ **Example:**
454
+
455
+ ```tsx
456
+ const { mapFirst } = useMapFirstCore({ ... });
457
+ const [primaryType, setPrimaryType] = usePrimaryType(mapFirst);
458
+
459
+ return (
460
+ <select value={primaryType} onChange={(e) => setPrimaryType(e.target.value as PropertyType)}>
461
+ <option value="Accommodation">Hotels</option>
462
+ <option value="Restaurant">Restaurants</option>
463
+ <option value="Attraction">Attractions</option>
464
+ </select>
465
+ );
466
+ ```
467
+
468
+ ### `useSelectedMarker(mapFirst)`
469
+
470
+ Returns the currently selected marker ID and a setter function. Re-renders when selection changes.
471
+
472
+ **Parameters:**
473
+
474
+ - `mapFirst` - SDK instance from `useMapFirstCore`
475
+
476
+ **Returns:** `[number | null, (id: number | null) => void]`
477
+
478
+ **Example:**
479
+
480
+ ```tsx
481
+ const { mapFirst } = useMapFirstCore({ ... });
482
+ const [selectedMarker, setSelectedMarker] = useSelectedMarker(mapFirst);
483
+
484
+ return (
485
+ <div>
486
+ <p>Selected: {selectedMarker || 'None'}</p>
487
+ <button onClick={() => setSelectedMarker(null)}>Clear Selection</button>
488
+ <button onClick={() => setSelectedMarker(123456)}>Select Property 123456</button>
489
+ </div>
490
+ );
491
+ ```
492
+
493
+ **Example:**
494
+
495
+ ```tsx
496
+ const { mapFirst } = useMapFirstCore({ ... });
497
+ const selectedId = useMapFirstSelectedProperty(mapFirst);
498
+
499
+ return <div>Selected: {selectedId || 'None'}</div>;
500
+ ```
501
+
502
+ ## Legacy API
503
+
504
+ The old `useMapFirst` hook is still available but deprecated:
505
+
506
+ ```tsx
507
+ const mapFirst = useMapFirst({
508
+ platform: "maplibre",
509
+ mapInstance: mapLibreInstance,
510
+ maplibregl: maplibregl,
511
+ // ... other options
512
+ });
513
+ ```
514
+
515
+ **Note:** This requires the map to be available immediately. Use the new two-phase initialization pattern instead.
516
+
517
+ ## License
518
+
519
+ MIT
@@ -0,0 +1,197 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+ import { BaseMapFirstOptions, MapFirstCore, MapState, Property, PropertyType, MapLibreNamespace, GoogleMapsNamespace, MapboxNamespace, MapFirstOptions } from '@mapfirst.ai/core';
4
+
5
+ /**
6
+ * Hook that creates a MapFirstCore instance that can be initialized before maps are ready.
7
+ * Supports two-phase initialization: create SDK first, attach map later.
8
+ * Returns the instance and reactive state that updates when SDK state changes.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * // Phase 1: Create SDK instance with location data
13
+ * const { mapFirst, state } = useMapFirstCore({
14
+ * initialLocationData: {
15
+ * city: "New York",
16
+ * country: "United States",
17
+ * currency: "USD"
18
+ * }
19
+ * });
20
+ *
21
+ * // Access reactive state
22
+ * console.log(state.properties); // Updates when properties change
23
+ * console.log(state.isSearching); // Updates when search state changes
24
+ *
25
+ * // Phase 2: Attach map when ready
26
+ * useEffect(() => {
27
+ * if (mapLibreInstance && mapFirst) {
28
+ * mapFirst.attachMap(mapLibreInstance, {
29
+ * platform: "maplibre",
30
+ * maplibregl: maplibregl,
31
+ * onMarkerClick: (marker) => console.log(marker)
32
+ * });
33
+ * }
34
+ * }, [mapLibreInstance, mapFirst]);
35
+ * ```
36
+ */
37
+ declare function useMapFirstCore(options: BaseMapFirstOptions): {
38
+ mapFirst: MapFirstCore | null;
39
+ state: MapState | null;
40
+ };
41
+ /**
42
+ * Hook to access reactive properties from MapFirst SDK.
43
+ * Returns the current properties array that updates when properties change.
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * const { mapFirst } = useMapFirstCore({ ... });
48
+ * const properties = useMapFirstProperties(mapFirst);
49
+ *
50
+ * return <div>Found {properties.length} properties</div>;
51
+ * ```
52
+ */
53
+ declare function useMapFirstProperties(mapFirst: MapFirstCore | null): Property[];
54
+ /**
55
+ * Hook to access the selected property ID from MapFirst SDK.
56
+ * Returns the currently selected property ID that updates when selection changes.
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * const { mapFirst } = useMapFirstCore({ ... });
61
+ * const selectedId = useMapFirstSelectedProperty(mapFirst);
62
+ *
63
+ * return <div>Selected: {selectedId || 'None'}</div>;
64
+ * ```
65
+ */
66
+ declare function useMapFirstSelectedProperty(mapFirst: MapFirstCore | null): number | null;
67
+ /**
68
+ * Hook to access and control the primary property type.
69
+ * Returns the current primary type and a setter function.
70
+ *
71
+ * @example
72
+ * ```tsx
73
+ * const { mapFirst } = useMapFirstCore({ ... });
74
+ * const [primaryType, setPrimaryType] = usePrimaryType(mapFirst);
75
+ *
76
+ * return (
77
+ * <select value={primaryType} onChange={(e) => setPrimaryType(e.target.value as PropertyType)}>
78
+ * <option value="Accommodation">Hotels</option>
79
+ * <option value="Restaurant">Restaurants</option>
80
+ * <option value="Attraction">Attractions</option>
81
+ * </select>
82
+ * );
83
+ * ```
84
+ */
85
+ declare function usePrimaryType(mapFirst: MapFirstCore | null): [PropertyType, (type: PropertyType) => void];
86
+ /**
87
+ * Hook to access and control the selected marker.
88
+ * Returns the current selected marker ID and a setter function.
89
+ *
90
+ * @example
91
+ * ```tsx
92
+ * const { mapFirst } = useMapFirstCore({ ... });
93
+ * const [selectedMarker, setSelectedMarker] = useSelectedMarker(mapFirst);
94
+ *
95
+ * return (
96
+ * <div>
97
+ * <p>Selected: {selectedMarker || 'None'}</p>
98
+ * <button onClick={() => setSelectedMarker(null)}>Clear Selection</button>
99
+ * </div>
100
+ * );
101
+ * ```
102
+ */
103
+ declare function useSelectedMarker(mapFirst: MapFirstCore | null): [number | null, (id: number | null) => void];
104
+ /**
105
+ * Hook for MapLibre GL JS integration.
106
+ * Automatically attaches the map when both the SDK instance and map are available.
107
+ *
108
+ * @example
109
+ * ```tsx
110
+ * const { mapFirst, state } = useMapFirstCore({ initialLocationData: { city: "Paris", country: "France" } });
111
+ * const mapRef = useRef<maplibregl.Map | null>(null);
112
+ *
113
+ * useMapLibreAttachment({
114
+ * mapFirst,
115
+ * map: mapRef.current,
116
+ * maplibregl: maplibregl,
117
+ * onMarkerClick: (marker) => console.log(marker)
118
+ * });
119
+ *
120
+ * // Access reactive state
121
+ * console.log(state?.properties);
122
+ * ```
123
+ */
124
+ declare function useMapLibreAttachment({ mapFirst, map, maplibregl, onMarkerClick, }: {
125
+ mapFirst: MapFirstCore | null;
126
+ map: any | null;
127
+ maplibregl: MapLibreNamespace;
128
+ onMarkerClick?: (marker: Property) => void;
129
+ }): void;
130
+ /**
131
+ * Hook for Google Maps integration.
132
+ * Automatically attaches the map when both the SDK instance and map are available.
133
+ *
134
+ * @example
135
+ * ```tsx
136
+ * const { mapFirst, state } = useMapFirstCore({ initialLocationData: { city: "Tokyo", country: "Japan" } });
137
+ * const mapRef = useRef<google.maps.Map | null>(null);
138
+ *
139
+ * useGoogleMapsAttachment({
140
+ * mapFirst,
141
+ * map: mapRef.current,
142
+ * google: window.google,
143
+ * onMarkerClick: (marker) => console.log(marker)
144
+ * });
145
+ *
146
+ * // Access reactive state
147
+ * console.log(state?.isSearching);
148
+ * ```
149
+ */
150
+ declare function useGoogleMapsAttachment({ mapFirst, map, google, onMarkerClick, }: {
151
+ mapFirst: MapFirstCore | null;
152
+ map: any | null;
153
+ google: GoogleMapsNamespace;
154
+ onMarkerClick?: (marker: Property) => void;
155
+ }): void;
156
+ /**
157
+ * Hook for Mapbox GL JS integration.
158
+ * Automatically attaches the map when both the SDK instance and map are available.
159
+ *
160
+ * @example
161
+ * ```tsx
162
+ * const { mapFirst, state } = useMapFirstCore({ initialLocationData: { city: "London", country: "United Kingdom" } });
163
+ * const mapRef = useRef<mapboxgl.Map | null>(null);
164
+ *
165
+ * useMapboxAttachment({
166
+ * mapFirst,
167
+ * map: mapRef.current,
168
+ * mapboxgl: mapboxgl,
169
+ * onMarkerClick: (marker) => console.log(marker)
170
+ * });
171
+ *
172
+ * // Access reactive state
173
+ * console.log(state?.filters);
174
+ * ```
175
+ */
176
+ declare function useMapboxAttachment({ mapFirst, map, mapboxgl, onMarkerClick, }: {
177
+ mapFirst: MapFirstCore | null;
178
+ map: any | null;
179
+ mapboxgl: MapboxNamespace;
180
+ onMarkerClick?: (marker: Property) => void;
181
+ }): void;
182
+ /**
183
+ * Legacy hook that creates the MapFirstCore instance with a map immediately.
184
+ * Use useMapFirstCore + useMap*Attachment hooks for better control.
185
+ *
186
+ * @deprecated Use useMapFirstCore and platform-specific attachment hooks instead
187
+ */
188
+ declare function useMapFirst(options: MapFirstOptions | null): React.RefObject<MapFirstCore | null>;
189
+ /**
190
+ * Helper component that simply renders the markers it receives so non-React environments
191
+ * can verify data flows before wiring the SDK into a map.
192
+ */
193
+ declare function MarkerDebugList({ markers }: {
194
+ markers: Property[];
195
+ }): react_jsx_runtime.JSX.Element;
196
+
197
+ export { MarkerDebugList, useGoogleMapsAttachment, useMapFirst, useMapFirstCore, useMapFirstProperties, useMapFirstSelectedProperty, useMapLibreAttachment, useMapboxAttachment, usePrimaryType, useSelectedMarker };