2

I'm trying to use google-maps-react component as part of a Kotlin JS project but running in to some issues with how the way it's used maps to Kotlin. I have following google-maps-react.kt file so far:

@file:JsModule("google-maps-react")

package org.example.kotlin.multiplatform.web


import react.*


@JsName("Map")
external val Map: RClass<RProps>


@JsName("GoogleApiWrapper")
external val GoogleApiWrapper: RClass<RProps>

If I try to use Map I'm getting following error. Has anyone tried this or knows of any sample code that does this? I understand that I need to set api key at least (using GoogleApiWrapper) but seems like more general issue with how "google" object is set (google={this.props.google} is what I see used in pure javascript usage of this)

Uncaught Error: You must include a google prop

John O'Reilly
  • 10,000
  • 4
  • 41
  • 63

1 Answers1

0

I have two files defined as follows

//googlemap.kt

@file:JsModule("@react-google-maps/api")

package tz.co.asoft.ui.react.maps.google

import react.Component
import react.RProps
import react.RState

external interface LatLng {
    var lat: Double
    var lng: Double
}

external class GoogleMap : Component<GoogleMap.Props, RState> {
    interface Props : RProps {
        var id: String
        var center: LatLng
        var zoom: Int
        var mapContainerStyle: dynamic
    }

    override fun render(): dynamic
}

external class Marker : Component<Marker.Props, RState> {
    interface Props : RProps {
        var position: LatLng
    }

    override fun render(): dynamic
}

external class InfoWindow : Component<InfoWindow.Props, RState> {
    interface Props : RProps {
        var position: LatLng
    }

    override fun render(): dynamic
}

external class LoadScript : Component<LoadScript.Props, RState> {
    interface Props : RProps {
        var id: String
        var googleMapsApiKey: String
    }

    override fun render(): dynamic
}

external class Polyline : Component<Polyline.Props, RState> {
    interface Props : RProps {
        var path: Array<LatLng>
        var options: Options
        var onLoad: (polyline:dynamic)->Unit
    }

    interface Options {
        var strokeColor: String
        var strokeOpacity: Double
        var strokeWeight: Int
        var fillColor: String
        var fillOpacity: Double
        var clickable: Boolean
        var draggable: Boolean
        var editable: Boolean
        var visible: Boolean
        var radius: Int
        var paths: Array<LatLng>
        var zIndex: Int
    }

    override fun render(): dynamic
}

I also have a file for making its dsl easy to use

//dsl.kt

package tz.co.asoft.ui.react.maps.google

import kotlinext.js.js
import kotlinext.js.jsObject
import react.RBuilder
import react.RHandler

private fun RBuilder.loadScript(handler: RHandler<LoadScript.Props> = {}) = child(LoadScript::class) {
    attrs {
        id = "google-maps-script"
        googleMapsApiKey = "<your api key>"
    }
    handler()
}

private fun RBuilder.googleMap(handler: RHandler<GoogleMap.Props> = {}) = child(GoogleMap::class) {
    attrs {
        center = jsObject { lat = 0.0; lng = 0.0 }
        zoom = 13
        mapContainerStyle = js {
            height = "90%"
            width = "100%"
        }
    }
    handler()
}

fun RBuilder.polyLine(paths: Array<LatLng>, handler: RHandler<Polyline.Props> = {}) = child(Polyline::class) {
    attrs {
        options = jsObject {
            strokeColor = "#FF0000"
            strokeOpacity = 0.8
            strokeWeight = 2
            fillColor = "#FF0000"
            fillOpacity = 0.35
            clickable = false
            draggable = false
            editable = false
            visible = true
            radius = 30000
            zIndex = 1
        }
        options.paths = paths
    }
    attrs.path = paths
    handler()
}

fun RBuilder.marker(handler: RHandler<Marker.Props> = {}) = child(Marker::class) {
    attrs { position = jsObject { lat = 0.0; lng = 0.0 } }
    handler()
}

fun RBuilder.infoWindow(handler: RHandler<InfoWindow.Props> = {}) = child(InfoWindow::class) {
    attrs { position = jsObject { lat = 0.0; lng = 0.0 } }
    handler()
}

fun RBuilder.map(handler: RHandler<GoogleMap.Props> = {}) = loadScript {
    googleMap {
        handler()
    }
}

fun Array<Double>.toLatLng() = jsObject<LatLng> {
    lat = get(0)
    lng = get(1)
}

Now I can use the lib in my react project as

div{
    map {
        marker {
            attrs { position = jsObject { lat = 0.0; lng = 0.0 } }
        }
    }
}

Hope this helps

andylamax
  • 1,858
  • 1
  • 14
  • 31
  • Even if I add ```@file:JsModule("@react-google-maps/api") @file:JsNonModule``` I get: `When accessing module declarations from UMD, they must be marked by both @JsModule and @JsNonModule`. Any idea? – Michel Jung Feb 22 '21 at 21:01