diff --git a/dataforge-vis-common/build.gradle.kts b/dataforge-vis-common/build.gradle.kts index 465b03c2..11236809 100644 --- a/dataforge-vis-common/build.gradle.kts +++ b/dataforge-vis-common/build.gradle.kts @@ -6,6 +6,10 @@ val dataforgeVersion: String by rootProject.extra //val kvisionVersion: String by rootProject.extra("2.0.0-M1") kotlin { + js { + useCommonJs() + } + sourceSets { commonMain { dependencies { diff --git a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/AbstractVisualObject.kt b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/AbstractVisualObject.kt index e355fa94..259a5e3a 100644 --- a/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/AbstractVisualObject.kt +++ b/dataforge-vis-common/src/commonMain/kotlin/hep/dataforge/vis/AbstractVisualObject.kt @@ -1,9 +1,11 @@ package hep.dataforge.vis import hep.dataforge.meta.* +import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.names.Name import hep.dataforge.names.asName import hep.dataforge.values.Value +import hep.dataforge.values.ValueType import hep.dataforge.vis.VisualObject.Companion.STYLE_KEY import kotlinx.serialization.Transient @@ -19,15 +21,15 @@ abstract class AbstractVisualObject : VisualObject { protected abstract var properties: Config? - override var styles: List + final override var styles: List get() = properties?.get(STYLE_KEY).stringList set(value) { - //val allStyles = (field + value).distinct() setProperty(STYLE_KEY, Value.of(value)) updateStyles(value) } protected fun updateStyles(names: List) { + styleCache = null names.mapNotNull { findStyle(it) }.asSequence() .flatMap { it.items.asSequence() } .distinctBy { it.key } @@ -77,7 +79,7 @@ abstract class AbstractVisualObject : VisualObject { /** * All available properties in a layered form */ - override fun allProperties(): Laminate = Laminate(properties, mergedStyles) + override fun allProperties(): Laminate = Laminate(properties, mergedStyles, parent?.allProperties()) override fun getProperty(name: Name, inherit: Boolean): MetaItem<*>? { return if (inherit) { @@ -86,6 +88,16 @@ abstract class AbstractVisualObject : VisualObject { properties?.get(name) ?: mergedStyles[name] } } + + companion object { + val descriptor = NodeDescriptor { + defineValue(STYLE_KEY){ + type(ValueType.STRING) + multiple = true + } + } + + } } //fun VisualObject.findStyle(styleName: Name): Meta? { 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 5f543dbe..0138393c 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,11 +1,28 @@ package hep.dataforge.js -import react.RBuilder +import react.* import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty +class RFBuilder : RBuilder() -fun RBuilder.initState(init: () -> T): ReadWriteProperty = +/** + * Get functional component from [func] + */ +fun

component( + func: RFBuilder.(props: P) -> Unit +): FunctionalComponent

{ + return { props: P -> + val nodes = RFBuilder().apply { func(props) }.childList + when (nodes.size) { + 0 -> null + 1 -> nodes.first() + else -> createElement(Fragment, kotlinext.js.js {}, *nodes.toTypedArray()) + } + } +} + +fun RFBuilder.initState(init: () -> T): ReadWriteProperty = object : ReadWriteProperty { val pair = react.useState(init) override fun getValue(thisRef: Any?, property: KProperty<*>): T { @@ -17,3 +34,5 @@ fun RBuilder.initState(init: () -> T): ReadWriteProperty = } } +fun RFBuilder.memoize(vararg deps: dynamic, builder: () -> T): T = useMemo(builder, deps) + diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ConfigEditorComponent.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ConfigEditorComponent.kt index 42c57a26..1a985f40 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ConfigEditorComponent.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ConfigEditorComponent.kt @@ -1,6 +1,9 @@ package hep.dataforge.vis.editor +import hep.dataforge.js.RFBuilder +import hep.dataforge.js.component import hep.dataforge.js.initState +import hep.dataforge.js.memoize import hep.dataforge.meta.* import hep.dataforge.meta.descriptors.* import hep.dataforge.names.Name @@ -37,11 +40,12 @@ interface ConfigEditorProps : RProps { var descriptor: NodeDescriptor? } -private fun RBuilder.configEditorItem(props: ConfigEditorProps) { +private fun RFBuilder.configEditorItem(props: ConfigEditorProps) { var expanded: Boolean by initState { true } - val item = props.root[props.name] - val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name) - val defaultItem = props.default?.get(props.name) + val item = memoize(props.root, props.name) { props.root[props.name] } + val descriptorItem: ItemDescriptor? = memoize(props.descriptor, props.name) { props.descriptor?.get(props.name) } + val defaultItem = memoize(props.default, props.name) { props.default?.get(props.name) } + val actualItem: MetaItem? = item ?: defaultItem ?: descriptorItem?.defaultItem() val token = props.name.last()?.toString() ?: "Properties" @@ -60,8 +64,6 @@ private fun RBuilder.configEditorItem(props: ConfigEditorProps) { return@useEffectWithCleanup { props.root.removeListener(this) } } - val actualItem: MetaItem? = item ?: defaultItem ?: descriptorItem?.defaultItem() - val expanderClick: (Event) -> Unit = { expanded = !expanded } @@ -162,7 +164,7 @@ private fun RBuilder.configEditorItem(props: ConfigEditorProps) { } } -val ConfigEditor: FunctionalComponent = functionalComponent { configEditorItem(it) } +val ConfigEditor: FunctionalComponent = component { configEditorItem(it) } fun RBuilder.configEditor( config: Config, 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 bae57a29..54891cc0 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,8 @@ package hep.dataforge.vis.editor +import hep.dataforge.js.RFBuilder import hep.dataforge.js.card +import hep.dataforge.js.component import hep.dataforge.js.initState import hep.dataforge.names.Name import hep.dataforge.names.plus @@ -26,7 +28,7 @@ interface TreeState : RState { var expanded: Boolean } -private fun RBuilder.objectTree(props: ObjectTreeProps): Unit { +private fun RFBuilder.objectTree(props: ObjectTreeProps): Unit { var expanded: Boolean by initState{ props.selected?.startsWith(props.name) ?: false } val onClick: (Event) -> Unit = { @@ -90,7 +92,7 @@ private fun RBuilder.objectTree(props: ObjectTreeProps): Unit { } } -val ObjectTree: FunctionalComponent = functionalComponent { props -> +val ObjectTree: FunctionalComponent = component { props -> objectTree(props) } diff --git a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ValueChooser.kt b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ValueChooser.kt index a74da773..642c7ee4 100644 --- a/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ValueChooser.kt +++ b/dataforge-vis-common/src/jsMain/kotlin/hep/dataforge/vis/editor/ValueChooser.kt @@ -1,5 +1,6 @@ package hep.dataforge.vis.editor +import hep.dataforge.js.component import hep.dataforge.meta.descriptors.ValueDescriptor import hep.dataforge.meta.get import hep.dataforge.meta.string @@ -11,11 +12,11 @@ import org.w3c.dom.HTMLInputElement import org.w3c.dom.HTMLSelectElement import org.w3c.dom.events.Event import react.RProps +import react.RState import react.dom.div import react.dom.input import react.dom.option import react.dom.select -import react.functionalComponent interface ValueChooserProps : RProps { var value: Value @@ -23,7 +24,35 @@ interface ValueChooserProps : RProps { var valueChanged: (Value?) -> Unit } -val ValueChooser = functionalComponent { props -> +interface ValueChooserState : RState { + var value: Value +} + +//class TextValueChooser(props: ValueChooserProps) : RComponent(props) { +// +// override fun ValueChooserState.init(props: ValueChooserProps) { +// this.value = props.value +// } +// +// val valueChanged: (Event) -> Unit = { +// val res = (it.target as HTMLInputElement).value.asValue() +// setState { +// this.value = res +// } +// props.valueChanged(res) +// } +// +// override fun RBuilder.render() { +// input(type = InputType.text, classes = "float-right") { +// attrs { +// this.value = state.value.string +// onChangeFunction = valueChanged +// } +// } +// } +//} + +val ValueChooser = component { props -> // var state by initState {props.value } val descriptor = props.descriptor diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt index b60f8d42..557d728d 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/Proxy.kt @@ -79,7 +79,8 @@ class Proxy private constructor( ?: error("Prototype with name $name not found in $this") } - override fun allProperties(): Laminate = Laminate(properties, mergedStyles, prototype.allProperties()) + override fun allProperties(): Laminate = + Laminate(properties, mergedStyles, prototype.allProperties(), parent?.allProperties()) override fun attachChildren() { //do nothing @@ -135,7 +136,8 @@ class Proxy private constructor( //do nothing } - override fun allProperties(): Laminate = Laminate(properties, mergedStyles, prototype.allProperties()) + override fun allProperties(): Laminate = + Laminate(properties, mergedStyles, prototype.allProperties(), parent?.allProperties()) } diff --git a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt index ebcb165c..1a4c5360 100644 --- a/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt +++ b/dataforge-vis-spatial/src/commonMain/kotlin/hep/dataforge/vis/spatial/VisualObject3D.kt @@ -70,6 +70,12 @@ interface VisualObject3D : VisualObject { defineItem(Material3D.MATERIAL_KEY.toString(), Material3D.descriptor) + //TODO replace by descriptor merge + defineValue(VisualObject.STYLE_KEY){ + type(ValueType.STRING) + multiple = true + } + // Material3D.MATERIAL_COLOR_KEY put "#ffffff" // Material3D.MATERIAL_OPACITY_KEY put 1.0 // Material3D.MATERIAL_WIREFRAME_KEY put false diff --git a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt index 5b77d1db..87f3f124 100644 --- a/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt +++ b/demo/muon-monitor/src/jsMain/kotlin/ru/mipt/npm/muon/monitor/MMAppComponent.kt @@ -2,6 +2,7 @@ package ru.mipt.npm.muon.monitor import hep.dataforge.context.Context import hep.dataforge.js.card +import hep.dataforge.js.component import hep.dataforge.js.initState import hep.dataforge.names.Name import hep.dataforge.names.NameToken @@ -21,7 +22,6 @@ import kotlinx.coroutines.launch import kotlinx.html.js.onClickFunction import react.RProps import react.dom.* -import react.functionalComponent import kotlin.math.PI interface MMAppProps : RProps { @@ -39,7 +39,7 @@ private val canvasConfig = Canvas { } } -val MMApp = functionalComponent { props -> +val MMApp = component { props -> var selected by initState { props.selected } var canvas: ThreeCanvas? by initState { null }