From aaad8365677118fb6e7e93eb839993d11c5731e5 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 30 Oct 2020 10:02:49 +0300 Subject: [PATCH] Refactor react ThreeCanvas to functional component --- .../vision/gdml/demo/GDMLAppComponent.kt | 26 ++-- .../mipt/npm/muon/monitor/MMAppComponent.kt | 21 ++-- playground/src/jsMain/kotlin/PlayGroundApp.kt | 21 +++- .../dataforge/vision/react/ConfigEditor.kt | 18 +-- .../hep/dataforge/vision/react/MetaViewer.kt | 14 +-- .../hep/dataforge/vision/react/ObjectTree.kt | 6 +- .../hep/dataforge/vision/react/TreeStyles.kt | 6 +- .../hep/dataforge/vision/react/layout.kt | 5 +- .../hep/dataforge/vision/react/react.kt | 24 ---- .../dataforge/vision/gdml/GdmlOptimizer.kt | 6 +- .../hep/dataforge/vision/gdml/gdmlJs.kt | 6 +- .../hep/dataforge/vision/gdml/gdmlJVM.kt | 2 +- .../vision/solid/three/ThreeCanvas.kt | 45 ++++--- .../solid/three/ThreeCanvasComponent.kt | 111 +++++++++++------- 14 files changed, 162 insertions(+), 149 deletions(-) delete mode 100644 ui/react/src/main/kotlin/hep/dataforge/vision/react/react.kt diff --git a/demo/gdml/src/jsMain/kotlin/hep/dataforge/vision/gdml/demo/GDMLAppComponent.kt b/demo/gdml/src/jsMain/kotlin/hep/dataforge/vision/gdml/demo/GDMLAppComponent.kt index 8624f141..f5704cb7 100644 --- a/demo/gdml/src/jsMain/kotlin/hep/dataforge/vision/gdml/demo/GDMLAppComponent.kt +++ b/demo/gdml/src/jsMain/kotlin/hep/dataforge/vision/gdml/demo/GDMLAppComponent.kt @@ -7,7 +7,6 @@ import hep.dataforge.vision.Vision import hep.dataforge.vision.VisionGroup import hep.dataforge.vision.bootstrap.* import hep.dataforge.vision.gdml.toVision -import hep.dataforge.vision.react.component import hep.dataforge.vision.react.objectTree import hep.dataforge.vision.solid.Solid import hep.dataforge.vision.solid.SolidGroup @@ -22,11 +21,8 @@ import kscience.gdml.GDML import kscience.gdml.decodeFromString import org.w3c.files.FileReader import org.w3c.files.get -import react.RProps +import react.* import react.dom.h1 -import react.getValue -import react.setValue -import react.useState import styled.css external interface GDMLAppProps : RProps { @@ -44,7 +40,7 @@ external interface GDMLAppProps : RProps { //} @JsExport -val GDMLApp = component { props -> +val GDMLApp = functionalComponent("GDMLApp") { props -> var selected by useState { props.selected } var canvas: ThreeCanvas? by useState { null } var vision: Vision? by useState { props.rootObject } @@ -113,16 +109,14 @@ val GDMLApp = component { props -> +"order-xl-2" } //canvas - (vision as? Solid)?.let { visual3D -> - child(ThreeCanvasComponent::class) { - attrs { - this.context = props.context - this.obj = visual3D - this.selected = selected - this.clickCallback = select - this.canvasCallback = { - canvas = it - } + child(ThreeCanvasComponent) { + attrs { + this.context = props.context + this.obj = vision as? Solid + this.selected = selected + this.clickCallback = select + this.canvasCallback = { + canvas = it } } } 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 d492b325..527c2b77 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 @@ -8,7 +8,6 @@ import hep.dataforge.names.length import hep.dataforge.vision.Vision import hep.dataforge.vision.bootstrap.canvasControls import hep.dataforge.vision.bootstrap.card -import hep.dataforge.vision.react.component import hep.dataforge.vision.react.configEditor import hep.dataforge.vision.react.objectTree import hep.dataforge.vision.solid.specifications.Camera @@ -20,11 +19,10 @@ import io.ktor.client.request.get import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.html.js.onClickFunction -import react.RProps +import react.* import react.dom.* -import react.getValue -import react.setValue -import react.useState +import styled.css +import styled.styledDiv import kotlin.math.PI external interface MMAppProps : RProps { @@ -43,8 +41,8 @@ private val canvasConfig = Canvas3DOptions { } @JsExport -val MMApp = component { props -> - var selected by useState { props.selected } +val MMApp = functionalComponent("Muon monitor") { props -> + var selected by useState { props.selected } var canvas: ThreeCanvas? by useState { null } val select: (Name?) -> Unit = { @@ -59,7 +57,12 @@ val MMApp = component { props -> } } div("row") { - div("col-lg-3 px-0 overflow-auto") { + styledDiv { + css { + +"col-lg-3" + +"px-0" + +"overflow-auto" + } //tree card("Object tree") { objectTree(root, selected, select) @@ -67,7 +70,7 @@ val MMApp = component { props -> } div("col-lg-6") { //canvas - child(ThreeCanvasComponent::class) { + child(ThreeCanvasComponent) { attrs { this.context = props.context this.obj = root diff --git a/playground/src/jsMain/kotlin/PlayGroundApp.kt b/playground/src/jsMain/kotlin/PlayGroundApp.kt index ea95c926..72196672 100644 --- a/playground/src/jsMain/kotlin/PlayGroundApp.kt +++ b/playground/src/jsMain/kotlin/PlayGroundApp.kt @@ -3,16 +3,25 @@ import hep.dataforge.js.Application import hep.dataforge.js.startApplication import hep.dataforge.vision.bootstrap.visionPropertyEditor import hep.dataforge.vision.react.objectTree -import hep.dataforge.vision.solid.Point3D -import hep.dataforge.vision.solid.SolidGroup -import hep.dataforge.vision.solid.box -import hep.dataforge.vision.solid.group +import hep.dataforge.vision.solid.* +import hep.dataforge.vision.solid.specifications.Canvas3DOptions +import hep.dataforge.vision.solid.three.ThreeCanvasComponent import hep.dataforge.vision.solid.three.ThreePlugin -import hep.dataforge.vision.solid.three.threeCanvas +import kotlinx.browser.document import org.w3c.dom.HTMLElement +import react.RBuilder +import react.child import react.dom.div import react.dom.render -import kotlin.browser.document + +public fun RBuilder.threeCanvas(object3D: Solid, options: Canvas3DOptions.() -> Unit = {}) { + child(ThreeCanvasComponent) { + attrs { + this.obj = object3D + this.options = Canvas3DOptions.invoke(options) + } + } +} private class PlayGroundApp : Application { diff --git a/ui/react/src/main/kotlin/hep/dataforge/vision/react/ConfigEditor.kt b/ui/react/src/main/kotlin/hep/dataforge/vision/react/ConfigEditor.kt index 8c749d47..9d9078f7 100644 --- a/ui/react/src/main/kotlin/hep/dataforge/vision/react/ConfigEditor.kt +++ b/ui/react/src/main/kotlin/hep/dataforge/vision/react/ConfigEditor.kt @@ -19,29 +19,29 @@ public external interface ConfigEditorItemProps : RProps { /** * Root config object - always non null */ - var root: Config + public var root: Config /** * Full path to the displayed node in [root]. Could be empty */ - var name: Name + public var name: Name /** * Root default */ - var default: Meta? + public var default: Meta? /** * Root descriptor */ - var descriptor: NodeDescriptor? + public var descriptor: NodeDescriptor? } -private val ConfigEditorItem: FunctionalComponent = component { props -> +private val ConfigEditorItem: FunctionalComponent = functionalComponent("ConfigEditorItem") { props -> configEditorItem(props) } -private fun RFBuilder.configEditorItem(props: ConfigEditorItemProps) { +private fun RBuilder.configEditorItem(props: ConfigEditorItemProps) { var expanded: Boolean by useState { true } var item: MetaItem? by useState { props.root[props.name] } val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name) @@ -198,7 +198,7 @@ public external interface ConfigEditorProps : RProps { } @JsExport -public val ConfigEditor: FunctionalComponent = component { props -> +public val ConfigEditor: FunctionalComponent = functionalComponent("ConfigEditor") { props -> child(ConfigEditorItem) { attrs { this.key = "" @@ -223,7 +223,7 @@ public fun Element.configEditor(config: Config, descriptor: NodeDescriptor? = nu } } -fun RBuilder.configEditor(config: Config, descriptor: NodeDescriptor? = null, default: Meta? = null, key: Any? = null) { +public fun RBuilder.configEditor(config: Config, descriptor: NodeDescriptor? = null, default: Meta? = null, key: Any? = null) { child(ConfigEditor) { attrs { this.key = key?.toString() ?: "" @@ -234,7 +234,7 @@ fun RBuilder.configEditor(config: Config, descriptor: NodeDescriptor? = null, de } } -fun RBuilder.configEditor( +public fun RBuilder.configEditor( obj: Configurable, descriptor: NodeDescriptor? = obj.descriptor, default: Meta? = null, diff --git a/ui/react/src/main/kotlin/hep/dataforge/vision/react/MetaViewer.kt b/ui/react/src/main/kotlin/hep/dataforge/vision/react/MetaViewer.kt index fbf6dcc5..9c17206d 100644 --- a/ui/react/src/main/kotlin/hep/dataforge/vision/react/MetaViewer.kt +++ b/ui/react/src/main/kotlin/hep/dataforge/vision/react/MetaViewer.kt @@ -21,24 +21,24 @@ public external interface MetaViewerProps : RProps { /** * Root meta */ - var root: Meta + public var root: Meta /** * Full path to the displayed node in [root]. Could be empty */ - var name: Name + public var name: Name /** * Root descriptor */ - var descriptor: NodeDescriptor? + public var descriptor: NodeDescriptor? } -private val MetaViewerItem: FunctionalComponent = component { props -> +private val MetaViewerItem: FunctionalComponent = functionalComponent("MetaViewerItem") { props -> metaViewerItem(props) } -private fun RFBuilder.metaViewerItem(props: MetaViewerProps) { +private fun RBuilder.metaViewerItem(props: MetaViewerProps) { var expanded: Boolean by useState { true } val item = props.root[props.name] val descriptorItem: ItemDescriptor? = props.descriptor?.get(props.name) @@ -137,7 +137,7 @@ private fun RFBuilder.metaViewerItem(props: MetaViewerProps) { } @JsExport -val MetaViewer = component { props -> +public val MetaViewer:FunctionalComponent = functionalComponent("MetaViewer") { props -> child(MetaViewerItem) { attrs { this.key = "" @@ -148,7 +148,7 @@ val MetaViewer = component { props -> } } -fun RBuilder.metaViewer(meta: Meta, descriptor: NodeDescriptor? = null, key: Any? = null) { +public fun RBuilder.metaViewer(meta: Meta, descriptor: NodeDescriptor? = null, key: Any? = null) { child(MetaViewer) { attrs { this.key = key?.toString() ?: "" diff --git a/ui/react/src/main/kotlin/hep/dataforge/vision/react/ObjectTree.kt b/ui/react/src/main/kotlin/hep/dataforge/vision/react/ObjectTree.kt index 053569d7..5faab7ba 100644 --- a/ui/react/src/main/kotlin/hep/dataforge/vision/react/ObjectTree.kt +++ b/ui/react/src/main/kotlin/hep/dataforge/vision/react/ObjectTree.kt @@ -19,7 +19,7 @@ public external interface ObjectTreeProps : RProps { public var clickCallback: (Name) -> Unit } -private fun RFBuilder.objectTree(props: ObjectTreeProps): Unit { +private fun RBuilder.objectTree(props: ObjectTreeProps): Unit { var expanded: Boolean by useState { props.selected?.startsWith(props.name) ?: false } val onClick: (Event) -> Unit = { @@ -103,11 +103,11 @@ private fun RFBuilder.objectTree(props: ObjectTreeProps): Unit { } @JsExport -val ObjectTree: FunctionalComponent = component { props -> +public val ObjectTree: FunctionalComponent = functionalComponent("ObjectTree") { props -> objectTree(props) } -fun RBuilder.objectTree( +public fun RBuilder.objectTree( vision: Vision, selected: Name? = null, clickCallback: (Name) -> Unit = {} diff --git a/ui/react/src/main/kotlin/hep/dataforge/vision/react/TreeStyles.kt b/ui/react/src/main/kotlin/hep/dataforge/vision/react/TreeStyles.kt index ead7d577..7cfb7d48 100644 --- a/ui/react/src/main/kotlin/hep/dataforge/vision/react/TreeStyles.kt +++ b/ui/react/src/main/kotlin/hep/dataforge/vision/react/TreeStyles.kt @@ -4,11 +4,11 @@ import kotlinx.css.* import kotlinx.css.properties.* import styled.StyleSheet -object TreeStyles : StyleSheet("treeStyles", true) { +public object TreeStyles : StyleSheet("treeStyles", true) { /** * Remove default bullets */ - val tree by css { + public val tree by css { paddingLeft = 8.px marginLeft = 0.px listStyleType = ListStyleType.none @@ -17,7 +17,7 @@ object TreeStyles : StyleSheet("treeStyles", true) { /** * Style the caret/arrow */ - val treeCaret by css { + public val treeCaret by css { cursor = Cursor.pointer userSelect = UserSelect.none /* Create the caret/arrow with a unicode, and style it */ diff --git a/ui/react/src/main/kotlin/hep/dataforge/vision/react/layout.kt b/ui/react/src/main/kotlin/hep/dataforge/vision/react/layout.kt index 5a13a089..cdafb527 100644 --- a/ui/react/src/main/kotlin/hep/dataforge/vision/react/layout.kt +++ b/ui/react/src/main/kotlin/hep/dataforge/vision/react/layout.kt @@ -6,11 +6,12 @@ import kotlinx.css.display import kotlinx.css.flexDirection import kotlinx.html.DIV import react.RBuilder +import react.ReactElement import styled.StyledDOMBuilder import styled.css import styled.styledDiv -inline fun RBuilder.flexColumn(block: StyledDOMBuilder
.() -> Unit) = +public inline fun RBuilder.flexColumn(block: StyledDOMBuilder
.() -> Unit): ReactElement = styledDiv { css { display = Display.flex @@ -19,7 +20,7 @@ inline fun RBuilder.flexColumn(block: StyledDOMBuilder
.() -> Unit) = block() } -inline fun RBuilder.flexRow(block: StyledDOMBuilder
.() -> Unit) = +public inline fun RBuilder.flexRow(block: StyledDOMBuilder
.() -> Unit): ReactElement = styledDiv { css { display = Display.flex diff --git a/ui/react/src/main/kotlin/hep/dataforge/vision/react/react.kt b/ui/react/src/main/kotlin/hep/dataforge/vision/react/react.kt deleted file mode 100644 index a0e2c787..00000000 --- a/ui/react/src/main/kotlin/hep/dataforge/vision/react/react.kt +++ /dev/null @@ -1,24 +0,0 @@ -package hep.dataforge.vision.react - -import react.* - -public class RFBuilder : RBuilder() - -/** - * Get functional component from [func] - */ -public inline fun

component( - crossinline 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()) - } - } -} -// -//public fun RFBuilder.memoize(vararg deps: dynamic, builder: () -> T): T = useMemo(builder, deps) - diff --git a/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GdmlOptimizer.kt b/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GdmlOptimizer.kt index dba7e32f..692c334b 100644 --- a/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GdmlOptimizer.kt +++ b/visionforge-gdml/src/commonMain/kotlin/hep/dataforge/vision/gdml/GdmlOptimizer.kt @@ -13,9 +13,9 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.coroutineScope import mu.KotlinLogging -expect class Counter() { - fun get(): Int - fun incrementAndGet(): Int +public expect class Counter() { + public fun get(): Int + public fun incrementAndGet(): Int } private fun Point3D?.safePlus(other: Point3D?): Point3D? = if (this == null && other == null) { diff --git a/visionforge-gdml/src/jsMain/kotlin/hep/dataforge/vision/gdml/gdmlJs.kt b/visionforge-gdml/src/jsMain/kotlin/hep/dataforge/vision/gdml/gdmlJs.kt index 44a36b6c..87b0f63c 100644 --- a/visionforge-gdml/src/jsMain/kotlin/hep/dataforge/vision/gdml/gdmlJs.kt +++ b/visionforge-gdml/src/jsMain/kotlin/hep/dataforge/vision/gdml/gdmlJs.kt @@ -1,8 +1,8 @@ package hep.dataforge.vision.gdml -actual class Counter { +public actual class Counter { private var count: Int = 0 - actual fun get(): Int = count + public actual fun get(): Int = count - actual fun incrementAndGet(): Int = count++ + public actual fun incrementAndGet(): Int = count++ } \ No newline at end of file diff --git a/visionforge-gdml/src/jvmMain/kotlin/hep/dataforge/vision/gdml/gdmlJVM.kt b/visionforge-gdml/src/jvmMain/kotlin/hep/dataforge/vision/gdml/gdmlJVM.kt index ab58deb9..685708da 100644 --- a/visionforge-gdml/src/jvmMain/kotlin/hep/dataforge/vision/gdml/gdmlJVM.kt +++ b/visionforge-gdml/src/jvmMain/kotlin/hep/dataforge/vision/gdml/gdmlJVM.kt @@ -7,7 +7,7 @@ import java.nio.file.Files import java.nio.file.Path import java.util.concurrent.atomic.AtomicInteger -actual typealias Counter = AtomicInteger +public actual typealias Counter = AtomicInteger fun GDML.Companion.readFile(file: Path): GDML { val xmlReader = StAXReader(Files.newInputStream(file), "UTF-8") diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvas.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvas.kt index a4e44f35..72db7ba4 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvas.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvas.kt @@ -29,11 +29,11 @@ import info.laht.threekt.math.Vector2 import info.laht.threekt.objects.LineSegments import info.laht.threekt.objects.Mesh import info.laht.threekt.scenes.Scene +import kotlinx.browser.window +import kotlinx.dom.clear import org.w3c.dom.HTMLElement import org.w3c.dom.Node import org.w3c.dom.events.MouseEvent -import kotlin.browser.window -import kotlin.dom.clear import kotlin.math.cos import kotlin.math.max import kotlin.math.sin @@ -41,11 +41,16 @@ import kotlin.math.sin /** * */ -class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val options: Canvas3DOptions) : Renderer { +public class ThreeCanvas( + element: HTMLElement, + public val three: ThreePlugin, + public val options: Canvas3DOptions, + public val onClick: ((Name?) -> Unit)? = null, +) : Renderer { override val context: Context get() = three.context - var content: Solid? = null + public var content: Solid? = null private set private var root: Object3D? = null @@ -53,17 +58,15 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val options: Can private val raycaster = Raycaster() private val mousePosition: Vector2 = Vector2() - var onClick: ((Name?) -> Unit)? = null - - val axes = AxesHelper(options.axes.size.toInt()).apply { + public val axes: AxesHelper = AxesHelper(options.axes.size.toInt()).apply { visible = options.axes.visible } - val scene: Scene = Scene().apply { + public val scene: Scene = Scene().apply { add(axes) } - val camera = buildCamera(options.camera) + public val camera: PerspectiveCamera = buildCamera(options.camera) private var picked: Object3D? = null @@ -166,7 +169,7 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val options: Can } } - fun clear() { + public fun clear() { scene.children.find { it.name == "@root" }?.let { scene.remove(it) } @@ -192,7 +195,7 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val options: Can private fun Object3D.toggleHighlight( highlight: Boolean, edgesName: String, - material: LineBasicMaterial = SELECTED_MATERIAL + material: LineBasicMaterial = SELECTED_MATERIAL, ) { if (userData[DO_NOT_HIGHLIGHT_TAG] == true) { return @@ -220,7 +223,7 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val options: Can /** * Toggle highlight for element with given name */ - fun select(name: Name?) { + public fun select(name: Name?) { if (name == null) { selected?.toggleHighlight(false, SELECT_NAME, SELECTED_MATERIAL) selected = null @@ -234,15 +237,21 @@ class ThreeCanvas(element: HTMLElement, val three: ThreePlugin, val options: Can } } - companion object { - const val DO_NOT_HIGHLIGHT_TAG = "doNotHighlight" + public companion object { + public const val DO_NOT_HIGHLIGHT_TAG = "doNotHighlight" private const val HIGHLIGHT_NAME = "@highlight" private const val SELECT_NAME = "@select" } } -fun ThreePlugin.output(element: HTMLElement, spec: Canvas3DOptions = Canvas3DOptions.empty()): ThreeCanvas = - ThreeCanvas(element, this, spec) +public fun ThreePlugin.output( + element: HTMLElement, + spec: Canvas3DOptions = Canvas3DOptions.empty(), + onClick: ((Name?) -> Unit)? = null, +): ThreeCanvas = ThreeCanvas(element, this, spec, onClick) -fun ThreePlugin.render(element: HTMLElement, obj: Solid, spec: Canvas3DOptions = Canvas3DOptions.empty()): Unit = - output(element, spec).render(obj) \ No newline at end of file +public fun ThreePlugin.render( + element: HTMLElement, obj: Solid, + spec: Canvas3DOptions = Canvas3DOptions.empty(), + onClick: ((Name?) -> Unit)? = null, +): Unit = output(element, spec, onClick).render(obj) \ No newline at end of file diff --git a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvasComponent.kt b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvasComponent.kt index ee033817..9f335642 100644 --- a/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvasComponent.kt +++ b/visionforge-solid/src/jsMain/kotlin/hep/dataforge/vision/solid/three/ThreeCanvasComponent.kt @@ -6,67 +6,88 @@ import hep.dataforge.vision.solid.Solid import hep.dataforge.vision.solid.specifications.Canvas3DOptions import org.w3c.dom.Element import org.w3c.dom.HTMLElement -import react.RBuilder -import react.RComponent -import react.RProps -import react.RState +import react.* import react.dom.div -import react.dom.findDOMNode public external interface ThreeCanvasProps : RProps { - var context: Context - var obj: Solid - var options: Canvas3DOptions? - var selected: Name? - var clickCallback: (Name?) -> Unit - var canvasCallback: ((ThreeCanvas?) -> Unit)? + public var context: Context + public var obj: Solid? + public var options: Canvas3DOptions? + public var selected: Name? + public var clickCallback: (Name?) -> Unit + public var canvasCallback: ((ThreeCanvas?) -> Unit)? } public external interface ThreeCanvasState : RState { - var element: Element? + public var element: Element? // var canvas: ThreeCanvas? } -@JsExport -public class ThreeCanvasComponent : RComponent() { +public val ThreeCanvasComponent: FunctionalComponent = functionalComponent( + "ThreeCanvasComponent" +) { props -> + val elementRef = useRef(null) + var canvas by useState(null) - private var canvas: ThreeCanvas? = null - - override fun componentDidMount() { - if(canvas == null) { - val element = state.element as? HTMLElement ?: error("Canvas element not found") + useEffect(listOf(props.context, props.obj, props.options, elementRef)) { + if (canvas == null) { + val element = elementRef.current as? HTMLElement ?: error("Canvas element not found") val three: ThreePlugin = props.context.plugins.fetch(ThreePlugin) - canvas = three.output(element, props.options ?: Canvas3DOptions.empty()).apply { - onClick = props.clickCallback - } - props.canvasCallback?.invoke(canvas) - } - canvas?.render(props.obj) - } - - override fun componentDidUpdate(prevProps: ThreeCanvasProps, prevState: ThreeCanvasState, snapshot: Any) { - if (prevProps.obj != props.obj) { - componentDidMount() - } - if (prevProps.selected != props.selected) { - canvas?.select(props.selected) + val newCanvas = three.output(element, props.options ?: Canvas3DOptions.empty(), props.clickCallback) + props.canvasCallback?.invoke(newCanvas) + canvas = newCanvas } } - override fun RBuilder.render() { - div { - ref { - state.element = findDOMNode(it) + useEffect(listOf(canvas, props.obj)) { + props.obj?.let { obj -> + if (canvas?.content != obj) { + canvas?.render(obj) } } } + + useEffect(listOf(canvas, props.selected)) { + canvas?.select(props.selected) + } + + div { + ref = elementRef + } } -public fun RBuilder.threeCanvas(object3D: Solid, options: Canvas3DOptions.() -> Unit = {}) { - child(ThreeCanvasComponent::class) { - attrs { - this.obj = object3D - this.options = Canvas3DOptions.invoke(options) - } - } -} \ No newline at end of file +//public class ThreeCanvasComponent : RComponent() { +// +// private var canvas: ThreeCanvas? = null +// +// override fun componentDidMount() { +// props.obj?.let { obj -> +// if (canvas == null) { +// val element = state.element as? HTMLElement ?: error("Canvas element not found") +// val three: ThreePlugin = props.context.plugins.fetch(ThreePlugin) +// canvas = three.output(element, props.options ?: Canvas3DOptions.empty()).apply { +// onClick = props.clickCallback +// } +// props.canvasCallback?.invoke(canvas) +// } +// canvas?.render(obj) +// } +// } +// +// override fun componentDidUpdate(prevProps: ThreeCanvasProps, prevState: ThreeCanvasState, snapshot: Any) { +// if (prevProps.obj != props.obj) { +// componentDidMount() +// } +// if (prevProps.selected != props.selected) { +// canvas?.select(props.selected) +// } +// } +// +// override fun RBuilder.render() { +// div { +// ref { +// state.element = findDOMNode(it) +// } +// } +// } +//} \ No newline at end of file