import { IControl, Map } from "mapbox-gl"; import { ControlPosition } from "mapbox-gl"; import { cloneElement, memo, ReactElement, useEffect, useState } from "react"; import { createPortal } from "react-dom"; import { useControl } from "react-map-gl/mapbox"; import { v4 as uuidv4 } from 'uuid'; type OverlayProps = { position: ControlPosition; children: ReactElement<{ map?: Map }>; id?: string; }; // Definisikan custom control untuk overlay class OverlayControl implements IControl { _map: Map | null = null; _container: HTMLElement | null = null; _position: ControlPosition; _id: string; _redraw?: () => void; constructor({ position, id, redraw }: { position: ControlPosition; id: string; redraw?: () => void }) { this._position = position; this._id = id; this._redraw = redraw; } onAdd(map: Map) { this._map = map; this._container = document.createElement('div'); this._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group'; this._container.id = this._id; if (this._redraw) { map.on('move', this._redraw); this._redraw(); } return this._container; } onRemove() { if (!this._map || !this._container) return; if (this._redraw) { this._map.off('move', this._redraw); } this._container.remove(); this._map = null; } getDefaultPosition() { return this._position; } getMap() { return this._map; } getElement() { return this._container; } } // Komponen Overlay yang telah ditingkatkan function _Overlay({ position, children, id = `overlay-${uuidv4()}` }: OverlayProps) { const [container, setContainer] = useState(null); const [map, setMap] = useState(null) // Gunakan useControl dengan ID unik untuk menghindari konflik const ctrl = useControl( () => new OverlayControl({ position, id }), { position } // Hanya menggunakan position yang valid dalam ControlOptions ); // Update container dan map instance ketika control siap useEffect(() => { if (ctrl) { setContainer(ctrl.getElement()); setMap(ctrl.getMap()); } }, [ctrl]); // Hanya render jika container sudah siap if (!container || !map) return null; // Gunakan createPortal untuk merender children ke container return createPortal( cloneElement(children, { map }), container ); } // Export sebagai komponen memoized export const Overlay = memo(_Overlay);