Clean up, release v. 1.0.0
This commit is contained in:
@@ -68,6 +68,7 @@ val javadocJar by tasks.registering(Jar::class) {
|
|||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
repositories {
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
maven {
|
maven {
|
||||||
name = "releases"
|
name = "releases"
|
||||||
// change to point to your repo, e.g. http://my.org/repo
|
// change to point to your repo, e.g. http://my.org/repo
|
||||||
|
|||||||
154
src/jsMain/kotlin/nl/astraeus/komp/ElementExtentions.kt
Normal file
154
src/jsMain/kotlin/nl/astraeus/komp/ElementExtentions.kt
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
package nl.astraeus.komp
|
||||||
|
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
import org.w3c.dom.HTMLInputElement
|
||||||
|
import org.w3c.dom.events.Event
|
||||||
|
import org.w3c.dom.get
|
||||||
|
|
||||||
|
private fun Int.asSpaces(): String {
|
||||||
|
val result = StringBuilder()
|
||||||
|
|
||||||
|
repeat(this) {
|
||||||
|
result.append(" ")
|
||||||
|
}
|
||||||
|
return result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.printTree(indent: Int = 0): String {
|
||||||
|
val result = StringBuilder()
|
||||||
|
|
||||||
|
result.append(indent.asSpaces())
|
||||||
|
result.append(tagName)
|
||||||
|
if (this.namespaceURI != "http://www.w3.org/1999/xhtml") {
|
||||||
|
result.append(" [")
|
||||||
|
result.append(namespaceURI)
|
||||||
|
result.append("]")
|
||||||
|
}
|
||||||
|
result.append(" (")
|
||||||
|
var first = true
|
||||||
|
if (hasAttributes()) {
|
||||||
|
for (index in 0 until attributes.length) {
|
||||||
|
if (!first) {
|
||||||
|
result.append(", ")
|
||||||
|
} else {
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
result.append(attributes[index]?.localName)
|
||||||
|
result.append("=")
|
||||||
|
result.append(attributes[index]?.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.append(") {")
|
||||||
|
result.append("\n")
|
||||||
|
for ((name, event) in getKompEvents()) {
|
||||||
|
result.append(indent.asSpaces())
|
||||||
|
result.append("on")
|
||||||
|
result.append(name)
|
||||||
|
result.append(" -> ")
|
||||||
|
result.append(event)
|
||||||
|
result.append("\n")
|
||||||
|
}
|
||||||
|
for (index in 0 until childNodes.length) {
|
||||||
|
childNodes[index]?.let {
|
||||||
|
if (it is Element) {
|
||||||
|
result.append(it.printTree(indent + 2))
|
||||||
|
} else {
|
||||||
|
result.append((indent + 2).asSpaces())
|
||||||
|
result.append(it.textContent)
|
||||||
|
result.append("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.append(indent.asSpaces())
|
||||||
|
result.append("}\n")
|
||||||
|
|
||||||
|
return result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Element.clearKompAttributes() {
|
||||||
|
val attributes = this.asDynamic()["komp-attributes"] as MutableSet<String>?
|
||||||
|
|
||||||
|
if (attributes == null) {
|
||||||
|
this.asDynamic()["komp-attributes"] = mutableSetOf<String>()
|
||||||
|
} else {
|
||||||
|
attributes.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this is HTMLInputElement) {
|
||||||
|
this.checked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Element.getKompAttributes(): MutableSet<String> {
|
||||||
|
var result: MutableSet<String>? = this.asDynamic()["komp-attributes"] as MutableSet<String>?
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
result = mutableSetOf()
|
||||||
|
|
||||||
|
this.asDynamic()["komp-attributes"] = result
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Element.setKompAttribute(name: String, value: String) {
|
||||||
|
val setAttrs: MutableSet<String> = getKompAttributes()
|
||||||
|
setAttrs.add(name)
|
||||||
|
|
||||||
|
if (this is HTMLInputElement) {
|
||||||
|
when (name) {
|
||||||
|
"checked" -> {
|
||||||
|
this.checked = value == "checked"
|
||||||
|
}
|
||||||
|
"value" -> {
|
||||||
|
this.value = value
|
||||||
|
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
setAttribute(name, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (this.getAttribute(name) != value) {
|
||||||
|
setAttribute(name, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Element.clearKompEvents() {
|
||||||
|
for ((name, event) in getKompEvents()) {
|
||||||
|
removeEventListener(name, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
val events = this.asDynamic()["komp-events"] as MutableMap<String, (Event) -> Unit>?
|
||||||
|
|
||||||
|
if (events == null) {
|
||||||
|
this.asDynamic()["komp-events"] = mutableMapOf<String, (Event) -> Unit>()
|
||||||
|
} else {
|
||||||
|
events.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Element.setKompEvent(name: String, event: (Event) -> Unit) {
|
||||||
|
val eventName: String = if (name.startsWith("on")) {
|
||||||
|
name.substring(2)
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
|
||||||
|
val events: MutableMap<String, (Event) -> Unit> = getKompEvents()
|
||||||
|
|
||||||
|
events[eventName]?.let {
|
||||||
|
println("Warn event '$eventName' already defined!")
|
||||||
|
removeEventListener(eventName, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
events[eventName] = event
|
||||||
|
|
||||||
|
this.asDynamic()["komp-events"] = events
|
||||||
|
|
||||||
|
this.addEventListener(eventName, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Element.getKompEvents(): MutableMap<String, (Event) -> Unit> {
|
||||||
|
return this.asDynamic()["komp-events"] ?: mutableMapOf()
|
||||||
|
}
|
||||||
|
|
||||||
@@ -24,155 +24,9 @@ interface HtmlConsumer : TagConsumer<Element> {
|
|||||||
fun debug(block: HtmlConsumer.() -> Unit)
|
fun debug(block: HtmlConsumer.() -> Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Int.asSpaces(): String {
|
|
||||||
val result = StringBuilder()
|
|
||||||
repeat(this) {
|
|
||||||
result.append(" ")
|
|
||||||
}
|
|
||||||
return result.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun FlowOrMetaDataOrPhrasingContent.currentElement(): Element =
|
fun FlowOrMetaDataOrPhrasingContent.currentElement(): Element =
|
||||||
currentElement ?: error("No current element defined!")
|
currentElement ?: error("No current element defined!")
|
||||||
|
|
||||||
fun Element.printTree(indent: Int = 0): String {
|
|
||||||
val result = StringBuilder()
|
|
||||||
|
|
||||||
result.append(indent.asSpaces())
|
|
||||||
result.append(tagName)
|
|
||||||
if (this.namespaceURI != "http://www.w3.org/1999/xhtml") {
|
|
||||||
result.append(" [")
|
|
||||||
result.append(namespaceURI)
|
|
||||||
result.append("]")
|
|
||||||
}
|
|
||||||
result.append(" (")
|
|
||||||
var first = true
|
|
||||||
if (hasAttributes()) {
|
|
||||||
for (index in 0 until attributes.length) {
|
|
||||||
if (!first) {
|
|
||||||
result.append(", ")
|
|
||||||
} else {
|
|
||||||
first = false
|
|
||||||
}
|
|
||||||
result.append(attributes[index]?.localName)
|
|
||||||
result.append("=")
|
|
||||||
result.append(attributes[index]?.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.append(") {")
|
|
||||||
result.append("\n")
|
|
||||||
for ((name, event) in getKompEvents()) {
|
|
||||||
result.append(indent.asSpaces())
|
|
||||||
result.append("on")
|
|
||||||
result.append(name)
|
|
||||||
result.append(" -> ")
|
|
||||||
result.append(event)
|
|
||||||
result.append("\n")
|
|
||||||
}
|
|
||||||
for (index in 0 until childNodes.length) {
|
|
||||||
childNodes[index]?.let {
|
|
||||||
if (it is Element) {
|
|
||||||
result.append(it.printTree(indent + 2))
|
|
||||||
} else {
|
|
||||||
result.append((indent + 2).asSpaces())
|
|
||||||
result.append(it.textContent)
|
|
||||||
result.append("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.append(indent.asSpaces())
|
|
||||||
result.append("}\n")
|
|
||||||
|
|
||||||
return result.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Element.clearKompAttributes() {
|
|
||||||
val attributes = this.asDynamic()["komp-attributes"] as MutableSet<String>?
|
|
||||||
|
|
||||||
if (attributes == null) {
|
|
||||||
this.asDynamic()["komp-attributes"] = mutableSetOf<String>()
|
|
||||||
} else {
|
|
||||||
attributes.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this is HTMLInputElement) {
|
|
||||||
this.checked = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Element.getKompAttributes(): MutableSet<String> {
|
|
||||||
var result: MutableSet<String>? = this.asDynamic()["komp-attributes"] as MutableSet<String>?
|
|
||||||
|
|
||||||
if (result == null) {
|
|
||||||
result = mutableSetOf()
|
|
||||||
|
|
||||||
this.asDynamic()["komp-attributes"] = result
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Element.setKompAttribute(name: String, value: String) {
|
|
||||||
val setAttrs: MutableSet<String> = getKompAttributes()
|
|
||||||
setAttrs.add(name)
|
|
||||||
|
|
||||||
if (this is HTMLInputElement) {
|
|
||||||
when (name) {
|
|
||||||
"checked" -> {
|
|
||||||
this.checked = value == "checked"
|
|
||||||
}
|
|
||||||
"value" -> {
|
|
||||||
this.value = value
|
|
||||||
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
setAttribute(name, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (this.getAttribute(name) != value) {
|
|
||||||
setAttribute(name, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Element.clearKompEvents() {
|
|
||||||
for ((name, event) in getKompEvents()) {
|
|
||||||
currentElement?.removeEventListener(name, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
val events = this.asDynamic()["komp-events"] as MutableMap<String, (Event) -> Unit>?
|
|
||||||
|
|
||||||
if (events == null) {
|
|
||||||
this.asDynamic()["komp-events"] = mutableMapOf<String, (Event) -> Unit>()
|
|
||||||
} else {
|
|
||||||
events.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Element.setKompEvent(name: String, event: (Event) -> Unit) {
|
|
||||||
val eventName: String = if (name.startsWith("on")) {
|
|
||||||
name.substring(2)
|
|
||||||
} else {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
|
|
||||||
val events: MutableMap<String, (Event) -> Unit> = getKompEvents()
|
|
||||||
|
|
||||||
events[eventName]?.let {
|
|
||||||
println("Warn event already defined!")
|
|
||||||
currentElement?.removeEventListener(eventName, it)
|
|
||||||
}
|
|
||||||
|
|
||||||
events[eventName] = event
|
|
||||||
|
|
||||||
this.asDynamic()["komp-events"] = events
|
|
||||||
|
|
||||||
this.addEventListener(eventName, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Element.getKompEvents(): MutableMap<String, (Event) -> Unit> {
|
|
||||||
return this.asDynamic()["komp-events"] ?: mutableMapOf()
|
|
||||||
}
|
|
||||||
|
|
||||||
private data class ElementIndex(
|
private data class ElementIndex(
|
||||||
val parent: Node,
|
val parent: Node,
|
||||||
var childIndex: Int
|
var childIndex: Int
|
||||||
@@ -219,14 +73,13 @@ private fun ArrayList<ElementIndex>.replace(new: Node) {
|
|||||||
private fun Node.asElement() = this as? HTMLElement
|
private fun Node.asElement() = this as? HTMLElement
|
||||||
|
|
||||||
class HtmlBuilder(
|
class HtmlBuilder(
|
||||||
val parent: Element,
|
parent: Element,
|
||||||
var childIndex: Int = 0
|
childIndex: Int = 0
|
||||||
) : HtmlConsumer {
|
) : HtmlConsumer {
|
||||||
private var currentPosition = arrayListOf<ElementIndex>()
|
private var currentPosition = arrayListOf<ElementIndex>()
|
||||||
private var inDebug = false
|
private var inDebug = false
|
||||||
var currentNode: Node? = null
|
var currentNode: Node? = null
|
||||||
var root: Element? = null
|
var root: Element? = null
|
||||||
val currentAttributes: MutableMap<String, String> = mutableMapOf()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
currentPosition.add(ElementIndex(parent, childIndex))
|
currentPosition.add(ElementIndex(parent, childIndex))
|
||||||
@@ -256,16 +109,19 @@ class HtmlBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun debug(block: HtmlConsumer.() -> Unit) {
|
override fun debug(block: HtmlConsumer.() -> Unit) {
|
||||||
|
val enableAssertions = Komponent.enableAssertions
|
||||||
|
Komponent.enableAssertions = true
|
||||||
inDebug = true
|
inDebug = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
block.invoke(this)
|
block.invoke(this)
|
||||||
} finally {
|
} finally {
|
||||||
inDebug = false
|
inDebug = false
|
||||||
|
Komponent.enableAssertions = enableAssertions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun logReplace(msg: String) {
|
private fun logReplace(msg: String) {
|
||||||
if (Komponent.logReplaceEvent && inDebug) {
|
if (Komponent.logReplaceEvent && inDebug) {
|
||||||
console.log(msg)
|
console.log(msg)
|
||||||
}
|
}
|
||||||
@@ -347,7 +203,9 @@ class HtmlBuilder(
|
|||||||
override fun onTagAttributeChange(tag: Tag, attribute: String, value: String?) {
|
override fun onTagAttributeChange(tag: Tag, attribute: String, value: String?) {
|
||||||
logReplace("onTagAttributeChange, ${tag.tagName} [$attribute, $value]")
|
logReplace("onTagAttributeChange, ${tag.tagName} [$attribute, $value]")
|
||||||
|
|
||||||
checkTag(tag)
|
if (Komponent.enableAssertions) {
|
||||||
|
checkTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
currentElement?.removeAttribute(attribute.lowercase())
|
currentElement?.removeAttribute(attribute.lowercase())
|
||||||
@@ -357,9 +215,11 @@ class HtmlBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onTagEvent(tag: Tag, event: String, value: (Event) -> Unit) {
|
override fun onTagEvent(tag: Tag, event: String, value: (Event) -> Unit) {
|
||||||
//logReplace"onTagEvent, ${tag.tagName} [$event, $value]")
|
logReplace("onTagEvent, ${tag.tagName} [$event, $value]")
|
||||||
|
|
||||||
checkTag(tag)
|
if (Komponent.enableAssertions) {
|
||||||
|
checkTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
currentElement?.setKompEvent(event.lowercase(), value)
|
currentElement?.setKompEvent(event.lowercase(), value)
|
||||||
}
|
}
|
||||||
@@ -371,7 +231,9 @@ class HtmlBuilder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkTag(tag)
|
if (Komponent.enableAssertions) {
|
||||||
|
checkTag(tag)
|
||||||
|
}
|
||||||
|
|
||||||
currentPosition.pop()
|
currentPosition.pop()
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,15 @@
|
|||||||
package nl.astraeus.komp
|
package nl.astraeus.komp
|
||||||
|
|
||||||
import kotlinx.browser.window
|
import kotlinx.browser.window
|
||||||
|
import kotlinx.html.FlowOrMetaDataOrPhrasingContent
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
import org.w3c.dom.Node
|
|
||||||
import org.w3c.dom.get
|
import org.w3c.dom.get
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
class StateDelegate<T>(
|
private var currentKomponent: Komponent? = null
|
||||||
val komponent: Komponent,
|
fun FlowOrMetaDataOrPhrasingContent.currentKomponent(): Komponent =
|
||||||
initialValue: T
|
currentKomponent ?: error("No current komponent defined! Only call from render code!")
|
||||||
) {
|
|
||||||
var value: T = initialValue
|
|
||||||
|
|
||||||
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
|
||||||
if (this.value?.equals(value) != true) {
|
|
||||||
this.value = value
|
|
||||||
komponent.requestUpdate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified T> Komponent.state(initialValue: T): StateDelegate<T> = StateDelegate(this, initialValue)
|
|
||||||
|
|
||||||
enum class UnsafeMode {
|
enum class UnsafeMode {
|
||||||
UNSAFE_ALLOWED,
|
UNSAFE_ALLOWED,
|
||||||
@@ -33,12 +17,23 @@ enum class UnsafeMode {
|
|||||||
UNSAFE_SVG_ONLY
|
UNSAFE_SVG_ONLY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var Element.memoizeHash: String?
|
||||||
|
get() {
|
||||||
|
return getAttribute("memoize-hash")
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
if (value != null) {
|
||||||
|
setAttribute("memoize-hash", value.toString())
|
||||||
|
} else {
|
||||||
|
removeAttribute("memoize-hash")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class Komponent {
|
abstract class Komponent {
|
||||||
val createIndex = getNextCreateIndex()
|
val createIndex = getNextCreateIndex()
|
||||||
private var dirty: Boolean = true
|
private var dirty: Boolean = true
|
||||||
private var lastMemoizeHash: Int? = null
|
|
||||||
|
|
||||||
var element: Node? = null
|
var element: Element? = null
|
||||||
|
|
||||||
open fun create(parent: Element, childIndex: Int? = null) {
|
open fun create(parent: Element, childIndex: Int? = null) {
|
||||||
onBeforeUpdate()
|
onBeforeUpdate()
|
||||||
@@ -47,13 +42,30 @@ abstract class Komponent {
|
|||||||
childIndex ?: parent.childNodes.length
|
childIndex ?: parent.childNodes.length
|
||||||
)
|
)
|
||||||
|
|
||||||
|
currentKomponent = this
|
||||||
builder.render()
|
builder.render()
|
||||||
|
currentKomponent = null
|
||||||
|
|
||||||
element = builder.root
|
element = builder.root
|
||||||
lastMemoizeHash = generateMemoizeHash()
|
updateMemoizeHash()
|
||||||
onAfterUpdate()
|
onAfterUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun memoizeChanged() = lastMemoizeHash == null || lastMemoizeHash != generateMemoizeHash()
|
fun memoizeChanged() = element?.memoizeHash == null || element?.memoizeHash != fullMemoizeHash()
|
||||||
|
|
||||||
|
fun updateMemoizeHash() {
|
||||||
|
element?.memoizeHash = fullMemoizeHash()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fullMemoizeHash(): String? {
|
||||||
|
val generated = generateMemoizeHash()
|
||||||
|
|
||||||
|
return if (generated != null) {
|
||||||
|
"${this::class.simpleName}:${generateMemoizeHash()}"
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract fun HtmlBuilder.render()
|
abstract fun HtmlBuilder.render()
|
||||||
|
|
||||||
@@ -121,7 +133,11 @@ abstract class Komponent {
|
|||||||
}
|
}
|
||||||
val consumer = HtmlBuilder(parent, childIndex)
|
val consumer = HtmlBuilder(parent, childIndex)
|
||||||
consumer.root = null
|
consumer.root = null
|
||||||
|
|
||||||
|
currentKomponent = this
|
||||||
consumer.render()
|
consumer.render()
|
||||||
|
currentKomponent = null
|
||||||
|
|
||||||
element = consumer.root
|
element = consumer.root
|
||||||
dirty = false
|
dirty = false
|
||||||
}
|
}
|
||||||
@@ -138,6 +154,7 @@ abstract class Komponent {
|
|||||||
|
|
||||||
var logRenderEvent = false
|
var logRenderEvent = false
|
||||||
var logReplaceEvent = false
|
var logReplaceEvent = false
|
||||||
|
var enableAssertions = false
|
||||||
var unsafeMode = UnsafeMode.UNSAFE_DISABLED
|
var unsafeMode = UnsafeMode.UNSAFE_DISABLED
|
||||||
|
|
||||||
fun create(parent: HTMLElement, component: Komponent) {
|
fun create(parent: HTMLElement, component: Komponent) {
|
||||||
@@ -183,10 +200,10 @@ abstract class Komponent {
|
|||||||
}
|
}
|
||||||
val memoizeHash = next.generateMemoizeHash()
|
val memoizeHash = next.generateMemoizeHash()
|
||||||
|
|
||||||
if (memoizeHash == null || next.lastMemoizeHash != memoizeHash) {
|
if (next.memoizeChanged()) {
|
||||||
next.onBeforeUpdate()
|
next.onBeforeUpdate()
|
||||||
next.update()
|
next.update()
|
||||||
next.lastMemoizeHash = memoizeHash
|
next.updateMemoizeHash()
|
||||||
next.onAfterUpdate()
|
next.onAfterUpdate()
|
||||||
} else if (logRenderEvent) {
|
} else if (logRenderEvent) {
|
||||||
console.log("Skipped render, memoizeHash is equal $next-[$memoizeHash]")
|
console.log("Skipped render, memoizeHash is equal $next-[$memoizeHash]")
|
||||||
|
|||||||
35
src/jsMain/kotlin/nl/astraeus/komp/State.kt
Normal file
35
src/jsMain/kotlin/nl/astraeus/komp/State.kt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package nl.astraeus.komp
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
class StateDelegate<T>(
|
||||||
|
val komponent: Komponent,
|
||||||
|
initialValue: T
|
||||||
|
) {
|
||||||
|
var value: T = initialValue
|
||||||
|
|
||||||
|
operator fun getValue(
|
||||||
|
thisRef: Any?,
|
||||||
|
property: KProperty<*>
|
||||||
|
): T {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun setValue(
|
||||||
|
thisRef: Any?,
|
||||||
|
property: KProperty<*>,
|
||||||
|
value: T
|
||||||
|
) {
|
||||||
|
if (this.value?.equals(value) != true) {
|
||||||
|
this.value = value
|
||||||
|
komponent.requestUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> Komponent.state(
|
||||||
|
initialValue: T
|
||||||
|
): StateDelegate<T> = StateDelegate(
|
||||||
|
this,
|
||||||
|
initialValue
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user