Skip to content

Commit 550f01e

Browse files
authored
Only one opened callout at a time (47) (#731)
* Only one opened callout at a time * Revert uneeded change * Update comment
1 parent 5a26455 commit 550f01e

File tree

3 files changed

+115
-42
lines changed

3 files changed

+115
-42
lines changed

packages/maps/src/components/MapMarker.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import {
77
Text,
88
} from "react-native";
99
import { Marker as MapMarkerComponent } from "./react-native-maps";
10-
import type { MapMarkerProps as MapMarkerComponentProps } from "react-native-maps";
10+
import type {
11+
MapMarkerProps as MapMarkerComponentProps,
12+
MapMarker as MapMarkerRefType,
13+
} from "react-native-maps";
1114
import MapCallout, { renderCallout } from "./MapCallout";
1215
import { flattenReactFragments } from "@draftbit/ui";
1316

@@ -43,7 +46,9 @@ export function renderMarker(
4346
description,
4447
...rest
4548
}: MapMarkerProps,
46-
key?: React.Key
49+
key?: React.Key,
50+
ref?: React.Ref<MapMarkerRefType>,
51+
onMarkerPress?: () => void
4752
) {
4853
const childrenArray = flattenReactFragments(
4954
React.Children.toArray(children) as React.ReactElement[]
@@ -73,12 +78,14 @@ export function renderMarker(
7378

7479
return (
7580
<MapMarkerComponent
81+
ref={ref}
7682
key={key}
7783
coordinate={{
7884
latitude,
7985
longitude,
8086
}}
8187
onPress={(event) => {
88+
onMarkerPress?.();
8289
const coordinate = event.nativeEvent.coordinate;
8390
onPress?.(coordinate.latitude, coordinate.longitude);
8491
}}

packages/maps/src/components/MapView.tsx

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ import MapMarkerCluster from "./marker-cluster/MapMarkerCluster";
1111
import { MapViewContext, ZoomLocation } from "./MapViewCommon";
1212
import { MapMarkerClusterView } from "./marker-cluster";
1313
import { flattenReactFragments } from "@draftbit/ui";
14+
import type { MapMarker as MapMarkerRefType } from "react-native-maps";
15+
16+
export interface MapMarkerContextType {
17+
onMarkerPress: (marker: MapMarkerProps) => void;
18+
getMarkerRef: (
19+
marker: MapMarkerProps
20+
) => React.Ref<MapMarkerRefType> | undefined;
21+
}
22+
23+
export const MapMarkerContext = React.createContext<MapMarkerContextType>({
24+
onMarkerPress: () => {},
25+
getMarkerRef: () => undefined,
26+
});
1427

1528
export interface MapViewProps<T>
1629
extends Omit<MapViewComponentProps, "onRegionChangeComplete"> {
@@ -35,10 +48,13 @@ class MapView<T> extends React.Component<
3548
MapViewState
3649
> {
3750
private mapRef: React.RefObject<any>;
51+
private markerRefs: Map<string, React.RefObject<MapMarkerRefType>>;
52+
3853
constructor(props: React.PropsWithChildren<MapViewProps<T>>) {
3954
super(props);
4055
this.state = { region: null };
4156
this.mapRef = React.createRef();
57+
this.markerRefs = new Map();
4258
}
4359

4460
componentDidUpdate(prevProps: React.PropsWithChildren<MapViewProps<T>>) {
@@ -163,6 +179,23 @@ class MapView<T> extends React.Component<
163179
return nearbyMarkers;
164180
}
165181

182+
// Dismiss all other callouts except the one just pressed. Maintains that only one is opened at a time
183+
private onMarkerPress(markerIdentifier: string) {
184+
for (const [idenfitifer, markerRef] of this.markerRefs) {
185+
if (idenfitifer !== markerIdentifier) markerRef.current?.hideCallout();
186+
}
187+
}
188+
189+
private getMarkerRef(markerIdentifier: string) {
190+
if (this.markerRefs.has(markerIdentifier)) {
191+
return this.markerRefs.get(markerIdentifier);
192+
} else {
193+
const ref = React.createRef<MapMarkerRefType>();
194+
this.markerRefs.set(markerIdentifier, ref);
195+
return ref;
196+
}
197+
}
198+
166199
render() {
167200
const {
168201
apiKey,
@@ -234,11 +267,31 @@ class MapView<T> extends React.Component<
234267
style={[styles.map, style]}
235268
{...rest}
236269
>
237-
{markers.map((marker, index) => renderMarker(marker.props, index))}
238-
239-
{clusters.map((cluster, index) => (
240-
<React.Fragment key={index}>{cluster}</React.Fragment>
241-
))}
270+
{markers.map((marker, index) =>
271+
renderMarker(
272+
marker.props,
273+
index,
274+
this.getMarkerRef(getMarkerIdentifier(marker.props)),
275+
() => this.onMarkerPress(getMarkerIdentifier(marker.props))
276+
)
277+
)}
278+
279+
{/*
280+
Markers within clusters also need to able to assign refs and propogate press.
281+
This is done through context to prevent exposing these internal config options as props of the cluster component
282+
*/}
283+
<MapMarkerContext.Provider
284+
value={{
285+
getMarkerRef: (marker) =>
286+
this.getMarkerRef(getMarkerIdentifier(marker)),
287+
onMarkerPress: (marker) =>
288+
this.onMarkerPress(getMarkerIdentifier(marker)),
289+
}}
290+
>
291+
{clusters.map((cluster, index) => (
292+
<React.Fragment key={index}>{cluster}</React.Fragment>
293+
))}
294+
</MapMarkerContext.Provider>
242295
</MapViewComponent>
243296
</MapViewContext.Provider>
244297
);
@@ -291,4 +344,8 @@ function degreeToRadian(deg: number) {
291344
return deg * (Math.PI / 180);
292345
}
293346

347+
function getMarkerIdentifier(marker: MapMarkerProps) {
348+
return `marker-${marker.latitude}-${marker.longitude}`;
349+
}
350+
294351
export default MapView;

packages/maps/src/components/marker-cluster/MapMarkerCluster.tsx

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import MapMarkerClusterView, {
77
import { MapMarkerClusterContext } from "./MapMarkerClusterContext";
88
import { MapViewContext } from "../MapViewCommon";
99
import { flattenReactFragments } from "@draftbit/ui";
10+
import { MapMarkerContext } from "../MapView";
1011

1112
/**
1213
* Component that clusters all markers provided in as children to a single point when zoomed out, and shows the markers themselves when zoomed in
@@ -41,44 +42,52 @@ const MapMarkerCluster: React.FC<React.PropsWithChildren> = ({
4142
);
4243

4344
return (
44-
<MarkerClusterer
45-
region={region}
46-
renderCluster={({ pointCount, coordinate, expansionZoom }) => {
47-
const { latitude, longitude } = coordinate;
45+
<MapMarkerContext.Consumer>
46+
{({ getMarkerRef, onMarkerPress }) => (
47+
<MarkerClusterer
48+
region={region}
49+
renderCluster={({ pointCount, coordinate, expansionZoom }) => {
50+
const { latitude, longitude } = coordinate;
4851

49-
// onPress needs to be lifted out and passed to Marker directly because Marker intercepts all touch events
50-
const clusterViewOnPress = clusterView.props?.onPress;
51-
const zoomOnPress = clusterView.props?.zoomOnPress ?? true;
52+
// onPress needs to be lifted out and passed to Marker directly because Marker intercepts all touch events
53+
const clusterViewOnPress = clusterView.props?.onPress;
54+
const zoomOnPress = clusterView.props?.zoomOnPress ?? true;
5255

53-
const onPress = () => {
54-
clusterViewOnPress?.(latitude, longitude);
55-
if (zoomOnPress) {
56-
animateToLocation({
57-
latitude,
58-
longitude,
59-
zoom: expansionZoom + 3,
60-
});
61-
}
62-
};
56+
const onPress = () => {
57+
clusterViewOnPress?.(latitude, longitude);
58+
if (zoomOnPress) {
59+
animateToLocation({
60+
latitude,
61+
longitude,
62+
zoom: expansionZoom + 3,
63+
});
64+
}
65+
};
6366

64-
return (
65-
<MapMarkerClusterContext.Provider
66-
value={{
67-
markerCount: pointCount,
68-
}}
69-
>
70-
{renderMarker({
71-
latitude,
72-
longitude,
73-
children: clusterView,
74-
onPress,
75-
})}
76-
</MapMarkerClusterContext.Provider>
77-
);
78-
}}
79-
>
80-
{markers.map((marker, index) => renderMarker(marker.props, index))}
81-
</MarkerClusterer>
67+
return (
68+
<MapMarkerClusterContext.Provider
69+
value={{
70+
markerCount: pointCount,
71+
}}
72+
>
73+
{renderMarker({
74+
latitude,
75+
longitude,
76+
children: clusterView,
77+
onPress,
78+
})}
79+
</MapMarkerClusterContext.Provider>
80+
);
81+
}}
82+
>
83+
{markers.map((marker, index) =>
84+
renderMarker(marker.props, index, getMarkerRef(marker.props), () =>
85+
onMarkerPress(marker.props)
86+
)
87+
)}
88+
</MarkerClusterer>
89+
)}
90+
</MapMarkerContext.Consumer>
8291
);
8392
};
8493

0 commit comments

Comments
 (0)