From 28ca287ccd2d323852038b3e36f3fc47ba2e6f87 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 18 Apr 2020 17:51:26 +0300 Subject: [PATCH] Refactor ObjectTree to functional component --- .../jsMain/kotlin/hep/dataforge/js/react.kt | 10 +- .../hep/dataforge/vis/editor/ObjectTree.kt | 95 +++++++++---------- 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/react.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/react.kt index c817012d..3b04817b 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/react.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/js/react.kt @@ -1,17 +1,17 @@ package hep.dataforge.js -import react.RComponent +import react.RBuilder import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty -fun RComponent<*, *>.initState(init: () -> T): ReadWriteProperty, T> = - object : ReadWriteProperty, T> { +fun RBuilder.initState(init: () -> T): ReadWriteProperty = + object : ReadWriteProperty { val pair = react.useState(init) - override fun getValue(thisRef: RComponent<*, *>, property: KProperty<*>): T { + override fun getValue(thisRef: Any?, property: KProperty<*>): T { return pair.first } - override fun setValue(thisRef: RComponent<*, *>, property: KProperty<*>, value: T) { + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { pair.second(value) } } diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ObjectTree.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ObjectTree.kt index a419b78d..6582957f 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ObjectTree.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ObjectTree.kt @@ -1,6 +1,7 @@ package hep.dataforge.vis.editor import hep.dataforge.js.card +import hep.dataforge.js.initState import hep.dataforge.names.Name import hep.dataforge.names.plus import hep.dataforge.names.startsWith @@ -25,20 +26,14 @@ interface TreeState : RState { var expanded: Boolean } -class ObjectTree : RComponent() { +private fun RBuilder.objectTree(props: ObjectTreeProps): Unit { + var expanded: Boolean by initState{ props.selected?.startsWith(props.name) ?: false } - override fun TreeState.init(props: ObjectTreeProps) { - expanded = props.selected?.startsWith(props.name) ?: false + val onClick: (Event) -> Unit = { + expanded = !expanded } - - private val onClick: (Event) -> Unit = { - setState { - expanded = !expanded - } - } - - private fun RBuilder.treeLabel(text: String) { + fun RBuilder.treeLabel(text: String) { button(classes = "btn btn-link tree-label p-0") { +text attrs { @@ -50,59 +45,61 @@ class ObjectTree : RComponent() { } } - override fun RBuilder.render() { - val token = props.name.last()?.toString() ?: "World" - val obj = props.obj + val token = props.name.last()?.toString() ?: "World" + val obj = props.obj - //display as node if any child is visible - if (obj is VisualGroup) { - div("d-inline-block text-truncate") { - if (obj.children.any { !it.key.body.startsWith("@") }) { - span("tree-caret") { - attrs { - if (state.expanded) { - classes += "tree-caret-down" - } - onClickFunction = onClick + //display as node if any child is visible + if (obj is VisualGroup) { + div("d-inline-block text-truncate") { + if (obj.children.any { !it.key.body.startsWith("@") }) { + span("tree-caret") { + attrs { + if (expanded) { + classes += "tree-caret-down" } + onClickFunction = onClick } } - treeLabel(token) } - if (state.expanded) { - ul("tree") { - obj.children.entries - .filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children - .sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true } - .forEach { (childToken, child) -> - li("tree-item") { - child(ObjectTree::class) { - attrs { - name = props.name + childToken - this.obj = child - this.selected = props.selected - clickCallback = props.clickCallback - } + treeLabel(token) + } + if (expanded) { + ul("tree") { + obj.children.entries + .filter { !it.key.toString().startsWith("@") } // ignore statics and other hidden children + .sortedBy { (it.value as? VisualGroup)?.isEmpty ?: true } + .forEach { (childToken, child) -> + li("tree-item") { + child(ObjectTree) { + attrs { + name = props.name + childToken + 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 = functionalComponent { props -> + objectTree(props) +} + fun Element.renderObjectTree( visualObject: VisualObject, clickCallback: (Name) -> Unit = {} -) = render(this){ +) = render(this) { card("Object tree") { - child(ObjectTree::class) { + child(ObjectTree) { attrs { this.name = Name.EMPTY this.obj = visualObject @@ -117,8 +114,8 @@ fun RBuilder.objectTree( visualObject: VisualObject, selected: Name? = null, clickCallback: (Name) -> Unit = {} -){ - child(ObjectTree::class) { +) { + child(ObjectTree) { attrs { this.name = Name.EMPTY this.obj = visualObject