feat: CSR WIP
This commit is contained in:
parent
0c0ed26408
commit
959241c16b
19 changed files with 172 additions and 65 deletions
27
README.md
Normal file
27
README.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
## $ whoami
|
||||||
|
|
||||||
|
SFS full name ScalaFullStack is a collection of libraries to make full stack development in scala easy and composable
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
This project is far from being ready to use so for now these also include planned features for 1.0
|
||||||
|
|
||||||
|
- [X] SSR support
|
||||||
|
- [ ] CSR support
|
||||||
|
- [ ] Hydration
|
||||||
|
- [ ] router
|
||||||
|
- [ ] RPC integration or server functions
|
||||||
|
- [ ] ReScala reactive backend
|
||||||
|
- [ ] zio server integration
|
||||||
|
|
||||||
|
### TODO
|
||||||
|
|
||||||
|
- [ ] Full type safety, eliminate ? as generic param and asInstanceOf where possible
|
||||||
|
- [ ] AirStream reactive backend
|
||||||
|
- [ ] other server integrations
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
|
||||||
|
- sfs - different renderers (String, dom, hydration) and reactivity bindings
|
||||||
|
- dom - shared jvm/js html builder which includes: tags, attributes, props, svg utils
|
||||||
|
- possible to use from other libraries which need a js+jvm html/dom builder
|
18
build.sbt
18
build.sbt
|
@ -1,4 +1,6 @@
|
||||||
ThisBuild / scalaVersion := "3.5.0"
|
ThisBuild / scalaVersion := "3.5.0"
|
||||||
|
ThisBuild / versionScheme := Some("semver-spec")
|
||||||
|
|
||||||
ThisBuild / publishMavenStyle := true
|
ThisBuild / publishMavenStyle := true
|
||||||
ThisBuild / publishTo := Some(
|
ThisBuild / publishTo := Some(
|
||||||
"GitHub Package Registry" at "https://maven.pkg.github.com/davidon-top/sfs"
|
"GitHub Package Registry" at "https://maven.pkg.github.com/davidon-top/sfs"
|
||||||
|
@ -9,14 +11,16 @@ ThisBuild / credentials += Credentials(
|
||||||
sys.env("THEHUB_USERNAME"),
|
sys.env("THEHUB_USERNAME"),
|
||||||
sys.env("THEHUB_TOKEN")
|
sys.env("THEHUB_TOKEN")
|
||||||
)
|
)
|
||||||
ThisBuild / versionScheme := Some("early-semver")
|
|
||||||
ThisBuild / licenses += ("MIT", url("https://opensource.org/license/MIT"))
|
ThisBuild / licenses += ("MIT", url("https://opensource.org/license/MIT"))
|
||||||
|
|
||||||
ThisBuild / scmInfo := Some(
|
ThisBuild / scmInfo := Some(
|
||||||
ScmInfo(
|
ScmInfo(
|
||||||
url("https://github.com/davidon-top/sfs"),
|
url("https://github.com/davidon-top/sfs"),
|
||||||
"scm:https://github.com/davidon-top/sfs.git"
|
"scm:https://github.com/davidon-top/sfs.git"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
ThisBuild / organization := "top.davidon.sfs"
|
ThisBuild / organization := "top.davidon.sfs"
|
||||||
ThisBuild / organizationName := "DavidOnTop"
|
ThisBuild / organizationName := "DavidOnTop"
|
||||||
ThisBuild / organizationHomepage := Some(url("https://davidon.top"))
|
ThisBuild / organizationHomepage := Some(url("https://davidon.top"))
|
||||||
|
@ -32,7 +36,7 @@ lazy val dom = crossProject(JSPlatform, JVMPlatform)
|
||||||
.in(file("./dom"))
|
.in(file("./dom"))
|
||||||
.settings(
|
.settings(
|
||||||
name := "sfs-dom",
|
name := "sfs-dom",
|
||||||
version := "0.1.0-SNAPSHOT"
|
version := "0.1.0-alpha"
|
||||||
)
|
)
|
||||||
.jvmSettings(
|
.jvmSettings(
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
|
@ -50,6 +54,14 @@ lazy val sfs = crossProject(JSPlatform, JVMPlatform)
|
||||||
.in(file("./sfs"))
|
.in(file("./sfs"))
|
||||||
.settings(
|
.settings(
|
||||||
name := "sfs",
|
name := "sfs",
|
||||||
version := "0.1.0-SNAPSHOT"
|
version := "0.1.0-alpha"
|
||||||
)
|
)
|
||||||
.dependsOn(dom)
|
.dependsOn(dom)
|
||||||
|
|
||||||
|
lazy val sfsReScala = crossProject(JSPlatform, JVMPlatform)
|
||||||
|
.crossType(CrossType.Pure)
|
||||||
|
.in(file("./reactive/rescala"))
|
||||||
|
.settings(
|
||||||
|
name := "sfs-rescala",
|
||||||
|
version := "0.1.0-alpha"
|
||||||
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package top.davidon.sfs.dom
|
package top.davidon.sfs.dom
|
||||||
|
|
||||||
|
import top.davidon.sfs.dom.codecs.StringCodec
|
||||||
import top.davidon.sfs.dom.tags.Tag
|
import top.davidon.sfs.dom.tags.Tag
|
||||||
|
|
||||||
/** tag + modifiers + value */
|
/** tag + modifiers + value */
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package top.davidon.sfs.dom
|
package top.davidon.sfs.dom
|
||||||
|
|
||||||
import top.davidon.sfs.dom.Value
|
import top.davidon.sfs.dom.codecs.Codec
|
||||||
import top.davidon.sfs.dom.keys.Key
|
import top.davidon.sfs.dom.keys.Key
|
||||||
|
|
||||||
class Modifier[F, T](val key: Key, val value: Value[F, T]) {}
|
class Modifier[F, T](
|
||||||
|
val key: Key,
|
||||||
|
val value: Value[F, T]
|
||||||
|
) {}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
package top.davidon.sfs.dom
|
|
||||||
|
|
||||||
object SFS extends ScalaFullStack {}
|
|
|
@ -7,7 +7,7 @@ import top.davidon.sfs.dom.defs.eventProps.GlobalEventProps
|
||||||
import top.davidon.sfs.dom.defs.props.HtmlProps
|
import top.davidon.sfs.dom.defs.props.HtmlProps
|
||||||
import top.davidon.sfs.dom.defs.tags.{HtmlTags, SvgTags}
|
import top.davidon.sfs.dom.defs.tags.{HtmlTags, SvgTags}
|
||||||
|
|
||||||
trait ScalaFullStack
|
trait ScalaFullStackDOM
|
||||||
extends HtmlTags
|
extends HtmlTags
|
||||||
with HtmlAttrs
|
with HtmlAttrs
|
||||||
with HtmlProps
|
with HtmlProps
|
|
@ -4,16 +4,22 @@ import top.davidon.sfs.dom.codecs.{Codec, StringAsIsCodec}
|
||||||
|
|
||||||
class Value[F, T](
|
class Value[F, T](
|
||||||
val value: F,
|
val value: F,
|
||||||
val codec: Codec[F, T],
|
val codec: Codec[F, T]
|
||||||
var isReactive: Boolean = false
|
|
||||||
) {
|
) {
|
||||||
def apply(): T = {
|
def apply(): T = {
|
||||||
codec.encode(value)
|
codec.encode(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
def reactive(value: Boolean = true): Value[F, T] = {
|
override def toString: String = {
|
||||||
isReactive = value
|
value match
|
||||||
this
|
case v: Int => codecs.IntAsStringCodec.encode(v)
|
||||||
|
case v: Long => codecs.LongAsStringCodec.encode(v)
|
||||||
|
case v: Double => codecs.DoubleAsStringCodec.encode(v)
|
||||||
|
case v: Boolean => codecs.BooleanAsTrueFalseStringCodec.encode(v)
|
||||||
|
case v: Iterable[String] =>
|
||||||
|
codecs.IterableAsSpaceSeparatedStringCodec.encode(v)
|
||||||
|
case _ =>
|
||||||
|
throw Exception("Couldn't find codec to convert a value to a string")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,9 +28,8 @@ object Value {
|
||||||
iterator: Iterable[Value[?, String]]
|
iterator: Iterable[Value[?, String]]
|
||||||
): Value[String, String] = {
|
): Value[String, String] = {
|
||||||
Value(
|
Value(
|
||||||
iterator.map(v => v.codec.encode(v.value)).mkString(""),
|
iterator.map(v => v.toString).mkString(""),
|
||||||
StringAsIsCodec,
|
StringAsIsCodec
|
||||||
iterator.exists(_.isReactive)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package top.davidon.sfs.dom.codecs
|
||||||
|
|
||||||
|
class AsIsCodec[T](val strCodec: StringCodec[T]) extends Codec[T, T] {
|
||||||
|
override def encode(scalaValue: T): T = scalaValue
|
||||||
|
|
||||||
|
override def decode(domValue: T): T = domValue
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package top.davidon.sfs.dom.codecs
|
||||||
|
|
||||||
|
//trait StringCodec[T] extends Codec[T, String] {}
|
||||||
|
type StringCodec[T] = Codec[T, String]
|
|
@ -2,7 +2,8 @@ package top.davidon.sfs.dom
|
||||||
|
|
||||||
package object codecs {
|
package object codecs {
|
||||||
|
|
||||||
lazy val IntAsStringCodec: Codec[Int, String] = new Codec[Int, String] {
|
lazy val IntAsStringCodec: StringCodec[Int] =
|
||||||
|
new StringCodec[Int] {
|
||||||
|
|
||||||
override def decode(domValue: String): Int =
|
override def decode(domValue: String): Int =
|
||||||
domValue.toInt // @TODO this can throw exception. How do we handle this?
|
domValue.toInt // @TODO this can throw exception. How do we handle this?
|
||||||
|
@ -10,20 +11,17 @@ package object codecs {
|
||||||
override def encode(scalaValue: Int): String = scalaValue.toString
|
override def encode(scalaValue: Int): String = scalaValue.toString
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val DoubleAsIsCodec: Codec[Double, Double] = AsIsCodec()
|
lazy val DoubleAsStringCodec: StringCodec[Double] =
|
||||||
|
new StringCodec[Double] {
|
||||||
lazy val DoubleAsStringCodec: Codec[Double, String] =
|
|
||||||
new Codec[Double, String] {
|
|
||||||
|
|
||||||
override def decode(domValue: String): Double =
|
override def decode(domValue: String): Double =
|
||||||
domValue.toDouble // @TODO this can throw exception. How do we handle this?
|
domValue.toDouble // @TODO this can throw exception. How do we handle this?
|
||||||
|
|
||||||
override def encode(scalaValue: Double): String = scalaValue.toString
|
override def encode(scalaValue: Double): String = scalaValue.toString
|
||||||
}
|
}
|
||||||
lazy val LongAsIsCodec: Codec[Long, Long] = AsIsCodec()
|
|
||||||
|
|
||||||
lazy val LongAsStringCodec: Codec[Long, String] =
|
lazy val LongAsStringCodec: StringCodec[Long] =
|
||||||
new Codec[Long, String] {
|
new StringCodec[Long] {
|
||||||
|
|
||||||
override def decode(domValue: String): Long =
|
override def decode(domValue: String): Long =
|
||||||
domValue.toLong // @TODO this can throw exception. How do we handle this?
|
domValue.toLong // @TODO this can throw exception. How do we handle this?
|
||||||
|
@ -31,8 +29,8 @@ package object codecs {
|
||||||
override def encode(scalaValue: Long): String = scalaValue.toString
|
override def encode(scalaValue: Long): String = scalaValue.toString
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val BooleanAsTrueFalseStringCodec: Codec[Boolean, String] =
|
lazy val BooleanAsTrueFalseStringCodec: StringCodec[Boolean] =
|
||||||
new Codec[Boolean, String] {
|
new StringCodec[Boolean] {
|
||||||
|
|
||||||
override def decode(domValue: String): Boolean = domValue == "true"
|
override def decode(domValue: String): Boolean = domValue == "true"
|
||||||
|
|
||||||
|
@ -40,16 +38,16 @@ package object codecs {
|
||||||
if scalaValue then "true" else "false"
|
if scalaValue then "true" else "false"
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val BooleanAsYesNoStringCodec: Codec[Boolean, String] =
|
lazy val BooleanAsYesNoStringCodec: StringCodec[Boolean] =
|
||||||
new Codec[Boolean, String] {
|
new StringCodec[Boolean] {
|
||||||
|
|
||||||
override def decode(domValue: String): Boolean = domValue == "yes"
|
override def decode(domValue: String): Boolean = domValue == "yes"
|
||||||
|
|
||||||
override def encode(scalaValue: Boolean): String =
|
override def encode(scalaValue: Boolean): String =
|
||||||
if scalaValue then "yes" else "no"
|
if scalaValue then "yes" else "no"
|
||||||
}
|
}
|
||||||
lazy val BooleanAsOnOffStringCodec: Codec[Boolean, String] =
|
lazy val BooleanAsOnOffStringCodec: StringCodec[Boolean] =
|
||||||
new Codec[Boolean, String] {
|
new StringCodec[Boolean] {
|
||||||
|
|
||||||
override def decode(domValue: String): Boolean = domValue == "on"
|
override def decode(domValue: String): Boolean = domValue == "on"
|
||||||
|
|
||||||
|
@ -57,9 +55,8 @@ package object codecs {
|
||||||
if scalaValue then "on" else "off"
|
if scalaValue then "on" else "off"
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val IterableAsSpaceSeparatedStringCodec
|
lazy val IterableAsSpaceSeparatedStringCodec: StringCodec[Iterable[String]] =
|
||||||
: Codec[Iterable[String], String] =
|
new StringCodec[Iterable[String]] { // could use for e.g. className
|
||||||
new Codec[Iterable[String], String] { // could use for e.g. className
|
|
||||||
|
|
||||||
override def decode(domValue: String): Iterable[String] =
|
override def decode(domValue: String): Iterable[String] =
|
||||||
if domValue == "" then Nil else domValue.split(' ')
|
if domValue == "" then Nil else domValue.split(' ')
|
||||||
|
@ -67,9 +64,8 @@ package object codecs {
|
||||||
override def encode(scalaValue: Iterable[String]): String =
|
override def encode(scalaValue: Iterable[String]): String =
|
||||||
scalaValue.mkString(" ")
|
scalaValue.mkString(" ")
|
||||||
}
|
}
|
||||||
lazy val IterableAsCommaSeparatedStringCodec
|
lazy val IterableAsCommaSeparatedStringCodec: StringCodec[Iterable[String]] =
|
||||||
: Codec[Iterable[String], String] =
|
new StringCodec[Iterable[String]] { // could use for lists of IDs
|
||||||
new Codec[Iterable[String], String] { // could use for lists of IDs
|
|
||||||
|
|
||||||
override def decode(domValue: String): Iterable[String] =
|
override def decode(domValue: String): Iterable[String] =
|
||||||
if domValue == "" then Nil else domValue.split(',')
|
if domValue == "" then Nil else domValue.split(',')
|
||||||
|
@ -77,12 +73,8 @@ package object codecs {
|
||||||
override def encode(scalaValue: Iterable[String]): String =
|
override def encode(scalaValue: Iterable[String]): String =
|
||||||
scalaValue.mkString(",")
|
scalaValue.mkString(",")
|
||||||
}
|
}
|
||||||
val StringAsIsCodec: Codec[String, String] = AsIsCodec()
|
lazy val BooleanAsAttrPresenceCodec: StringCodec[Boolean] =
|
||||||
val IntAsIsCodec: Codec[Int, Int] = AsIsCodec()
|
new StringCodec[Boolean] {
|
||||||
val BooleanAsIsCodec: Codec[Boolean, Boolean] = AsIsCodec()
|
|
||||||
|
|
||||||
val BooleanAsAttrPresenceCodec: Codec[Boolean, String] =
|
|
||||||
new Codec[Boolean, String] {
|
|
||||||
|
|
||||||
override def decode(domValue: String): Boolean = domValue != null
|
override def decode(domValue: String): Boolean = domValue != null
|
||||||
|
|
||||||
|
@ -90,9 +82,12 @@ package object codecs {
|
||||||
if scalaValue then "" else null
|
if scalaValue then "" else null
|
||||||
}
|
}
|
||||||
|
|
||||||
def AsIsCodec[V](): Codec[V, V] = new Codec[V, V] {
|
lazy val LongAsIsCodec: AsIsCodec[Long] = AsIsCodec(LongAsStringCodec)
|
||||||
override def encode(scalaValue: V): V = scalaValue
|
lazy val DoubleAsIsCodec: AsIsCodec[Double] = AsIsCodec(DoubleAsStringCodec)
|
||||||
|
lazy val StringAsIsCodec: AsIsCodec[String] & StringCodec[String] =
|
||||||
override def decode(domValue: V): V = domValue
|
new AsIsCodec[String](StringAsIsCodec) with StringCodec[String] {}
|
||||||
}
|
lazy val IntAsIsCodec: AsIsCodec[Int] = AsIsCodec(IntAsStringCodec)
|
||||||
|
lazy val BooleanAsIsCodec: AsIsCodec[Boolean] = AsIsCodec(
|
||||||
|
BooleanAsTrueFalseStringCodec
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package top.davidon.sfs.dom.keys
|
package top.davidon.sfs.dom.keys
|
||||||
import top.davidon.sfs.dom.codecs.Codec
|
import top.davidon.sfs.dom.codecs.{Codec, StringCodec}
|
||||||
import top.davidon.sfs.dom.{Modifier, Value}
|
import top.davidon.sfs.dom.{Modifier, Value}
|
||||||
|
|
||||||
class AriaAttr[V](
|
class AriaAttr[V](
|
||||||
suffix: String,
|
suffix: String,
|
||||||
val codec: Codec[V, String]
|
val codec: StringCodec[V]
|
||||||
) extends Key {
|
) extends Key {
|
||||||
override val name: String = "aria-" + suffix
|
override val name: String = "aria-" + suffix
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package top.davidon.sfs.dom.keys
|
package top.davidon.sfs.dom.keys
|
||||||
|
|
||||||
import top.davidon.sfs.dom.codecs.Codec
|
import top.davidon.sfs.dom.codecs.{Codec, StringCodec}
|
||||||
import top.davidon.sfs.dom.{Modifier, Value}
|
import top.davidon.sfs.dom.{Modifier, Value}
|
||||||
|
|
||||||
class HtmlAttr[V](
|
class HtmlAttr[V](
|
||||||
override val name: String,
|
override val name: String,
|
||||||
val codec: Codec[V, String]
|
val codec: StringCodec[V]
|
||||||
) extends Key {
|
) extends Key {
|
||||||
@inline def apply(value: V): Modifier[V, String] = {
|
@inline def apply(value: V): Modifier[V, String] = {
|
||||||
this := value
|
this := value
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package top.davidon.sfs.dom.keys
|
package top.davidon.sfs.dom.keys
|
||||||
import top.davidon.sfs.dom.codecs.Codec
|
import top.davidon.sfs.dom.codecs.{Codec, StringCodec}
|
||||||
import top.davidon.sfs.dom.{Modifier, Value}
|
import top.davidon.sfs.dom.{Modifier, Value}
|
||||||
|
|
||||||
class SvgAttr[V](
|
class SvgAttr[V](
|
||||||
val localName: String,
|
val localName: String,
|
||||||
val codec: Codec[V, String],
|
val codec: StringCodec[V],
|
||||||
val namespacePrefix: Option[String]
|
val namespacePrefix: Option[String]
|
||||||
) extends Key {
|
) extends Key {
|
||||||
override val name: String =
|
override val name: String =
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package top.davidon.sfs.dom.tags
|
package top.davidon.sfs.dom.tags
|
||||||
|
|
||||||
import org.scalajs.dom
|
import org.scalajs.dom
|
||||||
|
import top.davidon.sfs.dom.codecs.StringCodec
|
||||||
import top.davidon.sfs.dom.{Element, Modifier, Value}
|
import top.davidon.sfs.dom.{Element, Modifier, Value}
|
||||||
|
|
||||||
trait Tag[+Ref <: dom.Element] {
|
trait Tag[+Ref <: dom.Element] {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package top.davidon.sfs.renderers
|
||||||
|
|
||||||
|
import org.scalajs.dom
|
||||||
|
import top.davidon.sfs.dom.keys.{EventProp, HtmlProp}
|
||||||
|
import top.davidon.sfs.dom.{Element, Renderer, Value}
|
||||||
|
|
||||||
|
import scala.scalajs.js
|
||||||
|
|
||||||
|
class ClientSideRenderer(val root: dom.Element)
|
||||||
|
extends Renderer[Unit]
|
||||||
|
with ReactiveRenderer {
|
||||||
|
|
||||||
|
override def render(
|
||||||
|
elements: Element[dom.Element]*
|
||||||
|
): Unit = {
|
||||||
|
elements.foreach(renderElement(root, _))
|
||||||
|
}
|
||||||
|
|
||||||
|
override def valueFunc[F](element: dom.Element, value: F): Unit = {}
|
||||||
|
|
||||||
|
override def modifierFunc[F, T](
|
||||||
|
modifier: top.davidon.sfs.dom.Modifier[F, T],
|
||||||
|
value: F
|
||||||
|
): Unit = {}
|
||||||
|
|
||||||
|
private def renderElement(
|
||||||
|
parent: dom.Element,
|
||||||
|
element: Element[dom.Element]
|
||||||
|
): Unit = {
|
||||||
|
val el = dom.document.createElement(element.tag.name)
|
||||||
|
element.mods.foreach(m =>
|
||||||
|
m.key match {
|
||||||
|
case _: HtmlProp[?, ?] =>
|
||||||
|
el.asInstanceOf[js.Dynamic]
|
||||||
|
.updateDynamic(m.key.name)(m.value().asInstanceOf[js.Any])
|
||||||
|
case _: EventProp[?] => ???
|
||||||
|
case _ =>
|
||||||
|
el.setAttribute(m.key.name, m.value().asInstanceOf[String])
|
||||||
|
}
|
||||||
|
)
|
||||||
|
element.children.foreach {
|
||||||
|
case e: Element[dom.Element] => renderElement(el, e)
|
||||||
|
case s: Value[?, String] => el.append(s())
|
||||||
|
}
|
||||||
|
parent.append(el)
|
||||||
|
}
|
||||||
|
}
|
4
sfs/src/main/scala/top/davidon/sfs/SFS.scala
Normal file
4
sfs/src/main/scala/top/davidon/sfs/SFS.scala
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
package top.davidon.sfs
|
||||||
|
import top.davidon.sfs.dom.ScalaFullStackDOM
|
||||||
|
|
||||||
|
object SFS extends ScalaFullStackDOM {}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package top.davidon.sfs.renderers
|
||||||
|
|
||||||
|
import org.scalajs.dom
|
||||||
|
import top.davidon.sfs.dom.Modifier
|
||||||
|
|
||||||
|
trait ReactiveRenderer {
|
||||||
|
def valueFunc[F](element: dom.Element, value: F): Unit
|
||||||
|
def modifierFunc[F, T](modifier: Modifier[F, T], value: F): Unit
|
||||||
|
}
|
|
@ -1,10 +1,9 @@
|
||||||
package top.davidon.sfs.renderers
|
package top.davidon.sfs.renderers
|
||||||
|
|
||||||
import org.scalajs.dom
|
import org.scalajs.dom
|
||||||
import top.davidon.sfs.dom.SFS.given
|
|
||||||
import top.davidon.sfs.dom.{Element, Renderer, Value}
|
import top.davidon.sfs.dom.{Element, Renderer, Value}
|
||||||
|
|
||||||
class StringRenderer extends Renderer[String] {
|
class StringRenderer(val ssr: Boolean) extends Renderer[String] {
|
||||||
override def render(
|
override def render(
|
||||||
elements: Element[dom.Element]*
|
elements: Element[dom.Element]*
|
||||||
): String = {
|
): String = {
|
||||||
|
@ -13,17 +12,13 @@ class StringRenderer extends Renderer[String] {
|
||||||
|
|
||||||
private def renderElement(e: Element[dom.Element]): String = {
|
private def renderElement(e: Element[dom.Element]): String = {
|
||||||
val modsStr =
|
val modsStr =
|
||||||
e.mods.map(m => s" ${m.key.name}=\"${m.value()}\"").mkString("")
|
e.mods.map(m => s" ${m.key.name}=\"${m.value.toString}\"").mkString("")
|
||||||
val bodyStr = e.children
|
val bodyStr = e.children
|
||||||
.map {
|
.map {
|
||||||
case e: Element[?] =>
|
case e: Element[?] =>
|
||||||
renderElement(e)
|
renderElement(e)
|
||||||
case c: Value[?, String] =>
|
case c: Value[?, String] =>
|
||||||
c()
|
c()
|
||||||
case _ =>
|
|
||||||
throw Exception(
|
|
||||||
"attempted to parse child that was neither an Element or Value, this should never happen if it did its a bug"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
.mkString(" ")
|
.mkString(" ")
|
||||||
s"<${e.tag.name}$modsStr>$bodyStr${
|
s"<${e.tag.name}$modsStr>$bodyStr${
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue