From c39a04761aa2bc8b01184ca0fa8d22faf1bbaeab Mon Sep 17 00:00:00 2001 From: Anton Tranelis Date: Mon, 11 Aug 2025 13:36:56 +0200 Subject: [PATCH] improved locate control --- .../Subcomponents/Controls/LocateControl.tsx | 93 ++++++++++++------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/lib/src/Components/Map/Subcomponents/Controls/LocateControl.tsx b/lib/src/Components/Map/Subcomponents/Controls/LocateControl.tsx index ecc3a061..98115b1c 100644 --- a/lib/src/Components/Map/Subcomponents/Controls/LocateControl.tsx +++ b/lib/src/Components/Map/Subcomponents/Controls/LocateControl.tsx @@ -1,9 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/prefer-ts-expect-error */ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-call */ import { control } from 'leaflet' import { useEffect, useRef, useState } from 'react' import SVG from 'react-inlinesvg' @@ -14,20 +8,32 @@ import TargetSVG from '#assets/target.svg' // eslint-disable-next-line import/no-unassigned-import import 'leaflet.locatecontrol' -// Converts leaflet.locatecontrol to a React Component -export const LocateControl = () => { +// Type definitions for leaflet.locatecontrol +declare module 'leaflet' { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace control { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function locate(options?: object): any + } +} + +/** + * React wrapper for leaflet.locatecontrol that provides user geolocation functionality + * @category Map Controls + */ +export const LocateControl = (): JSX.Element => { const map = useMap() - // prevent react18 from calling useEffect twice + // Prevent React 18 StrictMode from calling useEffect twice const init = useRef(false) + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment const [lc, setLc] = useState(null) const [active, setActive] = useState(false) const [loading, setLoading] = useState(false) useEffect(() => { if (!init.current) { - // @ts-ignore setLc(control.locate().addTo(map)) init.current = true } @@ -39,34 +45,51 @@ export const LocateControl = () => { setLoading(false) setActive(true) }, + locationerror: () => { + setLoading(false) + setActive(false) + }, }) + const handleLocateClick = (): void => { + if (!lc) return + + if (active) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + lc.stop() + setActive(false) + } else { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + lc.start() + setLoading(true) + } + } + return ( - <> -
-
{ - if (active) { - lc.stop() - setActive(false) - } else { - lc.start() - setLoading(true) - } - }} - > - {loading ? ( - - ) : ( - - )} -
+
+
{ + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault() + handleLocateClick() + } + }} + aria-label={active ? 'Stop location tracking' : 'Start location tracking'} + > + {loading ? ( + + ) : ( + + )}
- +
) }