Skip to content

Commit

Permalink
Naming: ChildrenSeq -> laminar.Seq
Browse files Browse the repository at this point in the history
Hard to find a good name for this. It is an internal Laminar type, so I hope that it is not a big deal that it uses the same name as a Scala collection type. Internally, I always refer to it as `laminar.Seq` instead of just `Seq` to disambiguate it from the Scala collection type.
  • Loading branch information
raquo committed Feb 29, 2024
1 parent 265e58a commit b380508
Show file tree
Hide file tree
Showing 43 changed files with 114 additions and 108 deletions.
3 changes: 2 additions & 1 deletion src/main/scala/com/raquo/laminar/DomApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.raquo.laminar.tags.{HtmlTag, SvgTag, Tag}
import org.scalajs.dom

import scala.annotation.tailrec
import scala.collection.immutable
import scala.scalajs.js
import scala.scalajs.js.{JavaScriptException, |}

Expand Down Expand Up @@ -301,7 +302,7 @@ object DomApi {
@inline private[laminar] def setRefStyle(
ref: dom.html.Element,
styleCssName: String,
prefixes: Seq[String],
prefixes: immutable.Seq[String],
styleValue: String
): Unit = {
// #Note: we use setProperty / removeProperty instead of mutating ref.style directly to support custom CSS props / variables
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package com.raquo.laminar.inserters
package com.raquo.laminar

import com.raquo.ew.{JsArray, JsVector, ewArray}

import scala.scalajs.js

/**
* `ChildrenSeq[A]` is what Laminar needs to render sequences of things.
* `laminar.Seq[A]` is what Laminar needs to render sequences of things.
* It is less powerful than real collection types, and that lets us
* abstract away their differences, such as the lack of Scala semantics
* in JsVector, or the need for ClassTag when mapping a scala.Array.
*
* The purpose of this class is to allow users to provide arbitrary
* collection types to Laminar methods like `children <--`, including
* types that have better performance than native Scala collections,
* such as JsVector, or even a mutable JsArray.
* such as JsVector, or even a mutable js.Array.
*
* As a Laminar user, you shouldn't need to instantiate this class
* yourself, Laminar takes care of that behind the scenes.
Expand All @@ -27,13 +27,13 @@ import scala.scalajs.js
* Note: Mapping over ChildrenSeq may internally translate the source
* collection to another collection type (see comments below).
*/
class ChildrenSeq[+A] private (
class Seq[+A] private (
seq: collection.Seq[A], // nullable
scalaArray: scala.Array[A], // nullable
jsArray: JsArray[A] // nullable
) {

def map[B](project: A => B): ChildrenSeq[B] = {
def map[B](project: A => B): Seq[B] = {
// #TODO[Performance] May want to check this, if we don't get rid of this `map` method first.
// I'm pretty sure that native JS arrays are faster,
// so we convert to JsArray instead of creating a new
Expand All @@ -43,13 +43,13 @@ class ChildrenSeq[+A] private (
if (seq ne null) {
val jsArr = JsArray[B]()
seq.foreach(v => jsArr.push(project(v)))
ChildrenSeq.from(jsArr)
Seq.from(jsArr)
} else if (jsArray ne null) {
ChildrenSeq.from(jsArray.map(project))
Seq.from(jsArray.map(project))
} else {
val jsArr = JsArray[B]()
scalaArray.foreach(v => jsArr.push(project(v)))
ChildrenSeq.from(jsArr)
Seq.from(jsArr)
}
}

Expand All @@ -64,29 +64,29 @@ class ChildrenSeq[+A] private (
}
}

object ChildrenSeq {
object Seq {

private val _empty: ChildrenSeq[Nothing] = from(Nil)
private val _empty: Seq[Nothing] = from(Nil)

@inline def empty[A]: ChildrenSeq[A] = _empty
@inline def empty[A]: Seq[A] = _empty

def from[A](seq: collection.Seq[A]): ChildrenSeq[A] = {
new ChildrenSeq(seq, null, null)
def from[A](seq: collection.Seq[A]): Seq[A] = {
new Seq(seq, null, null)
}

def from[A](array: scala.Array[A]): ChildrenSeq[A] = {
new ChildrenSeq(null, array, null)
def from[A](array: scala.Array[A]): Seq[A] = {
new Seq(null, array, null)
}

def from[A](jsArray: JsArray[A]): ChildrenSeq[A] = {
new ChildrenSeq(null, null, jsArray)
def from[A](jsArray: JsArray[A]): Seq[A] = {
new Seq(null, null, jsArray)
}

def from[A](sjsArray: js.Array[A]): ChildrenSeq[A] = {
new ChildrenSeq(null, null, sjsArray.ew)
def from[A](sjsArray: js.Array[A]): Seq[A] = {
new Seq(null, null, sjsArray.ew)
}

def from[A](jsVector: JsVector[A]): ChildrenSeq[A] = {
new ChildrenSeq(null, null, jsVector.unsafeAsScalaJs.ew)
def from[A](jsVector: JsVector[A]): Seq[A] = {
new Seq(null, null, jsVector.unsafeAsScalaJs.ew)
}
}
6 changes: 3 additions & 3 deletions src/main/scala/com/raquo/laminar/api/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ trait Implicits extends Implicits.LowPriorityImplicits with CompositeValueMapper
implicit renderableSeq: RenderableSeq[Collection]
): Setter[El] = {
Setter { element =>
val settersSeq = renderableSeq.toChildrenSeq(setters)
val settersSeq = renderableSeq.toSeq(setters)
settersSeq.foreach(_.apply(element))
}
}
Expand Down Expand Up @@ -95,7 +95,7 @@ trait Implicits extends Implicits.LowPriorityImplicits with CompositeValueMapper
implicit asModifier: A => Modifier[El],
renderableSeq: RenderableSeq[Collection]
): Modifier[El] = {
Modifier(element => renderableSeq.toChildrenSeq(modifiers).foreach(asModifier(_).apply(element)))
Modifier(element => renderableSeq.toSeq(modifiers).foreach(asModifier(_).apply(element)))
}

// The various collection-to-modifier conversions below are cheaper and better equivalents of
Expand All @@ -115,7 +115,7 @@ trait Implicits extends Implicits.LowPriorityImplicits with CompositeValueMapper
implicit renderableSeq: RenderableSeq[Collection]
): Modifier.Base = {
Modifier { element =>
val nodesSeq = renderableSeq.toChildrenSeq(nodes)
val nodesSeq = renderableSeq.toSeq(nodes)
nodesSeq.foreach(_.apply(element))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.raquo.laminar.inserters

import com.raquo.airstream.core.Observable
import com.raquo.ew.JsMap
import com.raquo.laminar
import com.raquo.laminar.modifiers.{RenderableNode, RenderableSeq}
import com.raquo.laminar.nodes.{ChildNode, ParentNode, ReactiveElement}
import org.scalajs.dom
Expand Down Expand Up @@ -35,8 +36,8 @@ object ChildrenInserter {
// #TODO[Performance] This is not ideal – for CUSTOM renderable components asNodeSeq
// will need to map over the seq, creating a new seq of child nodes.
// Unfortunately, avoiding this is quite complicated.
val newChildren = renderableNode.asNodeChildrenSeq(
renderableSeq.toChildrenSeq(components)
val newChildren = renderableNode.asNodeSeq(
renderableSeq.toSeq(components)
)

// #TODO[Performance] Consider bringing back this eq check. Benchmark performance cost.
Expand All @@ -59,7 +60,7 @@ object ChildrenInserter {
}

def switchToChildren(
newChildren: ChildrenSeq[ChildNode.Base],
newChildren: laminar.Seq[ChildNode.Base],
ctx: InsertContext,
hooks: js.UndefOr[InserterHooks]
): Unit = {
Expand All @@ -86,7 +87,7 @@ object ChildrenInserter {
/** @return New child node count */
private def updateChildren(
prevChildren: JsMap[dom.Node, ChildNode.Base],
nextChildren: ChildrenSeq[ChildNode.Base],
nextChildren: laminar.Seq[ChildNode.Base],
nextChildrenMap: JsMap[dom.Node, ChildNode.Base],
parentNode: ReactiveElement.Base,
sentinelNode: ChildNode.Base,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.raquo.laminar.inserters

import com.raquo.ew.JsMap
import com.raquo.laminar
import com.raquo.laminar.DomApi
import com.raquo.laminar.nodes.{ChildNode, CommentNode, ParentNode, ReactiveElement}
import org.scalajs.dom

import scala.collection.immutable
import scala.scalajs.js

// #TODO[Naming] This feels more like InserterState?
Expand Down Expand Up @@ -186,7 +186,7 @@ object InsertContext {
)
}

private[laminar] def nodesToMap(nodes: ChildrenSeq[ChildNode.Base]): JsMap[dom.Node, ChildNode.Base] = {
private[laminar] def nodesToMap(nodes: laminar.Seq[ChildNode.Base]): JsMap[dom.Node, ChildNode.Base] = {
val acc = new JsMap[dom.Node, ChildNode.Base]()
nodes.foreach { node =>
acc.set(node.ref, node)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.raquo.laminar.inserters

import com.raquo.airstream.core.Transaction
import com.raquo.laminar
import com.raquo.laminar.modifiers.{RenderableNode, RenderableSeq}
import com.raquo.laminar.nodes.{ChildNode, ReactiveElement}

import scala.collection.immutable
import scala.scalajs.js

/**
Expand All @@ -13,7 +13,7 @@ import scala.scalajs.js
* than SingleStaticInserter.
*/
class StaticChildrenInserter(
nodes: ChildrenSeq[ChildNode.Base],
nodes: laminar.Seq[ChildNode.Base],
hooks: js.UndefOr[InserterHooks]
) extends StaticInserter with Hookable[StaticChildrenInserter] {

Expand Down Expand Up @@ -43,7 +43,7 @@ object StaticChildrenInserter {
renderableSeq: RenderableSeq[Collection],
renderableNode: RenderableNode[Component]
): StaticChildrenInserter = {
val children = renderableNode.asNodeChildrenSeq(renderableSeq.toChildrenSeq(components))
val children = renderableNode.asNodeSeq(renderableSeq.toSeq(components))
new StaticChildrenInserter(children, hooks = js.undefined)
}

Expand Down
10 changes: 4 additions & 6 deletions src/main/scala/com/raquo/laminar/modifiers/RenderableNode.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package com.raquo.laminar.modifiers

import com.raquo.ew.JsVector
import com.raquo.laminar.inserters.ChildrenSeq
import com.raquo.laminar
import com.raquo.laminar.nodes.ChildNode

import scala.annotation.implicitNotFound
import scala.collection.immutable

/** `RenderableNode[Component]` is evidence that you can convert a Component to
* a Laminar ChildNode.
Expand All @@ -32,7 +30,7 @@ trait RenderableNode[-Component] {
}

/** For every component, this MUST ALWAYS return the exact same node reference. */
def asNodeChildrenSeq(values: ChildrenSeq[Component]): ChildrenSeq[ChildNode.Base]
def asNodeSeq(values: laminar.Seq[Component]): laminar.Seq[ChildNode.Base]

/** For every component, this MUST ALWAYS return the exact same node reference. */
def asNodeOption(value: Option[Component]): Option[ChildNode.Base]
Expand All @@ -56,7 +54,7 @@ object RenderableNode {

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

override def asNodeChildrenSeq(values: ChildrenSeq[Component]): ChildrenSeq[ChildNode.Base] = values.map(renderNode)
override def asNodeSeq(values: laminar.Seq[Component]): laminar.Seq[ChildNode.Base] = values.map(renderNode)

override def asNodeOption(value: Option[Component]): Option[ChildNode.Base] = value.map(renderNode)
}
Expand All @@ -66,7 +64,7 @@ object RenderableNode {

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

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

override def asNodeOption(value: Option[ChildNode.Base]): Option[ChildNode.Base] = value
}
Expand Down
36 changes: 18 additions & 18 deletions src/main/scala/com/raquo/laminar/modifiers/RenderableSeq.scala
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
package com.raquo.laminar.modifiers

import com.raquo.ew.{JsArray, JsVector}
import com.raquo.laminar.inserters.ChildrenSeq
import com.raquo.laminar

import scala.scalajs.js

// #TODO[Naming] - LSeq + RenderableSeq? RenderableSeq + IsRenderableSeq? // #nc
trait RenderableSeq[-Collection[_]] {

def toChildrenSeq[A](values: Collection[A]): ChildrenSeq[A]
def toSeq[A](values: Collection[A]): laminar.Seq[A]
}

object RenderableSeq {

implicit object collectionSeqRenderable extends RenderableSeq[collection.Seq] {
override def toChildrenSeq[A](values: collection.Seq[A]): ChildrenSeq[A] = {
ChildrenSeq.from(values)
override def toSeq[A](values: collection.Seq[A]): laminar.Seq[A] = {
laminar.Seq.from(values)
}
}

implicit object scalaArrayRenderable extends RenderableSeq[scala.Array] {
override def toChildrenSeq[A](values: scala.Array[A]): ChildrenSeq[A] = {
ChildrenSeq.from(values)
override def toSeq[A](values: scala.Array[A]): laminar.Seq[A] = {
laminar.Seq.from(values)
}
}

implicit object jsArrayRenderable extends RenderableSeq[JsArray] {
override def toChildrenSeq[A](values: JsArray[A]): ChildrenSeq[A] = {
ChildrenSeq.from(values)
override def toSeq[A](values: JsArray[A]): laminar.Seq[A] = {
laminar.Seq.from(values)
}
}

implicit object sjsArrayRenderable extends RenderableSeq[js.Array] {
override def toChildrenSeq[A](values: js.Array[A]): ChildrenSeq[A] = {
ChildrenSeq.from(values)
override def toSeq[A](values: js.Array[A]): laminar.Seq[A] = {
laminar.Seq.from(values)
}
}

implicit object jsVectorRenderable extends RenderableSeq[JsVector] {
override def toChildrenSeq[A](values: JsVector[A]): ChildrenSeq[A] = {
ChildrenSeq.from(values)
override def toSeq[A](values: JsVector[A]): laminar.Seq[A] = {
laminar.Seq.from(values)
}
}

implicit object childrenSeqRenderable extends RenderableSeq[ChildrenSeq] {
override def toChildrenSeq[A](values: ChildrenSeq[A]): ChildrenSeq[A] = {
implicit object laminarSeqRenderable extends RenderableSeq[laminar.Seq] {
override def toSeq[A](values: laminar.Seq[A]): laminar.Seq[A] = {
values
}
}

// object optionRenderable extends RenderableSeq[Option] {
// override def toChildrenSeq[A](maybeValue: Option[A]): ChildrenSeq[A] = {
// ChildrenSeq.from(maybeValue.toList)
// override def toSeq[A](maybeValue: Option[A]): laminar.Seq[A] = {
// laminar.Seq.from(maybeValue.toList)
// }
// }
//
// object jsUndefOrRenderable extends RenderableSeq[js.UndefOr] {
// override def toChildrenSeq[A](maybeValue: js.UndefOr[A]): ChildrenSeq[A] = {
// ChildrenSeq.from(JsArray.from(maybeValue))
// override def toSeq[A](maybeValue: js.UndefOr[A]): laminar.Seq[A] = {
// laminar.Seq.from(JsArray.from(maybeValue))
// }
// }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.raquo.laminar.receivers

import com.raquo.airstream.core.Source
import com.raquo.laminar.inserters.{ChildrenInserter, ChildrenSeq, DynamicInserter}
import com.raquo.laminar
import com.raquo.laminar.inserters.{ChildrenInserter, DynamicInserter}
import com.raquo.laminar.modifiers.{RenderableNode, RenderableSeq}
import com.raquo.laminar.nodes.ChildNode

Expand All @@ -16,7 +17,7 @@ object ChildrenReceiver {
* children(component1, component2) <-- signalOfBoolean
*/
def apply(nodes: ChildNode.Base*): LockedChildrenReceiver = {
new LockedChildrenReceiver(ChildrenSeq.from(nodes))
new LockedChildrenReceiver(laminar.Seq.from(nodes))
}

implicit class RichChildrenReceiver(val self: ChildrenReceiver.type) extends AnyVal {
Expand All @@ -31,7 +32,7 @@ object ChildrenReceiver {
implicit renderableNode: RenderableNode[Component],
renderableSeq: RenderableSeq[Collection]
): LockedChildrenReceiver = {
val nodes = renderableNode.asNodeChildrenSeq(renderableSeq.toChildrenSeq(components))
val nodes = renderableNode.asNodeSeq(renderableSeq.toSeq(components))
new LockedChildrenReceiver(nodes)
}

Expand Down
Loading

0 comments on commit b380508

Please sign in to comment.