Search code examples
reactjskotlinkotlin-js-interopkotlin-frontendcreate-react-kotlin-app

What is the right way to import 3rd party React components into the kotlin.js project?


I'm trying to use this lib in my create-react-kotlin-app:

https://material-ui-next.com/

I want to generate bunch of type safe wrappers. I started like this:

@file:JsModule("material-ui")

package material

import react.RState
import react.React
import react.ReactElement

external class Typography : React.Component<dynamic, RState> {
    override fun render(): ReactElement
}

...

fun RBuilder.typography(
    classes: String = "",
    variant: Variant = Variant.body1,
    align: Align = Align.inherit,
    color: Color = Color.default,
    gutterBottom: Boolean = false,
    noWrap: Boolean = false,
    paragraph: Boolean = false,
    handler: RHandler<dynamic>
) = child(Typography::class) {
    attrs {
        this.className = classes
        this.align = align.name
        this.color = color.name
        this.variant = variant.name
        this.gutterBottom = gutterBottom
        this.noWrap = noWrap
        this.paragraph = paragraph
    }
    handler()
}

And use it like:

typography(variant = Variant.title, color = Color.inherit) {
    +"Hello World"
}

Is it correct approach?


Solution

  • Indeed that is the correct way but can make it to be the best as follows

    MaterialUi.kt

    @file:JsModule("material-ui")
    
    package material
    
    import react.RState
    import react.RProps
    import react.React
    import react.ReactElement
    
    external interface TypographyProps : RProps {
        var className: String
        var align : String
        var color : String
        var variant : String
        var gutterBottom : String
        var noWrap : String
        var paragraph : String
    }
    
    @JsName("Typography")
    external class Typography : RComponent<TypographyProps, RState> {
        override fun render(): ReactElement
    }
    

    And then create another file, say

    MaterialUiDsl.kt

    fun RBuilder.typography(
        classes: String = "",
        variant: Variant = Variant.body1,
        align: Align = Align.inherit,
        color: Color = Color.default,
        gutterBottom: Boolean = false,
        noWrap: Boolean = false,
        paragraph: Boolean = false,
        handler: RHandler<TypographyProps> // notice the change here
    ) = child(Typography::class) {
        attrs {
            this.className = classes
            this.align = align.name
            this.color = color.name
            this.variant = variant.name
            this.gutterBottom = gutterBottom
            this.noWrap = noWrap
            this.paragraph = paragraph
        }
        handler()
    }
    

    If the above file already seems verbose to you (Like how I often feel), you can change it to just

    MaterialUiDsl.kt

    fun RBuilder.typography(handler: RHandler<dynamic>) = child(Typography::class,handler)
    

    The you can use it whenever like this

    typography {
        attr {
            className = "my-typo"
            color = "#ff00ff"
            //. . .
        }
    }
    

    Easy peasy