aboutsummaryrefslogtreecommitdiff

KVision

Object oriented Web UI framework for Kotlin/JS.

KVision allows you to build user interface of modern web applications with the Kotlin language. It's designed to be object oriented in the "most classical" sense - it gives you a hierarchy of many different components, which are used to build application UI.

Unlike most of the popular web UI frameworks (AngularJS, React, Vue.js and others), KVision is not declarative - it is not designed to mix HTML code (or pseudo code) with a typical programming language like JavaScript. In KVision everything is just written in Kotlin, and your code can be reused not by creating any templates, but by using well known OOP design patterns - composition and inheritance.

This design is quite similar to many non-web UI programming libraries including Swing (Java), QT (C++) and WinForms (C#).

KVision is a new project in a development phase. Please create an issue for any bugs or feature requests.

Features

Getting started

Development

  1. Download KVision examples from GitHub:

    git clone https://github.com/rjaros/kvision-examples.git
    
  2. Enter one of the examples directory:

    cd kvision-examples/showcase                        (on Linux)
    cd kvision-examples\showcase                        (on Windows)
    
  3. Run Gradle incremental build with:

    ./gradlew -t run                                    (on Linux)
    gradlew.bat -t run                                  (on Windows)
    
  4. Open http://localhost:8088/ in your browser.

  5. Play with the code and see your changes immediately in the browser.

Production

To build complete application optimized for production run:

    ./gradlew -Pprod=true distZip                       (on Linux)
    gradlew.bat -Pprod=true distZip                     (on Windows)

Application package will be saved as build/distributions/showcase.zip.

Usage samples

Hello world

    val root = Root("root")
    val label = Label("Hello world!")
    root.add(label)

Basic components interactions

Simple, explicit way
    val root = Root("root")
    val panel = HPanel(spacing = 20, alignItems = FLEXALIGNITEMS.CENTER)
    val label = Label("Not yet clicked.")
    panel.add(label)
    var count = 0
    val button = Button("Click me")
    button.onClick {
        count++
        label.text = "You clicked the button $count times."
    }
    panel.add(button)
    root.add(panel)
Using Kotlin language features
    Root("root").add(
        HPanel(spacing = 20, alignItems = FLEXALIGNITEMS.CENTER).apply {
            val label = Label("Not yet clicked.").also { add(it) }
            var count = 0
            add(Button("Click me").onClick {
                label.text = "You clicked the button ${++count} times."
            })
        }
    )
Using type safe DSL builders
    Root("root") {
        hPanel(spacing = 20, alignItems = FLEXALIGNITEMS.CENTER) {
            val label = label("Not yet clicked.")
            var count = 0
            button("Click me") {
                onClick {
                    label.text = "You clicked the button ${++count} times."
                }
            }
        }
    }

Tab panel with JavaScript routing

    val firstPanel = Tag(TAG.DIV, "First")
    val secondPanel = Tag(TAG.DIV, "Second")
    val thirdPanel = Tag(TAG.DIV, "Third")

    Root("root").add(TabPanel().apply {
        addTab("First", firstPanel, route = "/first")
        addTab("Second", secondPanel, route = "/second")
        addTab("Third", thirdPanel, route = "/third")
    })

Type safe forms

    data class Model(val username: String?, val password: String?)

    Root("root").add(FormPanel {
        Model(it.string("username"), it.string("password"))
    }.apply {
        add("username", Text(label = "Username"), required = true)
        add("password", Password(label = "Password"), required = true)
        add(Button("OK").onClick {
            val data: Data = this@apply.getData()
            println("Username: ${data.username}")
            println("Password: ${data.password}")
        })
    })

Data binding with observable data model

    class Data(text: String) : BaseDataComponent() {
        var text: String by obs(text)
    }
    val model = observableListOf(
        Data("One"),
        Data("Two"),
        Data("Three")
    )
    Root("root").add(DataContainer(model, { index ->
        Label(model[index].text)
    }, child = HPanel(spacing = 10, wrap = FLEXWRAP.WRAP)))

    launch { // Kotlin coroutines
        while (true) {
            delay(1000)
            model.reverse()
        }
    }

API documentation

Full API documentation is available at https://rjaros.github.io/kvision/api/.