Skip to content

Commit 899f0b5

Browse files
authored
Only one opened callout at a time (#730)
* Only one opened callout at a time * Revert uneeded change * Update comment
1 parent 6cd3055 commit 899f0b5

File tree

3 files changed

+114
-41
lines changed

3 files changed

+114
-41
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: 61 additions & 4 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>>) {
@@ -162,6 +178,23 @@ class MapView<T> extends React.Component<
162178
return nearbyMarkers;
163179
}
164180

181+
// Dismiss all other callouts except the one just pressed. Maintains that only one is opened at a time
182+
private onMarkerPress(markerIdentifier: string) {
183+
for (const [idenfitifer, markerRef] of this.markerRefs) {
184+
if (idenfitifer !== markerIdentifier) markerRef.current?.hideCallout();
185+
}
186+
}
187+
188+
private getMarkerRef(markerIdentifier: string) {
189+
if (this.markerRefs.has(markerIdentifier)) {
190+
return this.markerRefs.get(markerIdentifier);
191+
} else {
192+
const ref = React.createRef<MapMarkerRefType>();
193+
this.markerRefs.set(markerIdentifier, ref);
194+
return ref;
195+
}
196+
}
197+
165198
render() {
166199
const {
167200
apiKey,
@@ -231,11 +264,31 @@ class MapView<T> extends React.Component<
231264
style={[styles.map, style]}
232265
{...rest}
233266
>
234-
{markers.map((marker, index) => renderMarker(marker.props, index))}
267+
{markers.map((marker, index) =>
268+
renderMarker(
269+
marker.props,
270+
index,
271+
this.getMarkerRef(getMarkerIdentifier(marker.props)),
272+
() => this.onMarkerPress(getMarkerIdentifier(marker.props))
273+
)
274+
)}
235275

236-
{clusters.map((cluster, index) => (
237-
<React.Fragment key={index}>{cluster}</React.Fragment>
238-
))}
276+
{/*
277+
Markers within clusters also need to able to assign refs and propogate press.
278+
This is done through context to prevent exposing these internal config options as props of the cluster component
279+
*/}
280+
<MapMarkerContext.Provider
281+
value={{
282+
getMarkerRef: (marker) =>
283+
this.getMarkerRef(getMarkerIdentifier(marker)),
284+
onMarkerPress: (marker) =>
285+
this.onMarkerPress(getMarkerIdentifier(marker)),
286+
}}
287+
>
288+
{clusters.map((cluster, index) => (
289+
<React.Fragment key={index}>{cluster}</React.Fragment>
290+
))}
291+
</MapMarkerContext.Provider>
239292
</MapViewComponent>
240293
</MapViewContext.Provider>
241294
);
@@ -288,4 +341,8 @@ function degreeToRadian(deg: number) {
288341
return deg * (Math.PI / 180);
289342
}
290343

344+
function getMarkerIdentifier(marker: MapMarkerProps) {
345+
return `marker-${marker.latitude}-${marker.longitude}`;
346+
}
347+
291348
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)