mirror of
https://github.com/phfroidmont/scalive.git
synced 2025-12-25 05:26:59 +01:00
Improve LiveView trait
This commit is contained in:
parent
bb062b9679
commit
57f43a0780
7 changed files with 133 additions and 141 deletions
54
core/src/TestLiveView.scala
Normal file
54
core/src/TestLiveView.scala
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import scalive.*
|
||||||
|
|
||||||
|
final case class MyModel(cls: String = "text-xs", bool: Boolean = true)
|
||||||
|
final case class Elem(name: String, age: Int)
|
||||||
|
|
||||||
|
class TestView extends LiveView[TestView.Cmd]:
|
||||||
|
import TestView.Cmd.*
|
||||||
|
|
||||||
|
private val textCls = LiveState.Key[String]
|
||||||
|
private val someBool = LiveState.Key[Boolean]
|
||||||
|
private val elems = LiveState.Key[List[Elem]]
|
||||||
|
|
||||||
|
def mount(state: LiveState): LiveState =
|
||||||
|
state
|
||||||
|
.set(textCls, "text-xs")
|
||||||
|
.set(someBool, true)
|
||||||
|
.set(
|
||||||
|
elems,
|
||||||
|
List(
|
||||||
|
Elem("a", 10),
|
||||||
|
Elem("b", 15),
|
||||||
|
Elem("c", 20)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def handleCommand(cmd: TestView.Cmd, state: LiveState): LiveState = cmd match
|
||||||
|
case UpdateElems(es) => state.set(elems, es)
|
||||||
|
case UpdateBool(b) => state.set(someBool, b)
|
||||||
|
case UpdateTextCls(cls) => state.set(textCls, cls)
|
||||||
|
|
||||||
|
val render =
|
||||||
|
div(
|
||||||
|
idAttr := "42",
|
||||||
|
cls := textCls,
|
||||||
|
draggable := someBool,
|
||||||
|
disabled := someBool,
|
||||||
|
ul(
|
||||||
|
elems.splitByIndex(elem =>
|
||||||
|
li(
|
||||||
|
"Nom: ",
|
||||||
|
elem(_.name),
|
||||||
|
" Age: ",
|
||||||
|
elem(_.age.toString)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end TestView
|
||||||
|
|
||||||
|
object TestView:
|
||||||
|
enum Cmd:
|
||||||
|
case UpdateElems(es: List[Elem])
|
||||||
|
case UpdateBool(b: Boolean)
|
||||||
|
case UpdateTextCls(cls: String)
|
||||||
62
core/src/main.scala
Normal file
62
core/src/main.scala
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
import scalive.*
|
||||||
|
|
||||||
|
@main
|
||||||
|
def main =
|
||||||
|
val s = Socket(TestView())
|
||||||
|
println("Init")
|
||||||
|
println(s.renderHtml)
|
||||||
|
s.syncClient
|
||||||
|
s.syncClient
|
||||||
|
|
||||||
|
println("Edit first and last")
|
||||||
|
s.receiveCommand(
|
||||||
|
TestView.Cmd.UpdateTextCls("text-lg")
|
||||||
|
)
|
||||||
|
s.syncClient
|
||||||
|
|
||||||
|
println("Edit first and last")
|
||||||
|
s.receiveCommand(
|
||||||
|
TestView.Cmd.UpdateElems(
|
||||||
|
List(
|
||||||
|
Elem("x", 10),
|
||||||
|
Elem("b", 15),
|
||||||
|
Elem("c", 99)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
s.syncClient
|
||||||
|
|
||||||
|
println("Add one")
|
||||||
|
s.receiveCommand(
|
||||||
|
TestView.Cmd.UpdateElems(
|
||||||
|
List(
|
||||||
|
Elem("x", 10),
|
||||||
|
Elem("b", 15),
|
||||||
|
Elem("c", 99),
|
||||||
|
Elem("d", 35)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
s.syncClient
|
||||||
|
|
||||||
|
//
|
||||||
|
// println("Remove first")
|
||||||
|
// lv.update(
|
||||||
|
// MyModel(
|
||||||
|
// List(
|
||||||
|
// NestedModel("b", 15),
|
||||||
|
// NestedModel("c", 99),
|
||||||
|
// NestedModel("d", 35)
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// println(lv.diff.toJsonPretty)
|
||||||
|
// println(HtmlBuilder.build(lv))
|
||||||
|
//
|
||||||
|
// println("Remove all")
|
||||||
|
// lv.update(
|
||||||
|
// MyModel(List.empty, "text-lg", bool = false)
|
||||||
|
// )
|
||||||
|
// println(lv.diff.toJsonPretty)
|
||||||
|
// println(HtmlBuilder.build(lv))
|
||||||
|
end main
|
||||||
|
|
@ -41,10 +41,6 @@ enum Mod:
|
||||||
dynList: Dyn[List[T]],
|
dynList: Dyn[List[T]],
|
||||||
project: Dyn[T] => HtmlElement)
|
project: Dyn[T] => HtmlElement)
|
||||||
|
|
||||||
given [T]: Conversion[HtmlElement, Mod] = Mod.Tag(_)
|
|
||||||
given [T]: Conversion[String, Mod] = Mod.Text(_)
|
|
||||||
given [T]: Conversion[Dyn[String], Mod] = Mod.DynText(_)
|
|
||||||
|
|
||||||
final case class Dyn[T](key: LiveState.Key, f: key.Type => T):
|
final case class Dyn[T](key: LiveState.Key, f: key.Type => T):
|
||||||
def render(state: LiveState, trackUpdates: Boolean): Option[T] =
|
def render(state: LiveState, trackUpdates: Boolean): Option[T] =
|
||||||
val entry = state(key)
|
val entry = state(key)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
package scalive
|
package scalive
|
||||||
|
|
||||||
trait LiveView:
|
trait LiveView[Cmd]:
|
||||||
|
def mount(state: LiveState): LiveState
|
||||||
|
def handleCommand(cmd: Cmd, state: LiveState): LiveState
|
||||||
def render: HtmlElement
|
def render: HtmlElement
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package scalive
|
|
||||||
|
|
||||||
import scalive.defs.attrs.HtmlAttrs
|
import scalive.defs.attrs.HtmlAttrs
|
||||||
import scalive.defs.complex.ComplexHtmlKeys
|
import scalive.defs.complex.ComplexHtmlKeys
|
||||||
import scalive.defs.tags.HtmlTags
|
import scalive.defs.tags.HtmlTags
|
||||||
|
|
||||||
object Scalive extends HtmlTags with HtmlAttrs with ComplexHtmlKeys
|
package object scalive extends HtmlTags with HtmlAttrs with ComplexHtmlKeys:
|
||||||
|
implicit def stringToMod(v: String): Mod = Mod.Text(v)
|
||||||
export Scalive.*
|
implicit def htmlElementToMod(el: HtmlElement): Mod = Mod.Tag(el)
|
||||||
|
implicit def dynStringToMod(d: Dyn[String]): Mod = Mod.DynText(d)
|
||||||
|
implicit def keyToDyn(k: LiveState.Key): Dyn[k.Type] = k.id
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,19 @@ package scalive
|
||||||
|
|
||||||
import zio.json.*
|
import zio.json.*
|
||||||
|
|
||||||
final case class Socket(view: LiveView, initState: LiveState):
|
final case class Socket[Cmd](lv: LiveView[Cmd]):
|
||||||
private var state: LiveState = initState
|
private var state: LiveState = lv.mount(LiveState.empty)
|
||||||
private var fingerprint: Fingerprint = Fingerprint.empty
|
private var fingerprint: Fingerprint = Fingerprint.empty
|
||||||
val id: String = "scl-123"
|
val id: String = "scl-123"
|
||||||
|
|
||||||
def setState(newState: LiveState): Unit = state = newState
|
def receiveCommand(cmd: Cmd): Unit =
|
||||||
def updateState(f: LiveState => LiveState): Unit = state = f(state)
|
state = lv.handleCommand(cmd, state)
|
||||||
def renderHtml: String =
|
|
||||||
HtmlBuilder.build(Rendered.render(view.render, state), isRoot = true)
|
def renderHtml: String =
|
||||||
|
HtmlBuilder.build(Rendered.render(lv.render, state), isRoot = true)
|
||||||
|
|
||||||
def syncClient: Unit =
|
def syncClient: Unit =
|
||||||
val r = Rendered.render(view.render, state)
|
val r = Rendered.render(lv.render, state)
|
||||||
println(DiffBuilder.build(r, fingerprint).toJsonPretty)
|
println(DiffBuilder.build(r, fingerprint).toJsonPretty)
|
||||||
fingerprint = Fingerprint(r)
|
fingerprint = Fingerprint(r)
|
||||||
println(fingerprint)
|
|
||||||
state = state.setAllUnchanged
|
state = state.setAllUnchanged
|
||||||
|
|
|
||||||
|
|
@ -1,123 +0,0 @@
|
||||||
package scalive
|
|
||||||
|
|
||||||
@main
|
|
||||||
def main =
|
|
||||||
val s = Socket(
|
|
||||||
TestView,
|
|
||||||
LiveState.empty.set(
|
|
||||||
TestView.model,
|
|
||||||
MyModel(
|
|
||||||
List(
|
|
||||||
NestedModel("a", 10),
|
|
||||||
NestedModel("b", 15),
|
|
||||||
NestedModel("c", 20)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
println("Init")
|
|
||||||
println(s.renderHtml)
|
|
||||||
s.syncClient
|
|
||||||
s.syncClient
|
|
||||||
|
|
||||||
println("Edit first and last")
|
|
||||||
s.updateState(
|
|
||||||
_.set(
|
|
||||||
TestView.model,
|
|
||||||
MyModel(
|
|
||||||
List(
|
|
||||||
NestedModel("x", 10),
|
|
||||||
NestedModel("b", 15),
|
|
||||||
NestedModel("c", 99)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
s.syncClient
|
|
||||||
// val lv =
|
|
||||||
// LiveView(
|
|
||||||
// TestView,
|
|
||||||
// LiveState.empty.set(
|
|
||||||
// TestView.model,
|
|
||||||
// MyModel(
|
|
||||||
// List(
|
|
||||||
// NestedModel("a", 10),
|
|
||||||
// NestedModel("b", 15),
|
|
||||||
// NestedModel("c", 20)
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// println(lv.fullDiff.toJsonPretty)
|
|
||||||
// println(HtmlBuilder.build(lv))
|
|
||||||
//
|
|
||||||
// println("Edit first and last")
|
|
||||||
// lv.update(
|
|
||||||
// MyModel(
|
|
||||||
// List(
|
|
||||||
// NestedModel("x", 10),
|
|
||||||
// NestedModel("b", 15),
|
|
||||||
// NestedModel("c", 99)
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// println(lv.diff.toJsonPretty)
|
|
||||||
// println(HtmlBuilder.build(lv))
|
|
||||||
//
|
|
||||||
// println("Add one")
|
|
||||||
// lv.update(
|
|
||||||
// MyModel(
|
|
||||||
// List(
|
|
||||||
// NestedModel("x", 10),
|
|
||||||
// NestedModel("b", 15),
|
|
||||||
// NestedModel("c", 99),
|
|
||||||
// NestedModel("d", 35)
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// println(lv.diff.toJsonPretty)
|
|
||||||
// println(HtmlBuilder.build(lv))
|
|
||||||
//
|
|
||||||
// println("Remove first")
|
|
||||||
// lv.update(
|
|
||||||
// MyModel(
|
|
||||||
// List(
|
|
||||||
// NestedModel("b", 15),
|
|
||||||
// NestedModel("c", 99),
|
|
||||||
// NestedModel("d", 35)
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// println(lv.diff.toJsonPretty)
|
|
||||||
// println(HtmlBuilder.build(lv))
|
|
||||||
//
|
|
||||||
// println("Remove all")
|
|
||||||
// lv.update(
|
|
||||||
// MyModel(List.empty, "text-lg", bool = false)
|
|
||||||
// )
|
|
||||||
// println(lv.diff.toJsonPretty)
|
|
||||||
// println(HtmlBuilder.build(lv))
|
|
||||||
end main
|
|
||||||
|
|
||||||
final case class MyModel(elems: List[NestedModel], cls: String = "text-xs", bool: Boolean = true)
|
|
||||||
final case class NestedModel(name: String, age: Int)
|
|
||||||
|
|
||||||
object TestView extends LiveView:
|
|
||||||
val model = LiveState.Key[MyModel]
|
|
||||||
val render =
|
|
||||||
div(
|
|
||||||
idAttr := "42",
|
|
||||||
cls := model(_.cls),
|
|
||||||
draggable := model(_.bool),
|
|
||||||
disabled := model(_.bool),
|
|
||||||
ul(
|
|
||||||
model(_.elems).splitByIndex(elem =>
|
|
||||||
li(
|
|
||||||
"Nom: ",
|
|
||||||
elem(_.name),
|
|
||||||
" Age: ",
|
|
||||||
elem(_.age.toString)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue