@@ -31,6 +31,10 @@ export function isAdvancedMarker(
31
31
) ;
32
32
}
33
33
34
+ function isElementNode ( node : Node ) : node is HTMLElement {
35
+ return node . nodeType === Node . ELEMENT_NODE ;
36
+ }
37
+
34
38
/**
35
39
* Copy of the `google.maps.CollisionBehavior` constants.
36
40
* They have to be duplicated here since we can't wait for the maps API to load to be able to use them.
@@ -48,19 +52,19 @@ export const AdvancedMarkerContext =
48
52
49
53
// [xPosition, yPosition] when the top left corner is [0, 0]
50
54
export const AdvancedMarkerAnchorPoint = {
51
- TOP_LEFT : [ '0' , '0' ] ,
52
- TOP_CENTER : [ '50%' , '0' ] ,
53
- TOP : [ '50%' , '0' ] ,
54
- TOP_RIGHT : [ '100%' , '0' ] ,
55
- LEFT_CENTER : [ '0' , '50%' ] ,
56
- LEFT_TOP : [ '0' , '0' ] ,
57
- LEFT : [ '0' , '50%' ] ,
58
- LEFT_BOTTOM : [ '0' , '100%' ] ,
59
- RIGHT_TOP : [ '100%' , '0' ] ,
55
+ TOP_LEFT : [ '0% ' , '0% ' ] ,
56
+ TOP_CENTER : [ '50%' , '0% ' ] ,
57
+ TOP : [ '50%' , '0% ' ] ,
58
+ TOP_RIGHT : [ '100%' , '0% ' ] ,
59
+ LEFT_CENTER : [ '0% ' , '50%' ] ,
60
+ LEFT_TOP : [ '0% ' , '0% ' ] ,
61
+ LEFT : [ '0% ' , '50%' ] ,
62
+ LEFT_BOTTOM : [ '0% ' , '100%' ] ,
63
+ RIGHT_TOP : [ '100%' , '0% ' ] ,
60
64
RIGHT : [ '100%' , '50%' ] ,
61
65
RIGHT_CENTER : [ '100%' , '50%' ] ,
62
66
RIGHT_BOTTOM : [ '100%' , '100%' ] ,
63
- BOTTOM_LEFT : [ '0' , '100%' ] ,
67
+ BOTTOM_LEFT : [ '0% ' , '100%' ] ,
64
68
BOTTOM_CENTER : [ '50%' , '100%' ] ,
65
69
BOTTOM : [ '50%' , '100%' ] ,
66
70
BOTTOM_RIGHT : [ '100%' , '100%' ] ,
@@ -124,28 +128,25 @@ const MarkerContent = ({
124
128
const [ xTranslation , yTranslation ] =
125
129
anchorPoint ?? AdvancedMarkerAnchorPoint [ 'BOTTOM' ] ;
126
130
127
- const { transform : userTransform , ... restStyles } = styles ?? { } ;
128
-
129
- let transformStyle = `translate(-${ xTranslation } , -${ yTranslation } )` ;
131
+ // The "translate(50%, 100%)" is here to counter and reset the default anchoring of the advanced marker element
132
+ // that comes from the api
133
+ const transformStyle = `translate(50%, 100%) translate(-${ xTranslation } , -${ yTranslation } )` ;
130
134
131
- // preserve extra transform styles that were set by the user
132
- if ( userTransform ) {
133
- transformStyle += ` ${ userTransform } ` ;
134
- }
135
135
return (
136
- < div
137
- className = { className }
138
- style = { {
139
- width : 'fit-content' ,
140
- transformOrigin : `${ xTranslation } ${ yTranslation } ` ,
141
- transform : transformStyle ,
142
- ...restStyles
143
- } } >
144
- { children }
136
+ // anchoring container
137
+ < div style = { { transform : transformStyle } } >
138
+ { /* AdvancedMarker div that user can give styles and classes */ }
139
+ < div className = { className } style = { styles } >
140
+ { children }
141
+ </ div >
145
142
</ div >
146
143
) ;
147
144
} ;
148
145
146
+ export type CustomMarkerContent =
147
+ | ( HTMLDivElement & { isCustomMarker ?: boolean } )
148
+ | null ;
149
+
149
150
export type AdvancedMarkerRef = google . maps . marker . AdvancedMarkerElement | null ;
150
151
function useAdvancedMarker ( props : AdvancedMarkerProps ) {
151
152
const [ marker , setMarker ] =
@@ -185,11 +186,14 @@ function useAdvancedMarker(props: AdvancedMarkerProps) {
185
186
setMarker ( newMarker ) ;
186
187
187
188
// create the container for marker content if there are children
188
- let contentElement : HTMLDivElement | null = null ;
189
+ let contentElement : CustomMarkerContent = null ;
189
190
if ( numChildren > 0 ) {
190
191
contentElement = document . createElement ( 'div' ) ;
191
- contentElement . style . width = '0' ;
192
- contentElement . style . height = '0' ;
192
+
193
+ // We need some kind of flag to identify the custom marker content
194
+ // in the infowindow component. Choosing a custom property instead of a className
195
+ // to not encourage users to style the marker content directly.
196
+ contentElement . isCustomMarker = true ;
193
197
194
198
newMarker . content = contentElement ;
195
199
setContentContainer ( contentElement ) ;
@@ -233,15 +237,31 @@ function useAdvancedMarker(props: AdvancedMarkerProps) {
233
237
else marker . gmpDraggable = false ;
234
238
} , [ marker , draggable , onDrag , onDragEnd , onDragStart ] ) ;
235
239
236
- // set gmpClickable from props (when unspecified, it's true if the onClick event
237
- // callback is specified)
240
+ // set gmpClickable from props (when unspecified, it's true if the onClick or one of
241
+ // the hover events callbacks are specified)
238
242
useEffect ( ( ) => {
239
243
if ( ! marker ) return ;
240
244
241
- if ( clickable !== undefined ) marker . gmpClickable = clickable ;
242
- else if ( onClick ) marker . gmpClickable = true ;
243
- else marker . gmpClickable = false ;
244
- } , [ marker , clickable , onClick ] ) ;
245
+ const gmpClickable =
246
+ clickable !== undefined ||
247
+ Boolean ( onClick ) ||
248
+ Boolean ( onMouseEnter ) ||
249
+ Boolean ( onMouseLeave ) ;
250
+
251
+ // gmpClickable is only available in beta version of the
252
+ // maps api (as of 2024-10-10)
253
+ marker . gmpClickable = gmpClickable ;
254
+
255
+ // enable pointer events for the markers with custom content
256
+ if ( gmpClickable && marker ?. content && isElementNode ( marker . content ) ) {
257
+ marker . content . style . pointerEvents = 'none' ;
258
+
259
+ if ( marker . content . firstElementChild ) {
260
+ ( marker . content . firstElementChild as HTMLElement ) . style . pointerEvents =
261
+ 'all' ;
262
+ }
263
+ }
264
+ } , [ marker , clickable , onClick , onMouseEnter , onMouseLeave ] ) ;
245
265
246
266
useMapsEventListener ( marker , 'click' , onClick ) ;
247
267
useMapsEventListener ( marker , 'drag' , onDrag ) ;
0 commit comments