Fix first city click handling on flights map

This commit is contained in:
2026-04-30 18:53:03 +03:00
parent ac7095a5e9
commit e33baad901
3 changed files with 65 additions and 5 deletions
@@ -313,6 +313,8 @@
border: none;
box-shadow: none;
padding: 0;
pointer-events: auto;
cursor: pointer;
font-family: 'Inter', 'Roboto', Arial, sans-serif;
color: colors.$text-color;
font-size: fonts.$font-size-s;
@@ -323,7 +325,6 @@
1px 0 rgba(255, 255, 255, 0.53),
0 1px rgba(255, 255, 255, 0.53),
0 -1px rgba(255, 255, 255, 0.53);
pointer-events: none;
&::before { display: none; }
}
@@ -13,15 +13,17 @@ import type { IMapMarker } from "../types.js";
interface MockMarker {
icon: unknown;
tooltipArgs: unknown[] | null;
tooltipHandlers: Record<string, Array<(e?: unknown) => void>>;
addTo: ReturnType<typeof vi.fn>;
on: ReturnType<typeof vi.fn>;
bindTooltip: ReturnType<typeof vi.fn>;
getTooltip: ReturnType<typeof vi.fn>;
openTooltip: ReturnType<typeof vi.fn>;
closeTooltip: ReturnType<typeof vi.fn>;
setIcon: ReturnType<typeof vi.fn>;
setLatLng: ReturnType<typeof vi.fn>;
getLatLng: ReturnType<typeof vi.fn>;
options: { title?: string };
options: { title?: string; autoPanOnFocus?: boolean };
}
interface MockLayerGroup {
@@ -71,10 +73,22 @@ function resetLeafletMockState() {
vi.mock("leaflet/dist/leaflet.css", () => ({}));
vi.mock("leaflet", () => {
function marker(_latlng: unknown, opts: { icon?: unknown; title?: string } = {}) {
function marker(
_latlng: unknown,
opts: { icon?: unknown; title?: string; autoPanOnFocus?: boolean } = {},
) {
const tooltip = {
on: vi.fn((evt: string, fn: (e?: unknown) => void) => {
m.tooltipHandlers[evt] ??= [];
m.tooltipHandlers[evt]!.push(fn);
return tooltip;
}),
};
const m: MockMarker = {
icon: opts.icon,
tooltipArgs: null,
tooltipHandlers: {},
addTo: vi.fn((target: { addLayer?: (l: MockMarker) => unknown }) => {
target.addLayer?.(m);
return m;
@@ -84,6 +98,7 @@ vi.mock("leaflet", () => {
m.tooltipArgs = args;
return m;
}),
getTooltip: vi.fn(() => tooltip),
openTooltip: vi.fn(() => m),
closeTooltip: vi.fn(() => m),
setIcon: vi.fn((ic: unknown) => {
@@ -92,7 +107,10 @@ vi.mock("leaflet", () => {
}),
setLatLng: vi.fn(() => m),
getLatLng: vi.fn(() => ({ lat: 0, lng: 0 })),
options: opts.title !== undefined ? { title: opts.title } : {},
options: {
...(opts.title !== undefined ? { title: opts.title } : {}),
...(opts.autoPanOnFocus !== undefined ? { autoPanOnFocus: opts.autoPanOnFocus } : {}),
},
};
createdMarkers.push(m);
return m;
@@ -192,7 +210,11 @@ vi.mock("leaflet", () => {
};
}
const L = { marker, layerGroup, map: mapFn, tileLayer, icon, latLng, polyline, popup };
const DomEvent = {
stop: vi.fn(),
};
const L = { marker, layerGroup, map: mapFn, tileLayer, icon, latLng, polyline, popup, DomEvent };
return { default: L, ...L };
});
@@ -254,6 +276,35 @@ describe("MapCanvas — legacy (flat) path", () => {
const allMarkers = createdLayerGroups.flatMap((l) => l._markers);
expect(allMarkers).toContain(createdMarkers[0]);
});
it("creates markers with no auto-pan on focus and interactive city labels", () => {
renderCanvas([
{ id: "MOW", lat: 1, lng: 2, style: "blue-small", label: "Москва", tooltipPermanent: true },
]);
const marker = createdMarkers[0];
expect(marker).toBeTruthy();
if (!marker) return;
expect(marker.options).toMatchObject({ title: "MOW", autoPanOnFocus: false });
expect(marker.tooltipArgs?.[1]).toMatchObject({ interactive: true });
});
it("treats city-label click as marker click", () => {
const onMarkerClick = vi.fn();
renderCanvas(
[{ id: "MOW", lat: 1, lng: 2, style: "blue-small", label: "Москва", tooltipPermanent: true }],
{ onMarkerClick },
);
const marker = createdMarkers[0];
if (!marker) {
throw new Error("expected marker to be created");
}
const clickHandlers = marker?.tooltipHandlers["click"];
expect(clickHandlers?.length).toBeGreaterThan(0);
clickHandlers?.[0]?.({} as unknown);
expect(onMarkerClick).toHaveBeenCalledWith("MOW");
});
});
describe("MapCanvas — categorized: visibility predicate", () => {
@@ -376,6 +376,7 @@ export const MapCanvas: FC<MapCanvasProps> = ({
const marker = L.marker([m.lat, m.lng], {
icon: getIcon(iconStyle),
title: m.id,
autoPanOnFocus: false,
});
if (m.label) {
@@ -383,6 +384,13 @@ export const MapCanvas: FC<MapCanvasProps> = ({
permanent: m.tooltipPermanent ?? false,
direction: "top",
className: "city-label",
interactive: true,
});
const tooltip = marker.getTooltip();
tooltip?.on("click", (event: L.LeafletMouseEvent) => {
L.DomEvent.stop(event);
onMarkerClickRef.current?.(m.id);
});
}