diff --git a/examples/main-launcher/index.html b/examples/main-launcher/index.html
index 0d93745b..c4d9bfaa 100644
--- a/examples/main-launcher/index.html
+++ b/examples/main-launcher/index.html
@@ -10,7 +10,6 @@
Main launcher example
-
diff --git a/examples/main-launcher/src/main/scala/example/ChatApp.scala b/examples/main-launcher/src/main/scala/example/ChatApp.scala
index 2f0ff9f1..5b24a7b9 100644
--- a/examples/main-launcher/src/main/scala/example/ChatApp.scala
+++ b/examples/main-launcher/src/main/scala/example/ChatApp.scala
@@ -16,6 +16,7 @@ object ChatApp extends TyrianApp[ChatAppMsg, ChatAppModel]:
def update(model: ChatAppModel): ChatAppMsg => (ChatAppModel, Cmd[IO, ChatAppMsg]) =
case ChatInput(input) => (model.copy(chatInput = input), Cmd.None)
case SendChat() => (model.copy(chatInput = "", messages = model.messages :+ model.chatInput), Cmd.None)
+ case RouteMsg() => (model, Cmd.None)
def view(model: ChatAppModel): Html[ChatAppMsg] =
div(
@@ -27,12 +28,16 @@ object ChatApp extends TyrianApp[ChatAppMsg, ChatAppModel]:
button(onClick(SendChat()))("Send Chat")
)
+ def router: Location => ChatAppMsg =
+ _ => RouteMsg()
+
def subscriptions(model: ChatAppModel): Sub[IO, ChatAppMsg] =
Sub.None
case class ChatAppModel(chatInput: String, messages: Seq[String])
sealed abstract class ChatAppMsg
+case class RouteMsg() extends ChatAppMsg
case class ChatInput(input: String) extends ChatAppMsg
case class SendChat() extends ChatAppMsg
diff --git a/examples/main-launcher/src/main/scala/example/CounterApp.scala b/examples/main-launcher/src/main/scala/example/CounterApp.scala
index 9169c248..955c9bc3 100644
--- a/examples/main-launcher/src/main/scala/example/CounterApp.scala
+++ b/examples/main-launcher/src/main/scala/example/CounterApp.scala
@@ -19,6 +19,7 @@ object CounterApp extends TyrianApp[Msg, Model]:
def update(model: Model): Msg => (Model, Cmd[IO, Msg]) =
case Msg.Increment => (model + 1, Cmd.None)
case Msg.Decrement => (model - 1, Cmd.None)
+ case Msg.RouteMsg => (model, Cmd.None)
def view(model: Model): Html[Msg] =
div(
@@ -27,6 +28,9 @@ object CounterApp extends TyrianApp[Msg, Model]:
button(onClick(Msg.Increment))("+")
)
+ def router: Location => Msg =
+ _ => Msg.RouteMsg
+
def subscriptions(model: Model): Sub[IO, Msg] =
Sub.None
@@ -39,4 +43,4 @@ object Model:
def -(other: Int): Model = i - other
enum Msg:
- case Increment, Decrement
+ case Increment, Decrement, RouteMsg
diff --git a/examples/main-launcher/src/main/scala/example/Main.scala b/examples/main-launcher/src/main/scala/example/Main.scala
index 9ee01de2..a726eb14 100644
--- a/examples/main-launcher/src/main/scala/example/Main.scala
+++ b/examples/main-launcher/src/main/scala/example/Main.scala
@@ -6,9 +6,8 @@ import tyrian.*
object Main {
def main(args: Array[String]): Unit =
- TyrianAppF.launchOnContentLoaded(Map(
- "CounterApp" -> (() => CounterApp),
- "ChatApp" -> (() => ChatApp)
- ))
- println("")
+ TyrianApp.onLoad(
+ "CounterApp" -> CounterApp,
+ "ChatApp" -> ChatApp
+ )
}
\ No newline at end of file
diff --git a/tyrian-io/src/main/scala/tyrian/TyrianApp.scala b/tyrian-io/src/main/scala/tyrian/TyrianApp.scala
index 89d7501f..696d339a 100644
--- a/tyrian-io/src/main/scala/tyrian/TyrianApp.scala
+++ b/tyrian-io/src/main/scala/tyrian/TyrianApp.scala
@@ -1,6 +1,7 @@
package tyrian
import cats.effect.IO
+import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import cats.effect.unsafe.implicits.global
import tyrian.TyrianAppF
@@ -13,3 +14,10 @@ trait TyrianApp[Msg, Model] extends TyrianAppF[IO, Msg, Model]:
val run: Resource[IO, TyrianRuntime[IO, Model, Msg]] => Unit =
_.map(_.start()).useForever.unsafeRunAndForget()
+
+object TyrianApp:
+ def onLoad[F[_] : Async](appDirectory: (String, TyrianAppF[F, _, _])*): Unit =
+ TyrianAppF.onLoad(appDirectory: _*)
+
+ def launch[F[_] : Async](appDirectory: (String, TyrianAppF[F, _, _])*): Unit =
+ TyrianAppF.launch(appDirectory: _*)
diff --git a/tyrian-zio/src/main/scala/tyrian/TyrianApp.scala b/tyrian-zio/src/main/scala/tyrian/TyrianApp.scala
index 591bda77..be2042be 100644
--- a/tyrian-zio/src/main/scala/tyrian/TyrianApp.scala
+++ b/tyrian-zio/src/main/scala/tyrian/TyrianApp.scala
@@ -1,6 +1,7 @@
package tyrian
import cats.effect.Async
+import cats.effect.kernel.Async
import cats.effect.kernel.Resource
import tyrian.TyrianAppF
import tyrian.runtime.TyrianRuntime
@@ -20,3 +21,10 @@ trait TyrianApp[Msg, Model](using Async[Task]) extends TyrianAppF[Task, Msg, Mod
Unsafe.unsafe { implicit unsafe =>
runtime.unsafe.run(runnable).getOrThrowFiberFailure()
}
+
+object TyrianApp:
+ def onLoad[F[_] : Async](appDirectory: (String, TyrianAppF[F, _, _])*): Unit =
+ TyrianAppF.onLoad(appDirectory: _*)
+
+ def launch[F[_] : Async](appDirectory: (String, TyrianAppF[F, _, _])*): Unit =
+ TyrianAppF.launch(appDirectory: _*)
diff --git a/tyrian/js/src/main/scala/tyrian/TyrianAppF.scala b/tyrian/js/src/main/scala/tyrian/TyrianAppF.scala
index aa4324ec..e5e66c68 100644
--- a/tyrian/js/src/main/scala/tyrian/TyrianAppF.scala
+++ b/tyrian/js/src/main/scala/tyrian/TyrianAppF.scala
@@ -134,7 +134,7 @@ trait TyrianAppF[F[_]: Async, Msg, Model]:
object TyrianAppF:
/** Launch app instances after DOMContentLoaded.
*/
- def launchOnContentLoaded[F[_] : Async](appDirectory: Map[String, () => TyrianAppF[F, _, _]]): Unit = {
+ def onLoad[F[_] : Async](appDirectory: (String, TyrianAppF[F, _, _])*): Unit =
val documentReady = new Promise((resolve, _reject) => {
document.addEventListener("DOMContentLoaded", _ => {
resolve(())
@@ -144,29 +144,28 @@ object TyrianAppF:
}
})
documentReady.`then`(_ => {
- launch[F](appDirectory)
+ launch[F](appDirectory: _*)
})
- }
/** Find data-tyrian-app HTMLElements and launch corresponding TyrianAppF instances
*/
- def launch[F[_] : Async](appDirectory: Map[String, () => TyrianAppF[F, _, _]]): Unit = {
+ def launch[F[_] : Async](appDirectory: (String, TyrianAppF[F, _, _])*): Unit =
+ val appMap = appDirectory.toMap
for {
element <- document.querySelectorAll("[data-tyrian-app]")
} yield {
val tyrianAppElement = element.asInstanceOf[HTMLElement]
+ val tyrianAppName = tyrianAppElement.dataset.get("tyrianApp")
val appSupplierOption = for {
- appName <- tyrianAppElement.dataset.get("tyrianApp")
- appSupplier <- appDirectory.get(appName)
+ appName <- tyrianAppName
+ appSupplier <- appMap.get(appName)
} yield appSupplier
appSupplierOption match
case Some(appSupplier) =>
- appSupplier().launch(tyrianAppElement, appElementFlags(tyrianAppElement))
+ appSupplier.launch(tyrianAppElement, appElementFlags(tyrianAppElement))
case _ =>
- // Log a warning message?
- ()
+ println(s"Could not find an app entry for ${tyrianAppName.getOrElse("")}")
}
- }
private def appElementFlags(tyrianAppElement: HTMLElement): Map[String,String] =
val appFlags = for {