@@ -163,6 +163,7 @@ var LitGoogleMap = (function (exports) {
163163 } ) ;
164164 this . updateMarkers ( ) ;
165165 this . updateShapes ( ) ;
166+ this . updateControls ( ) ;
166167 }
167168 getMapOptions ( ) {
168169 return {
@@ -257,6 +258,15 @@ var LitGoogleMap = (function (exports) {
257258 s . attachToMap ( this . map ) ;
258259 }
259260 }
261+ updateControls ( ) {
262+ const controlsSelector = this . shadowRoot . getElementById ( "controls-selector" ) ;
263+ if ( ! controlsSelector )
264+ return ;
265+ this . controls = controlsSelector . items ;
266+ for ( const c of this . controls ) {
267+ c . changeMap ( this . map ) ;
268+ }
269+ }
260270 fitToMarkersChanged ( retryAttempt = 0 ) {
261271 if ( this . map && this . fitToMarkers && this . markers . length > 0 ) {
262272 const latLngBounds = new google . maps . LatLngBounds ( ) ;
@@ -316,6 +326,13 @@ var LitGoogleMap = (function (exports) {
316326 >
317327 <slot id="shapes" name="shapes"></slot>
318328 </lit-selector>
329+ <lit-selector
330+ id="controls-selector"
331+ selected-attribute="open"
332+ activate-event="google-map-control-activate"
333+ >
334+ <slot id="controls" name="controls"></slot>
335+ </lit-selector>
319336 <div id="map"></div>
320337 ` ;
321338 }
@@ -471,6 +488,210 @@ var LitGoogleMap = (function (exports) {
471488 t ( "lit-google-map-circle" )
472489 ] , exports . LitGoogleMapCircle ) ;
473490
491+ exports . LitGoogleMapLocationButton = class LitGoogleMapLocationButton extends i {
492+ constructor ( ) {
493+ super ( ...arguments ) ;
494+ this . position = "RIGHT_BOTTOM" ;
495+ this . label = "My Location" ;
496+ this . disabled = false ;
497+ this . map = null ;
498+ this . controlDiv = null ;
499+ this . controlButton = null ;
500+ this . isRequesting = false ;
501+ }
502+ changeMap ( newMap ) {
503+ this . map = newMap ;
504+ this . mapChanged ( ) ;
505+ }
506+ mapChanged ( ) {
507+ if ( this . controlDiv && this . map ) {
508+ this . controlDiv = null ;
509+ this . controlButton = null ;
510+ }
511+ if ( this . map && this . map instanceof google . maps . Map ) {
512+ this . mapReady ( ) ;
513+ }
514+ }
515+ mapReady ( ) {
516+ this . controlDiv = this . createControlButton ( ) ;
517+ const controlPosition = google . maps . ControlPosition [ this . position ] ;
518+ if ( controlPosition !== undefined ) {
519+ this . map . controls [ controlPosition ] . push ( this . controlDiv ) ;
520+ }
521+ }
522+ createControlButton ( ) {
523+ const controlDiv = document . createElement ( "div" ) ;
524+ controlDiv . style . margin = "10px" ;
525+ const controlButton = document . createElement ( "button" ) ;
526+ controlButton . type = "button" ;
527+ controlButton . title = this . label ;
528+ controlButton . setAttribute ( "aria-label" , this . label ) ;
529+ controlButton . innerHTML = `
530+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18">
531+ <path fill="currentColor" d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm8.94 3A8.994 8.994 0 0 0 13 3.06V1h-2v2.06A8.994 8.994 0 0 0 3.06 11H1v2h2.06A8.994 8.994 0 0 0 11 20.94V23h2v-2.06A8.994 8.994 0 0 0 20.94 13H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/>
532+ </svg>
533+ ` ;
534+ Object . assign ( controlButton . style , {
535+ backgroundColor : "#fff" ,
536+ border : "0" ,
537+ borderRadius : "2px" ,
538+ boxShadow : "0 1px 4px rgba(0,0,0,0.3)" ,
539+ cursor : "pointer" ,
540+ padding : "10px" ,
541+ display : "flex" ,
542+ alignItems : "center" ,
543+ justifyContent : "center" ,
544+ width : "40px" ,
545+ height : "40px" ,
546+ color : "#666" ,
547+ } ) ;
548+ controlButton . addEventListener ( "mouseenter" , ( ) => {
549+ if ( ! this . disabled && ! this . isRequesting ) {
550+ controlButton . style . backgroundColor = "#f8f8f8" ;
551+ }
552+ } ) ;
553+ controlButton . addEventListener ( "mouseleave" , ( ) => {
554+ if ( ! this . disabled && ! this . isRequesting ) {
555+ controlButton . style . backgroundColor = "#fff" ;
556+ }
557+ } ) ;
558+ controlButton . addEventListener ( "click" , ( ) => {
559+ if ( ! this . disabled && ! this . isRequesting ) {
560+ this . handleLocationRequest ( ) ;
561+ }
562+ } ) ;
563+ this . controlButton = controlButton ;
564+ controlDiv . appendChild ( controlButton ) ;
565+ return controlDiv ;
566+ }
567+ async handleLocationRequest ( ) {
568+ if ( ! navigator . geolocation ) {
569+ this . dispatchEvent ( new CustomEvent ( "location-error" , {
570+ detail : {
571+ code : - 1 ,
572+ message : "Geolocation is not supported by your browser" ,
573+ } ,
574+ bubbles : true ,
575+ composed : true ,
576+ } ) ) ;
577+ return ;
578+ }
579+ this . isRequesting = true ;
580+ this . setLoadingState ( true ) ;
581+ this . dispatchEvent ( new CustomEvent ( "location-requested" , {
582+ bubbles : true ,
583+ composed : true ,
584+ } ) ) ;
585+ try {
586+ const position = await this . getCurrentPosition ( ) ;
587+ const lat = position . coords . latitude ;
588+ const lng = position . coords . longitude ;
589+ this . map . setCenter ( { lat, lng } ) ;
590+ this . map . setZoom ( 14 ) ;
591+ this . dispatchEvent ( new CustomEvent ( "location-found" , {
592+ detail : { lat, lng } ,
593+ bubbles : true ,
594+ composed : true ,
595+ } ) ) ;
596+ }
597+ catch ( error ) {
598+ let message = "Unable to retrieve your location" ;
599+ let code = - 1 ;
600+ if ( error instanceof GeolocationPositionError ) {
601+ code = error . code ;
602+ if ( error . code === error . PERMISSION_DENIED ) {
603+ message =
604+ "Location access denied. Please enable location permissions." ;
605+ }
606+ else if ( error . code === error . TIMEOUT ) {
607+ message = "Location request timed out. Please try again." ;
608+ }
609+ else if ( error . code === error . POSITION_UNAVAILABLE ) {
610+ message = "Location information is unavailable." ;
611+ }
612+ }
613+ this . dispatchEvent ( new CustomEvent ( "location-error" , {
614+ detail : { code, message } ,
615+ bubbles : true ,
616+ composed : true ,
617+ } ) ) ;
618+ }
619+ finally {
620+ this . isRequesting = false ;
621+ this . setLoadingState ( false ) ;
622+ }
623+ }
624+ getCurrentPosition ( ) {
625+ return new Promise ( ( resolve , reject ) => {
626+ navigator . geolocation . getCurrentPosition ( resolve , reject , {
627+ timeout : 10000 ,
628+ enableHighAccuracy : true ,
629+ } ) ;
630+ } ) ;
631+ }
632+ setLoadingState ( loading ) {
633+ if ( ! this . controlButton )
634+ return ;
635+ if ( loading ) {
636+ this . controlButton . style . backgroundColor = "#f0f0f0" ;
637+ this . controlButton . style . cursor = "wait" ;
638+ const svg = this . controlButton . querySelector ( "svg" ) ;
639+ if ( svg ) {
640+ svg . style . animation = "spin 1s linear infinite" ;
641+ const style = document . createElement ( "style" ) ;
642+ style . textContent = `
643+ @keyframes spin {
644+ from { transform: rotate(0deg); }
645+ to { transform: rotate(360deg); }
646+ }
647+ ` ;
648+ if ( ! document . querySelector ( "style[data-location-button-spin]" ) ) {
649+ style . setAttribute ( "data-location-button-spin" , "true" ) ;
650+ document . head . appendChild ( style ) ;
651+ }
652+ }
653+ }
654+ else {
655+ this . controlButton . style . backgroundColor = "#fff" ;
656+ this . controlButton . style . cursor = "pointer" ;
657+ const svg = this . controlButton . querySelector ( "svg" ) ;
658+ if ( svg ) {
659+ svg . style . animation = "" ;
660+ }
661+ }
662+ }
663+ attributeChangedCallback ( name , oldval , newval ) {
664+ super . attributeChangedCallback ( name , oldval , newval ) ;
665+ if ( name === "disabled" && this . controlButton ) {
666+ if ( this . disabled ) {
667+ this . controlButton . style . backgroundColor = "#f0f0f0" ;
668+ this . controlButton . style . cursor = "not-allowed" ;
669+ this . controlButton . style . opacity = "0.6" ;
670+ }
671+ else {
672+ this . controlButton . style . backgroundColor = "#fff" ;
673+ this . controlButton . style . cursor = "pointer" ;
674+ this . controlButton . style . opacity = "1" ;
675+ }
676+ }
677+ }
678+ } ;
679+ __decorate ( [
680+ n ( { type : String , reflect : true } ) ,
681+ __metadata ( "design:type" , Object )
682+ ] , exports . LitGoogleMapLocationButton . prototype , "position" , void 0 ) ;
683+ __decorate ( [
684+ n ( { type : String , reflect : true } ) ,
685+ __metadata ( "design:type" , Object )
686+ ] , exports . LitGoogleMapLocationButton . prototype , "label" , void 0 ) ;
687+ __decorate ( [
688+ n ( { type : Boolean , reflect : true } ) ,
689+ __metadata ( "design:type" , Object )
690+ ] , exports . LitGoogleMapLocationButton . prototype , "disabled" , void 0 ) ;
691+ exports . LitGoogleMapLocationButton = __decorate ( [
692+ t ( "lit-google-map-location-button" )
693+ ] , exports . LitGoogleMapLocationButton ) ;
694+
474695 exports . LitGoogleMapMarker = class LitGoogleMapMarker extends i {
475696 constructor ( ) {
476697 super ( ...arguments ) ;
0 commit comments