Skip to content

Commit

Permalink
API: Simplify public RenderableNode constructor
Browse files Browse the repository at this point in the history
- Also replace `asNodeIterable` with `asNodeJsVector`
  • Loading branch information
raquo committed Feb 27, 2024
1 parent 5a023c4 commit b46941d
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 17 deletions.
34 changes: 23 additions & 11 deletions src/main/scala/com/raquo/laminar/modifiers/RenderableNode.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.raquo.laminar.modifiers

import com.raquo.laminar.nodes.{ChildNode, CommentNode}
import com.raquo.ew.JsVector
import com.raquo.laminar.nodes.ChildNode

import scala.annotation.implicitNotFound
import scala.collection.immutable
Expand Down Expand Up @@ -28,7 +29,7 @@ trait RenderableNode[-Component] {
def asNodeSeq(values: immutable.Seq[Component]): immutable.Seq[ChildNode.Base]

/** For every component in the sequence, this MUST ALWAYS return the exact same node reference. */
def asNodeIterable(values: Iterable[Component]): Iterable[ChildNode.Base]
def asNodeJsVector(values: JsVector[Component]): JsVector[ChildNode.Base]

/** For every component, this MUST ALWAYS return the exact same node reference. */
def asNodeOption(value: Option[Component]): Option[ChildNode.Base]
Expand All @@ -40,24 +41,35 @@ object RenderableNode {
* A `Component` must have a 1-to-1 relationship to a Laminar ChildNode.
* Your Component class/trait should have something like `val node: ChildNode.Base`
* or `lazy val node: ChildNode.Base` in it, it must not be a `var` or a `def`.
*
* Note: This implementation works for essentially all use cases,
* and while it is USUALLY the most efficient, that is not always the case.
* For example, `nodeRenderable` below is a special implementation that
* avoids mapping over the input collections because that is not needed.
*/
def apply[Component](
renderNode: Component => ChildNode.Base,
renderNodeSeq: immutable.Seq[Component] => immutable.Seq[ChildNode.Base],
renderNodeIterable: Iterable[Component] => Iterable[ChildNode.Base],
renderNodeOption: Option[Component] => Option[ChildNode.Base]
renderNode: Component => ChildNode.Base
): RenderableNode[Component] = new RenderableNode[Component] {

override def asNode(value: Component): ChildNode.Base = renderNode(value)

override def asNodeSeq(values: immutable.Seq[Component]): immutable.Seq[ChildNode.Base] = renderNodeSeq(values)
override def asNodeSeq(values: immutable.Seq[Component]): immutable.Seq[ChildNode.Base] = values.map(renderNode)

override def asNodeIterable(values: Iterable[Component]): Iterable[ChildNode.Base] = renderNodeIterable(values)
override def asNodeJsVector(values: JsVector[Component]): JsVector[ChildNode.Base] = values.map(renderNode)

override def asNodeOption(value: Option[Component]): Option[ChildNode.Base] = renderNodeOption(value)
override def asNodeOption(value: Option[Component]): Option[ChildNode.Base] = value.map(renderNode)
}

implicit val nodeRenderable: RenderableNode[ChildNode.Base] =
RenderableNode[ChildNode.Base](identity, identity, identity, identity)
/** This low level implementation avoids mapping over collections for maximum efficiency. */
implicit val nodeRenderable: RenderableNode[ChildNode.Base] = new RenderableNode[ChildNode.Base] {

override def asNode(value: ChildNode.Base): ChildNode.Base = value

override def asNodeSeq(values: Seq[ChildNode.Base]): Seq[ChildNode.Base] = values

override def asNodeJsVector(values: JsVector[ChildNode.Base]): JsVector[ChildNode.Base] = values

override def asNodeOption(value: Option[ChildNode.Base]): Option[ChildNode.Base] = value
}

}
3 changes: 1 addition & 2 deletions src/test/scala/com/raquo/laminar/ChildReceiverSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,7 @@ class ChildReceiverSpec extends UnitSpec {
val node: Span = span(text)
}

implicit val componentRenderable: RenderableNode[Component] =
RenderableNode(_.node, _.map(_.node), _.map(_.node), _.map(_.node))
implicit val componentRenderable: RenderableNode[Component] = RenderableNode(_.node)


val v = Var(true)
Expand Down
3 changes: 1 addition & 2 deletions src/test/scala/com/raquo/laminar/ChildrenReceiverSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -968,8 +968,7 @@ class ChildrenReceiverSpec extends UnitSpec with BeforeAndAfter {
val node: Span = span(text)
}

implicit val componentRenderable: RenderableNode[Component] =
RenderableNode(_.node, _.map(_.node), _.map(_.node), _.map(_.node))
implicit val componentRenderable: RenderableNode[Component] = RenderableNode(_.node)

val v = Var(true)

Expand Down
3 changes: 1 addition & 2 deletions src/test/scala/com/raquo/laminar/RenderableSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ class RenderableSpec extends UnitSpec {
)
}

implicit val componentRenderable: RenderableNode[Component] =
RenderableNode(_.node, _.map(_.node), _.map(_.node), _.map(_.node))
implicit val componentRenderable: RenderableNode[Component] = RenderableNode(_.node)


it("Component rendering") {
Expand Down

0 comments on commit b46941d

Please sign in to comment.