UNPKG

react-bkoi-gl

Version:

React components for Barikoi GL JS

97 lines (83 loc) 3.05 kB
import * as React from "react"; import { useImperativeHandle, useRef, useEffect, forwardRef, memo, } from "react"; import { applyReactStyle } from "../utils/apply-react-style"; import { useControl } from "./use-control"; import type { ControlPosition, GeolocateControl as GeolocateControlInstance, GeolocateControlOptions, } from "../types/lib"; import type { GeolocateEvent, GeolocateResultEvent, GeolocateErrorEvent, } from "../types/events"; export type GeolocateControlProps = GeolocateControlOptions & { /** Placement of the control relative to the map. */ position?: ControlPosition; /** CSS style override, applied to the control's container */ style?: React.CSSProperties; /** Called on each Geolocation API position update that returned as success. */ onGeolocate?: (e: GeolocateResultEvent) => void; /** Called on each Geolocation API position update that returned as an error. */ onError?: (e: GeolocateErrorEvent) => void; /** Called on each Geolocation API position update that returned as success but user position * is out of map `maxBounds`. */ onOutOfMaxBounds?: (e: GeolocateResultEvent) => void; /** Called when the GeolocateControl changes to the active lock state. */ onTrackUserLocationStart?: (e: GeolocateEvent) => void; /** Called when the GeolocateControl changes to the background state. */ onTrackUserLocationEnd?: (e: GeolocateEvent) => void; }; function _GeolocateControl( props: GeolocateControlProps, ref: React.Ref<GeolocateControlInstance>, ) { const thisRef = useRef({ props }); const ctrl = useControl( ({ mapLib }) => { const gc = new mapLib.GeolocateControl(props); // Hack: fix GeolocateControl reuse // When using React strict mode, the component is mounted twice. // GeolocateControl's UI creation is asynchronous. Removing and adding it back causes the UI to be initialized twice. const setupUI = gc._setupUI; gc._setupUI = () => { if (!gc._container.hasChildNodes()) { setupUI(); } }; gc.on("geolocate", (e) => { thisRef.current.props.onGeolocate?.(e as GeolocateResultEvent); }); gc.on("error", (e) => { thisRef.current.props.onError?.(e as GeolocateErrorEvent); }); gc.on("outofmaxbounds", (e) => { thisRef.current.props.onOutOfMaxBounds?.(e as GeolocateResultEvent); }); gc.on("trackuserlocationstart", (e) => { thisRef.current.props.onTrackUserLocationStart?.(e as GeolocateEvent); }); gc.on("trackuserlocationend", (e) => { thisRef.current.props.onTrackUserLocationEnd?.(e as GeolocateEvent); }); return gc; }, { position: props.position }, ); thisRef.current.props = props; useImperativeHandle(ref, () => ctrl, []); useEffect(() => { applyReactStyle(ctrl._container, props.style); }, [props.style]); return null; } export const GeolocateControl: React.FC<GeolocateControlProps> = memo( forwardRef(_GeolocateControl), );