diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/ComputableComponent.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/ComputableComponent.scala new file mode 100644 index 0000000..3272cad --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/ComputableComponent.scala @@ -0,0 +1,26 @@ +package works.iterative.ui.components.laminar + +import com.raquo.laminar.api.L.{*, given} +import works.iterative.ui.model.Computable +import works.iterative.ui.model.Computable.* +import com.raquo.laminar.tags.HtmlTag +import com.raquo.laminar.nodes.ReactiveHtmlElement +import com.raquo.laminar.nodes.CommentNode +import org.scalajs.dom + +class ComputableComponent[Ref <: dom.html.Element]( + as: HtmlTag[Ref], + mods: Mod[ReactiveHtmlElement[Ref]]* +)( + c: Signal[Computable[HtmlElement]] +): + val element: ReactiveHtmlElement[Ref] = as( + mods, + child <-- c.map { + case Uninitialized => CommentNode("Uninitialized") + case Computing(_) => CommentNode("Computing") + case Ready(element) => element + case Failed(_) => CommentNode("Failed") + case Recomputing(_, element) => element + } + ) diff --git a/ui/js/src/main/scala/works/iterative/ui/components/laminar/ComputableComponent.scala b/ui/js/src/main/scala/works/iterative/ui/components/laminar/ComputableComponent.scala new file mode 100644 index 0000000..3272cad --- /dev/null +++ b/ui/js/src/main/scala/works/iterative/ui/components/laminar/ComputableComponent.scala @@ -0,0 +1,26 @@ +package works.iterative.ui.components.laminar + +import com.raquo.laminar.api.L.{*, given} +import works.iterative.ui.model.Computable +import works.iterative.ui.model.Computable.* +import com.raquo.laminar.tags.HtmlTag +import com.raquo.laminar.nodes.ReactiveHtmlElement +import com.raquo.laminar.nodes.CommentNode +import org.scalajs.dom + +class ComputableComponent[Ref <: dom.html.Element]( + as: HtmlTag[Ref], + mods: Mod[ReactiveHtmlElement[Ref]]* +)( + c: Signal[Computable[HtmlElement]] +): + val element: ReactiveHtmlElement[Ref] = as( + mods, + child <-- c.map { + case Uninitialized => CommentNode("Uninitialized") + case Computing(_) => CommentNode("Computing") + case Ready(element) => element + case Failed(_) => CommentNode("Failed") + case Recomputing(_, element) => element + } + ) diff --git a/ui/shared/src/main/scala/works/iterative/ui/model/Computable.scala b/ui/shared/src/main/scala/works/iterative/ui/model/Computable.scala index fa537d0..2eae37d 100644 --- a/ui/shared/src/main/scala/works/iterative/ui/model/Computable.scala +++ b/ui/shared/src/main/scala/works/iterative/ui/model/Computable.scala @@ -2,6 +2,7 @@ import works.iterative.core.UserMessage import java.time.Instant +import zio.prelude.Covariant /** A class representing the states of a model that needs computation */ @@ -46,3 +47,12 @@ case class Failed(error: UserMessage) extends Computable[Nothing]: override def update[B](m: B): Computable[B] = Ready(m) override def started: Computable[Nothing] = Computing(Instant.now()) + + given Covariant[Computable] with + def map[A, B](f: A => B): Computable[A] => Computable[B] = + _ match + case Uninitialized => Uninitialized + case Computing(start) => Computing(start) + case Ready(model) => Ready(f(model)) + case Failed(error) => Failed(error) + case Recomputing(start, model) => Recomputing(start, f(model))