elmish.View.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package elmish
import org.w3c.dom.Element
import org.w3c.dom.events.Event
import kotlinx.dom.addClass
import kotlinx.dom.appendElement
import kotlinx.dom.appendText
val empty = View.Empty
val h1 = ViewFactory("h1")
val h2 = ViewFactory("h2")
val div = ViewFactory("div")
val pre = ViewFactory("pre")
val code = ViewFactory("code")
val span = ViewFactory("span")
val small = ViewFactory("small")
val ol = ViewFactory("ol")
val ul = ViewFactory("ul")
val li = ViewFactory("li")
val a = ViewFactory("a")
fun render(view: View, into: Element, send: (I) -> Unit) {
into.innerHTML = ""
into.appendElementFor(view, send)
}
data class ViewFactory(val elementName: String) {
operator fun invoke(innerText: String): View =
View(elementName, innerText = innerText)
operator fun invoke(children: List>): View =
View(elementName, children = children)
operator fun invoke(vararg children: View): View =
View(elementName, children = children.asList())
operator fun invoke(
attributes: List>,
vararg children: View
): View = View(
elementName,
attributes = attributes,
children = children.asList()
)
operator fun invoke(
attributes: List>,
innerText: String
): View = View(
elementName,
attributes = attributes,
innerText = innerText
)
operator fun invoke(
innerText: String,
vararg children: View
): View = View(
elementName,
innerText = innerText,
children = children.asList()
)
}
/**
* A minimalist HTML data structure for type-safe composition of fragments.
*/
sealed class View {
fun map(f: (I) -> O): View =
MappedView(this, f)
companion object {
operator fun invoke(
elementName: String,
attributes: List> = emptyList(),
innerText: String? = null,
children: List> = emptyList()
): View = Element(
elementName,
attributes,
innerText,
children
)
}
object Empty : View()
data class Element(
val elementName: String,
val attributes: List> = emptyList(),
val innerText: String? = null,
val children: List> = emptyList()
) : View()
data class MappedView(
val view: View,
val mapping: (I) -> O
) : View()
}
fun attributes(builder: Attributes.() -> Unit): List> =
mutableListOf>().also { attributes ->
builder(Attributes { attributes.add(it) })
}
class Attributes(private val add: (Attribute) -> Unit) {
fun onClick(handler: EventHandler) = add(Attribute.OnEvent("click", handler))
fun className(value: String) = add(Attribute.ClassName(value))
fun title(value: String) = add(Attribute.Named("title", value))
fun href(value: String) = add(Attribute.Named("href", value))
fun src(value: String) = add(Attribute.Named("src", value))
}
typealias EventHandler = (Event) -> I
sealed class Attribute {
class OnEvent(
val eventName: String,
val handler: (Event) -> I
) : Attribute()
class ClassName(
val value: String
) : Attribute()
class Named(
val name: String,
val value: String
) : Attribute()
}
private
fun Element.appendElementFor(view: View, send: (I) -> Unit) {
when (view) {
is View.Element -> appendElement(view.elementName) {
view.innerText?.let(this::appendText)
view.children.forEach { child ->
appendElementFor(child, send)
}
view.attributes.forEach { a ->
when (a) {
is Attribute.OnEvent -> addEventListener(
a.eventName,
{ event ->
event.stopPropagation()
send(a.handler(event))
}
)
is Attribute.ClassName -> addClass(
a.value
)
is Attribute.Named -> setAttribute(
a.name,
a.value
)
}
}
}
is View.MappedView<*, *> -> {
@Suppress("unchecked_cast")
val mappedView = view as View.MappedView
appendElementFor(mappedView.view) {
send(mappedView.mapping(it))
}
}
View.Empty -> return
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy