base commit

This commit is contained in:
@kirill.komarov
2026-04-29 18:39:40 +05:00
parent 326521c9e6
commit c1773e5c57
@@ -2,15 +2,19 @@ import { useEffect, useMemo, useRef, useState } from 'react'
import Box from '@mui/material/Box' import Box from '@mui/material/Box'
import Button from '@mui/material/Button' import Button from '@mui/material/Button'
import CircularProgress from '@mui/material/CircularProgress' import CircularProgress from '@mui/material/CircularProgress'
import IconButton from '@mui/material/IconButton'
import List from '@mui/material/List' import List from '@mui/material/List'
import ListItemButton from '@mui/material/ListItemButton' import ListItemButton from '@mui/material/ListItemButton'
import ListItemText from '@mui/material/ListItemText' import ListItemText from '@mui/material/ListItemText'
import Stack from '@mui/material/Stack' import Stack from '@mui/material/Stack'
import TextField from '@mui/material/TextField' import TextField from '@mui/material/TextField'
import Tooltip from '@mui/material/Tooltip'
import Typography from '@mui/material/Typography' import Typography from '@mui/material/Typography'
import MyLocationOutlinedIcon from '@mui/icons-material/MyLocationOutlined'
import * as maplibregl from 'maplibre-gl' import * as maplibregl from 'maplibre-gl'
import Map, { Marker } from 'react-map-gl/maplibre' import Map, { Marker } from 'react-map-gl/maplibre'
import type { MapMouseEvent } from 'react-map-gl/maplibre' import type { MapMouseEvent } from 'react-map-gl/maplibre'
import type { MapRef } from 'react-map-gl/maplibre'
type NominatimItem = { display_name: string; lat: string; lon: string } type NominatimItem = { display_name: string; lat: string; lon: string }
@@ -48,8 +52,10 @@ export function AddressMapPicker(props: {
onChange: (v: { lat: number; lng: number; addressLine?: string | null }) => void onChange: (v: { lat: number; lng: number; addressLine?: string | null }) => void
}) { }) {
const { value, onChange } = props const { value, onChange } = props
const mapRef = useRef<MapRef | null>(null)
const [q, setQ] = useState('') const [q, setQ] = useState('')
const [searching, setSearching] = useState(false) const [searching, setSearching] = useState(false)
const [locating, setLocating] = useState(false)
const [results, setResults] = useState<NominatimItem[]>([]) const [results, setResults] = useState<NominatimItem[]>([])
const [hint, setHint] = useState<string | null>(null) const [hint, setHint] = useState<string | null>(null)
const abortRef = useRef<AbortController | null>(null) const abortRef = useRef<AbortController | null>(null)
@@ -169,10 +175,12 @@ export function AddressMapPicker(props: {
overflow: 'hidden', overflow: 'hidden',
border: 1, border: 1,
borderColor: 'divider', borderColor: 'divider',
position: 'relative',
}} }}
> >
<Map <Map
mapLib={maplibregl} mapLib={maplibregl}
ref={mapRef}
initialViewState={{ latitude: center.lat, longitude: center.lng, zoom: 12 }} initialViewState={{ latitude: center.lat, longitude: center.lng, zoom: 12 }}
style={{ width: '100%', height: 280 }} style={{ width: '100%', height: 280 }}
mapStyle={{ mapStyle={{
@@ -217,9 +225,48 @@ export function AddressMapPicker(props: {
</Marker> </Marker>
)} )}
</Map> </Map>
<Tooltip title="Моё местоположение">
<span>
<IconButton
size="small"
disabled={locating || !('geolocation' in navigator)}
onClick={() => {
if (!('geolocation' in navigator)) return
setLocating(true)
navigator.geolocation.getCurrentPosition(
(pos) => {
const lat = pos.coords.latitude
const lng = pos.coords.longitude
mapRef.current?.flyTo({ center: [lng, lat], zoom: 15, duration: 800 })
void pick({ lat, lng })
setLocating(false)
},
() => {
setLocating(false)
},
{ enableHighAccuracy: true, timeout: 8000, maximumAge: 60_000 },
)
}}
sx={{
position: 'absolute',
top: 10,
right: 10,
bgcolor: 'background.paper',
border: 1,
borderColor: 'divider',
boxShadow: 2,
'&:hover': { bgcolor: 'background.paper' },
}}
aria-label="Моё местоположение"
>
{locating ? <CircularProgress size={16} /> : <MyLocationOutlinedIcon fontSize="small" />}
</IconButton>
</span>
</Tooltip>
</Box> </Box>
<Box sx={{ minHeight: 18 }}> <Box sx={{ minHeight: 32, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
{hint && ( {hint && (
<Typography variant="caption" color="text.secondary"> <Typography variant="caption" color="text.secondary">
Подсказка адреса: {hint} Подсказка адреса: {hint}