fix(tradein): MapPicker через portal в document.body — z-index конфликт с SourcesProgress (#771) #782

Merged
bot-reviewer merged 1 commit from feat/771-mappicker-portal into main 2026-05-30 16:37:04 +00:00

View file

@ -3,6 +3,7 @@
/* Выбор адреса на карте ЕКБ (Leaflet + OSM). Клик по дому → reverse-геокодинг. */ /* Выбор адреса на карте ЕКБ (Leaflet + OSM). Клик по дому → reverse-геокодинг. */
/* eslint-disable @typescript-eslint/no-explicit-any -- интероп с CDN-библиотекой Leaflet */ /* eslint-disable @typescript-eslint/no-explicit-any -- интероп с CDN-библиотекой Leaflet */
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { API_BASE_URL } from "@/lib/api"; import { API_BASE_URL } from "@/lib/api";
@ -98,6 +99,11 @@ export function MapPicker({ onPick, onClose }: Props) {
// тонкий hint «Точка дома по Яндексу», чтобы user понимал почему marker // тонкий hint «Точка дома по Яндексу», чтобы user понимал почему marker
// переехал на пару метров от его клика. // переехал на пару метров от его клика.
const [snapped, setSnapped] = useState(false); const [snapped, setSnapped] = useState(false);
// Portal-mount guard (SSR-safe): document доступен только после монтирования.
// Рендерим оверлей в document.body, чтобы position:fixed/z-index:1000 не были
// заперты в stacking-context формы (#771: полоски SourcesProgress наезжали).
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
useEffect(() => { useEffect(() => {
let map: any = null; let map: any = null;
@ -212,7 +218,9 @@ export function MapPicker({ onPick, onClose }: Props) {
} }
}; };
return ( if (!mounted) return null;
return createPortal(
<div <div
onClick={onClose} onClick={onClose}
style={{ style={{
@ -316,6 +324,7 @@ export function MapPicker({ onPick, onClose }: Props) {
</button> </button>
</div> </div>
</div> </div>
</div> </div>,
document.body,
); );
} }