Skip to content

Commit

Permalink
API: Use by-name arguments for when and whenNot.
Browse files Browse the repository at this point in the history
- Note: Scala 2 does not support by-name varargs, so in Scala 2 these methods are now limited to at most one argument
- This required an alternative implementation vs #169.
  • Loading branch information
raquo committed Jan 16, 2025
1 parent 343811c commit 44d927c
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 57 deletions.
1 change: 1 addition & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ runner.dialect = "scala213"
# - Maybe make a separate config for these files, that has two lines before method names, see https://scalameta.org/scalafmt/docs/configuration.html#fileoverride
# - Does this exclusion actually work? IntelliJ seems to ignore it
project.excludePaths = [
"glob:**/src/*/scala-3/**",
"glob:**/src/main/scala/com/raquo/laminar/defs/**",
"glob:**/project/VersionHelper.scala",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.raquo.laminar.api

trait LaminarPlatformSpecific { this: LaminarAliases =>

/** Returns a Modifier that applies another Modifier if `condition` is true
*
* Note:
* - The inner Modifier is evaluated only if `condition` is `true`.
* - Scala 3 version of `when` supports passing multiple modifiers.
*/
def when[El <: Element](condition: Boolean)(mod: => Modifier[El]): Modifier[El] = {
if (condition) {
mod // implicitly converted to a single modifier
} else {
Modifier.empty
}
}

/** Returns a Modifier that applies another Modifier if `condition` is true.
*
* Note:
* - The inner Modifier is evaluated only if `condition` is `false`.
* - Scala 3 version of `when` supports passing multiple modifiers.
*/
@inline def whenNot[El <: Element](condition: Boolean)(mod: => Modifier[El]): Modifier[El] = when(!condition)(mod)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.raquo.laminar.api

trait LaminarPlatformSpecific { this: LaminarAliases =>

/** Returns a Modifier that applies one or more Modifiers if `condition` is `true`.
* Note: The inner Modifier-s are evaluated only if the condition is `true`.
*/
def when[El <: Element](condition: Boolean)(mods: => Modifier[El]*): Modifier[El] = {
if (condition) {
mods // implicitly converted to a single modifier
} else {
Modifier.empty
}
}

/** Returns a Modifier that applies one or more modifiers if `condition` is `true`.
* Note: The inner Modifier-s are evaluated only if the condition is `false`.
*/
@inline def whenNot[El <: Element](condition: Boolean)(mods: => Modifier[El]*): Modifier[El] = when(!condition)(mods)
}
19 changes: 3 additions & 16 deletions src/main/scala/com/raquo/laminar/api/Laminar.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.raquo.laminar.api

import com.raquo.airstream.web.DomEventStream
import com.raquo.laminar.{DomApi, nodes}
import com.raquo.laminar.{nodes, DomApi}
import com.raquo.laminar.defs.attrs.{AriaAttrs, HtmlAttrs, SvgAttrs}
import com.raquo.laminar.defs.complex.{ComplexHtmlKeys, ComplexSvgKeys}
import com.raquo.laminar.defs.eventProps.{DocumentEventProps, GlobalEventProps, WindowEventProps}
Expand All @@ -19,7 +19,8 @@ import org.scalajs.dom
// @TODO[Performance] Check if order of traits matters for quicker access (given trait linearization). Not sure how it's encoded in JS.

trait Laminar
extends HtmlTags
extends LaminarPlatformSpecific
with HtmlTags
with HtmlAttrs
with HtmlProps
with GlobalEventProps
Expand Down Expand Up @@ -251,20 +252,6 @@ with Implicits {

//

/** Modifier that applies one or more modifiers if `condition` is true */
def when[El <: Element](condition: Boolean)(mods: Modifier[El]*): Modifier[El] = {
if (condition) {
mods // implicitly converted to a single modifier
} else {
emptyMod
}
}

/** Modifier that applies one or more modifiers if `condition` is true */
@inline def whenNot[El <: Element](condition: Boolean)(mods: Modifier[El]*): Modifier[El] = when(!condition)(mods)

//

/** Creates controlled input block.
* See [[https://laminar.dev/documentation#controlled-inputs Controlled Inputs docs]]
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.raquo.laminar.tests.basic

import com.raquo.laminar.api.L._

import com.raquo.laminar.utils.UnitSpec

class ModSpecScala2 extends UnitSpec {

it("when keyword") {

var evaluatedUsed = false
var evaluatedUnused = false

val el = div(
when(true) {
evaluatedUsed = true
title("foo")
},
when(false) {
evaluatedUnused = true
title("bar")
},
when(true)(
height.px(100)
),
when(true) {
List(minAttr("10"), maxAttr("20"))
},
when(true)(div("hello")),
when(true) {
onMountInsert(_ =>
"world"
)
},
when(true) {
text <-- Val("text")
}
)

mount(el)

expectNode(div.of(
title is "foo",
height is "100px",
minAttr is "10",
maxAttr is "20",
div.of("hello"),
"world",
"text"
))

assertEquals(evaluatedUsed, true)
assertEquals(evaluatedUnused, false)
}
}
56 changes: 56 additions & 0 deletions src/test/scala-3/com/raquo/laminar/tests/basic/ModSpecScala3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.raquo.laminar.tests.basic

import com.raquo.laminar.api.L.{*, given}
import com.raquo.laminar.utils.UnitSpec

class ModSpecScala3 extends UnitSpec {

it("when keyword") {

var evaluatedUsed = false
var evaluatedUnused = false

val el = div(
when(true) {
evaluatedUsed = true
title("foo")
},
when(false) {
evaluatedUnused = true
title("bar")
},
when(true)(
height.px(100),
width.px(200)
),
when(true) {
List(minAttr("10"), maxAttr("20"))
},
when(true)(div("hello")),
when(true) {
onMountInsert(_ =>
"world"
)
},
when(true) {
text <-- Val("text")
}
)

mount(el)

expectNode(div.of(
title is "foo",
height is "100px",
width is "200px",
minAttr is "10",
maxAttr is "20",
div.of("hello"),
"world",
"text"
))

assertEquals(evaluatedUsed, true)
assertEquals(evaluatedUnused, false)
}
}
41 changes: 0 additions & 41 deletions src/test/scala/com/raquo/laminar/tests/basic/ModSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,6 @@ import scala.scalajs.js

class ModSpec extends UnitSpec {

it("when keyword") {

val el = div(
when(true) {
title("foo")
},
when(false) {
title("bar")
},
when(true)(
height.px(100),
width.px(200)
),
when(true) {
List(minAttr("10"), maxAttr("20"))
},
when(true)(div("hello")),
when(true) {
onMountInsert(_ =>
"world"
)
},
when(true) {
text <-- Val("text")
}
)

mount(el)

expectNode(div.of(
title is "foo",
height is "100px",
width is "200px",
minAttr is "10",
maxAttr is "20",
div.of("hello"),
"world",
"text"
))
}

it("nodeSeq type inference") {

val nodes = nodeSeq("text", span("element"))
Expand Down

0 comments on commit 44d927c

Please sign in to comment.