Refactor ObjectTree to functional component

This commit is contained in:
Alexander Nozik 2020-04-18 17:51:26 +03:00
parent ac86832616
commit 28ca287ccd
2 changed files with 51 additions and 54 deletions

View File

@ -1,17 +1,17 @@
package hep.dataforge.js package hep.dataforge.js
import react.RComponent import react.RBuilder
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
fun <T> RComponent<*, *>.initState(init: () -> T): ReadWriteProperty<RComponent<*, *>, T> = fun <T> RBuilder.initState(init: () -> T): ReadWriteProperty<Any?, T> =
object : ReadWriteProperty<RComponent<*, *>, T> { object : ReadWriteProperty<Any?, T> {
val pair = react.useState(init) val pair = react.useState(init)
override fun getValue(thisRef: RComponent<*, *>, property: KProperty<*>): T { override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return pair.first return pair.first
} }
override fun setValue(thisRef: RComponent<*, *>, property: KProperty<*>, value: T) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
pair.second(value) pair.second(value)
} }
} }

View File

@ -1,6 +1,7 @@
package hep.dataforge.vis.editor package hep.dataforge.vis.editor
import hep.dataforge.js.card import hep.dataforge.js.card
import hep.dataforge.js.initState
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.names.startsWith import hep.dataforge.names.startsWith
@ -25,20 +26,14 @@ interface TreeState : RState {
var expanded: Boolean var expanded: Boolean
} }
class ObjectTree : RComponent<ObjectTreeProps, TreeState>() { private fun RBuilder.objectTree(props: ObjectTreeProps): Unit {
var expanded: Boolean by initState{ props.selected?.startsWith(props.name) ?: false }
override fun TreeState.init(props: ObjectTreeProps) { val onClick: (Event) -> Unit = {
expanded = props.selected?.startsWith(props.name) ?: false expanded = !expanded
} }
fun RBuilder.treeLabel(text: String) {
private val onClick: (Event) -> Unit = {
setState {
expanded = !expanded
}
}
private fun RBuilder.treeLabel(text: String) {
button(classes = "btn btn-link tree-label p-0") { button(classes = "btn btn-link tree-label p-0") {
+text +text
attrs { attrs {
@ -50,59 +45,61 @@ class ObjectTree : RComponent<ObjectTreeProps, TreeState>() {
} }
} }
override fun RBuilder.render() { val token = props.name.last()?.toString() ?: "World"
val token = props.name.last()?.toString() ?: "World" val obj = props.obj
val obj = props.obj
//display as node if any child is visible //display as node if any child is visible
if (obj is VisualGroup) { if (obj is VisualGroup) {
div("d-inline-block text-truncate") { div("d-inline-block text-truncate") {
if (obj.children.any { !it.key.body.startsWith("@") }) { if (obj.children.any { !it.key.body.startsWith("@") }) {
span("tree-caret") { span("tree-caret") {
attrs { attrs {
if (state.expanded) { if (expanded) {
classes += "tree-caret-down" classes += "tree-caret-down"
}
onClickFunction = onClick
} }
onClickFunction = onClick
} }
} }
treeLabel(token)
} }
if (state.expanded) { treeLabel(token)
ul("tree") { }
obj.children.entries if (expanded) {
.filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children ul("tree") {
.sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true } obj.children.entries
.forEach { (childToken, child) -> .filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children
li("tree-item") { .sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true }
child(ObjectTree::class) { .forEach { (childToken, child) ->
attrs { li("tree-item") {
name = props.name + childToken child(ObjectTree) {
this.obj = child attrs {
this.selected = props.selected name = props.name + childToken
clickCallback = props.clickCallback this.obj = child
} this.selected = props.selected
clickCallback = props.clickCallback
} }
} }
} }
} }
}
} else {
div("d-inline-block text-truncate") {
span("tree-leaf") {}
treeLabel(token)
} }
} }
} else {
div("d-inline-block text-truncate") {
span("tree-leaf") {}
treeLabel(token)
}
} }
} }
val ObjectTree: FunctionalComponent<ObjectTreeProps> = functionalComponent { props ->
objectTree(props)
}
fun Element.renderObjectTree( fun Element.renderObjectTree(
visualObject: VisualObject, visualObject: VisualObject,
clickCallback: (Name) -> Unit = {} clickCallback: (Name) -> Unit = {}
) = render(this){ ) = render(this) {
card("Object tree") { card("Object tree") {
child(ObjectTree::class) { child(ObjectTree) {
attrs { attrs {
this.name = Name.EMPTY this.name = Name.EMPTY
this.obj = visualObject this.obj = visualObject
@ -117,8 +114,8 @@ fun RBuilder.objectTree(
visualObject: VisualObject, visualObject: VisualObject,
selected: Name? = null, selected: Name? = null,
clickCallback: (Name) -> Unit = {} clickCallback: (Name) -> Unit = {}
){ ) {
child(ObjectTree::class) { child(ObjectTree) {
attrs { attrs {
this.name = Name.EMPTY this.name = Name.EMPTY
this.obj = visualObject this.obj = visualObject