Skip to content
This repository has been archived by the owner on Aug 10, 2024. It is now read-only.

Commit

Permalink
Changed Component class into ElementCreator typealias (#397)
Browse files Browse the repository at this point in the history
Co-authored-by: Ian Clarke <[email protected]>
  • Loading branch information
sigmadeltasoftware and sanity authored Nov 24, 2022
1 parent 99e9269 commit eb6dc0d
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 144 deletions.
9 changes: 0 additions & 9 deletions api/kweb-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1720,10 +1720,6 @@ public final class kweb/routing/RouteReceiver {
public final fun path (Ljava/lang/String;Lkotlin/jvm/functions/Function2;)V
}

public abstract interface class kweb/state/AdvancedComponent {
public abstract fun render (Lkweb/ElementCreator;)Ljava/lang/Object;
}

public final class kweb/state/CloseReason {
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Throwable;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
Expand All @@ -1738,10 +1734,6 @@ public final class kweb/state/CloseReason {
public fun toString ()Ljava/lang/String;
}

public abstract interface class kweb/state/Component : kweb/state/AdvancedComponent {
public abstract fun render (Lkweb/ElementCreator;)V
}

public class kweb/state/KVal : java/lang/AutoCloseable {
public fun <init> (Ljava/lang/Object;)V
public final fun addListener (Lkotlin/jvm/functions/Function2;)J
Expand Down Expand Up @@ -1861,7 +1853,6 @@ public final class kweb/state/RenderHandle {

public final class kweb/state/RenderKt {
public static final fun closeOnElementCreatorCleanup (Lkweb/ElementCreator;Lkweb/state/KVal;)V
public static final fun render (Lkweb/ElementCreator;Lkweb/state/AdvancedComponent;)Ljava/lang/Object;
public static final fun render (Lkweb/ElementCreator;Lkweb/state/KVal;Lkotlin/jvm/functions/Function2;)Lkweb/state/RenderFragment;
}

Expand Down
40 changes: 3 additions & 37 deletions src/main/kotlin/kweb/state/render.kt
Original file line number Diff line number Diff line change
Expand Up @@ -125,44 +125,10 @@ fun ElementCreator<*>.closeOnElementCreatorCleanup(kv: KVal<*>) {
}

/**
* Render the value of a [KVar] into DOM elements, and automatically re-render those
* elements whenever the value changes.
*/
fun <PARENT_ELEMENT_TYPE : Element, RETURN_TYPE> ElementCreator<PARENT_ELEMENT_TYPE>.render(
component: AdvancedComponent<PARENT_ELEMENT_TYPE, RETURN_TYPE>
) : RETURN_TYPE {
return component.render(this)
}

// ANCHOR: component_definition
/**
* [AdvancedComponent]s can be rendered into DOM elements by calling [AdvancedComponent.render].
*
* Unlike [Component], [AdvancedComponent]s allows the parent element type to be configured, and a return
* type to be specified.
*/
interface AdvancedComponent<in PARENT_ELEMENT_TYPE : Element, out RETURN_TYPE> {

/**
* Render this [Component] into DOM elements, returning an arbitrary
* value of type [RETURN_TYPE].
*/
fun render(elementCreator: ElementCreator<PARENT_ELEMENT_TYPE>) : RETURN_TYPE
}
// ANCHOR_END: component_definition

/**
* [Component]s can be rendered into DOM elements by calling [Component.render].
*
* For more flexibility, see [AdvancedComponent].
* Typealias for [ElementCreator] to simply create and manage components using an
* extension function
*/
interface Component : AdvancedComponent<Element, Unit> {

/**
* Render this [Component] into DOM elements
*/
override fun render(elementCreator: ElementCreator<Element>)
}
typealias Component = ElementCreator<*>

class RenderFragment(val startId: String, val endId: String) {
private val deletionListeners = ArrayList<() -> Unit>()
Expand Down
183 changes: 85 additions & 98 deletions src/test/kotlin/kweb/docs/components.kt
Original file line number Diff line number Diff line change
@@ -1,135 +1,122 @@
package kweb.docs

import kweb.ElementCreator
import kweb.*
import kweb.InputType.text
import kweb.docs.BulmaInput.BulmaColor
import kweb.docs.BulmaInput.BulmaColor.SUCCESS
import kweb.docs.BulmaInput.BulmaColor.WARNING
import kweb.state.*
import kweb.util.json

// ANCHOR: simple_component
class SimpleComponent(
val prompt: String = "Enter Your Name",
val name: KVar<String>
) : Component {
override fun render(elementCreator: ElementCreator<Element>) {
with(elementCreator) {
div {
h1().text(prompt)
input(type = text).value = name
}
div {
span().text(name.map { "Hello, $it" })
}
}
fun Component.simple(
prompt: String = "Enter Your Name",
name: KVar<String>
) {
div {
h1().text(prompt)
input(type = text).value = name
}
div {
span().text(name.map { "Hello, $it" })
}
}
// ANCHOR_END: simple_component

fun simple_component() {
// ANCHOR: component_usage
Kweb(port = 16097) {
doc.body {
render(SimpleComponent(name = kvar("World")))
Kweb(port = 16097) {
doc.body {
simple(name = kvar("World"))
}
}
}
// ANCHOR_END: component_usage
}


// ANCHOR: bulma_component_example
class BulmaInput(
val type : InputType,
val color: KVal<BulmaColor>? = null,
val size: KVal<BulmaSize>? = null,
val style: KVal<BulmaStyle>? = null,
val state: KVal<BulmaState>? = null,
val disabled: KVal<Boolean>? = null,
val value: KVar<String>
) : Component {

override fun render(elementCreator: ElementCreator<*>) {
with(elementCreator) {
input(type = type) { inputElement ->
var inputClassList: KVal<List<String>> = kval(listOf("input"))
with(inputElement) {

if (color != null) {
inputClassList += color.map { listOf(it.cssClassName) }
}
if (size != null) {
inputClassList += size.map { listOf(it.cssClassName) }
}
if (this@BulmaInput.style != null) {
inputClassList += this@BulmaInput.style.map { listOf(it.cssClassName) }
}
if (state != null) {
inputClassList += state.map { listOf(it.cssClassName) }
}

if (disabled != null) {
this["disabled"] = disabled.map { it.json }
}

classes(inputClassList.map { it.joinToString(" ") })

this.value = this@BulmaInput.value

}
enum class BulmaColor(val cssClassName: String) {
PRIMARY("is-primary"),
LINK("is-link"),
INFO("is-info"),
SUCCESS("is-success"),
WARNING("is-warning"),
DANGER("is-danger")
}

enum class BulmaSize(val cssClassName: String) {
SMALL("is-small"),
NORMAL("is-normal"),
MEDIUM("is-medium"),
LARGE("is-large")
}

enum class BulmaStyle(val cssClassName: String) {
ROUNDED("is-rounded"),
FOCUSED("is-focused")
}

enum class BulmaState(val cssClassName: String) {
NORMAL("is-normal"),
HOVER("is-hovered"),
FOCUS("is-focused"),
LOADING("is-loading"),
}

fun Component.bulmaInput(
type: InputType,
color: KVal<BulmaColor>? = null,
size: KVal<BulmaSize>? = null,
style: KVal<BulmaStyle>? = null,
state: KVal<BulmaState>? = null,
disabled: KVal<Boolean>? = null,
value: KVar<String>
) {
input(type = type) { inputElement ->
var inputClassList: KVal<List<String>> = kval(listOf("input"))
with(inputElement) {

if (color != null) {
inputClassList += color.map { listOf(it.cssClassName) }
}
if (size != null) {
inputClassList += size.map { listOf(it.cssClassName) }
}
if (style != null) {
inputClassList += style.map { listOf(it.cssClassName) }
}
if (state != null) {
inputClassList += state.map { listOf(it.cssClassName) }
}
}
}

enum class BulmaColor(val cssClassName: String) {
PRIMARY("is-primary"),
LINK("is-link"),
INFO("is-info"),
SUCCESS("is-success"),
WARNING("is-warning"),
DANGER("is-danger")
}
if (disabled != null) {
this["disabled"] = disabled.map { it.json }
}

enum class BulmaSize(val cssClassName: String) {
SMALL("is-small"),
NORMAL("is-normal"),
MEDIUM("is-medium"),
LARGE("is-large")
}
classes(inputClassList.map { it.joinToString(" ") })

enum class BulmaStyle(val cssClassName: String) {
ROUNDED("is-rounded"),
FOCUSED("is-focused")
}
this.value = value

enum class BulmaState(val cssClassName: String) {
NORMAL("is-normal"),
HOVER("is-hovered"),
FOCUS("is-focused"),
LOADING("is-loading"),
}
}
}
// ANCHOR_END: bulma_component_example

fun bulmaComponentUsageExample() {
// ANCHOR: bulma_component_usage
Kweb(port = 12354) {
doc.head {
element("link",
attributes = mapOf(
"rel" to "stylesheet".json,
"href" to "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css".json
Kweb(port = 12354) {
doc.head {
element(
"link",
attributes = mapOf(
"rel" to "stylesheet".json,
"href" to "https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css".json
)
)
)
}
}

doc.body {
val username = kvar("")
val color = username.map { if (it.length < 5) { WARNING } else { SUCCESS }
doc.body {
val username = kvar("")
val color = username.map { if (it.length < 5) BulmaColor.WARNING else BulmaColor.SUCCESS }
bulmaInput(type = text, value = username, color = color)
}
render(BulmaInput(type = text, value = username, color = color))
}
}
// ANCHOR_END: bulma_component_usage
}

0 comments on commit eb6dc0d

Please sign in to comment.