Add mutableCollectionState and docs.

This commit is contained in:
2022-01-16 14:50:58 +01:00
parent ebb8e9a3c5
commit 0b12c37558
7 changed files with 226 additions and 11 deletions

View File

@@ -6,7 +6,7 @@ plugins {
}
group = "nl.astraeus"
version = "1.0.0"
version = "1.0.1-SNAPSHOT"
repositories {
mavenCentral()

136
docs/getting-started.md Normal file
View File

@@ -0,0 +1,136 @@
# Table of contents
[home](home.md)
[getting started](getting-started.md)
# Getting started
To get started create a new kotlin project in intellij of the type 'Browser application'
![Create 'Browser Application' project](/docs/img/create-project.png "Create 'Browser Application' project")
Add the 'sourceSets' block with the kotlin-komponent dependency so your build.gradle.kts looks like this:
```gradle
plugins {
kotlin("js") version "1.6.10"
}
group = "com.test"
version = "1.0.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
api("nl.astraeus:kotlin-komponent-js:1.0.0")
testImplementation(kotlin("test"))
}
kotlin {
js(IR) {
binaries.executable()
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
}
}
}
```
Refresh the gradle project to import the dependency.
There is now only one kt file in the project called Simple.kt, it should look like this:
```kotin
fun main() {
console.log("Hello, ${greet()}")
}
fun greet() = "world"
```
Replace the code in the file with the following for a simple click app:
```koltin
import kotlinx.browser.document
import kotlinx.html.button
import kotlinx.html.div
import kotlinx.html.hr
import kotlinx.html.js.onClickFunction
import nl.astraeus.komp.HtmlBuilder
import nl.astraeus.komp.Komponent
import nl.astraeus.komp.mutableCollectionState
import nl.astraeus.komp.state
import kotlin.js.Date
fun main() {
console.log("Hello, ${greet()}")
Komponent.create(document.body!!, TestKomponent())
}
fun greet() = "world"
class TestKomponent : Komponent() {
var clicks: Int = 0
val lines: MutableCollection<String> = mutableListOf()
override fun HtmlBuilder.render() {
div {
div {
+"Hello Komponent!"
}
div {
+"Clicks $clicks"
}
div {
button {
+"Click"
onClickFunction = {
clicks++
lines.add("click $clicks at ${Date()}")
requestUpdate()
}
}
}
hr()
for (line in lines) {
div {
+ line
}
}
}
}
}
```
First in the main we add our TestKomponent to the document body with the following line:
```kotlin
Komponent.create(document.body!!, TestKomponent())
```
The TestKomponent.render method will be called to render our Komponent.
As you can see events can be attached inline with the on<event>Function methods.
The requestUpdate method will call the render method again and update the page accordingly.
If you like you can use some helpers that will automatically call the requestUpdate method if
the data changes, that would look like this:
```kotlin
var clicks: Int by state(0)
val lines: MutableCollection<String> = mutableCollectionState(mutableListOf())
```
In that case you can remove the requestUpdate call from the onClickFunction.
You can find a working repository of this example here: [example]()

4
docs/home.md Normal file
View File

@@ -0,0 +1,4 @@
# Table of contents
[home](home.md)
[getting started](getting-started.md)

BIN
docs/img/create project.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View File

@@ -0,0 +1,54 @@
package nl.astraeus.komp
inline fun <reified T> Komponent.mutableCollectionState(
initialValue: MutableCollection<T>
): MutableCollection<T> = MutableCollectionStateDelegate(
this,
initialValue
)
class MutableCollectionStateDelegate<T>(
val komponent: Komponent,
val collection: MutableCollection<T>
): MutableCollection<T> by collection {
override fun add(element: T): Boolean {
komponent.requestUpdate()
return collection.add(element)
}
override fun addAll(elements: Collection<T>): Boolean {
komponent.requestUpdate()
return collection.addAll(elements)
}
override fun clear() {
komponent.requestUpdate()
collection.clear()
}
// todo: return iterator wrapper to update at changes?
// override fun iterator(): MutableIterator<T> = collection.iterator()
override fun remove(element: T): Boolean {
komponent.requestUpdate()
return collection.remove(element)
}
override fun removeAll(elements: Collection<T>): Boolean {
komponent.requestUpdate()
return collection.removeAll(elements)
}
override fun retainAll(elements: Collection<T>): Boolean {
komponent.requestUpdate()
return collection.retainAll(elements)
}
}

View File

@@ -2,20 +2,41 @@ package nl.astraeus.komp
import kotlin.reflect.KProperty
class StateDelegate<T>(
val komponent: Komponent,
initialValue: T
) {
var value: T = initialValue
interface Delegate<T> {
operator fun getValue(
thisRef: Any?,
property: KProperty<*>
): T
operator fun setValue(
thisRef: Any?,
property: KProperty<*>,
value: T
)
}
open class StateDelegate<T>(
val komponent: Komponent,
initialValue: T
) : Delegate<T> {
private var value: T = initialValue
init {
if (value is MutableCollection<*>) {
error("Use mutableList to create a collection!")
}
}
override operator fun getValue(
thisRef: Any?,
property: KProperty<*>
): T {
return value
}
operator fun setValue(
override operator fun setValue(
thisRef: Any?,
property: KProperty<*>,
value: T
@@ -29,7 +50,7 @@ class StateDelegate<T>(
inline fun <reified T> Komponent.state(
initialValue: T
): StateDelegate<T> = StateDelegate(
this,
initialValue
)
): Delegate<T> = StateDelegate(
this,
initialValue
)