Fix popup issue (#1368)

## Launch Checklist

When clicking the map to create a popup and then clicking on the map
again without closing the popup something breaks in react.
This PR fixes it.

Steps to reproduce:
1. Click on the map
2. Click on the map but not on the popup

The following malformed popup appears:
Before:
<img width="610" height="626" alt="image"
src="https://github.com/user-attachments/assets/99cbdf9a-0b3c-436d-ab13-f219ee3c6e75"
/>

After - popup looks good.
<img width="610" height="626" alt="image"
src="https://github.com/user-attachments/assets/6b379c0d-cbbf-40ed-916d-3cc10eaf4410"
/>

I couldn't make cypress reproduce the exact scenario, but I added some
basic tests for popups.

 - [x] Briefly describe the changes in this PR.
- [x] Include before/after visuals or gifs if this PR includes visual
changes.
 - [x] Write tests for all new functionality.
 - [x] Add an entry to `CHANGELOG.md` under the `## main` section.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Harel M
2025-09-10 14:44:38 +03:00
committed by GitHub
parent 9c85883b8a
commit c3c6118df1
8 changed files with 146 additions and 26 deletions

View File

@@ -1,4 +1,4 @@
import React, {type JSX} from 'react'
import React from 'react'
import {createRoot} from 'react-dom/client'
import MapLibreGl, {LayerSpecification, LngLat, Map, MapOptions, SourceSpecification, StyleSpecification} from 'maplibre-gl'
import MaplibreInspect from '@maplibre/maplibre-gl-inspect'
@@ -17,17 +17,6 @@ import { withTranslation, WithTranslation } from 'react-i18next'
import i18next from 'i18next'
import { Protocol } from "pmtiles";
function renderPopup(
popupElement: JSX.Element,
mountNode: HTMLElement,
popup: MapLibreGl.Popup
): HTMLElement {
const root = createRoot(mountNode);
popup.once('close', () => root.unmount());
root.render(popupElement);
return mountNode as HTMLElement;
}
function buildInspectStyle(originalMapStyle: StyleSpecification, coloredLayers: HighlightedLayer[], highlightedLayer?: HighlightedLayer) {
const backgroundLayer = {
"id": "background",
@@ -179,6 +168,7 @@ class MapMaplibreGlInternal extends React.Component<MapMaplibreGlInternalProps,
map.addControl(nav, 'top-right');
const tmpNode = document.createElement('div');
const root = createRoot(tmpNode);
const inspectPopup = new MapLibreGl.Popup({
closeOnClick: false
@@ -197,21 +187,19 @@ class MapMaplibreGlInternal extends React.Component<MapMaplibreGlInternalProps,
buildInspectStyle: (originalMapStyle: StyleSpecification, coloredLayers: HighlightedLayer[]) => buildInspectStyle(originalMapStyle, coloredLayers, this.props.highlightedLayer),
renderPopup: (features: InspectFeature[]) => {
if(this.props.inspectModeEnabled) {
return renderPopup(
<MapMaplibreGlFeaturePropertyPopup features={features} />,
tmpNode,
inspectPopup
);
inspectPopup.once('open', () => {
root.render(<MapMaplibreGlFeaturePropertyPopup features={features} />);
});
return tmpNode;
} else {
return renderPopup(
<MapMaplibreGlLayerPopup
inspectPopup.once('open', () => {
root.render(<MapMaplibreGlLayerPopup
features={features}
onLayerSelect={this.onLayerSelectById}
zoom={this.state.zoom}
/>,
tmpNode,
inspectPopup
);
/>,);
});
return tmpNode;
}
}
})

View File

@@ -66,7 +66,7 @@ type FeaturePropertyPopupProps = {
class FeaturePropertyPopup extends React.Component<FeaturePropertyPopupProps> {
render() {
const features = removeDuplicatedFeatures(this.props.features)
return <div className="maputnik-feature-property-popup">
return <div className="maputnik-feature-property-popup" dir="ltr" data-wd-key="feature-property-popup">
<table className="maputnik-popup-table">
<tbody>
{features.map(renderFeature)}

View File

@@ -104,7 +104,7 @@ class FeatureLayerPopup extends React.Component<FeatureLayerPopupProps> {
</div>
})
return <div className="maputnik-feature-layer-popup">
return <div className="maputnik-feature-layer-popup" data-wd-key="feature-layer-popup" dir="ltr">
{items}
</div>
}