'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
)}
)
})