how can I use something like <http://recharts.org/...
# react
c
how can I use something like http://recharts.org/ with kotlin/js? all the demos on their site seem to use jsx
r
c
does that mean its possible to have generic react component support without generating wrappers for each react component?
kvision looks great but i want to keep it simple while i learn the javascript parts of kotlin. and kvision seems to do a lot of things in the gradle build that i did not really understand
r
I understand. But you will probably end up having those things in your build files after all :-)
Unfortunately with KVision you need to generate some wrappers as well. But you get easy start with many other things :-)
This is working code, which I've just created to use Recharts component with KVision (I've never used this library before):
Copy code
package com.example

import pl.treksoft.kvision.Application
import pl.treksoft.kvision.panel.root
import pl.treksoft.kvision.react.react
import pl.treksoft.kvision.require
import pl.treksoft.kvision.startApplication
import pl.treksoft.kvision.utils.obj
import react.RClass
import react.RProps

external interface RechartsProps : RProps {
    var width: Number
    var height: Number
    var data: Array<dynamic>
}

external interface DataKeyProps : RProps {
    var dataKey: String
}

val LineChart: RClass<RechartsProps> = require("recharts").LineChart
val Legend: RClass<RProps> = require("recharts").Legend
val Line: RClass<DataKeyProps> = require("recharts").Line
val XAxis: RClass<DataKeyProps> = require("recharts").XAxis
val YAxis: RClass<RProps> = require("recharts").YAxis

class App : Application() {

    override fun start() {
        val data = arrayOf(obj {
            name = "Page A"
            uv = 4000
            pv = 2400
        }, obj {
            name = "Page B"
            uv = 3000
            pv = 1398
        }, obj {
            name = "Page C"
            uv = 2000
            pv = 9800
        }, obj {
            name = "Page D"
            uv = 2780
            pv = 3908
        })
        root("kvapp") {
            react {
                LineChart {
                    attrs.width = 400
                    attrs.height = 300
                    attrs.data = data
                    Line {
                        attrs.dataKey = "uv"
                    }
                    Line {
                        attrs.dataKey = "pv"
                    }
                    XAxis {
                        attrs.dataKey = "name"
                    }
                    YAxis {}
                    Legend {}
                }
            }
        }
    }
}

fun main() {
    startApplication(::App)
}
I hope it will help.
c
cool
kvision kotlin api really looks great, but the gradle build is a bit scary. I don’t understand anything below that line: https://github.com/rjaros/kvision-examples/blob/master/template/build.gradle.kts#L117
i.e. why do i need a grunt file, why do i need a potfile, why is po converted to json
r
these tasks do only two things 1. add internationalization support with gettext library 2. manage some resources (css and js files) which are distributed in jar's with kvision artifacts (unfortunately currently kotlin plugin does not support such features, so it has to be done manually)
c
ok so for development it should work without?
r
if you do not need i18n you could safely drop generateGruntfile and generatePotFile tasks and the first part of the processResources task
c
ok thanks i will try that then.
r
but you need to keep those tasks with
Copy code
include("css/**")
                                include("img/**")
                                include("js/**")
fragments to get the resources copied in the right places
c
ok the copy task from line 193
what is
$buildDir/tmp/expandedArchives/
? what task expands to that location?
r
I have not tried without all those things 😉 you will probably just miss some more or less important css for different kvision components
kotlin plugin expands downloaded jar artifacts into this directory
this task finds all directories with
kvision-
prefix and copies css, img and js files into directory where DCE and webpack can find them
it's so complicated, because resources processing with DCE and webpack is currently hard to understand 😉
it's perhaps easy to create apps where all your resources are in one directory
but when you want some externals, its a mess
it's changing from version to version, so this build configuration changes also from time to time
c
are all the files in webpack.config.d necessary?
if i add `
Copy code
implementation("pl.treksoft:kvision-react:$kvisionVersion")
to the kvision template project i can no longer import the gradle file and the error message is cryptic:
Copy code
Warning:<i><b>root project 'template': Unable to build Kotlin project configuration</b>
Details: org.gradle.internal.operations.BuildOperationQueueFailure: There was a failure while populating the build operation queue:                 Process 'Resolving NPM dependencies using yarn' returns 1
                
                yarn install v1.21.1
[1/4] Resolving packages...
info Visit <https://yarnpkg.com/en/docs/cli/install> for documentation about this command.

Caused by: java.lang.IllegalStateException:                 Process 'Resolving NPM dependencies using yarn' returns 1
                
                yarn install v1.21.1
[1/4] Resolving packages...
info Visit <https://yarnpkg.com/en/docs/cli/install> for documentation about this command.
</i>
r
have you made other changes or just this dependency?
It works for me without problems
but what do you exactly mean by "import the gradle file" ? Import where?
c
idea
r
so you mean just opening the project in idea?
c
i have the project open in idea, when i add the react dependency and click on the gradle reload icon i get the error, when i delete it again and click on reload it works
this is my diff from the template project:
Copy code
sourceSets["main"].dependencies {
+        val kotlinWrappersVersion = "-pre.107-kotlin-1.3.72"
+        val reactVersion = "16.13.1"
+        implementation("org.jetbrains:kotlin-react:$reactVersion$kotlinWrappersVersion")
+        implementation("org.jetbrains:kotlin-react-dom:$reactVersion$kotlinWrappersVersion")
+
         implementation(kotlin("stdlib-js"))
         implementation(npm("po2json"))
         implementation(npm("grunt"))
@@ -97,6 +102,9 @@ kotlin {
         implementation("pl.treksoft:kvision-pace:$kvisionVersion")
         implementation("pl.treksoft:kvision-moment:$kvisionVersion")
         implementation("pl.treksoft:kvision-toast:$kvisionVersion")
+//        implementation("pl.treksoft:kvision-react:$kvisionVersion")
+
+
     }
i don’t know what task idea runs and i don’t know how to get a better error message
r
the lines with kotlin wrappers are doing this
it's unnecessery
c
now i got a better error message:
Copy code
error Couldn't find any versions for "kotlinx-html-js" that matches "0.7.1"
r
kotlin-react libs are already available when you add kvision-react module
so just remove it and add only kvision-react dependency
c
ok. i thought i read in the docs that kvision react support needs the wrappers
it works now, thanks!
theres a lot of great ideas in your demo code and in kvision, for example just defining require as external, or the
obj
helper method
if i wanted to set nested attributes on the LineChart, how would that work? for example setting the dot color
<Line dataKey="value" dot={{ stroke: 'red', strokeWidth: 2 }} />
r
you should change the interface
instead of
DataKeyProps
create a new one, with additional
dot: dynamic
property.
you can call it
LineProps
and declare
Line
as
RClass<LineProps>
after that you will be able to set
attrs.dot
inside
Line { }
I've created
DataKeyProps
in my example code for simplicity - you will probably need dedicated interface for every react component.
c
ah thanks
can i also use a type instead of dynamic?
i have declared it as dot and created
Copy code
external interface Dot  {
    var stroke: String
    var strokeWidth: Number
}
but now i have to set it like this:
Copy code
Line {
                    attrs.dot = obj {
                    }
                    attrs.dot.stroke = "#8884d8"
                    attrs.dataKey = "uv"
                }
r
You can't use external interfaces this way in Kotlin/JS. The fact you declare an external interface doesn't really help you create an instance of such interface in Kotlin. You still need to create a dynamic object (using obj {} or something similar).
But you can of course create a helper function or method, that will do all this things. And than use this function in your code many times.
Or the other way - declare some normal kotlin types (data classes) with some extension functions to convert kotlin data classes to JS external objects. Like this: https://github.com/rjaros/kvision/blob/c2716ef0aae16553655cab4ea24f685e49e5fee8/kvision-modules/kvision-tabulator/src/main/kotlin/pl/treksoft/kvision/tabulator/Options.kt#L260
c
would be cool to have something like your
obj
method, but with generics
Copy code
inline fun <T> iobj(init: T.() -> Unit): dynamic
r
it's very simple to implement it:
Copy code
inline fun <T> iobj(init: T.() -> Unit): T {
    val o = js("{}")
    (o as T).init()
    return o
}
Now you can do:
Copy code
val dot = iobj<Dot> {
                stroke = "5"
                strokeWidth = 5
            }
in fact it would be nice addon to KVision 🙂 and it can be named
obj
without conflict
c
🙂
that was much easier than i thought.