Skip to content

Commit fbf0ae4

Browse files
authored
Merge pull request #177 from armanbilge/update/fs2-dom-0.2.0-M3
Update fs2-dom to 0.2.0-M3
2 parents 2962749 + c179c40 commit fbf0ae4

File tree

6 files changed

+47
-46
lines changed

6 files changed

+47
-46
lines changed

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ ThisBuild / tlJdkRelease := Some(8)
2121
val CatsVersion = "2.9.0"
2222
val CatsEffectVersion = "3.4.6"
2323
val Fs2Version = "3.5.0"
24-
val Fs2DomVersion = "0.2.0-M2"
24+
val Fs2DomVersion = "0.2.0-M3"
2525
val MonocleVersion = "3.2.0"
2626

2727
lazy val root =

calico/src/main/scala/calico/IOWebApp.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@ import calico.syntax.*
2020
import calico.unsafe.given
2121
import cats.effect.IO
2222
import cats.effect.Resource
23-
import org.scalajs.dom
23+
import fs2.dom.Window
2424

2525
trait IOWebApp:
2626

2727
def rootElementId: String = "app"
2828

29+
val window: Window[IO] = Window[IO]
30+
2931
def render: Resource[IO, fs2.dom.HtmlElement[IO]]
3032

3133
def main(args: Array[String]): Unit =
32-
val document = fs2.dom.Document[IO]
33-
val rootElement = document.getElementById(rootElementId).map(_.get)
34+
val rootElement = window.document.getElementById(rootElementId).map(_.get)
3435
rootElement.flatMap(render.renderInto(_).useForever).unsafeRunAndForget()

calico/src/main/scala/calico/html/Html.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package html
2020
import cats.effect.IO
2121
import cats.effect.kernel.Async
2222
import cats.effect.kernel.Resource
23+
import fs2.dom.Dom
2324

2425
object io extends Html[IO]
2526

@@ -41,6 +42,8 @@ sealed class Html[F[_]](using F: Async[F])
4142
KeyedChildrenModifiers[F],
4243
HtmlAttrModifiers[F]:
4344

45+
given Dom[F] = Dom.forAsync
46+
4447
def aria: Aria[F] = Aria[F]
4548

4649
def cls: ClassProp[F] = ClassProp[F]

docs/router.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
libraryDependencies += "com.armanbilge" %%% "calico-router" % "@VERSION@"
77
```
88

9-
`calico-router` is built only with Cats Effect, FS2, http4s, and scala-js-dom, and has no dependency on `calico` core, such that it is framework-agnostic. Integration with **Calico** is seamless.
9+
`calico-router` is built only with Cats Effect, FS2-DOM, and http4s, and has no dependency on `calico` core, such that it is framework-agnostic. Integration with **Calico** is seamless.
1010

1111
Special thanks to [@jberggg](https://github.com/jberggg) whose [fs2-spa-router](https://github.com/jberggg/fs2-spa-router) inspired this project.
1212

@@ -40,7 +40,7 @@ import fs2.dom.*
4040
import org.http4s.*
4141
import org.http4s.syntax.all.*
4242

43-
val app = Resource.eval(Router(Location[IO], History[IO, Unit])).flatMap { router =>
43+
val app = Resource.eval(Router(Window[IO])).flatMap { router =>
4444
(SignallingRef[IO].of(0), SignallingRef[IO].of(0)).tupled.toResource.flatMap {
4545
(helloCounter, countCounter) =>
4646

router/src/main/scala/calico/router/Router.scala

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ import fs2.Stream
2626
import fs2.concurrent.Signal
2727
import fs2.concurrent.Topic
2828
import fs2.dom.Dom
29-
import fs2.dom.History
30-
import fs2.dom.Location
29+
import fs2.dom.Window
3130
import org.http4s.Uri
3231
import org.scalajs.dom
3332
import org.scalajs.macrotaskexecutor.MacrotaskExecutor
@@ -81,10 +80,9 @@ abstract class Router[F[_]] private ():
8180
Resource.eval(routes).flatMap(dispatch)
8281

8382
object Router:
84-
def apply[F[_]: Dom](location: Location[F], history: History[F, Unit])(
85-
using F: Async[F]): F[Router[F]] =
83+
def apply[F[_]: Dom](window: Window[F])(using F: Async[F]): F[Router[F]] =
8684
Topic[F, Uri].map { gps =>
87-
val _location = location
85+
val history = window.history[Unit]
8886
new:
8987
export history.{back, forward, go, length}
9088

@@ -101,15 +99,15 @@ object Router:
10199
yield ()
102100

103101
private def mkAbsolute(uri: Uri): F[Uri] =
104-
_location.href.get.flatMap(Uri.fromString(_).liftTo).map(_.resolve(uri))
102+
window.location.href.get.flatMap(Uri.fromString(_).liftTo).map(_.resolve(uri))
105103

106104
def location = new:
107-
def get = _location.href.get.flatMap(Uri.fromString(_).liftTo[F])
105+
def get = window.location.href.get.flatMap(Uri.fromString(_).liftTo[F])
108106
def continuous = Stream.repeatEval(get)
109107
def discrete = history.state.discrete.evalMap(_ => get).merge(gps.subscribe(0))
110108

111109
def dispatch(routes: Routes[F]) = for
112-
container <- fs2.dom.Document[F].createElement("div").toResource
110+
container <- window.document.createElement("div").toResource
113111
currentRoute <- Resource.make(
114112
F.ref(Option.empty[(Unique.Token, fs2.dom.Node[F], RefSink[F, Uri], F[Unit])]))(
115113
_.get.flatMap(_.foldMapA(_._4)))

todo-mvc/src/main/scala/todomvc/TodoMvc.scala

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -40,33 +40,32 @@ import scala.collection.immutable.SortedMap
4040

4141
object TodoMvc extends IOWebApp:
4242

43-
def render = (TodoStore.make, Router(Location[IO], History[IO, Unit]).toResource).flatMapN {
44-
(store, router) =>
45-
router.dispatch {
46-
Routes.one[IO] {
47-
case uri if uri.fragment == Some("/active") => Filter.Active
48-
case uri if uri.fragment == Some("/completed") => Filter.Completed
49-
case _ => Filter.All
50-
} { filter =>
43+
def render = (TodoStore(window), Router(window).toResource).flatMapN { (store, router) =>
44+
router.dispatch {
45+
Routes.one[IO] {
46+
case uri if uri.fragment == Some("/active") => Filter.Active
47+
case uri if uri.fragment == Some("/completed") => Filter.Completed
48+
case _ => Filter.All
49+
} { filter =>
50+
div(
51+
cls := "todoapp",
52+
div(cls := "header", h1("todos"), TodoInput(store)),
5153
div(
52-
cls := "todoapp",
53-
div(cls := "header", h1("todos"), TodoInput(store)),
54-
div(
55-
cls := "main",
56-
ul(
57-
cls := "todo-list",
58-
children[Long](id => TodoItem(store.entry(id))) <-- filter.flatMap(store.ids(_))
59-
)
60-
),
61-
store
62-
.size
63-
.map(_ > 0)
64-
.changes
65-
.map(if _ then StatusBar(store.activeCount, filter, router).some else None)
66-
)
67-
}
68-
54+
cls := "main",
55+
ul(
56+
cls := "todo-list",
57+
children[Long](id => TodoItem(store.entry(id))) <-- filter.flatMap(store.ids(_))
58+
)
59+
),
60+
store
61+
.size
62+
.map(_ > 0)
63+
.changes
64+
.map(if _ then StatusBar(store.activeCount, filter, router).some else None)
65+
)
6966
}
67+
68+
}
7069
}
7170

7271
def TodoInput(store: TodoStore) =
@@ -176,21 +175,21 @@ class TodoStore(entries: SignallingSortedMapRef[IO, Long, Todo], nextId: IO[Long
176175

177176
object TodoStore:
178177

179-
def make: Resource[IO, TodoStore] =
178+
def apply(window: Window[IO]): Resource[IO, TodoStore] =
180179
val key = "todos-calico"
181180

182181
for
183182
mapRef <- SignallingSortedMapRef[IO, Long, Todo].toResource
184183

185184
_ <- Resource.eval {
186-
OptionT(Storage.local[IO].getItem(key))
185+
OptionT(window.localStorage.getItem(key))
187186
.subflatMap(jawn.decode[SortedMap[Long, Todo]](_).toOption)
188187
.foreachF(mapRef.set(_))
189188
}
190189

191-
_ <- Storage
192-
.local[IO]
193-
.events
190+
_ <- window
191+
.localStorage
192+
.events(window)
194193
.foreach {
195194
case Storage.Event.Updated(`key`, _, value, _) =>
196195
jawn.decode[SortedMap[Long, Todo]](value).foldMapM(mapRef.set(_))
@@ -202,11 +201,11 @@ object TodoStore:
202201

203202
_ <- mapRef
204203
.discrete
205-
.foreach(todos => Storage.local[IO].setItem(key, todos.asJson.noSpaces))
204+
.foreach(todos => window.localStorage.setItem(key, todos.asJson.noSpaces))
206205
.compile
207206
.drain
208207
.backgroundOn(calico.unsafe.MacrotaskExecutor)
209-
yield TodoStore(mapRef, IO.realTime.map(_.toMillis))
208+
yield new TodoStore(mapRef, IO.realTime.map(_.toMillis))
210209

211210
case class Todo(text: String, completed: Boolean) derives Codec.AsObject
212211

0 commit comments

Comments
 (0)