Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use fs2.dom.Event[F] and friends #172

Merged
merged 6 commits into from
Jan 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ ThisBuild / tlJdkRelease := Some(8)
val CatsVersion = "2.9.0"
val CatsEffectVersion = "3.4.5"
val Fs2Version = "3.5.0"
val Fs2DomVersion = "0.2.0-M1"
val Fs2DomVersion = "0.2.0-M2"
val MonocleVersion = "3.2.0"

lazy val root =
Expand Down
33 changes: 17 additions & 16 deletions calico/src/main/scala/calico/html/Prop.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import cats.syntax.all.*
import fs2.Pipe
import fs2.Stream
import fs2.concurrent.Signal
import org.scalajs.dom

Expand Down Expand Up @@ -146,37 +147,37 @@ private trait PropModifiers[F[_]](using F: Async[F]):
Modifier.forSignalResource[F, Any, OptionSignalResourceModifier[F, Any, Any], Option[Any]](
_.values) { (m, n) => setPropOption(n, m.name, m.encode) }

final class EventProp[F[_], E, A] private[calico] (key: String, pipe: Pipe[F, E, A]):
final class EventProp[F[_], A] private[calico] (key: String, pipe: Pipe[F, Any, A]):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bye E, hope we don't miss you.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I think it wasn't needed even before, but I only realized when I did this PR.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think this is an orthogonal change. It would bother me because I like to pretend Any doesn't exist, but I see that we need that later on either way, because it helps us saving evil allocs ;)

import EventProp.*

@inline def -->(sink: Pipe[F, A, Nothing]): PipeModifier[F, E] =
@inline def -->(sink: Pipe[F, A, Nothing]): PipeModifier[F] =
PipeModifier(key, pipe.andThen(sink))

@inline private def through[B](pipe: Pipe[F, A, B]): EventProp[F, E, B] =
@inline private def through[B](pipe: Pipe[F, A, B]): EventProp[F, B] =
new EventProp(key, this.pipe.andThen(pipe))

object EventProp:
def apply[F[_], E](key: String): EventProp[F, E, E] =
new EventProp(key, identity(_))
@inline private[html] def apply[F[_], E](key: String, f: Any => E): EventProp[F, E] =
new EventProp(key, _.map(f))

final class PipeModifier[F[_], E] private[calico] (
final class PipeModifier[F[_]] private[calico] (
private[calico] val key: String,
private[calico] val sink: Pipe[F, E, Nothing])
private[calico] val sink: Pipe[F, Any, Nothing])

inline given [F[_], E]: (Functor[EventProp[F, E, _]] & FunctorFilter[EventProp[F, E, _]]) =
_functor.asInstanceOf[Functor[EventProp[F, E, _]] & FunctorFilter[EventProp[F, E, _]]]
private val _functor: Functor[EventProp[Id, Any, _]] & FunctorFilter[EventProp[Id, Any, _]] =
new Functor[EventProp[Id, Any, _]] with FunctorFilter[EventProp[Id, Any, _]]:
def map[A, B](fa: EventProp[Id, Any, A])(f: A => B) = fa.through(_.map(f))
inline given [F[_]]: (Functor[EventProp[F, _]] & FunctorFilter[EventProp[F, _]]) =
_functor.asInstanceOf[Functor[EventProp[F, _]] & FunctorFilter[EventProp[F, _]]]
private val _functor: Functor[EventProp[Id, _]] & FunctorFilter[EventProp[Id, _]] =
new Functor[EventProp[Id, _]] with FunctorFilter[EventProp[Id, _]]:
def map[A, B](fa: EventProp[Id, A])(f: A => B) = fa.through(_.map(f))
def functor = this
def mapFilter[A, B](fa: EventProp[Id, Any, A])(f: A => Option[B]) =
def mapFilter[A, B](fa: EventProp[Id, A])(f: A => Option[B]) =
fa.through(_.mapFilter(f))

private trait EventPropModifiers[F[_]](using F: Async[F]):
import EventProp.*
inline given forPipeEventProp[T <: fs2.dom.Node[F], E]: Modifier[F, T, PipeModifier[F, E]] =
_forPipeEventProp.asInstanceOf[Modifier[F, T, PipeModifier[F, E]]]
private val _forPipeEventProp: Modifier[F, dom.EventTarget, PipeModifier[F, Any]] =
inline given forPipeEventProp[T <: fs2.dom.Node[F]]: Modifier[F, T, PipeModifier[F]] =
_forPipeEventProp.asInstanceOf[Modifier[F, T, PipeModifier[F]]]
private val _forPipeEventProp: Modifier[F, dom.EventTarget, PipeModifier[F]] =
(m, t) => fs2.dom.events(t, m.key).through(m.sink).compile.drain.cedeBackground.void

final class ClassProp[F[_]] private[calico]
Expand Down
29 changes: 16 additions & 13 deletions project/src/main/scala/calico/html/codegen/CalicoGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -245,15 +245,6 @@ private[codegen] class CalicoGenerator(srcManaged: File)
defType: DefType): String = {
val (defs, defGroupComments) = defsAndGroupComments(defSources, printDefGroupComments)

val baseImplDef =
if (outputBaseImpl)
List(
s"@inline private[calico] def ${keyImplName}[Ev <: ${baseScalaJsEventType}](key: String): ${keyKind}[F, Ev, Ev] = ${keyKind}(key)"
)
else {
Nil
}

val headerLines = List(
s"package $eventPropDefsPackagePath",
"",
Expand All @@ -268,17 +259,29 @@ private[codegen] class CalicoGenerator(srcManaged: File)
headerLines = headerLines,
traitCommentLines = traitCommentLines,
traitModifiers = traitModifiers,
traitName = traitName,
traitName = s"${traitName}(using cats.effect.kernel.Async[F])",
traitExtends = traitExtends,
traitThisType = traitThisType,
defType = _ => defType,
keyKind = keyKind,
keyImplName = _ => keyImplName,
baseImplDefComments = baseImplDefComments,
baseImplDef = baseImplDef,
baseImplDefComments = Nil,
baseImplDef = Nil,
outputImplDefs = true,
format = format
).printTrait().getOutput()
) {

override def impl(keyDef: EventPropDef): String = {
List[String](
"EventProp(",
repr(keyDef.domName),
", ",
s"e => fs2.dom.${keyDef.javascriptEventType}(e.asInstanceOf[dom.${keyDef.javascriptEventType}])",
")"
).mkString
}

}.printTrait().getOutput()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,7 @@ object DomDefsGenerator {
(
key,
vals.map(attr =>
attr.copy(scalaJsEventType =
s"F, ${attr.scalaJsEventType}, ${attr.scalaJsEventType}")))
attr.copy(scalaJsEventType = s"F, fs2.${attr.scalaJsEventType}[F]")))
},
printDefGroupComments = true,
traitCommentLines = Nil,
Expand Down Expand Up @@ -313,8 +312,7 @@ object DomDefsGenerator {
(
key,
vals.map(attr =>
attr.copy(scalaJsEventType =
s"F, ${attr.scalaJsEventType}, ${attr.scalaJsEventType}")))
attr.copy(scalaJsEventType = s"F, fs2.${attr.scalaJsEventType}[F]")))
},
printDefGroupComments = true,
traitCommentLines = List(eventPropsDefGroups.head._1),
Expand Down
6 changes: 3 additions & 3 deletions todo-mvc/src/main/scala/todomvc/TodoMvc.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import io.circe.Codec
import io.circe.jawn
import io.circe.syntax.*
import org.http4s.*
import org.scalajs.dom.KeyCode
import org.scalajs.dom.KeyValue

import scala.collection.immutable.SortedMap

Expand Down Expand Up @@ -76,7 +76,7 @@ object TodoMvc extends IOWebApp:
placeholder := "What needs to be done?",
autoFocus := true,
onKeyDown --> {
_.filter(_.keyCode == KeyCode.Enter)
_.filter(_.key == KeyValue.Enter)
.evalMap(_ => self.value.get)
.filterNot(_.isEmpty)
.foreach(store.create(_) *> self.value.set(""))
Expand Down Expand Up @@ -105,7 +105,7 @@ object TodoMvc extends IOWebApp:
cls := "edit",
defaultValue <-- todo.map(_.foldMap(_.text)),
onKeyDown --> {
_.filter(_.keyCode == KeyCode.Enter).foreach(_ => endEdit)
_.filter(_.key == KeyValue.Enter).foreach(_ => endEdit)
},
onBlur --> (_.foreach(_ => endEdit))
)
Expand Down