PurpleKingdomGames / tyrian

Elm-inspired Scala UI library.
https://tyrian.indigoengine.io/
MIT License
350 stars 26 forks source link

Provide an `empty` Elem and support rendering of `Option[Elem]` #205

Closed Tvaroh closed 1 year ago

Tvaroh commented 1 year ago

My use case simplified is my model has an errorMessage: Option[String] field which I want to render when there's something there. So it would be nice to have an empty: Elem provided out of the box which would allow to write something like this:

errorMessage.map(span(_)).getOrElse(empty)

Although that .getOrElse(empty) can get repetitive and annoying very quickly, so some extension or implicit conversion would be great to support rendering Option[Elem]:

errorMessage.map(span(_))
// or
errorMessage.map(span(_)).orEmpty
davesmith00000 commented 1 year ago

Thanks for reporting, this is a good idea that I'll look into. It requires a new primitive type to be added and for the renderer to understand that it needs to be ignored, but that's doable.

In the meantime, for others facing the same issue, there is a workaround:

All the tags have a number of constructors to make writing them convenient, but in essence they all boil down to Lists of stuff.

So you can solve this situation with list operations:

div(id := "test")(
  p("a"),
  Option(p("b")), // doesn't work
  p("c")
)

Like this (for example):

div(id := "test")(
  List(p("a")) ++
    Option(p("b")).toList ++
    List(p("c"))
)

It's noisy, but it works.

Tvaroh commented 1 year ago

It's a bit intrusive approach, would require too much changes after. I'd rather do .getOrElse(text("")) or something like that, even though it's ugly as well. Even opt.orNull would be kinda acceptable if null was allowed there.

davesmith00000 commented 1 year ago

I agree @Tvaroh, don't worry. Another person was asking the same question so I thought I'd quickly explain the workaround for now. I'm working on a solution. :+1:

davesmith00000 commented 1 year ago

Here we go: https://github.com/PurpleKingdomGames/tyrian/pull/208

This allows for this:

import tyrian.syntax.*

div(
  p("Optional elements:"),
  Option(p("This will show, but then... nothing!")).orEmpty,
  Option.empty[Html[Msg]].orEmpty,
  p("Then something with a predicate"),
  if true then p("Showing") else Empty,
  if false then p("Showing") else Empty
)
Tvaroh commented 1 year ago

@davesmith00000 perfect, Sir! 🙏

davesmith00000 commented 1 year ago

@Tvaroh you can give it a shot: https://github.com/PurpleKingdomGames/tyrian/releases/tag/v0.7.1

(It should be available by now, if not, wait a bit and try again! You'll need to upgrade to Scala 3.3.0.)