'use client' import { useCallback, memo, type ReactNode, type KeyboardEvent } from 'react' import { Marker, type MarkerEvent, type MarkerDragEvent } from 'react-map-gl/maplibre' import type { LngLat } from 'maplibre-gl' import type { MarkerData } from '../types' export interface MapMarkerProps { marker: MarkerData onClick?: (marker: MarkerData) => void children?: ReactNode anchor?: 'center' | 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' draggable?: boolean onDragStart?: (marker: MarkerData) => void onDrag?: (marker: MarkerData, lngLat: LngLat) => void onDragEnd?: (marker: MarkerData, lngLat: LngLat) => void color?: string size?: number /** Accessible label for the marker (used when onClick is set) */ ariaLabel?: string } const DefaultPin = memo(function DefaultPin({ size = 24, color = '#ef4444' }: { size?: number color?: string }) { return ( ) }) export const MapMarker = memo(function MapMarker({ marker, onClick, children, anchor = 'bottom', draggable = false, onDragStart, onDrag, onDragEnd, color, size, ariaLabel, }: MapMarkerProps) { const handleClick = useCallback( (e: MarkerEvent) => { e.originalEvent.stopPropagation() onClick?.(marker) }, [onClick, marker] ) const handleDragStart = useCallback( (e: MarkerDragEvent) => { onDragStart?.(marker) }, [onDragStart, marker] ) const handleDrag = useCallback( (e: MarkerDragEvent) => { onDrag?.(marker, e.lngLat) }, [onDrag, marker] ) const handleDragEnd = useCallback( (e: MarkerDragEvent) => { onDragEnd?.(marker, e.lngLat) }, [onDragEnd, marker] ) const handleKeyDown = useCallback( (e: KeyboardEvent) => { if (!onClick) return if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() onClick(marker) } }, [onClick, marker] ) const content = children ?? return ( {onClick ? (
{content}
) : ( content )}
) })