react-bkoi-gl
Version:
React components for Barikoi GL JS
97 lines (83 loc) • 3.05 kB
text/typescript
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),
);