@@ -6,6 +6,7 @@ import 'mapbox-gl/dist/mapbox-gl.css';
66
77import mapboxgl from 'mapbox-gl' ;
88import React , { forwardRef , useCallback , useEffect , useImperativeHandle , useRef , useState } from 'react' ;
9+ import ReactDOM from 'react-dom' ;
910
1011import { Env } from '@/lib/env' ;
1112
@@ -238,7 +239,7 @@ interface PointAnnotationProps {
238239 coordinate : [ number , number ] ;
239240 title ?: string ;
240241 children ?: React . ReactNode ;
241- anchor ?: { x : number ; y : number } ;
242+ anchor ?: string | { x : number ; y : number } ;
242243 onSelected ?: ( ) => void ;
243244}
244245
@@ -256,32 +257,61 @@ export const PointAnnotation: React.FC<PointAnnotationProps> = ({ id, coordinate
256257 container . style . cursor = 'pointer' ;
257258 containerRef . current = container ;
258259
259- // If there are children, render them into the container
260+ // Render React children into the container using createPortal
260261 if ( children ) {
261- // Simple case - just show a marker
262- container . innerHTML = '<div style="width: 24px; height: 24px; background: #3b82f6; border-radius: 50%; border: 3px solid white; box-shadow: 0 2px 4px rgba(0,0,0,0.3);"></div>' ;
262+ ReactDOM . render ( < > { children } </ > , container ) ;
263263 }
264264
265- markerRef . current = new mapboxgl . Marker ( {
265+ // Determine marker options based on anchor prop
266+ const markerOptions : mapboxgl . MarkerOptions = {
266267 element : container ,
267- anchor : 'center' ,
268- } )
268+ } ;
269+
270+ // Handle anchor prop - if it's a string, use it as mapbox anchor
271+ if ( typeof anchor === 'string' ) {
272+ markerOptions . anchor = anchor as mapboxgl . Anchor ;
273+ }
274+
275+ markerRef . current = new mapboxgl . Marker ( markerOptions )
269276 . setLngLat ( coordinate )
270277 . addTo ( map ) ;
271278
279+ // If anchor is an {x, y} object, convert to pixel offset
280+ if ( typeof anchor === 'object' && anchor !== null && 'x' in anchor && 'y' in anchor ) {
281+ // Calculate offset based on container size
282+ // Mapbox expects offset in pixels, anchor is typically 0-1 range
283+ // Convert anchor position to offset (center is anchor {0.5, 0.5})
284+ const rect = container . getBoundingClientRect ( ) ;
285+ const xOffset = ( anchor . x - 0.5 ) * rect . width ;
286+ const yOffset = ( anchor . y - 0.5 ) * rect . height ;
287+ markerRef . current . setOffset ( [ xOffset , yOffset ] ) ;
288+ }
289+
272290 if ( title ) {
273291 markerRef . current . setPopup ( new mapboxgl . Popup ( ) . setText ( title ) ) ;
274292 }
275293
276- if ( onSelected ) {
277- container . addEventListener ( 'click' , onSelected ) ;
294+ // Attach click listener to container
295+ if ( onSelected && containerRef . current ) {
296+ containerRef . current . addEventListener ( 'click' , onSelected ) ;
278297 }
279298
280299 return ( ) => {
300+ // Clean up click listener
301+ if ( onSelected && containerRef . current ) {
302+ containerRef . current . removeEventListener ( 'click' , onSelected ) ;
303+ }
304+
305+ // Unmount React children from the portal
306+ if ( children && containerRef . current ) {
307+ ReactDOM . unmountComponentAtNode ( containerRef . current ) ;
308+ }
309+
310+ // Remove marker from map
281311 markerRef . current ?. remove ( ) ;
282312 } ;
283313 // eslint-disable-next-line react-hooks/exhaustive-deps
284- } , [ map , coordinate , id ] ) ;
314+ } , [ map , coordinate , id , children , anchor , onSelected , title ] ) ;
285315
286316 // Update position when coordinate changes
287317 useEffect ( ( ) => {
@@ -317,9 +347,19 @@ export const UserLocation: React.FC<UserLocationProps> = ({ visible = true, show
317347 map . addControl ( geolocate ) ;
318348
319349 // Auto-trigger to show user location
320- map . on ( 'load' , ( ) => {
350+ if ( map . loaded ( ) ) {
321351 geolocate . trigger ( ) ;
322- } ) ;
352+ } else {
353+ const onMapLoad = ( ) => {
354+ geolocate . trigger ( ) ;
355+ } ;
356+ map . on ( 'load' , onMapLoad ) ;
357+
358+ return ( ) => {
359+ map . off ( 'load' , onMapLoad ) ;
360+ map . removeControl ( geolocate ) ;
361+ } ;
362+ }
323363
324364 return ( ) => {
325365 map . removeControl ( geolocate ) ;
0 commit comments