refactor compose-html
This commit is contained in:
parent
38d6a9c419
commit
d90c1edc6c
@ -30,7 +30,6 @@ kscience {
|
|||||||
|
|
||||||
commonMain {
|
commonMain {
|
||||||
implementation(projects.visionforgeSolid)
|
implementation(projects.visionforgeSolid)
|
||||||
implementation(projects.visionforgeComposeHtml)
|
|
||||||
}
|
}
|
||||||
jvmMain {
|
jvmMain {
|
||||||
implementation("org.apache.commons:commons-math3:3.6.1")
|
implementation("org.apache.commons:commons-math3:3.6.1")
|
||||||
@ -40,12 +39,15 @@ kscience {
|
|||||||
implementation("ch.qos.logback:logback-classic:1.2.11")
|
implementation("ch.qos.logback:logback-classic:1.2.11")
|
||||||
}
|
}
|
||||||
jsMain {
|
jsMain {
|
||||||
|
// implementation(projects.visionforgeComposeHtml)
|
||||||
implementation(projects.visionforgeThreejs)
|
implementation(projects.visionforgeThreejs)
|
||||||
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
|
//implementation(devNpm("webpack-bundle-analyzer", "4.4.0"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
kotlin{
|
||||||
|
explicitApi = null
|
||||||
|
}
|
||||||
|
|
||||||
kotlin.explicitApi = null
|
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
|
mainClass.set("ru.mipt.npm.muon.monitor.server.MMServerKt")
|
||||||
|
@ -4,9 +4,8 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
jvm()
|
|
||||||
js()
|
js()
|
||||||
// wasm()
|
jvm()
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
@ -15,23 +14,22 @@ kotlin {
|
|||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.visionforgeCore)
|
api(projects.visionforgeCore)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jvmMain{
|
||||||
|
//need this to placate compose compiler in MPP applications
|
||||||
|
dependencies{
|
||||||
api(compose.runtime)
|
api(compose.runtime)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val jvmMain by getting {
|
jsMain{
|
||||||
dependencies {
|
dependencies {
|
||||||
api(compose.foundation)
|
|
||||||
api(compose.material)
|
|
||||||
api(compose.preview)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val jsMain by getting {
|
|
||||||
dependencies {
|
|
||||||
api(compose.html.core)
|
|
||||||
api("app.softwork:bootstrap-compose:0.1.15")
|
api("app.softwork:bootstrap-compose:0.1.15")
|
||||||
api("app.softwork:bootstrap-compose-icons:0.1.15")
|
api("app.softwork:bootstrap-compose-icons:0.1.15")
|
||||||
|
|
||||||
|
api(compose.runtime)
|
||||||
|
api(compose.html.core)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,20 +9,19 @@ import space.kscience.dataforge.meta.Meta
|
|||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.visionforge.ElementVisionRenderer
|
import space.kscience.visionforge.ElementVisionRenderer
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionClient
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An [ElementVisionRenderer] that could be used directly in Compose-html as well as a stand-alone renderer
|
* An [ElementVisionRenderer] that could be used directly in Compose-html as well as a stand-alone renderer
|
||||||
*/
|
*/
|
||||||
public interface ComposeVisionRenderer: ElementVisionRenderer {
|
public interface ComposeHtmlVisionRenderer : ElementVisionRenderer {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
public fun DOMScope<Element>.render(client: VisionClient, name: Name, vision: Vision, meta: Meta)
|
public fun DOMScope<Element>.render(name: Name, vision: Vision, meta: Meta)
|
||||||
|
|
||||||
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||||
renderComposable(element) {
|
renderComposable(element) {
|
||||||
Style(VisionForgeStyles)
|
Style(VisionForgeStyles)
|
||||||
render(client, name, vision, meta)
|
render(name, vision, meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -48,7 +48,7 @@ public fun Vision(
|
|||||||
}
|
}
|
||||||
|
|
||||||
DisposableEffect(vision, name, renderer, meta) {
|
DisposableEffect(vision, name, renderer, meta) {
|
||||||
renderer.render(scopeElement, client, name, vision, meta)
|
renderer.render(scopeElement, name, vision, meta)
|
||||||
onDispose {
|
onDispose {
|
||||||
scopeElement.clear()
|
scopeElement.clear()
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ plugins {
|
|||||||
|
|
||||||
kscience {
|
kscience {
|
||||||
jvm()
|
jvm()
|
||||||
wasm()
|
// wasm()
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
@ -16,6 +16,10 @@ kotlin {
|
|||||||
api(projects.visionforgeCore)
|
api(projects.visionforgeCore)
|
||||||
api(compose.runtime)
|
api(compose.runtime)
|
||||||
api(compose.foundation)
|
api(compose.foundation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jvmMain{
|
||||||
|
dependencies{
|
||||||
api(compose.material)
|
api(compose.material)
|
||||||
api(compose.preview)
|
api(compose.preview)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.VisionClient
|
||||||
|
|
||||||
|
public interface ComposeVisionRenderer {
|
||||||
|
public fun rateVision(vision: Vision): Int
|
||||||
|
@Composable
|
||||||
|
public fun render(client: VisionClient, name: Name, vision: Vision, meta: Meta)
|
||||||
|
|
||||||
|
public companion object
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package space.kscience.visionforge.compose
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import space.kscience.dataforge.context.Context
|
||||||
|
import space.kscience.dataforge.meta.Meta
|
||||||
|
import space.kscience.dataforge.names.Name
|
||||||
|
import space.kscience.dataforge.names.asName
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render an Element vision via injected vision renderer inside compose-html
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
public fun Vision(
|
||||||
|
context: Context,
|
||||||
|
vision: Vision,
|
||||||
|
name: Name = "@vision[${vision.hashCode().toString(16)}]".asName(),
|
||||||
|
meta: Meta = Meta.EMPTY,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
@ -8,7 +8,7 @@ kscience {
|
|||||||
jvm()
|
jvm()
|
||||||
js()
|
js()
|
||||||
native()
|
native()
|
||||||
// wasm()
|
wasm()
|
||||||
useCoroutines()
|
useCoroutines()
|
||||||
commonMain {
|
commonMain {
|
||||||
api("space.kscience:dataforge-context:$dataforgeVersion")
|
api("space.kscience:dataforge-context:$dataforgeVersion")
|
||||||
|
@ -2,12 +2,11 @@ package space.kscience.visionforge
|
|||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.flow.filterIsInstance
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.Transient
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.parseAsName
|
import space.kscience.dataforge.names.parseAsName
|
||||||
@ -23,6 +22,9 @@ public abstract class VisionControlEvent : VisionEvent, MetaRepr {
|
|||||||
public interface ControlVision : Vision {
|
public interface ControlVision : Vision {
|
||||||
public val controlEventFlow: SharedFlow<VisionControlEvent>
|
public val controlEventFlow: SharedFlow<VisionControlEvent>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fire a [VisionControlEvent] on this [ControlVision]
|
||||||
|
*/
|
||||||
public suspend fun dispatchControlEvent(event: VisionControlEvent)
|
public suspend fun dispatchControlEvent(event: VisionControlEvent)
|
||||||
|
|
||||||
override suspend fun receiveEvent(event: VisionEvent) {
|
override suspend fun receiveEvent(event: VisionEvent) {
|
||||||
@ -32,6 +34,28 @@ public interface ControlVision : Vision {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun ControlVision.asyncControlEvent(
|
||||||
|
event: VisionControlEvent,
|
||||||
|
scope: CoroutineScope = manager?.context ?: error("Can't fire asynchronous event for an orphan vision. Provide a scope."),
|
||||||
|
) {
|
||||||
|
scope.launch { dispatchControlEvent(event) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
public abstract class AbstractControlVision : AbstractVision(), ControlVision {
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private val mutableControlEventFlow = MutableSharedFlow<VisionControlEvent>()
|
||||||
|
|
||||||
|
override val controlEventFlow: SharedFlow<VisionControlEvent>
|
||||||
|
get() = mutableControlEventFlow
|
||||||
|
|
||||||
|
override suspend fun dispatchControlEvent(event: VisionControlEvent) {
|
||||||
|
mutableControlEventFlow.emit(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event for submitting changes
|
* An event for submitting changes
|
||||||
|
@ -2,21 +2,21 @@ package space.kscience.visionforge.html
|
|||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.filterIsInstance
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.html.DIV
|
import kotlinx.html.DIV
|
||||||
import kotlinx.html.InputType
|
import kotlinx.html.InputType
|
||||||
import kotlinx.html.div
|
import kotlinx.html.div
|
||||||
import kotlinx.html.stream.createHTML
|
import kotlinx.html.stream.createHTML
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.Transient
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
|
|
||||||
|
|
||||||
@Serializable
|
public interface VisionOfHtml : Vision {
|
||||||
public abstract class VisionOfHtml : AbstractVision() {
|
|
||||||
public var classes: Set<String>
|
public var classes: Set<String>
|
||||||
get() = properties[::classes.name, false].stringList?.toSet() ?: emptySet()
|
get() = properties[::classes.name, false].stringList?.toSet() ?: emptySet()
|
||||||
set(value) {
|
set(value) {
|
||||||
@ -26,7 +26,7 @@ public abstract class VisionOfHtml : AbstractVision() {
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("html.plain")
|
@SerialName("html.plain")
|
||||||
public class VisionOfPlainHtml : VisionOfHtml() {
|
public class VisionOfPlainHtml : AbstractVision(), VisionOfHtml {
|
||||||
public var content: String? by properties.string()
|
public var content: String? by properties.string()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,26 +59,11 @@ public enum class InputFeedbackMode {
|
|||||||
NONE
|
NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
|
||||||
public abstract class VisionOfHtmlControl: VisionOfHtml(), ControlVision{
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
private val mutableControlEventFlow = MutableSharedFlow<VisionControlEvent>()
|
|
||||||
|
|
||||||
override val controlEventFlow: SharedFlow<VisionControlEvent>
|
|
||||||
get() = mutableControlEventFlow
|
|
||||||
|
|
||||||
override suspend fun dispatchControlEvent(event: VisionControlEvent) {
|
|
||||||
mutableControlEventFlow.emit(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("html.input")
|
@SerialName("html.input")
|
||||||
public open class VisionOfHtmlInput(
|
public open class VisionOfHtmlInput(
|
||||||
public val inputType: String,
|
public val inputType: String,
|
||||||
) : VisionOfHtmlControl() {
|
) : AbstractControlVision(), VisionOfHtml {
|
||||||
public var value: Value? by properties.value()
|
public var value: Value? by properties.value()
|
||||||
public var disabled: Boolean by properties.boolean { false }
|
public var disabled: Boolean by properties.boolean { false }
|
||||||
public var fieldName: String? by properties.string()
|
public var fieldName: String? by properties.string()
|
||||||
|
@ -8,6 +8,7 @@ import kotlinx.serialization.Serializable
|
|||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.meta.node
|
import space.kscience.dataforge.meta.node
|
||||||
import space.kscience.dataforge.meta.string
|
import space.kscience.dataforge.meta.string
|
||||||
|
import space.kscience.visionforge.AbstractControlVision
|
||||||
import space.kscience.visionforge.DataControl
|
import space.kscience.visionforge.DataControl
|
||||||
import space.kscience.visionforge.onSubmit
|
import space.kscience.visionforge.onSubmit
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ import space.kscience.visionforge.onSubmit
|
|||||||
@SerialName("html.form")
|
@SerialName("html.form")
|
||||||
public class VisionOfHtmlForm(
|
public class VisionOfHtmlForm(
|
||||||
public val formId: String,
|
public val formId: String,
|
||||||
) : VisionOfHtmlControl(), DataControl {
|
) : AbstractControlVision(), DataControl, VisionOfHtml {
|
||||||
public var values: Meta? by properties.node()
|
public var values: Meta? by properties.node()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ public fun VisionOfHtmlForm.onFormSubmit(scope: CoroutineScope, block: (Meta?) -
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("html.button")
|
@SerialName("html.button")
|
||||||
public class VisionOfHtmlButton : VisionOfHtmlControl(), DataControl {
|
public class VisionOfHtmlButton : AbstractControlVision(), DataControl, VisionOfHtml {
|
||||||
public var label: String? by properties.string()
|
public var label: String? by properties.string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,6 @@ public interface ElementVisionRenderer {
|
|||||||
*/
|
*/
|
||||||
public fun render(
|
public fun render(
|
||||||
element: Element,
|
element: Element,
|
||||||
client: VisionClient,
|
|
||||||
name: Name,
|
name: Name,
|
||||||
vision: Vision,
|
vision: Vision,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
@ -49,7 +48,7 @@ public interface ElementVisionRenderer {
|
|||||||
public class SingleTypeVisionRenderer<T : Vision>(
|
public class SingleTypeVisionRenderer<T : Vision>(
|
||||||
public val kClass: KClass<T>,
|
public val kClass: KClass<T>,
|
||||||
private val acceptRating: Int = ElementVisionRenderer.DEFAULT_RATING,
|
private val acceptRating: Int = ElementVisionRenderer.DEFAULT_RATING,
|
||||||
private val renderFunction: TagConsumer<HTMLElement>.(name: Name, client: VisionClient, vision: T, meta: Meta) -> Unit,
|
private val renderFunction: TagConsumer<HTMLElement>.(name: Name, vision: T, meta: Meta) -> Unit,
|
||||||
) : ElementVisionRenderer {
|
) : ElementVisionRenderer {
|
||||||
|
|
||||||
override fun rateVision(vision: Vision): Int =
|
override fun rateVision(vision: Vision): Int =
|
||||||
@ -57,19 +56,18 @@ public class SingleTypeVisionRenderer<T : Vision>(
|
|||||||
|
|
||||||
override fun render(
|
override fun render(
|
||||||
element: Element,
|
element: Element,
|
||||||
client: VisionClient,
|
|
||||||
name: Name,
|
name: Name,
|
||||||
vision: Vision,
|
vision: Vision,
|
||||||
meta: Meta,
|
meta: Meta,
|
||||||
) {
|
) {
|
||||||
element.clear()
|
element.clear()
|
||||||
element.append {
|
element.append {
|
||||||
renderFunction(name, client, kClass.cast(vision), meta)
|
renderFunction(name, kClass.cast(vision), meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline fun <reified T : Vision> ElementVisionRenderer(
|
public inline fun <reified T : Vision> ElementVisionRenderer(
|
||||||
acceptRating: Int = ElementVisionRenderer.DEFAULT_RATING,
|
acceptRating: Int = ElementVisionRenderer.DEFAULT_RATING,
|
||||||
noinline renderFunction: TagConsumer<HTMLElement>.(name: Name, client: VisionClient, vision: T, meta: Meta) -> Unit,
|
noinline renderFunction: TagConsumer<HTMLElement>.(name: Name, vision: T, meta: Meta) -> Unit,
|
||||||
): ElementVisionRenderer = SingleTypeVisionRenderer(T::class, acceptRating, renderFunction)
|
): ElementVisionRenderer = SingleTypeVisionRenderer(T::class, acceptRating, renderFunction)
|
||||||
|
@ -96,7 +96,13 @@ public class JsVisionClient : AbstractPlugin(), VisionClient {
|
|||||||
vision.setAsRoot(visionManager)
|
vision.setAsRoot(visionManager)
|
||||||
val renderer: ElementVisionRenderer =
|
val renderer: ElementVisionRenderer =
|
||||||
findRendererFor(vision) ?: error("Could not find renderer for ${vision::class}")
|
findRendererFor(vision) ?: error("Could not find renderer for ${vision::class}")
|
||||||
renderer.render(element, this, name, vision, outputMeta)
|
//subscribe to a backwards events propagation for control visions
|
||||||
|
if(vision is ControlVision){
|
||||||
|
vision.controlEventFlow.onEach {
|
||||||
|
sendEvent(name,it)
|
||||||
|
}.launchIn(context)
|
||||||
|
}
|
||||||
|
renderer.render(element, name, vision, outputMeta)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startVisionUpdate(element: Element, visionName: Name, vision: Vision, outputMeta: Meta) {
|
private fun startVisionUpdate(element: Element, visionName: Name, vision: Vision, outputMeta: Meta) {
|
||||||
|
@ -49,7 +49,7 @@ public fun VisionClient.sendMetaEvent(targetName: Name, payload: MetaRepr): Unit
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val formVisionRenderer: ElementVisionRenderer =
|
internal val formVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfHtmlForm> { name, client, vision, _ ->
|
ElementVisionRenderer<VisionOfHtmlForm> { name, vision, _ ->
|
||||||
|
|
||||||
val form = document.getElementById(vision.formId) as? HTMLFormElement
|
val form = document.getElementById(vision.formId) as? HTMLFormElement
|
||||||
?: error("An element with id = '${vision.formId} is not a form")
|
?: error("An element with id = '${vision.formId} is not a form")
|
||||||
@ -69,22 +69,18 @@ internal val formVisionRenderer: ElementVisionRenderer =
|
|||||||
form.onsubmit = { event ->
|
form.onsubmit = { event ->
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
val formData = FormData(form).toMeta()
|
val formData = FormData(form).toMeta()
|
||||||
client.context.launch {
|
vision.asyncControlEvent(VisionSubmitEvent(name = name, payload = formData))
|
||||||
client.sendEvent(name, VisionSubmitEvent(name = name, payload = formData))
|
|
||||||
}
|
|
||||||
console.info("Sent form data: ${formData.toMap()}")
|
console.info("Sent form data: ${formData.toMap()}")
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val buttonVisionRenderer: ElementVisionRenderer =
|
internal val buttonVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfHtmlButton> { name, client, vision, _ ->
|
ElementVisionRenderer<VisionOfHtmlButton> { name, vision, _ ->
|
||||||
button(type = ButtonType.button).also { button ->
|
button(type = ButtonType.button).also { button ->
|
||||||
button.subscribeToVision(vision)
|
button.subscribeToVision(vision)
|
||||||
button.onclick = {
|
button.onclick = {
|
||||||
client.context.launch {
|
vision.asyncControlEvent(VisionSubmitEvent(name = name))
|
||||||
client.sendEvent(name, VisionSubmitEvent(name = name))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
vision.useProperty(VisionOfHtmlButton::label) {
|
vision.useProperty(VisionOfHtmlButton::label) {
|
||||||
button.innerHTML = it ?: ""
|
button.innerHTML = it ?: ""
|
||||||
|
@ -35,7 +35,7 @@ private fun HTMLInputElement.subscribeToInput(inputVision: VisionOfHtmlInput) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val htmlVisionRenderer: ElementVisionRenderer =
|
internal val htmlVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfPlainHtml> { _, _, vision, _ ->
|
ElementVisionRenderer<VisionOfPlainHtml> { _, vision, _ ->
|
||||||
div().also { div ->
|
div().also { div ->
|
||||||
div.subscribeToVision(vision)
|
div.subscribeToVision(vision)
|
||||||
vision.useProperty(VisionOfPlainHtml::content) {
|
vision.useProperty(VisionOfPlainHtml::content) {
|
||||||
@ -47,17 +47,18 @@ internal val htmlVisionRenderer: ElementVisionRenderer =
|
|||||||
|
|
||||||
internal val inputVisionRenderer: ElementVisionRenderer = ElementVisionRenderer<VisionOfHtmlInput>(
|
internal val inputVisionRenderer: ElementVisionRenderer = ElementVisionRenderer<VisionOfHtmlInput>(
|
||||||
acceptRating = ElementVisionRenderer.DEFAULT_RATING - 1
|
acceptRating = ElementVisionRenderer.DEFAULT_RATING - 1
|
||||||
) { name, client, vision, _ ->
|
) { name, vision, _ ->
|
||||||
|
|
||||||
input {
|
input {
|
||||||
type = InputType.text
|
type = InputType.text
|
||||||
}.also { htmlInputElement ->
|
}.also { htmlInputElement ->
|
||||||
|
|
||||||
htmlInputElement.onchange = {
|
htmlInputElement.onchange = {
|
||||||
client.sendEventAsync(name, VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
vision.asyncControlEvent( VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.oninput = {
|
htmlInputElement.oninput = {
|
||||||
client.sendEventAsync(name, VisionInputEvent(htmlInputElement.value.asValue(), name))
|
vision.asyncControlEvent(VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.subscribeToInput(vision)
|
htmlInputElement.subscribeToInput(vision)
|
||||||
@ -68,17 +69,17 @@ internal val inputVisionRenderer: ElementVisionRenderer = ElementVisionRenderer<
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val checkboxVisionRenderer: ElementVisionRenderer =
|
internal val checkboxVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfCheckbox> { name, client, vision, _ ->
|
ElementVisionRenderer<VisionOfCheckbox> { name, vision, _ ->
|
||||||
input {
|
input {
|
||||||
type = InputType.checkBox
|
type = InputType.checkBox
|
||||||
}.also { htmlInputElement ->
|
}.also { htmlInputElement ->
|
||||||
|
|
||||||
htmlInputElement.onchange = {
|
htmlInputElement.onchange = {
|
||||||
client.sendEventAsync(name, VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
vision.asyncControlEvent(VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.oninput = {
|
htmlInputElement.oninput = {
|
||||||
client.sendEventAsync(name, VisionInputEvent(htmlInputElement.value.asValue(), name))
|
vision.asyncControlEvent(VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -90,17 +91,17 @@ internal val checkboxVisionRenderer: ElementVisionRenderer =
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val textVisionRenderer: ElementVisionRenderer =
|
internal val textVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfTextField> { name, client, vision, _ ->
|
ElementVisionRenderer<VisionOfTextField> { name, vision, _ ->
|
||||||
input {
|
input {
|
||||||
type = InputType.text
|
type = InputType.text
|
||||||
}.also { htmlInputElement ->
|
}.also { htmlInputElement ->
|
||||||
|
|
||||||
htmlInputElement.onchange = {
|
htmlInputElement.onchange = {
|
||||||
client.sendEventAsync(name, VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
vision.asyncControlEvent(VisionValueChangeEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.oninput = {
|
htmlInputElement.oninput = {
|
||||||
client.sendEventAsync(name, VisionInputEvent(htmlInputElement.value.asValue(), name))
|
vision.asyncControlEvent(VisionInputEvent(htmlInputElement.value.asValue(), name))
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.subscribeToInput(vision)
|
htmlInputElement.subscribeToInput(vision)
|
||||||
@ -111,20 +112,20 @@ internal val textVisionRenderer: ElementVisionRenderer =
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val numberVisionRenderer: ElementVisionRenderer =
|
internal val numberVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfNumberField> { name, client, vision, _ ->
|
ElementVisionRenderer<VisionOfNumberField> { name, vision, _ ->
|
||||||
input {
|
input {
|
||||||
type = InputType.number
|
type = InputType.number
|
||||||
}.also { htmlInputElement ->
|
}.also { htmlInputElement ->
|
||||||
|
|
||||||
htmlInputElement.onchange = {
|
htmlInputElement.onchange = {
|
||||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||||
client.sendEventAsync(name, VisionValueChangeEvent(it.asValue(), name))
|
vision.asyncControlEvent(VisionValueChangeEvent(it.asValue(), name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.oninput = {
|
htmlInputElement.oninput = {
|
||||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||||
client.sendEventAsync(name, VisionInputEvent(it.asValue(), name))
|
vision.asyncControlEvent(VisionInputEvent(it.asValue(), name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +138,7 @@ internal val numberVisionRenderer: ElementVisionRenderer =
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal val rangeVisionRenderer: ElementVisionRenderer =
|
internal val rangeVisionRenderer: ElementVisionRenderer =
|
||||||
ElementVisionRenderer<VisionOfRangeField> { name, client, vision, _ ->
|
ElementVisionRenderer<VisionOfRangeField> { name, vision, _ ->
|
||||||
input {
|
input {
|
||||||
type = InputType.range
|
type = InputType.range
|
||||||
min = vision.min.toString()
|
min = vision.min.toString()
|
||||||
@ -147,13 +148,13 @@ internal val rangeVisionRenderer: ElementVisionRenderer =
|
|||||||
|
|
||||||
htmlInputElement.onchange = {
|
htmlInputElement.onchange = {
|
||||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||||
client.sendEventAsync(name, VisionValueChangeEvent(it.asValue(), name))
|
vision.asyncControlEvent(VisionValueChangeEvent(it.asValue(), name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlInputElement.oninput = {
|
htmlInputElement.oninput = {
|
||||||
htmlInputElement.value.toDoubleOrNull()?.let {
|
htmlInputElement.value.toDoubleOrNull()?.let {
|
||||||
client.sendEventAsync(name, VisionInputEvent(it.asValue(), name))
|
vision.asyncControlEvent(VisionInputEvent(it.asValue(), name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ public actual class MarkupPlugin : VisionPlugin(), ElementVisionRenderer {
|
|||||||
else -> ElementVisionRenderer.ZERO_RATING
|
else -> ElementVisionRenderer.ZERO_RATING
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
override fun render(element: Element,name: Name, vision: Vision, meta: Meta) {
|
||||||
require(vision is VisionOfMarkup) { "The vision is not a markup vision" }
|
require(vision is VisionOfMarkup) { "The vision is not a markup vision" }
|
||||||
val div = document.createElement("div")
|
val div = document.createElement("div")
|
||||||
val flavour = when (vision.format) {
|
val flavour = when (vision.format) {
|
||||||
|
@ -10,7 +10,10 @@ import space.kscience.dataforge.names.Name
|
|||||||
import space.kscience.dataforge.names.asName
|
import space.kscience.dataforge.names.asName
|
||||||
import space.kscience.plotly.PlotlyConfig
|
import space.kscience.plotly.PlotlyConfig
|
||||||
import space.kscience.plotly.plot
|
import space.kscience.plotly.plot
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.ElementVisionRenderer
|
||||||
|
import space.kscience.visionforge.JsVisionClient
|
||||||
|
import space.kscience.visionforge.Vision
|
||||||
|
import space.kscience.visionforge.VisionPlugin
|
||||||
|
|
||||||
public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||||
public val visionClient: JsVisionClient by require(JsVisionClient)
|
public val visionClient: JsVisionClient by require(JsVisionClient)
|
||||||
@ -24,7 +27,7 @@ public actual class PlotlyPlugin : VisionPlugin(), ElementVisionRenderer {
|
|||||||
else -> ElementVisionRenderer.ZERO_RATING
|
else -> ElementVisionRenderer.ZERO_RATING
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||||
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
|
val plot = (vision as? VisionOfPlotly)?.plot ?: error("VisionOfPlotly expected but ${vision::class} found")
|
||||||
val config = PlotlyConfig.read(meta)
|
val config = PlotlyConfig.read(meta)
|
||||||
element.plot(config, plot)
|
element.plot(config, plot)
|
||||||
|
@ -14,7 +14,6 @@ import space.kscience.dataforge.names.asName
|
|||||||
import space.kscience.visionforge.ElementVisionRenderer
|
import space.kscience.visionforge.ElementVisionRenderer
|
||||||
import space.kscience.visionforge.JsVisionClient
|
import space.kscience.visionforge.JsVisionClient
|
||||||
import space.kscience.visionforge.Vision
|
import space.kscience.visionforge.Vision
|
||||||
import space.kscience.visionforge.VisionClient
|
|
||||||
import tabulator.Tabulator
|
import tabulator.Tabulator
|
||||||
import tabulator.TabulatorFull
|
import tabulator.TabulatorFull
|
||||||
|
|
||||||
@ -35,7 +34,7 @@ public class TableVisionJsPlugin : AbstractPlugin(), ElementVisionRenderer {
|
|||||||
else -> ElementVisionRenderer.ZERO_RATING
|
else -> ElementVisionRenderer.ZERO_RATING
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(element: Element, client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
override fun render(element: Element, name: Name, vision: Vision, meta: Meta) {
|
||||||
val table: VisionOfTable = (vision as? VisionOfTable)
|
val table: VisionOfTable = (vision as? VisionOfTable)
|
||||||
?: error("VisionOfTable expected but ${vision::class} found")
|
?: error("VisionOfTable expected but ${vision::class} found")
|
||||||
|
|
||||||
|
@ -14,10 +14,10 @@ kscience {
|
|||||||
|
|
||||||
commonMain {
|
commonMain {
|
||||||
api(projects.visionforgeSolid)
|
api(projects.visionforgeSolid)
|
||||||
api(projects.visionforgeComposeHtml)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jsMain {
|
jsMain {
|
||||||
|
api(projects.visionforgeComposeHtml)
|
||||||
implementation(npm("three", "0.143.0"))
|
implementation(npm("three", "0.143.0"))
|
||||||
implementation(npm("three-csg-ts", "3.1.13"))
|
implementation(npm("three-csg-ts", "3.1.13"))
|
||||||
implementation(npm("three.meshline", "1.4.0"))
|
implementation(npm("three.meshline", "1.4.0"))
|
||||||
|
@ -10,7 +10,7 @@ import space.kscience.dataforge.context.*
|
|||||||
import space.kscience.dataforge.meta.Meta
|
import space.kscience.dataforge.meta.Meta
|
||||||
import space.kscience.dataforge.names.*
|
import space.kscience.dataforge.names.*
|
||||||
import space.kscience.visionforge.*
|
import space.kscience.visionforge.*
|
||||||
import space.kscience.visionforge.html.ComposeVisionRenderer
|
import space.kscience.visionforge.html.ComposeHtmlVisionRenderer
|
||||||
import space.kscience.visionforge.solid.*
|
import space.kscience.visionforge.solid.*
|
||||||
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
import space.kscience.visionforge.solid.specifications.Canvas3DOptions
|
||||||
import space.kscience.visionforge.solid.three.compose.ThreeView
|
import space.kscience.visionforge.solid.three.compose.ThreeView
|
||||||
@ -22,7 +22,7 @@ import three.objects.Group as ThreeGroup
|
|||||||
/**
|
/**
|
||||||
* A plugin that handles Three Object3D representation of Visions.
|
* A plugin that handles Three Object3D representation of Visions.
|
||||||
*/
|
*/
|
||||||
public class ThreePlugin : AbstractPlugin(), ComposeVisionRenderer {
|
public class ThreePlugin : AbstractPlugin(), ComposeHtmlVisionRenderer {
|
||||||
override val tag: PluginTag get() = Companion.tag
|
override val tag: PluginTag get() = Companion.tag
|
||||||
|
|
||||||
public val solids: Solids by require(Solids)
|
public val solids: Solids by require(Solids)
|
||||||
@ -186,7 +186,7 @@ public class ThreePlugin : AbstractPlugin(), ComposeVisionRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun DOMScope<Element>.render(client: VisionClient, name: Name, vision: Vision, meta: Meta) {
|
override fun DOMScope<Element>.render(name: Name, vision: Vision, meta: Meta) {
|
||||||
require(vision is Solid) { "Expected Solid but found ${vision::class}" }
|
require(vision is Solid) { "Expected Solid but found ${vision::class}" }
|
||||||
ThreeView(context, vision, null, Canvas3DOptions.read(meta))
|
ThreeView(context, vision, null, Canvas3DOptions.read(meta))
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("space.kscience.gradle.mpp")
|
id("space.kscience.gradle.mpp")
|
||||||
alias(spclibs.plugins.compose)
|
alias(spclibs.plugins.compose)
|
||||||
@ -22,7 +23,6 @@ kscience {
|
|||||||
|
|
||||||
commonMain {
|
commonMain {
|
||||||
api(projects.visionforgeSolid)
|
api(projects.visionforgeSolid)
|
||||||
api(projects.visionforgeComposeHtml)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jvmMain {
|
jvmMain {
|
||||||
|
Loading…
Reference in New Issue
Block a user