mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2026-04-04 08:35:28 +00:00
improved locate control
This commit is contained in:
parent
4e6fb57042
commit
c39a04761a
@ -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 { control } from 'leaflet'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import SVG from 'react-inlinesvg'
|
import SVG from 'react-inlinesvg'
|
||||||
@ -14,20 +8,32 @@ import TargetSVG from '#assets/target.svg'
|
|||||||
// eslint-disable-next-line import/no-unassigned-import
|
// eslint-disable-next-line import/no-unassigned-import
|
||||||
import 'leaflet.locatecontrol'
|
import 'leaflet.locatecontrol'
|
||||||
|
|
||||||
// Converts leaflet.locatecontrol to a React Component
|
// Type definitions for leaflet.locatecontrol
|
||||||
export const 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()
|
const map = useMap()
|
||||||
|
|
||||||
// prevent react18 from calling useEffect twice
|
// Prevent React 18 StrictMode from calling useEffect twice
|
||||||
const init = useRef(false)
|
const init = useRef(false)
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
|
||||||
const [lc, setLc] = useState<any>(null)
|
const [lc, setLc] = useState<any>(null)
|
||||||
const [active, setActive] = useState<boolean>(false)
|
const [active, setActive] = useState<boolean>(false)
|
||||||
const [loading, setLoading] = useState<boolean>(false)
|
const [loading, setLoading] = useState<boolean>(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!init.current) {
|
if (!init.current) {
|
||||||
// @ts-ignore
|
|
||||||
setLc(control.locate().addTo(map))
|
setLc(control.locate().addTo(map))
|
||||||
init.current = true
|
init.current = true
|
||||||
}
|
}
|
||||||
@ -39,34 +45,51 @@ export const LocateControl = () => {
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
setActive(true)
|
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 (
|
return (
|
||||||
<>
|
<div className='tw:card tw:flex-none tw:h-12 tw:w-12 tw:bg-base-100 tw:shadow-xl tw:items-center tw:justify-center tw:hover:bg-slate-300 tw:hover:cursor-pointer tw:transition-all tw:duration-300 tw:ml-2'>
|
||||||
<div className='tw:card tw:flex-none tw:h-12 tw:w-12 tw:bg-base-100 tw:shadow-xl tw:items-center tw:justify-center tw:hover:bg-slate-300 tw:hover:cursor-pointer tw:transition-all tw:duration-300 tw:ml-2'>
|
<div
|
||||||
<div
|
className='tw:card-body tw:card tw:p-2 tw:h-10 tw:w-10'
|
||||||
className='tw:card-body tw:card tw:p-2 tw:h-10 tw:w-10 '
|
onClick={handleLocateClick}
|
||||||
onClick={() => {
|
role='button'
|
||||||
if (active) {
|
tabIndex={0}
|
||||||
lc.stop()
|
onKeyDown={(e) => {
|
||||||
setActive(false)
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
} else {
|
e.preventDefault()
|
||||||
lc.start()
|
handleLocateClick()
|
||||||
setLoading(true)
|
}
|
||||||
}
|
}}
|
||||||
}}
|
aria-label={active ? 'Stop location tracking' : 'Start location tracking'}
|
||||||
>
|
>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<span className='tw:loading tw:loading-spinner tw:loading-md tw:mt-1'></span>
|
<span className='tw:loading tw:loading-spinner tw:loading-md tw:mt-1' />
|
||||||
) : (
|
) : (
|
||||||
<SVG
|
<SVG
|
||||||
src={TargetSVG}
|
src={TargetSVG}
|
||||||
className='tw:mt-1 tw:p-[1px]'
|
className='tw:mt-1 tw:p-[1px]'
|
||||||
style={{ fill: `${active ? '#fc8702' : 'currentColor'}` }}
|
style={{ fill: active ? '#fc8702' : 'currentColor' }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user