diff --git a/.gitignore b/.gitignore index 2f7896d1..cca306ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +.scalafmt.conf target/ diff --git a/.scalafmt.conf b/.scalafmt.conf deleted file mode 100644 index ed3dac48..00000000 --- a/.scalafmt.conf +++ /dev/null @@ -1,6 +0,0 @@ -# Auto generated scalafmt rules -# Use `scalafmtRules` sbt setting to modify -assumeStandardLibraryStripMargin = true -maxColumn = 80 -rewrite.rules = [sortimports] -version=2.0.0 \ No newline at end of file diff --git a/core/.js/src/main/scala/io/taig/schelm/BrowserDom.scala b/core/.js/src/main/scala/io/taig/schelm/BrowserDom.scala index da977b37..b5de6f2d 100644 --- a/core/.js/src/main/scala/io/taig/schelm/BrowserDom.scala +++ b/core/.js/src/main/scala/io/taig/schelm/BrowserDom.scala @@ -57,6 +57,12 @@ final class BrowserDom[F[_], Event]( override def createElement(name: String): F[dom.Element] = F.delay(document.createElement(name)) + override def createElementNS( + namespace: String, + name: String + ): F[dom.Element] = + F.delay(document.createElementNS(namespace, name)) + override def createTextNode(value: String): F[dom.Text] = F.delay(document.createTextNode(value)) diff --git a/core/.jvm/src/main/scala/io/taig/schelm/ServerDom.scala b/core/.jvm/src/main/scala/io/taig/schelm/ServerDom.scala index 77910e18..0977b5d6 100644 --- a/core/.jvm/src/main/scala/io/taig/schelm/ServerDom.scala +++ b/core/.jvm/src/main/scala/io/taig/schelm/ServerDom.scala @@ -42,6 +42,9 @@ final class ServerDom[F[_], Event](document: JDocument)(implicit F: Sync[F]) override def createElement(name: String): F[JElement] = F.delay(new JElement(name)) + override def createElementNS(namespace: String, name: String): F[Element] = + createElement(name) + override def createTextNode(value: String): F[JText] = F.delay(new JText(value)) diff --git a/core/src/main/scala/io/taig/schelm/Children.scala b/core/src/main/scala/io/taig/schelm/Children.scala index 1b3e9ae3..2cc18f9a 100644 --- a/core/src/main/scala/io/taig/schelm/Children.scala +++ b/core/src/main/scala/io/taig/schelm/Children.scala @@ -16,6 +16,22 @@ sealed abstract class Children[A] extends Product with Serializable { case Children.Identified(values) => values.size } + def ++(children: Children[A]): Children[A] = + (this, children) match { + case (Children.Indexed(x), Children.Indexed(y)) => + Children.Indexed(x ++ y) + case (Children.Identified(x), Children.Identified(y)) => + Children.Identified(x ++ y) + case (Children.Indexed(x), Children.Identified(y)) => + Children.Identified(ListMap(x.zipWithIndex.map { + case (value, index) => (String.valueOf(index), value) + }: _*) ++ y) + case (Children.Identified(x), Children.Indexed(y)) => + Children.Identified(x ++ ListMap(y.zipWithIndex.map { + case (value, index) => (String.valueOf(index), value) + }: _*)) + } + def indexOf(key: Key): Option[Int] = (key, this) match { case (Key.Index(index), _) => index.some diff --git a/core/src/main/scala/io/taig/schelm/Cofree.scala b/core/src/main/scala/io/taig/schelm/Cofree.scala deleted file mode 100644 index 4bcaf461..00000000 --- a/core/src/main/scala/io/taig/schelm/Cofree.scala +++ /dev/null @@ -1,3 +0,0 @@ -package io.taig.schelm - -final case class Cofree[+F[+_], +A](head: A, tail: F[Cofree[F, A]]) diff --git a/core/src/main/scala/io/taig/schelm/Component.scala b/core/src/main/scala/io/taig/schelm/Component.scala index eb1c23bf..061b9e92 100644 --- a/core/src/main/scala/io/taig/schelm/Component.scala +++ b/core/src/main/scala/io/taig/schelm/Component.scala @@ -7,6 +7,7 @@ sealed abstract class Component[+A, +Event] extends Product with Serializable object Component { final case class Element[A, Event]( name: String, + namespace: Option[String], attributes: Attributes, listeners: Listeners[Event], children: Children[A] @@ -26,9 +27,10 @@ object Component { fa: Component[A, Event] )(f: A => B): Component[B, Event] = fa match { - case Element(name, attributes, listeners, children) => + case Element(name, namespace, attributes, listeners, children) => Element( name, + namespace, attributes, listeners, children.map((_, value) => f(value)) diff --git a/core/src/main/scala/io/taig/schelm/ComponentOps.scala b/core/src/main/scala/io/taig/schelm/ComponentOps.scala index 525a5b0d..f477a075 100644 --- a/core/src/main/scala/io/taig/schelm/ComponentOps.scala +++ b/core/src/main/scala/io/taig/schelm/ComponentOps.scala @@ -19,9 +19,6 @@ abstract class ComponentOps[F[_], A]( final def updateListeners(f: Listeners[A] => Listeners[A]): F[A] = ComponentOps.updateListeners(component, extract, inject)(f) - final def children: Children[F[A]] = - ComponentOps.children(component, extract, inject) - final def setChildren(children: Children[F[A]]): F[A] = updateChildren(_ => children) diff --git a/core/src/main/scala/io/taig/schelm/Dom.scala b/core/src/main/scala/io/taig/schelm/Dom.scala index d77a3065..96016115 100644 --- a/core/src/main/scala/io/taig/schelm/Dom.scala +++ b/core/src/main/scala/io/taig/schelm/Dom.scala @@ -28,6 +28,8 @@ abstract class Dom[F[_], Event] { def createElement(name: String): F[Element] + def createElementNS(namespace: String, name: String): F[Element] + def createTextNode(value: String): F[Text] def childAt(element: Element, index: Int): F[Option[Node]] diff --git a/core/src/main/scala/io/taig/schelm/Fix.scala b/core/src/main/scala/io/taig/schelm/Fix.scala deleted file mode 100644 index 19797ddd..00000000 --- a/core/src/main/scala/io/taig/schelm/Fix.scala +++ /dev/null @@ -1,3 +0,0 @@ -package io.taig.schelm - -final case class Fix[+F[+_]](value: F[Fix[F]]) diff --git a/core/src/main/scala/io/taig/schelm/Html.scala b/core/src/main/scala/io/taig/schelm/Html.scala new file mode 100644 index 00000000..91b291f3 --- /dev/null +++ b/core/src/main/scala/io/taig/schelm/Html.scala @@ -0,0 +1,3 @@ +package io.taig.schelm + +final case class Html[+A](component: Component[Html[A], A]) diff --git a/core/src/main/scala/io/taig/schelm/HtmlDiffer.scala b/core/src/main/scala/io/taig/schelm/HtmlDiffer.scala index 9b00f883..6ae13151 100644 --- a/core/src/main/scala/io/taig/schelm/HtmlDiffer.scala +++ b/core/src/main/scala/io/taig/schelm/HtmlDiffer.scala @@ -6,7 +6,7 @@ import cats.implicits._ class HtmlDiffer[A] extends Differ[Html[A], HtmlDiff[A]] { override def diff(previous: Html[A], next: Html[A]): Option[HtmlDiff[A]] = // format: off - (previous.value, next.value) match { + (previous.component, next.component) match { case (previous: Component.Element[Html[A], A], next: Component.Element[Html[A], A]) => element(previous, next) case (previous: Component.Fragment[Html[A]], next: Component.Fragment[Html[A]]) => diff --git a/core/src/main/scala/io/taig/schelm/HtmlRenderer.scala b/core/src/main/scala/io/taig/schelm/HtmlRenderer.scala index 32cc68d2..3c7e4994 100644 --- a/core/src/main/scala/io/taig/schelm/HtmlRenderer.scala +++ b/core/src/main/scala/io/taig/schelm/HtmlRenderer.scala @@ -8,30 +8,38 @@ final class HtmlRenderer[F[_], Event](dom: Dom[F, Event])( ) extends Renderer[F, Html[Event], Reference[Event]] { override def render( html: Html[Event], + parent: Option[Element], path: Path ): F[Reference[Event]] = - html.value match { + html.component match { case component: Component.Element[Html[Event], Event] => + val name = component.name + for { - element <- dom.createElement(component.name) + element <- component.namespace.fold(dom.createElement(name))( + dom.createElementNS(_, name) + ) + _ <- parent.traverse_(dom.appendChild(_, element)) + parent = element.some _ <- component.attributes.traverse_(register(element, _)) _ <- component.listeners.traverse_(register(element, path, _)) - children <- component.children.traverse( - (key, child) => render(child, path / key) - ) - _ <- dom.appendChildren(element, children.values.flatMap(_.root)) + children <- component.children.traverse { (key, child) => + render(child, parent, path / key) + } } yield Reference.Element(component.copy(children = children), element) case component: Component.Fragment[Html[Event]] => - component.children - .traverse((key, child) => render(child, path / key)) - .map(component.copy) - .map(Reference.Fragment.apply) + for { + children <- component.children.traverse { (key, child) => + render(child, parent, path / key) + } + } yield Reference.Fragment(component.copy(children = children)) case component: Component.Lazy[Html[Event]] => - render(component.eval.value, path) + render(component.eval.value, parent, path) case component: Component.Text => - dom - .createTextNode(component.value) - .map(Reference.Text(component, _)) + for { + text <- dom.createTextNode(component.value) + _ <- parent.traverse_(dom.appendChild(_, text)) + } yield Reference.Text(component, text) } def register(element: Element, attribute: Attribute): F[Unit] = diff --git a/core/src/main/scala/io/taig/schelm/ReferencePatcher.scala b/core/src/main/scala/io/taig/schelm/ReferencePatcher.scala index d1160626..13f8988d 100644 --- a/core/src/main/scala/io/taig/schelm/ReferencePatcher.scala +++ b/core/src/main/scala/io/taig/schelm/ReferencePatcher.scala @@ -17,8 +17,10 @@ final class ReferencePatcher[F[_], A]( // format: off (reference, diff) match { case (_, diff: HtmlDiff.Group[A]) => group(reference, diff, path) - case (reference: Reference.Element[A], diff: HtmlDiff.AddAttribute) => addAttribute(reference, diff) - case (reference: Reference.Element[A], diff: HtmlDiff.RemoveAttribute) => removeAttribute(reference, diff) + case (reference: Reference.Element[A], diff: HtmlDiff.AddAttribute) => + addAttribute(reference, diff) + case (reference: Reference.Element[A], diff: HtmlDiff.RemoveAttribute) => + removeAttribute(reference, diff) case (element@Reference.Element(_, node), HtmlDiff.RemoveListener(event)) => dom.removeEventListener(node, event, path) *> element.updateListeners(_ - event).pure[F] @@ -45,7 +47,7 @@ final class ReferencePatcher[F[_], A]( reference <- child(component.children, key) child <- patch(reference, diff, path / key) } yield parent.updateChildren(_.updated(key, child)) - case (_, HtmlDiff.Replace(html)) => renderer.render(html, path) + case (_, HtmlDiff.Replace(html)) => renderer.render(html, parent = None, path) case (reference @ Reference.Text(_, node), HtmlDiff.UpdateText(value)) => dom.data(node, value) *> reference.pure[F].widen case _ => diff --git a/core/src/main/scala/io/taig/schelm/Renderer.scala b/core/src/main/scala/io/taig/schelm/Renderer.scala index 2b2116d7..dab528bf 100644 --- a/core/src/main/scala/io/taig/schelm/Renderer.scala +++ b/core/src/main/scala/io/taig/schelm/Renderer.scala @@ -1,5 +1,5 @@ package io.taig.schelm abstract class Renderer[F[_], A, B] { - def render(value: A, path: Path): F[B] + def render(value: A, parent: Option[Element], path: Path): F[B] } diff --git a/core/src/main/scala/io/taig/schelm/Schelm.scala b/core/src/main/scala/io/taig/schelm/Schelm.scala index 6729bb95..c2179406 100644 --- a/core/src/main/scala/io/taig/schelm/Schelm.scala +++ b/core/src/main/scala/io/taig/schelm/Schelm.scala @@ -38,7 +38,7 @@ final class Schelm[F[_], Event, Component, Reference, Diff]( val component = render(initial) for { - reference <- renderer.render(component, Path.Root) + reference <- renderer.render(component, parent = None, Path.Root) _ <- attacher.attach(container, reference) htmls = (manager.subscription merge subscriptions) .evalScan(initial) { (state, event) => diff --git a/core/src/main/scala/io/taig/schelm/Property.scala b/core/src/main/scala/io/taig/schelm/Value.scala similarity index 100% rename from core/src/main/scala/io/taig/schelm/Property.scala rename to core/src/main/scala/io/taig/schelm/Value.scala diff --git a/core/src/main/scala/io/taig/schelm/Widget.scala b/core/src/main/scala/io/taig/schelm/Widget.scala new file mode 100644 index 00000000..af91cc70 --- /dev/null +++ b/core/src/main/scala/io/taig/schelm/Widget.scala @@ -0,0 +1,136 @@ +package io.taig.schelm + +import cats.Monoid +import cats.implicits._ + +import scala.annotation.tailrec + +sealed abstract class Widget[+Event, Context, Payload] + extends Product + with Serializable { + def component( + context: Context + ): Component[Widget[Event, Context, Payload], Event] = this match { + case Widget.Pure(component, _) => component + case Widget.Render(apply) => apply(context).component(context) + case Widget.Local(f, widget) => widget.component(f(context)) + } + + def component( + implicit ev: Unit =:= Context + ): Component[Widget[Event, Context, Payload], Event] = component(unit) + + def payload(context: Context): Payload = this match { + case Widget.Pure(_, payload) => payload + case Widget.Render(apply) => apply(context).payload(context) + case Widget.Local(f, widget) => widget.payload(f(context)) + } + + def payload(implicit ev: Unit =:= Context): Payload = payload(unit) + + def render(context: Context): Widget[Event, Unit, Payload] = + Widget.render(context, this) + + def merge(implicit F: Monoid[Payload], ev: Unit =:= Context): Payload = { + val payloads = component match { + case component: Component.Element[Widget[_, Context, Payload], _] => + component.children.values.map(_.merge).combineAll + case component: Component.Fragment[Widget[_, Context, Payload]] => + component.children.values.map(_.merge).combineAll + case component: Component.Lazy[Widget[_, Context, Payload]] => + component.eval.value.merge + case _: Component.Text => F.empty + } + + payload(unit) |+| payloads + } +} + +object Widget { + final case class Pure[+Event, Context, Payload]( + component: Component[Widget[Event, Context, Payload], Event], + payload: Payload + ) extends Widget[Event, Context, Payload] + + final case class Render[+Event, Context, Payload]( + apply: Context => Widget[Event, Context, Payload] + ) extends Widget[Event, Context, Payload] + + final case class Local[+Event, Context, Payload]( + f: Context => Context, + widget: Widget[Event, Context, Payload] + ) extends Widget[Event, Context, Payload] + + def apply[Event, Context, Payload]( + apply: Context => Widget[Event, Context, Payload] + ): Widget[Event, Context, Payload] = + Render(apply) + + def pure[Event, Context, Payload]( + component: Component[Widget[Event, Context, Payload], Event], + payload: Payload + ): Widget[Event, Context, Payload] = Pure(component, payload) + + def empty[Event, Context, Payload: Monoid]( + component: Component[Widget[Event, Context, Payload], Event] + ): Widget[Event, Context, Payload] = + Pure(component, Monoid[Payload].empty) + + def local[Event, Context, Payload]( + f: Context => Context + )(widget: Widget[Event, Context, Payload]): Widget[Event, Context, Payload] = + Local(f, widget) + + @tailrec + def render[Event, Context, Payload]( + context: Context, + widget: Widget[Event, Context, Payload] + ): Widget[Event, Unit, Payload] = + widget match { + case Pure(component, payload) => Pure(render(context, component), payload) + case Render(apply) => render(context, apply(context)) + case Local(f, widget) => render(f(context), widget) + } + + def render[Event, Context, Payload]( + context: Context, + component: Component[Widget[Event, Context, Payload], Event] + ): Component[Widget[Event, Unit, Payload], Event] = + component match { + case component: Component.Element[Widget[Event, Context, Payload], Event] => + val children = component.children.map { (_, child) => + render(context, child) + } + component.copy(children = children) + case Component.Fragment(children) => + Component.Fragment(children.map((_, child) => render(context, child))) + case Component.Lazy(eval, hash) => + Component.Lazy(eval.map(render(context, _)), hash) + case component: Component.Text => component + } + + def payload[Event, Context, Payload]( + widget: Widget[Event, Context, Payload] + )(transform: Payload => Payload): Widget[Event, Context, Payload] = + widget match { + case Pure(component, payload) => Pure(component, transform(payload)) + case Render(apply) => + Render(context => payload(apply(context))(transform)) + case Local(f, widget) => Local(f, payload(widget)(transform)) + } + + def component[Event, Context, Payload]( + widget: Widget[Event, Context, Payload] + )( + transform: Component[Widget[Event, Context, Payload], Event] => Component[ + Widget[Event, Context, Payload], + Event + ] + ): Widget[Event, Context, Payload] = + widget match { + case Pure(component, payload) => Pure(transform(component), payload) + case Render(apply) => + Render(context => component(apply(context))(transform)) + case Local(f, widget) => Local(f, component(widget)(transform)) + } +} diff --git a/core/src/main/scala/io/taig/schelm/package.scala b/core/src/main/scala/io/taig/schelm/package.scala index 44b3b875..e43a8b00 100644 --- a/core/src/main/scala/io/taig/schelm/package.scala +++ b/core/src/main/scala/io/taig/schelm/package.scala @@ -10,46 +10,18 @@ package object schelm extends internal.Nodes { type EventHandler[State, Event, Command] = (State, Event) => Result[State, Command] - type Html[+Event] = Fix[Component[+?, Event]] - - object Html { - def apply[Event](component: Component[Html[Event], Event]): Html[Event] = - Fix[Component[+?, Event]](component) - } - - implicit final class HtmlSyntax[A](html: Html[A]) - extends ComponentOps[Html, A]( - html, - _.value, - (component, _) => Html(component) - ) - - type Document[+Event, A] = Cofree[Component[+?, Event], A] - - object Document { - def apply[Event, A]( - component: Component[Document[Event, A], Event], - value: A - ): Document[Event, A] = Cofree[Component[+?, Event], A](value, component) - } - - def toHtml[Event](value: Document[Event, _]): Html[Event] = - value.tail match { - case component: Component.Element[Document[Event, _], Event] => - val children = component.children.map((_, child) => toHtml(child)) - Html( - Component.Element( - component.name, - component.attributes, - component.listeners, - children - ) - ) - case component: Component.Fragment[Document[Event, _]] => - val children = component.children.map((_, child) => toHtml(child)) + val unit: Unit = () + + def toHtml[A](widget: Widget[A, Unit, _]): Html[A] = + widget.component(unit) match { + case component: Component.Element[Widget[A, Unit, _], A] => + val children = component.children.map((_, child) => toHtml[A](child)) + Html(component.copy(children = children)) + case component: Component.Fragment[Widget[A, Unit, _]] => + val children = component.children.map((_, child) => toHtml[A](child)) Html(Component.Fragment(children)) - case component: Component.Lazy[Document[Event, _]] => - Html(component.copy(eval = component.eval.map(toHtml))) + case component: Component.Lazy[Widget[A, Unit, _]] => + Html(component.copy(eval = component.eval.map(toHtml[A]))) case component: Component.Text => Html(component) } } diff --git a/css/src/main/scala/io/taig/schelm/css/CssSchelm.scala b/css/src/main/scala/io/taig/schelm/css/CssSchelm.scala index 99ec50b5..2b419a52 100644 --- a/css/src/main/scala/io/taig/schelm/css/CssSchelm.scala +++ b/css/src/main/scala/io/taig/schelm/css/CssSchelm.scala @@ -8,7 +8,9 @@ object CssSchelm { manager: EventManager[F, A], dom: Dom[F, A], globals: Stylesheet - ): Schelm[F, A, StyledHtml[A], StyledReference[A], StyledHtmlDiff[A]] = { + ): Schelm[F, A, StylesheetWidget[A], StyledReference[A], StyledHtmlDiff[ + A + ]] = { val renderer = HtmlRenderer(dom) Schelm( dom, diff --git a/css/src/main/scala/io/taig/schelm/css/Style.scala b/css/src/main/scala/io/taig/schelm/css/Style.scala index 4816034c..17df362b 100644 --- a/css/src/main/scala/io/taig/schelm/css/Style.scala +++ b/css/src/main/scala/io/taig/schelm/css/Style.scala @@ -18,6 +18,9 @@ final case class Style( def ++(pseudos: PseudoDeclarations): Style = Style(declarations, this.pseudos ++ pseudos) + def ++(style: Style): Style = + Style(declarations ++ style.declarations, pseudos ++ style.pseudos) + def toStylesheet(selectors: Selectors): Stylesheet = pseudos.toStylesheet(selectors) + Rule.Style(selectors, declarations) } diff --git a/css/src/main/scala/io/taig/schelm/css/StyledHtmlDiffer.scala b/css/src/main/scala/io/taig/schelm/css/StyledHtmlDiffer.scala index a32847e2..f8c4ad0a 100644 --- a/css/src/main/scala/io/taig/schelm/css/StyledHtmlDiffer.scala +++ b/css/src/main/scala/io/taig/schelm/css/StyledHtmlDiffer.scala @@ -6,11 +6,11 @@ import io.taig.schelm._ final class StyledHtmlDiffer[A]( html: Differ[Html[A], HtmlDiff[A]], - stylesheet: Differ[StyledHtml[A], StylesheetDiff] -) extends Differ[StyledHtml[A], StyledHtmlDiff[A]] { + stylesheet: Differ[StylesheetWidget[A], StylesheetDiff] +) extends Differ[StylesheetWidget[A], StyledHtmlDiff[A]] { override def diff( - previous: StyledHtml[A], - next: StyledHtml[A] + previous: StylesheetWidget[A], + next: StylesheetWidget[A] ): Option[StyledHtmlDiff[A]] = (html.diff(toHtml(previous), toHtml(next)), stylesheet.diff(previous, next)) match { case (Some(html), Some(stylesheet)) => Ior.both(html, stylesheet).some @@ -21,6 +21,6 @@ final class StyledHtmlDiffer[A]( } object StyledHtmlDiffer { - def apply[A]: Differ[StyledHtml[A], StyledHtmlDiff[A]] = + def apply[A]: Differ[StylesheetWidget[A], StyledHtmlDiff[A]] = new StyledHtmlDiffer[A](HtmlDiffer[A], StylesheetDiffer[A]) } diff --git a/css/src/main/scala/io/taig/schelm/css/StyledHtmlRenderer.scala b/css/src/main/scala/io/taig/schelm/css/StyledHtmlRenderer.scala index 51dbbf07..ac3fcb67 100644 --- a/css/src/main/scala/io/taig/schelm/css/StyledHtmlRenderer.scala +++ b/css/src/main/scala/io/taig/schelm/css/StyledHtmlRenderer.scala @@ -6,20 +6,20 @@ import io.taig.schelm._ final class StyledHtmlRenderer[F[_]: Functor, A]( renderer: Renderer[F, Html[A], Reference[A]] -) extends Renderer[F, StyledHtml[A], StyledReference[A]] { +) extends Renderer[F, StylesheetWidget[A], StyledReference[A]] { override def render( - styled: StyledHtml[A], + styled: StylesheetWidget[A], + parent: Option[Element], path: Path ): F[StyledReference[A]] = - renderer.render(toHtml(styled), path).map { reference => - val stylesheet = toStylesheet(styled) - StyledReference(reference, stylesheet) + renderer.render(toHtml(styled), parent, path).map { reference => + StyledReference(reference, styled.merge) } } object StyledHtmlRenderer { def apply[F[_]: Monad, A]( renderer: Renderer[F, Html[A], Reference[A]] - ): Renderer[F, StyledHtml[A], StyledReference[A]] = + ): Renderer[F, StylesheetWidget[A], StyledReference[A]] = new StyledHtmlRenderer[F, A](renderer) } diff --git a/css/src/main/scala/io/taig/schelm/css/StylesheetDiffer.scala b/css/src/main/scala/io/taig/schelm/css/StylesheetDiffer.scala index bedab8e5..9ab67921 100644 --- a/css/src/main/scala/io/taig/schelm/css/StylesheetDiffer.scala +++ b/css/src/main/scala/io/taig/schelm/css/StylesheetDiffer.scala @@ -3,31 +3,32 @@ package io.taig.schelm.css import cats.implicits._ import io.taig.schelm._ -final class StylesheetDiffer[A] extends Differ[StyledHtml[A], StylesheetDiff] { +final class StylesheetDiffer[A] + extends Differ[StylesheetWidget[A], StylesheetDiff] { override def diff( - previous: StyledHtml[A], - next: StyledHtml[A] + previous: StylesheetWidget[A], + next: StylesheetWidget[A] ): Option[StylesheetDiff] = { val stylesheet = compare(previous, next) if (stylesheet.isEmpty) None else StylesheetDiff(stylesheet).some } def compare( - previous: StyledHtml[A], - next: StyledHtml[A] + previous: StylesheetWidget[A], + next: StylesheetWidget[A] ): Stylesheet = { - val node = next.head + val node = next.payload(unit) // format: off - val children = (previous.tail, next.tail) match { - case (previous: Component.Element[StyledHtml[A], A], next: Component.Element[StyledHtml[A], A]) => + val children = (previous.component(unit), next.component(unit)) match { + case (previous: Component.Element[StylesheetWidget[A], A], next: Component.Element[StylesheetWidget[A], A]) => element(previous, next) - case (previous: Component.Fragment[StyledHtml[A]], next: Component.Fragment[StyledHtml[A]]) => + case (previous: Component.Fragment[StylesheetWidget[A]], next: Component.Fragment[StylesheetWidget[A]]) => fragment(previous, next) - case (previous: Component.Lazy[StyledHtml[A]], next: Component.Lazy[StyledHtml[A]]) => + case (previous: Component.Lazy[StylesheetWidget[A]], next: Component.Lazy[StylesheetWidget[A]]) => lzy(previous, next) case (_: Component.Text, _: Component.Text) => Stylesheet.Empty - case _ => toStylesheet(next) + case _ => next.merge } // format: on @@ -35,51 +36,52 @@ final class StylesheetDiffer[A] extends Differ[StyledHtml[A], StylesheetDiff] { } def element( - previous: Component.Element[StyledHtml[A], A], - next: Component.Element[StyledHtml[A], A] + previous: Component.Element[StylesheetWidget[A], A], + next: Component.Element[StylesheetWidget[A], A] ): Stylesheet = children(previous.children, next.children) def fragment( - previous: Component.Fragment[StyledHtml[A]], - next: Component.Fragment[StyledHtml[A]] + previous: Component.Fragment[StylesheetWidget[A]], + next: Component.Fragment[StylesheetWidget[A]] ): Stylesheet = children(previous.children, next.children) def lzy( - previous: Component.Lazy[StyledHtml[A]], - next: Component.Lazy[StyledHtml[A]] + previous: Component.Lazy[StylesheetWidget[A]], + next: Component.Lazy[StylesheetWidget[A]] ): Stylesheet = if (previous.hash == next.hash) Stylesheet.Empty else compare(previous.eval.value, next.eval.value) def children( - previous: Children[StyledHtml[A]], - next: Children[StyledHtml[A]] + previous: Children[StylesheetWidget[A]], + next: Children[StylesheetWidget[A]] ): Stylesheet = // format: off (previous, next) match { - case (previous: Children.Indexed[StyledHtml[A]], next: Children.Indexed[StyledHtml[A]]) => + case (previous: Children.Indexed[StylesheetWidget[A]], next: Children.Indexed[StylesheetWidget[A]]) => children(previous, next) - case (previous: Children.Identified[StyledHtml[A]], next: Children.Identified[StyledHtml[A]]) => + case (previous: Children.Identified[StylesheetWidget[A]], next: Children.Identified[StylesheetWidget[A]]) => // TODO Stylesheet.Empty - case _ => next.values.map(toStylesheet).combineAll + case _ => next.values.map(_.merge).combineAll } // format: on def children( - previous: Children.Indexed[StyledHtml[A]], - next: Children.Indexed[StyledHtml[A]] + previous: Children.Indexed[StylesheetWidget[A]], + next: Children.Indexed[StylesheetWidget[A]] ): Stylesheet = if (next.isEmpty) Stylesheet.Empty else { val left = previous.values val right = next.values val comparisons = (left zip right).map(compare _ tupled).combineAll - val additions = right.drop(left.length).map(toStylesheet).combineAll + val additions = right.drop(left.length).map(_.merge).combineAll comparisons ++ additions } } object StylesheetDiffer { - def apply[A]: Differ[StyledHtml[A], StylesheetDiff] = new StylesheetDiffer[A] + def apply[A]: Differ[StylesheetWidget[A], StylesheetDiff] = + new StylesheetDiffer[A] } diff --git a/css/src/main/scala/io/taig/schelm/css/package.scala b/css/src/main/scala/io/taig/schelm/css/package.scala index ac1be7ad..975e2f0a 100644 --- a/css/src/main/scala/io/taig/schelm/css/package.scala +++ b/css/src/main/scala/io/taig/schelm/css/package.scala @@ -6,43 +6,14 @@ import cats.implicits._ package object css extends NormalizeCss { type StyledHtmlDiff[A] = Ior[HtmlDiff[A], StylesheetDiff] - type Widget[+A] = Document[A, Styles] + type StyledWidget[+A] = Widget[A, Unit, Styles] - object Widget { - def apply[A]( - component: Component[Widget[A], A], - styles: Styles - ): Widget[A] = Document(component, styles) - } + type StylesheetWidget[+A] = Widget[A, Unit, Stylesheet] - implicit final class WidgetSyntax[A](widget: Widget[A]) - extends ComponentOps[Widget, A]( - widget, - _.tail, - (component, widget) => Widget[A](component, widget.head) - ) { - def setStyles(styles: Styles): Widget[A] = Widget(widget.tail, styles) - } - - type StyledHtml[+Event] = Document[Event, Stylesheet] - - object StyledHtml { - def apply[Event]( - component: Component[StyledHtml[Event], Event], - stylesheet: Stylesheet - ): StyledHtml[Event] = - Document(component, stylesheet) - - def empty[Event]( - component: Component[StyledHtml[Event], Event] - ): StyledHtml[Event] = - StyledHtml(component, Stylesheet.Empty) - } - - def toStyledHtml[Event](widget: Widget[Event]): StyledHtml[Event] = - widget.tail match { - case component: Component.Element[Widget[Event], Event] => - val styles = widget.head.map { style => + def toStylesheetWidget[A](widget: StyledWidget[A]): StylesheetWidget[A] = + widget.component match { + case component: Component.Element[StyledWidget[A], A] => + val styles = widget.payload.map { style => val identifier = Identifier(style.hashCode) val selectors = Selectors.of(identifier.selector) identifier -> style.toStylesheet(selectors) @@ -55,35 +26,27 @@ package object css extends NormalizeCss { if (identifiers.isEmpty) component.attributes else component.attributes.merge(cls(identifiers.map(_.cls))) - val children = component.children.map((_, child) => toStyledHtml(child)) + val children = component.children.map { (_, child) => + toStylesheetWidget(child) + } - StyledHtml( + Widget.pure( component.copy(attributes = attributes, children = children), stylesheet ) - case component: Component.Fragment[Widget[Event]] => - val children = component.children.map((_, child) => toStyledHtml(child)) - StyledHtml.empty(component.copy(children = children)) - case component: Component.Lazy[Widget[Event]] => - val eval = component.eval.map(toStyledHtml[Event]) - StyledHtml.empty(component.copy(eval = eval)) - case component: Component.Text => - StyledHtml(component, Stylesheet.Empty) - } - - def toStylesheet[A](html: StyledHtml[A]): Stylesheet = - html.tail match { - case component: Component.Element[StyledHtml[A], A] => - component.children.foldLeft(html.head) { (stylesheet, A, html) => - stylesheet |+| toStylesheet(html) + case component: Component.Fragment[StyledWidget[A]] => + val payload = widget.payload + val children = component.children.map { (_, child) => + toStylesheetWidget(Widget.payload(child)(payload ++ _)) } - case component: Component.Fragment[StyledHtml[A]] => - component.children.foldLeft(Stylesheet.Empty) { (stylesheet, _, html) => - stylesheet |+| toStylesheet(html) + Widget.empty(component.copy(children = children)) + case component: Component.Lazy[StyledWidget[A]] => + val eval = component.eval.map { widget => + val payload = widget.payload + toStylesheetWidget[A](Widget.payload(widget)(payload ++ _)) } - case component: Component.Lazy[StyledHtml[A]] => - toStylesheet(component.eval.value) - case _: Component.Text => Stylesheet.Empty + Widget.empty(component.copy(eval = eval)) + case component: Component.Text => Widget.empty(component) } private def cls(values: List[String]): Attribute = diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/AttributesDsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/AttributesDsl.scala new file mode 100644 index 00000000..d334ae71 --- /dev/null +++ b/dsl/src/main/scala/io/taig/schelm/dsl/AttributesDsl.scala @@ -0,0 +1,46 @@ +package io.taig.schelm.dsl + +import io.taig.schelm.css._ +import io.taig.schelm._ + +trait AttributesDsl { + final def attr(key: String, value: String): Attribute = + Attribute(key, Value.One(value)) + + final def attrs( + key: String, + values: List[String], + accumulator: Accumulator + ): Attribute = + Attribute(key, Value.Multiple(values, accumulator)) + + final def data(key: String, value: String): Attribute = + attr(s"data-$key", value) + + final def aria(key: String, value: String): Attribute = + attr(s"aria-$key", value) + + final def flag(key: String, value: Boolean): Attribute = + Attribute(key, Value.Flag(value)) + + final def cls(values: String*): Attribute = + attrs("class", values.toList, Accumulator.Whitespace) + + // format: off + final def cx(value: String): Attribute = attr("cx", value) + final def rx(value: String): Attribute = attr("rx", value) + final def ry(value: String): Attribute = attr("ry", value) + final def cy(value: String): Attribute = attr("cy", value) + final def d(value: String): Attribute = attr("d", value) + final def disabled(value: Boolean): Attribute = flag("disabled", value) + final val disabled: Attribute = disabled(true) + final def href(value: String): Attribute = attr("href", value) + final def id(value: String): Attribute = attr("id", value) + // format: on + + final def style(declarations: Declarations): Attribute = + attrs("style", declarations.rows, Accumulator.Whitespace) + + final def style(declarations: Declaration*): Attribute = + style(Declarations.from(declarations)) +} diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/Builders.scala b/dsl/src/main/scala/io/taig/schelm/dsl/Builders.scala deleted file mode 100644 index f3037cf4..00000000 --- a/dsl/src/main/scala/io/taig/schelm/dsl/Builders.scala +++ /dev/null @@ -1,32 +0,0 @@ -package io.taig.schelm.dsl - -import io.taig.schelm.Children -import io.taig.schelm.css.Widget - -final class NodeBuilder[A](val widget: Widget[A]) extends AnyVal { - def apply( - property: Property[A], - properties: Property[A]* - ): ChildrenBuilder[A] = { - val (attributes, listeners, styles) = split(property +: properties) - val update = widget - .setAttributes(attributes) - .setListeners(listeners) - .setStyles(styles) - new ChildrenBuilder(update) - } - - def apply(children: Widget[A]*): Widget[A] = - new ChildrenBuilder(widget)(children: _*) - - def apply(children: List[(String, Widget[A])]): Widget[A] = - new ChildrenBuilder(widget)(children) -} - -final class ChildrenBuilder[A](val widget: Widget[A]) extends AnyVal { - def apply(children: Widget[A]*): Widget[A] = - widget.setChildren(Children.indexed(children)) - - def apply(children: List[(String, Widget[A])]): Widget[A] = - widget.setChildren(Children.identified(children)) -} diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/CssDsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/CssDsl.scala index 1a42794d..99e19eea 100644 --- a/dsl/src/main/scala/io/taig/schelm/dsl/CssDsl.scala +++ b/dsl/src/main/scala/io/taig/schelm/dsl/CssDsl.scala @@ -1,36 +1,46 @@ package io.taig.schelm.dsl import cats.implicits._ +import io.taig.schelm.Widget import io.taig.schelm.css._ -trait CssDsl extends CssKeysDsl with CssValuesDsl { - implicit def declarationToEither( +trait CssDsl[Context] extends CssKeysDsl with CssValuesDsl { + this: WidgetDsl[Context, Styles] => + implicit final def declarationToEither( declaration: Declaration ): DeclarationOrPseudo = declaration.asLeft - implicit def pseudoToEither( + implicit final def pseudoToEither( declaration: PseudoDeclaration ): DeclarationOrPseudo = declaration.asRight - implicit def numericToScaleUnitsOps[B: Numeric](value: B): CssScaleUnitOps = + implicit final def numericToScaleUnitsOps[B: Numeric]( + value: B + ): CssScaleUnitOps = new CssScaleUnitOps(value.toString) - implicit def numericToTimeUnitsOps[B: Numeric](value: B): CssTimeUnitOps = + implicit final def numericToTimeUnitsOps[B: Numeric]( + value: B + ): CssTimeUnitOps = new CssTimeUnitOps(value.toString) - def stylesheet(styles: Styles): Property[Nothing] = - Property.fromStyles(styles) + implicit final class CssBuilder[A](component: Widget[A, Context, Styles]) { + def styles(styles: Styles): Widget[A, Context, Styles] = + updatePayload(component, _ ++ styles) - def stylesheet( - declaration: DeclarationOrPseudo, - declarations: DeclarationOrPseudo* - ): Property[Nothing] = - stylesheet(styles(declaration, declarations: _*)) + def styles(style: Style): Widget[A, Context, Styles] = + updatePayload(component, _ :+ style) - def styles( - declaration: DeclarationOrPseudo, - declarations: DeclarationOrPseudo* - ): Styles = Styles.of(reduce(declaration +: declarations)) + def styles( + declarations: DeclarationOrPseudo* + ): Widget[A, Context, Styles] = styles(css(declarations: _*)) + } + + def css(declarations: DeclarationOrPseudo*): Style = + declarations.foldLeft(Style.Empty) { + case (style, Left(declaration)) => style :+ declaration + case (style, Right(declaration)) => style :+ declaration + } object & extends CssPseudoDsl } diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/CssKeysDsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/CssKeysDsl.scala index b431d995..e422fad6 100644 --- a/dsl/src/main/scala/io/taig/schelm/dsl/CssKeysDsl.scala +++ b/dsl/src/main/scala/io/taig/schelm/dsl/CssKeysDsl.scala @@ -3,270 +3,177 @@ package io.taig.schelm.dsl import io.taig.schelm.css.Declaration trait CssKeysDsl { - def declaration(key: String, value: String): Declaration = + final def declaration(key: String, value: String): Declaration = Declaration(key, value) - def alignContent(value: String): Declaration = - declaration("align-content", value) - def alignItems(value: String): Declaration = declaration("align-items", value) - def alignSelf(value: String): Declaration = declaration("align-self", value) - def animation(value: String): Declaration = declaration("animation", value) - def animationDelay(value: String): Declaration = - declaration("animation-delay", value) - def animationDirection(value: String): Declaration = - declaration("animation-direction", value) - def animationDuration(value: String): Declaration = - declaration("animation-duration", value) - def animationFillMode(value: String): Declaration = - declaration("animation-fill-mode", value) - def animationIterationCount(value: String): Declaration = - declaration("animation-iteration-count", value) - def animationName(value: String): Declaration = - declaration("animation-name", value) - def animationPlayState(value: String): Declaration = - declaration("animation-play-state", value) - def animationTimingFunction(value: String): Declaration = - declaration("animation-timing-function", value) - def backfaceVisibility(value: String): Declaration = - declaration("backface-visibility", value) - def background(value: String): Declaration = declaration("background", value) - def backgroundAttachment(value: String): Declaration = - declaration("background-attachment", value) - def backgroundClip(value: String): Declaration = - declaration("background-clip", value) - def backgroundColor(value: String): Declaration = - declaration("background-color", value) - def backgroundImage(value: String): Declaration = - declaration("background-image", value) - def backgroundOrigin(value: String): Declaration = - declaration("background-origin", value) - def backgroundPosition(value: String): Declaration = - declaration("background-position", value) - def backgroundRepeat(value: String): Declaration = - declaration("background-repeat", value) - def backgroundSize(value: String): Declaration = - declaration("background-size", value) - def border(value: String): Declaration = declaration("border", value) - def borderBottom(value: String): Declaration = - declaration("border-bottom", value) - def borderBottomColor(value: String): Declaration = - declaration("border-bottom-color", value) - def borderBottomLeftRadius(value: String): Declaration = - declaration("border-bottom-left-radius", value) - def borderBottomRightRadius(value: String): Declaration = - declaration("border-bottom-right-radius", value) - def borderBottomStyle(value: String): Declaration = - declaration("border-bottom-style", value) - def borderBottomWidth(value: String): Declaration = - declaration("border-bottom-width", value) - def borderCollapse(value: String): Declaration = - declaration("border-collapse", value) - def borderColor(value: String): Declaration = - declaration("border-color", value) - def borderImage(value: String): Declaration = - declaration("border-image", value) - def borderImageOutset(value: String): Declaration = - declaration("border-image-outset", value) - def borderImageRepeat(value: String): Declaration = - declaration("border-image-repeat", value) - def borderImageSlice(value: String): Declaration = - declaration("border-image-slice", value) - def borderImageSource(value: String): Declaration = - declaration("border-image-source", value) - def borderImageWidth(value: String): Declaration = - declaration("border-image-width", value) - def borderLeft(value: String): Declaration = declaration("border-left", value) - def borderLeftColor(value: String): Declaration = - declaration("border-left-color", value) - def borderLeftStyle(value: String): Declaration = - declaration("border-left-style", value) - def borderLeftWidth(value: String): Declaration = - declaration("border-left-width", value) - def borderRadius(value: String): Declaration = - declaration("border-radius", value) - def borderRight(value: String): Declaration = - declaration("border-right", value) - def borderRightColor(value: String): Declaration = - declaration("border-right-color", value) - def borderRightStyle(value: String): Declaration = - declaration("border-right-style", value) - def borderRightWidth(value: String): Declaration = - declaration("border-right-width", value) - def borderSpacing(value: String): Declaration = - declaration("border-spacing", value) - def borderStyle(value: String): Declaration = - declaration("border-style", value) - def borderTop(value: String): Declaration = declaration("border-top", value) - def borderTopColor(value: String): Declaration = - declaration("border-top-color", value) - def borderTopLeftRadius(value: String): Declaration = - declaration("border-top-left-radius", value) - def borderTopRightRadius(value: String): Declaration = - declaration("border-top-right-radius", value) - def borderTopStyle(value: String): Declaration = - declaration("border-top-style", value) - def borderTopWidth(value: String): Declaration = - declaration("border-top-width", value) - def borderWidth(value: String): Declaration = - declaration("border-width", value) - def bottom(value: String): Declaration = declaration("bottom", value) - def boxShadow(value: String): Declaration = declaration("box-shadow", value) - def boxSizing(value: String): Declaration = declaration("box-sizing", value) - def captionSide(value: String): Declaration = - declaration("caption-side", value) - def clear(value: String): Declaration = declaration("clear", value) - def clip(value: String): Declaration = declaration("clip", value) - def color(value: String): Declaration = declaration("color", value) - def columnCount(value: String): Declaration = - declaration("column-count", value) - def columnFill(value: String): Declaration = declaration("column-fill", value) - def columnGap(value: String): Declaration = declaration("column-gap", value) - def columnRule(value: String): Declaration = declaration("column-rule", value) - def columnRuleColor(value: String): Declaration = - declaration("column-rule-color", value) - def columnRuleStyle(value: String): Declaration = - declaration("column-rule-style", value) - def columnRuleWidth(value: String): Declaration = - declaration("column-rule-width", value) - def columnSpan(value: String): Declaration = declaration("column-span", value) - def columnWidth(value: String): Declaration = - declaration("column-width", value) - def columns(value: String): Declaration = declaration("columns", value) - def content(value: String): Declaration = declaration("content", value) - def counterIncrement(value: String): Declaration = - declaration("counter-increment", value) - def counterReset(value: String): Declaration = - declaration("counter-reset", value) - def cursor(value: String): Declaration = declaration("cursor", value) - def direction(value: String): Declaration = declaration("direction", value) - def display(value: String): Declaration = declaration("display", value) - def emptyCells(value: String): Declaration = declaration("empty-cells", value) - def flex(value: String): Declaration = declaration("flex", value) - def flexBasis(value: String): Declaration = declaration("flex-basis", value) - def flexDirection(value: String): Declaration = - declaration("flex-direction", value) - def flexFlow(value: String): Declaration = declaration("flex-flow", value) - def flexGrow(value: String): Declaration = declaration("flex-grow", value) - def flexShrink(value: String): Declaration = declaration("flex-shrink", value) - def flexWrap(value: String): Declaration = declaration("flex-wrap", value) - def float(value: String): Declaration = declaration("float", value) - def font(value: String): Declaration = declaration("font", value) - def fontFamily(value: String): Declaration = declaration("font-family", value) - def fontSize(value: String): Declaration = declaration("font-size", value) - def fontSizeAdjust(value: String): Declaration = - declaration("font-size-adjust", value) - def fontStretch(value: String): Declaration = - declaration("font-stretch", value) - def fontStyle(value: String): Declaration = declaration("font-style", value) - def fontVariant(value: String): Declaration = - declaration("font-variant", value) - def fontWeight(value: String): Declaration = declaration("font-weight", value) - def height(value: String): Declaration = declaration("height", value) - def justifyContent(value: String): Declaration = - declaration("justify-content", value) - def left(value: String): Declaration = declaration("left", value) - def letterSpacing(value: String): Declaration = - declaration("letter-spacing", value) - def lineHeight(value: String): Declaration = declaration("line-height", value) - def listStyle(value: String): Declaration = declaration("list-style", value) - def listStyleImage(value: String): Declaration = - declaration("list-style-image", value) - def listStylePosition(value: String): Declaration = - declaration("list-style-position", value) - def listStyleType(value: String): Declaration = - declaration("list-style-type", value) - def margin(value: String): Declaration = declaration("margin", value) - def marginBottom(value: String): Declaration = - declaration("margin-bottom", value) - def marginLeft(value: String): Declaration = declaration("margin-left", value) - def marginRight(value: String): Declaration = - declaration("margin-right", value) - def marginTop(value: String): Declaration = declaration("margin-top", value) - def maxHeight(value: String): Declaration = declaration("max-height", value) - def maxWidth(value: String): Declaration = declaration("max-width", value) - def minHeight(value: String): Declaration = declaration("min-height", value) - def minWidth(value: String): Declaration = declaration("min-width", value) - def opacity(value: String): Declaration = declaration("opacity", value) - def order(value: String): Declaration = declaration("order", value) - def outline(value: String): Declaration = declaration("outline", value) - def outlineColor(value: String): Declaration = - declaration("outline-color", value) - def outlineOffset(value: String): Declaration = - declaration("outline-offset", value) - def outlineStyle(value: String): Declaration = - declaration("outline-style", value) - def outlineWidth(value: String): Declaration = - declaration("outline-width", value) - def overflow(value: String): Declaration = declaration("overflow", value) - def overflowX(value: String): Declaration = declaration("overflow-x", value) - def overflowY(value: String): Declaration = declaration("overflow-y", value) - def padding(value: String): Declaration = declaration("padding", value) - def paddingBottom(value: String): Declaration = - declaration("padding-bottom", value) - def paddingLeft(value: String): Declaration = - declaration("padding-left", value) - def paddingRight(value: String): Declaration = - declaration("padding-right", value) - def paddingTop(value: String): Declaration = declaration("padding-top", value) - def pageBreakAfter(value: String): Declaration = - declaration("page-break-after", value) - def pageBreakBefore(value: String): Declaration = - declaration("page-break-before", value) - def pageBreakInside(value: String): Declaration = - declaration("page-break-inside", value) - def perspective(value: String): Declaration = - declaration("perspective", value) - def perspectiveOrigin(value: String): Declaration = - declaration("perspective-origin", value) - def position(value: String): Declaration = declaration("position", value) - def quotes(value: String): Declaration = declaration("quotes", value) - def resize(value: String): Declaration = declaration("resize", value) - def right(value: String): Declaration = declaration("right", value) - def tabSize(value: String): Declaration = declaration("tab-size", value) - def tableLayout(value: String): Declaration = - declaration("table-layout", value) - def textAlign(value: String): Declaration = declaration("text-align", value) - def textAlignLast(value: String): Declaration = - declaration("text-align-last", value) - def textDecoration(value: String): Declaration = - declaration("text-decoration", value) - def textDecorationColor(value: String): Declaration = - declaration("text-decoration-color", value) - def textDecorationLine(value: String): Declaration = - declaration("text-decoration-line", value) - def textDecorationStyle(value: String): Declaration = - declaration("text-decoration-style", value) - def textIndent(value: String): Declaration = declaration("text-indent", value) - def textJustify(value: String): Declaration = - declaration("text-justify", value) - def textOverflow(value: String): Declaration = - declaration("text-overflow", value) - def textShadow(value: String): Declaration = declaration("text-shadow", value) - def textTransform(value: String): Declaration = - declaration("text-transform", value) - def top(value: String): Declaration = declaration("top", value) - def transform(value: String): Declaration = declaration("transform", value) - def transformOrigin(value: String): Declaration = - declaration("transform-origin", value) - def transformStyle(value: String): Declaration = - declaration("transform-style", value) - def transition(value: String): Declaration = declaration("transition", value) - def transitionDelay(value: String): Declaration = - declaration("transition-delay", value) - def transitionDuration(value: String): Declaration = - declaration("transition-duration", value) - def transitionProperty(value: String): Declaration = - declaration("transition-property", value) - def transitionTimingFunction(value: String): Declaration = - declaration("transition-timing-function", value) - def verticalAlign(value: String): Declaration = - declaration("vertical-align", value) - def visibility(value: String): Declaration = declaration("visibility", value) - def whiteSpace(value: String): Declaration = declaration("white-space", value) - def width(value: String): Declaration = declaration("width", value) - def wordBreak(value: String): Declaration = declaration("word-break", value) - def wordSpacing(value: String): Declaration = - declaration("word-spacing", value) - def wordWrap(value: String): Declaration = declaration("word-wrap", value) - def zIndex(value: String): Declaration = declaration("z-index", value) + // format: off + final def alignContent(value: String): Declaration = declaration("align-content", value) + final def alignItems(value: String): Declaration = declaration("align-items", value) + final def alignSelf(value: String): Declaration = declaration("align-self", value) + final def animation(value: String): Declaration = declaration("animation", value) + final def animationDelay(value: String): Declaration = declaration("animation-delay", value) + final def animationDirection(value: String): Declaration = declaration("animation-direction", value) + final def animationDuration(value: String): Declaration = declaration("animation-duration", value) + final def animationFillMode(value: String): Declaration = declaration("animation-fill-mode", value) + final def animationIterationCount(value: String): Declaration = declaration("animation-iteration-count", value) + final def animationName(value: String): Declaration = declaration("animation-name", value) + final def animationPlayState(value: String): Declaration = declaration("animation-play-state", value) + final def animationTimingFunction(value: String): Declaration = declaration("animation-timing-function", value) + final def backfaceVisibility(value: String): Declaration = declaration("backface-visibility", value) + final def background(value: String): Declaration = declaration("background", value) + final def backgroundAttachment(value: String): Declaration = declaration("background-attachment", value) + final def backgroundClip(value: String): Declaration = declaration("background-clip", value) + final def backgroundColor(value: String): Declaration = declaration("background-color", value) + final def backgroundImage(value: String): Declaration = declaration("background-image", value) + final def backgroundOrigin(value: String): Declaration = declaration("background-origin", value) + final def backgroundPosition(value: String): Declaration = declaration("background-position", value) + final def backgroundRepeat(value: String): Declaration = declaration("background-repeat", value) + final def backgroundSize(value: String): Declaration = declaration("background-size", value) + final def border(value: String): Declaration = declaration("border", value) + final def borderBottom(value: String): Declaration = declaration("border-bottom", value) + final def borderBottomColor(value: String): Declaration = declaration("border-bottom-color", value) + final def borderBottomLeftRadius(value: String): Declaration = declaration("border-bottom-left-radius", value) + final def borderBottomRightRadius(value: String): Declaration = declaration("border-bottom-right-radius", value) + final def borderBottomStyle(value: String): Declaration = declaration("border-bottom-style", value) + final def borderBottomWidth(value: String): Declaration = declaration("border-bottom-width", value) + final def borderCollapse(value: String): Declaration = declaration("border-collapse", value) + final def borderColor(value: String): Declaration = declaration("border-color", value) + final def borderImage(value: String): Declaration = declaration("border-image", value) + final def borderImageOutset(value: String): Declaration = declaration("border-image-outset", value) + final def borderImageRepeat(value: String): Declaration = declaration("border-image-repeat", value) + final def borderImageSlice(value: String): Declaration = declaration("border-image-slice", value) + final def borderImageSource(value: String): Declaration = declaration("border-image-source", value) + final def borderImageWidth(value: String): Declaration = declaration("border-image-width", value) + final def borderLeft(value: String): Declaration = declaration("border-left", value) + final def borderLeftColor(value: String): Declaration = declaration("border-left-color", value) + final def borderLeftStyle(value: String): Declaration = declaration("border-left-style", value) + final def borderLeftWidth(value: String): Declaration = declaration("border-left-width", value) + final def borderRadius(value: String): Declaration = declaration("border-radius", value) + final def borderRight(value: String): Declaration = declaration("border-right", value) + final def borderRightColor(value: String): Declaration = declaration("border-right-color", value) + final def borderRightStyle(value: String): Declaration = declaration("border-right-style", value) + final def borderRightWidth(value: String): Declaration = declaration("border-right-width", value) + final def borderSpacing(value: String): Declaration = declaration("border-spacing", value) + final def borderStyle(value: String): Declaration = declaration("border-style", value) + final def borderTop(value: String): Declaration = declaration("border-top", value) + final def borderTopColor(value: String): Declaration = declaration("border-top-color", value) + final def borderTopLeftRadius(value: String): Declaration = declaration("border-top-left-radius", value) + final def borderTopRightRadius(value: String): Declaration = declaration("border-top-right-radius", value) + final def borderTopStyle(value: String): Declaration = declaration("border-top-style", value) + final def borderTopWidth(value: String): Declaration = declaration("border-top-width", value) + final def borderWidth(value: String): Declaration = declaration("border-width", value) + final def bottom(value: String): Declaration = declaration("bottom", value) + final def boxShadow(value: String): Declaration = declaration("box-shadow", value) + final def boxSizing(value: String): Declaration = declaration("box-sizing", value) + final def captionSide(value: String): Declaration = declaration("caption-side", value) + final def clear(value: String): Declaration = declaration("clear", value) + final def clip(value: String): Declaration = declaration("clip", value) + final def color(value: String): Declaration = declaration("color", value) + final def columnCount(value: String): Declaration = declaration("column-count", value) + final def columnFill(value: String): Declaration = declaration("column-fill", value) + final def columnGap(value: String): Declaration = declaration("column-gap", value) + final def columnRule(value: String): Declaration = declaration("column-rule", value) + final def columnRuleColor(value: String): Declaration = declaration("column-rule-color", value) + final def columnRuleStyle(value: String): Declaration = declaration("column-rule-style", value) + final def columnRuleWidth(value: String): Declaration = declaration("column-rule-width", value) + final def columnSpan(value: String): Declaration = declaration("column-span", value) + final def columnWidth(value: String): Declaration = declaration("column-width", value) + final def columns(value: String): Declaration = declaration("columns", value) + final def content(value: String): Declaration = declaration("content", value) + final def counterIncrement(value: String): Declaration = declaration("counter-increment", value) + final def counterReset(value: String): Declaration = declaration("counter-reset", value) + final def cursor(value: String): Declaration = declaration("cursor", value) + final def direction(value: String): Declaration = declaration("direction", value) + final def display(value: String): Declaration = declaration("display", value) + final def emptyCells(value: String): Declaration = declaration("empty-cells", value) + final def flex(value: String): Declaration = declaration("flex", value) + final def flexBasis(value: String): Declaration = declaration("flex-basis", value) + final def flexDirection(value: String): Declaration = declaration("flex-direction", value) + final def flexFlow(value: String): Declaration = declaration("flex-flow", value) + final def flexGrow(value: String): Declaration = declaration("flex-grow", value) + final def flexShrink(value: String): Declaration = declaration("flex-shrink", value) + final def flexWrap(value: String): Declaration = declaration("flex-wrap", value) + final def float(value: String): Declaration = declaration("float", value) + final def font(value: String): Declaration = declaration("font", value) + final def fontFamily(value: String): Declaration = declaration("font-family", value) + final def fontSize(value: String): Declaration = declaration("font-size", value) + final def fontSizeAdjust(value: String): Declaration = declaration("font-size-adjust", value) + final def fontStretch(value: String): Declaration = declaration("font-stretch", value) + final def fontStyle(value: String): Declaration = declaration("font-style", value) + final def fontVariant(value: String): Declaration = declaration("font-variant", value) + final def fontWeight(value: String): Declaration = declaration("font-weight", value) + final def height(value: String): Declaration = declaration("height", value) + final def justifyContent(value: String): Declaration = declaration("justify-content", value) + final def left(value: String): Declaration = declaration("left", value) + final def letterSpacing(value: String): Declaration = declaration("letter-spacing", value) + final def lineHeight(value: String): Declaration = declaration("line-height", value) + final def listStyle(value: String): Declaration = declaration("list-style", value) + final def listStyleImage(value: String): Declaration = declaration("list-style-image", value) + final def listStylePosition(value: String): Declaration = declaration("list-style-position", value) + final def listStyleType(value: String): Declaration = declaration("list-style-type", value) + final def margin(value: String): Declaration = declaration("margin", value) + final def marginBottom(value: String): Declaration = declaration("margin-bottom", value) + final def marginLeft(value: String): Declaration = declaration("margin-left", value) + final def marginRight(value: String): Declaration = declaration("margin-right", value) + final def marginTop(value: String): Declaration = declaration("margin-top", value) + final def maxHeight(value: String): Declaration = declaration("max-height", value) + final def maxWidth(value: String): Declaration = declaration("max-width", value) + final def minHeight(value: String): Declaration = declaration("min-height", value) + final def minWidth(value: String): Declaration = declaration("min-width", value) + final def opacity(value: String): Declaration = declaration("opacity", value) + final def order(value: String): Declaration = declaration("order", value) + final def outline(value: String): Declaration = declaration("outline", value) + final def outlineColor(value: String): Declaration = declaration("outline-color", value) + final def outlineOffset(value: String): Declaration = declaration("outline-offset", value) + final def outlineStyle(value: String): Declaration = declaration("outline-style", value) + final def outlineWidth(value: String): Declaration = declaration("outline-width", value) + final def overflow(value: String): Declaration = declaration("overflow", value) + final def overflowX(value: String): Declaration = declaration("overflow-x", value) + final def overflowY(value: String): Declaration = declaration("overflow-y", value) + final def padding(value: String): Declaration = declaration("padding", value) + final def paddingBottom(value: String): Declaration = declaration("padding-bottom", value) + final def paddingLeft(value: String): Declaration = declaration("padding-left", value) + final def paddingRight(value: String): Declaration = declaration("padding-right", value) + final def paddingTop(value: String): Declaration = declaration("padding-top", value) + final def pageBreakAfter(value: String): Declaration = declaration("page-break-after", value) + final def pageBreakBefore(value: String): Declaration = declaration("page-break-before", value) + final def pageBreakInside(value: String): Declaration = declaration("page-break-inside", value) + final def perspective(value: String): Declaration = declaration("perspective", value) + final def perspectiveOrigin(value: String): Declaration = declaration("perspective-origin", value) + final def position(value: String): Declaration = declaration("position", value) + final def quotes(value: String): Declaration = declaration("quotes", value) + final def resize(value: String): Declaration = declaration("resize", value) + final def right(value: String): Declaration = declaration("right", value) + final def tabSize(value: String): Declaration = declaration("tab-size", value) + final def tableLayout(value: String): Declaration = declaration("table-layout", value) + final def textAlign(value: String): Declaration = declaration("text-align", value) + final def textAlignLast(value: String): Declaration = declaration("text-align-last", value) + final def textDecoration(value: String): Declaration = declaration("text-decoration", value) + final def textDecorationColor(value: String): Declaration = declaration("text-decoration-color", value) + final def textDecorationLine(value: String): Declaration = declaration("text-decoration-line", value) + final def textDecorationStyle(value: String): Declaration = declaration("text-decoration-style", value) + final def textIndent(value: String): Declaration = declaration("text-indent", value) + final def textJustify(value: String): Declaration = declaration("text-justify", value) + final def textOverflow(value: String): Declaration = declaration("text-overflow", value) + final def textShadow(value: String): Declaration = declaration("text-shadow", value) + final def textTransform(value: String): Declaration = declaration("text-transform", value) + final def top(value: String): Declaration = declaration("top", value) + final def transform(value: String): Declaration = declaration("transform", value) + final def transformOrigin(value: String): Declaration = declaration("transform-origin", value) + final def transformStyle(value: String): Declaration = declaration("transform-style", value) + final def transition(value: String): Declaration = declaration("transition", value) + final def transitionDelay(value: String): Declaration = declaration("transition-delay", value) + final def transitionDuration(value: String): Declaration = declaration("transition-duration", value) + final def transitionProperty(value: String): Declaration = declaration("transition-property", value) + final def transitionTimingFunction(value: String): Declaration = declaration("transition-timing-function", value) + final def userSelect(value: String): Declaration = declaration("user-select", value) + final def verticalAlign(value: String): Declaration = declaration("vertical-align", value) + final def visibility(value: String): Declaration = declaration("visibility", value) + final def whiteSpace(value: String): Declaration = declaration("white-space", value) + final def width(value: String): Declaration = declaration("width", value) + final def wordBreak(value: String): Declaration = declaration("word-break", value) + final def wordSpacing(value: String): Declaration = declaration("word-spacing", value) + final def wordWrap(value: String): Declaration = declaration("word-wrap", value) + final def zIndex(value: String): Declaration = declaration("z-index", value) + // format: on } diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/CssPseudoDsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/CssPseudoDsl.scala index e03c5e46..aafed0ae 100644 --- a/dsl/src/main/scala/io/taig/schelm/dsl/CssPseudoDsl.scala +++ b/dsl/src/main/scala/io/taig/schelm/dsl/CssPseudoDsl.scala @@ -8,103 +8,108 @@ import io.taig.schelm.css.{ } trait CssPseudoDsl { - def pseudo( + final def pseudo( modifier: String )(declarations: Declaration*): PseudoDeclaration = PseudoDeclaration(Modifier(modifier), Declarations.from(declarations)) - def after(declarations: Declaration*): PseudoDeclaration = + + final def after(declarations: Declaration*): PseudoDeclaration = pseudo("::after")(declarations: _*) - def active(declarations: Declaration*): PseudoDeclaration = + final def active(declarations: Declaration*): PseudoDeclaration = pseudo(":active")(declarations: _*) - def before(declarations: Declaration*): PseudoDeclaration = + final def before(declarations: Declaration*): PseudoDeclaration = pseudo("::before")(declarations: _*) - def checked(declarations: Declaration*): PseudoDeclaration = + final def checked(declarations: Declaration*): PseudoDeclaration = pseudo(":checked")(declarations: _*) - def default(declarations: Declaration*): PseudoDeclaration = + final def default(declarations: Declaration*): PseudoDeclaration = pseudo(":default")(declarations: _*) - def dir(direction: String)(declarations: Declaration*): PseudoDeclaration = + final def dir( + direction: String + )(declarations: Declaration*): PseudoDeclaration = pseudo(s":dir($direction)")(declarations: _*) - def disabled(declarations: Declaration*): PseudoDeclaration = + final def disabled(declarations: Declaration*): PseudoDeclaration = pseudo(":disabled")(declarations: _*) - def empty(declarations: Declaration*): PseudoDeclaration = + final def empty(declarations: Declaration*): PseudoDeclaration = pseudo(":empty")(declarations: _*) - def enabled(declarations: Declaration*): PseudoDeclaration = + final def enabled(declarations: Declaration*): PseudoDeclaration = pseudo(":enabled")(declarations: _*) - def first(declarations: Declaration*): PseudoDeclaration = + final def first(declarations: Declaration*): PseudoDeclaration = pseudo(":first")(declarations: _*) - def firstChild(declarations: Declaration*): PseudoDeclaration = + final def firstChild(declarations: Declaration*): PseudoDeclaration = pseudo(":first-child")(declarations: _*) - def firstOfType(declarations: Declaration*): PseudoDeclaration = + final def firstOfType(declarations: Declaration*): PseudoDeclaration = pseudo(":first-of-type")(declarations: _*) - def fullscreen(declarations: Declaration*): PseudoDeclaration = + final def fullscreen(declarations: Declaration*): PseudoDeclaration = pseudo(":fullscreen")(declarations: _*) - def focus(declarations: Declaration*): PseudoDeclaration = + final def focus(declarations: Declaration*): PseudoDeclaration = pseudo(":focus")(declarations: _*) - def hover(declarations: Declaration*): PseudoDeclaration = + final def hover(declarations: Declaration*): PseudoDeclaration = pseudo(":hover")(declarations: _*) - def indeterminate(declarations: Declaration*): PseudoDeclaration = + final def indeterminate(declarations: Declaration*): PseudoDeclaration = pseudo(":indeterminate")(declarations: _*) - def inRange(declarations: Declaration*): PseudoDeclaration = + final def inRange(declarations: Declaration*): PseudoDeclaration = pseudo(":in-range")(declarations: _*) - def invalid(declarations: Declaration*): PseudoDeclaration = + final def invalid(declarations: Declaration*): PseudoDeclaration = pseudo(":invalid")(declarations: _*) - def lang(code: String)(declarations: Declaration*): PseudoDeclaration = + final def lang(code: String)(declarations: Declaration*): PseudoDeclaration = pseudo(s":lang($code)")(declarations: _*) - def lastChild(declarations: Declaration*): PseudoDeclaration = + final def lastChild(declarations: Declaration*): PseudoDeclaration = pseudo(":last-child")(declarations: _*) - def lastOfType(declarations: Declaration*): PseudoDeclaration = + final def lastOfType(declarations: Declaration*): PseudoDeclaration = pseudo(":last-of-type")(declarations: _*) - def not(selector: String)(declarations: Declaration*): PseudoDeclaration = + final def not( + selector: String + )(declarations: Declaration*): PseudoDeclaration = pseudo(s":not($selector)")(declarations: _*) - def nthChild(declarations: Declaration*): PseudoDeclaration = + final def nthChild(declarations: Declaration*): PseudoDeclaration = pseudo(":nth-child")(declarations: _*) - def nthLastChild(declarations: Declaration*): PseudoDeclaration = + final def nthLastChild(declarations: Declaration*): PseudoDeclaration = pseudo(":nth-last-child")(declarations: _*) - def nthLastOfType(declarations: Declaration*): PseudoDeclaration = + final def nthLastOfType(declarations: Declaration*): PseudoDeclaration = pseudo(":nth-last-of-type")(declarations: _*) - def nthOfType(declarations: Declaration*): PseudoDeclaration = + final def nthOfType(declarations: Declaration*): PseudoDeclaration = pseudo(":nth-of-type")(declarations: _*) - def onlyChild(declarations: Declaration*): PseudoDeclaration = + final def onlyChild(declarations: Declaration*): PseudoDeclaration = pseudo(":only-child")(declarations: _*) - def onlyOfType(declarations: Declaration*): PseudoDeclaration = + final def onlyOfType(declarations: Declaration*): PseudoDeclaration = pseudo(":only-of-type")(declarations: _*) - def optional(declarations: Declaration*): PseudoDeclaration = + final def optional(declarations: Declaration*): PseudoDeclaration = pseudo(":optional")(declarations: _*) - def outOfRange(declarations: Declaration*): PseudoDeclaration = + final def outOfRange(declarations: Declaration*): PseudoDeclaration = pseudo(":out-of-range")(declarations: _*) - def required(declarations: Declaration*): PseudoDeclaration = + final def required(declarations: Declaration*): PseudoDeclaration = pseudo(":required")(declarations: _*) - def visited(declarations: Declaration*): PseudoDeclaration = + final def visited(declarations: Declaration*): PseudoDeclaration = pseudo(":visited")(declarations: _*) } diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/CssValuesDsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/CssValuesDsl.scala index 4c381ae2..3a02b589 100644 --- a/dsl/src/main/scala/io/taig/schelm/dsl/CssValuesDsl.scala +++ b/dsl/src/main/scala/io/taig/schelm/dsl/CssValuesDsl.scala @@ -1,109 +1,110 @@ package io.taig.schelm.dsl trait CssValuesDsl { - def url(value: String) = s"url('$value')" - val absolute: String = "absolute" - val alternate: String = "alternate" - val alternateReverse: String = "alternate-reverse" - val auto: String = "auto" - val backwards: String = "backwards" - val baseline: String = "baseline" - val block: String = "block" - val bolder: String = "bolder" - val borderBox: String = "border-box" - val both: String = "both" - val bottom: String = "bottom" - val breakWord: String = "break-word" - val capitalize: String = "capitalize" - val center: String = "center" - val clip: String = "clip" - val collapse: String = "collapse" - val column: String = "column" - val columnReverse: String = "column-reverse" - val contain: String = "contain" - val contentBox: String = "content-box" - val contents: String = "contents" - val cover: String = "cover" - val dashed: String = "dashed" - val default: String = "default" - val dotted: String = "dotted" - val double: String = "double" - val ellipsis: String = "ellipsis" - val end: String = "end" - val fill: String = "fill" - val fixed: String = "fixed" - val flex: String = "flex" - val flexEnd: String = "flex-end" - val flexStart: String = "flex-start" - val forwards: String = "forwards" - val grid: String = "grid" - val hidden: String = "hidden" - val hide: String = "hide" - val infinite: String = "infinite" - val inherit: String = "inherit" - val initial: String = "initial" - val inline: String = "inline" - val inlineBlock: String = "inline-block" - val inlineFlex: String = "inline-flex" - val inlineGrid: String = "inline-grid" - val inlineTable: String = "inline-table" - val justify: String = "justify" - val left: String = "left" - val lineThrough: String = "line-through" - val listItem: String = "list-item" - val local: String = "local" - val lowercase: String = "lowercase" - val ltr: String = "ltr" - val medium: String = "medium" - val monospace: String = "monospace" - val none: String = "none" - val noRepeat: String = "no-repeat" - val normal: String = "normal" - val noWrap: String = "no-wrap" - val overline: String = "overline" - val paddingBox: String = "padding-box" - val paused: String = "paused" - val pointer: String = "pointer" - val relative: String = "relative" - val repeat: String = "repeat" - val repeatX: String = "repeat-x" - val repeatY: String = "repeat-y" - val reverse: String = "reverse" - val right: String = "right" - val round: String = "round" - val row: String = "row" - val rowReverse: String = "row-reverse" - val rtl: String = "rtl" - val runIn: String = "run-in" - val running: String = "running" - val scroll: String = "scroll" - val separate: String = "separate" - val show: String = "show" - val solid: String = "solid" - val space: String = "space" - val spaceAround: String = "space-around" - val spaceBetween: String = "space-between" - val start: String = "start" - val static: String = "static" - val sticky: String = "sticky" - val stretch: String = "stretch" - val tableCaption: String = "table-caption" - val tableCell: String = "table-cell" - val tableColumn: String = "table-column" - val tableColumnGroup: String = "table-column-group" - val tableFooterGroup: String = "table-footer-group" - val tableHeaderGroup: String = "table-header-group" - val tableRow: String = "table-row" - val tableRowGroup: String = "table-row-group" - val thick: String = "thick" - val thin: String = "thin" - val top: String = "top" - val transparent: String = "transparent" - val underline: String = "underline" - val uppercase: String = "uppercase" - val visible: String = "visible" - val wavy: String = "wavy" - val wrap: String = "wrap" - val wrapReverse: String = "wrap-reverse" - val zero: String = "0" + final def url(value: String) = s"url('$value')" + final val absolute: String = "absolute" + final val alternate: String = "alternate" + final val alternateReverse: String = "alternate-reverse" + final val auto: String = "auto" + final val backwards: String = "backwards" + final val baseline: String = "baseline" + final val block: String = "block" + final val bold: String = "bold" + final val bolder: String = "bolder" + final val borderBox: String = "border-box" + final val both: String = "both" + final val bottom: String = "bottom" + final val breakWord: String = "break-word" + final val capitalize: String = "capitalize" + final val center: String = "center" + final val clip: String = "clip" + final val collapse: String = "collapse" + final val column: String = "column" + final val columnReverse: String = "column-reverse" + final val contain: String = "contain" + final val contentBox: String = "content-box" + final val contents: String = "contents" + final val cover: String = "cover" + final val dashed: String = "dashed" + final val default: String = "default" + final val dotted: String = "dotted" + final val double: String = "double" + final val ellipsis: String = "ellipsis" + final val end: String = "end" + final val fill: String = "fill" + final val fixed: String = "fixed" + final val flex: String = "flex" + final val flexEnd: String = "flex-end" + final val flexStart: String = "flex-start" + final val forwards: String = "forwards" + final val grid: String = "grid" + final val hidden: String = "hidden" + final val hide: String = "hide" + final val infinite: String = "infinite" + final val inherit: String = "inherit" + final val initial: String = "initial" + final val inline: String = "inline" + final val inlineBlock: String = "inline-block" + final val inlineFlex: String = "inline-flex" + final val inlineGrid: String = "inline-grid" + final val inlineTable: String = "inline-table" + final val justify: String = "justify" + final val left: String = "left" + final val lineThrough: String = "line-through" + final val listItem: String = "list-item" + final val local: String = "local" + final val lowercase: String = "lowercase" + final val ltr: String = "ltr" + final val medium: String = "medium" + final val monospace: String = "monospace" + final val none: String = "none" + final val noRepeat: String = "no-repeat" + final val normal: String = "normal" + final val noWrap: String = "no-wrap" + final val overline: String = "overline" + final val paddingBox: String = "padding-box" + final val paused: String = "paused" + final val pointer: String = "pointer" + final val relative: String = "relative" + final val repeat: String = "repeat" + final val repeatX: String = "repeat-x" + final val repeatY: String = "repeat-y" + final val reverse: String = "reverse" + final val right: String = "right" + final val round: String = "round" + final val row: String = "row" + final val rowReverse: String = "row-reverse" + final val rtl: String = "rtl" + final val runIn: String = "run-in" + final val running: String = "running" + final val scroll: String = "scroll" + final val separate: String = "separate" + final val show: String = "show" + final val solid: String = "solid" + final val space: String = "space" + final val spaceAround: String = "space-around" + final val spaceBetween: String = "space-between" + final val start: String = "start" + final val static: String = "static" + final val sticky: String = "sticky" + final val stretch: String = "stretch" + final val tableCaption: String = "table-caption" + final val tableCell: String = "table-cell" + final val tableColumn: String = "table-column" + final val tableColumnGroup: String = "table-column-group" + final val tableFooterGroup: String = "table-footer-group" + final val tableHeaderGroup: String = "table-header-group" + final val tableRow: String = "table-row" + final val tableRowGroup: String = "table-row-group" + final val thick: String = "thick" + final val thin: String = "thin" + final val top: String = "top" + final val transparent: String = "transparent" + final val underline: String = "underline" + final val uppercase: String = "uppercase" + final val visible: String = "visible" + final val wavy: String = "wavy" + final val wrap: String = "wrap" + final val wrapReverse: String = "wrap-reverse" + final val zero: String = "0" } diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/Dsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/Dsl.scala new file mode 100644 index 00000000..ac8d72ca --- /dev/null +++ b/dsl/src/main/scala/io/taig/schelm/dsl/Dsl.scala @@ -0,0 +1,6 @@ +package io.taig.schelm.dsl + +trait Dsl[Context, Payload] + extends AttributesDsl + with ListenersDsl + with WidgetDsl[Context, Payload] diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/ListenersDsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/ListenersDsl.scala new file mode 100644 index 00000000..330b4905 --- /dev/null +++ b/dsl/src/main/scala/io/taig/schelm/dsl/ListenersDsl.scala @@ -0,0 +1,13 @@ +package io.taig.schelm.dsl + +import io.taig.schelm.{Action, Listener} + +trait ListenersDsl { + def on[A](event: String, action: Action[A]): Listener[A] = + Listener(event, action) + + // format: off + def onClick[A](value: A): Listener[A] = on("click", Action.Pure(value)) + def onSubmit[A](value: A): Listener[A] = on("submit", Action.Pure(value)) + // format: on +} diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/NamespaceDsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/NamespaceDsl.scala new file mode 100644 index 00000000..bf67d5bb --- /dev/null +++ b/dsl/src/main/scala/io/taig/schelm/dsl/NamespaceDsl.scala @@ -0,0 +1,6 @@ +package io.taig.schelm.dsl + +trait NamespaceDsl { + val HTML: String = "http://www.w3.org/1999/xhtml" + val SVG: String = "http://www.w3.org/2000/svg" +} diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/PropertiesDsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/PropertiesDsl.scala deleted file mode 100644 index 62faba6a..00000000 --- a/dsl/src/main/scala/io/taig/schelm/dsl/PropertiesDsl.scala +++ /dev/null @@ -1,53 +0,0 @@ -package io.taig.schelm.dsl - -import io.taig.schelm.css._ -import io.taig.schelm._ - -trait PropertiesDsl { - def attr(key: String, value: String): Property[Nothing] = - Property.fromAttribute(Attribute(key, Value.One(value))) - - def attrs( - key: String, - values: List[String], - accumulator: Accumulator - ): Property[Nothing] = - Property.fromAttribute(Attribute(key, Value.Multiple(values, accumulator))) - - def data(key: String, value: String): Property[Nothing] = - attr(s"data-$key", value) - - def flag(key: String, value: Boolean): Property[Nothing] = - Property.fromAttribute(Attribute(key, Value.Flag(value))) - - def on[A](event: String, action: Action[A]): Property[A] = - Property.fromListener(Listener(event, action)) - - def cls(values: String*): Property[Nothing] = - attrs("class", values.toList, Accumulator.Whitespace) - - def disabled(value: Boolean): Property[Nothing] = flag("disabled", value) - - val disabled: Property[Nothing] = disabled(true) - - def href(value: String): Property[Nothing] = attr("href", value) - - def id(value: String): Property[Nothing] = attr("id", value) - - def onClick[A](value: A): Property[A] = on("click", Action.Pure(value)) - - def onSubmit[A](value: A): Property[A] = on("submit", Action.Pure(value)) - - def style(declarations: Declarations): Property[Nothing] = - attrs( - "style", - declarations.rows, - Accumulator.Semicolon + Accumulator.Whitespace - ) - - def style( - declaration: Declaration, - declarations: Declaration* - ): Property[Nothing] = - style(Declarations.from(declaration +: declarations)) -} diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/Property.scala b/dsl/src/main/scala/io/taig/schelm/dsl/Property.scala deleted file mode 100644 index bc34f1c3..00000000 --- a/dsl/src/main/scala/io/taig/schelm/dsl/Property.scala +++ /dev/null @@ -1,27 +0,0 @@ -package io.taig.schelm.dsl - -import io.taig.schelm.{Attribute => SAttribute} -import io.taig.schelm.{Listener => SListener} -import io.taig.schelm.css.{Styles => SStyles} - -sealed abstract class Property[+A] extends Product with Serializable - -object Property { - final case class Attribute(value: SAttribute) extends Property[Nothing] - final case class Listener[A](value: SListener[A]) extends Property[A] - final case class Optional[A](property: Option[Property[A]]) - extends Property[A] - final case class Styles(value: SStyles) extends Property[Nothing] - - implicit def optional[A](property: Option[Property[A]]): Property[A] = - Optional(property) - - val none: Property[Nothing] = optional(None) - - def fromAttribute(attribute: SAttribute): Property[Nothing] = - Attribute(attribute) - - def fromListener[A](listener: SListener[A]): Property[A] = Listener(listener) - - def fromStyles(styles: SStyles): Property[Nothing] = Styles(styles) -} diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/StyledHtmlDsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/StyledHtmlDsl.scala new file mode 100644 index 00000000..95665ddb --- /dev/null +++ b/dsl/src/main/scala/io/taig/schelm/dsl/StyledHtmlDsl.scala @@ -0,0 +1,40 @@ +package io.taig.schelm.dsl + +import cats.implicits._ +import io.taig.schelm._ +import io.taig.schelm.css.Styles + +trait StyledHtmlDsl extends Dsl[Unit, Styles] with CssDsl[Unit] { + override def element(name: String): Widget[Nothing, Unit, Styles] = { + val component = Component.Element( + name, + namespace = None, + Attributes.Empty, + Listeners.empty, + Children.empty + ) + Widget.empty(component) + } + + override def element( + namespace: String, + name: String + ): Widget[Nothing, Unit, Styles] = { + val component = Component.Element( + name, + namespace.some, + Attributes.Empty, + Listeners.empty, + Children.empty + ) + Widget.empty(component) + } + + override val fragment: Widget[Nothing, Unit, Styles] = + Widget.empty(Component.Fragment(Children.empty)) + + override def text(value: String): Widget[Nothing, Unit, Styles] = + Widget.empty(Component.Text(value)) +} + +object StyledHtmlDsl extends StyledHtmlDsl diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/WidgetDsl.scala b/dsl/src/main/scala/io/taig/schelm/dsl/WidgetDsl.scala index 321eea2c..52c2b513 100644 --- a/dsl/src/main/scala/io/taig/schelm/dsl/WidgetDsl.scala +++ b/dsl/src/main/scala/io/taig/schelm/dsl/WidgetDsl.scala @@ -1,143 +1,189 @@ package io.taig.schelm.dsl -import io.taig.schelm.css.{Styles, Widget} -import io.taig.schelm.{Attributes, Children, Component, Listeners} +import io.taig.schelm._ -trait WidgetDsl { - implicit def childrenBuilderToWidget[A]( - builder: ChildrenBuilder[A] - ): Widget[A] = builder.widget +trait WidgetDsl[Context, Payload] extends NamespaceDsl { + def element(name: String): Widget[Nothing, Context, Payload] - implicit def childrenBuilderNothingToWidget[A]( - builder: ChildrenBuilder[Nothing] - ): Widget[A] = builder.widget + def element( + namespace: String, + name: String + ): Widget[Nothing, Context, Payload] - implicit def nodeBuilderToWidget[A](builder: NodeBuilder[A]): Widget[A] = - builder.widget + def fragment: Widget[Nothing, Context, Payload] - implicit def nodeBuilderNothingToWidget[A]( - builder: NodeBuilder[Nothing] - ): Widget[A] = - builder.widget + def text(value: String): Widget[Nothing, Context, Payload] - implicit def textToWidget[A](value: String): Widget[A] = text(value) + final implicit class Builder[A](widget: Widget[A, Context, Payload]) { + def attributes(attributes: Attribute*): Widget[A, Context, Payload] = + updateAttributes(widget, _ ++ Attributes.from(attributes)) - def widget[A](name: String): Widget[A] = - Widget[A]( - Component - .Element(name, Attributes.Empty, Listeners.empty, Children.empty), - Styles.Empty - ) + def listeners(listeners: Listener[A]*): Widget[A, Context, Payload] = + updateListeners[A](widget, _ ++ Listeners.from(listeners)) - def fragment[A](children: Widget[A]*): Widget[A] = - Widget( - Component.Fragment(Children.indexed(children.toList)), - Styles.Empty - ) + def children( + children: Widget[A, Context, Payload]* + ): Widget[A, Context, Payload] = + updateChildren[A](widget, _ ++ Children.indexed(children)) + } - def node[A](name: String): NodeBuilder[A] = new NodeBuilder[A](widget(name)) + final def updateAttributes[A]( + widget: Widget[A, Context, Payload], + f: Attributes => Attributes + ): Widget[A, Context, Payload] = + Widget.component(widget) { + case component: Component.Element[Widget[A, Context, Payload], A] => + component.copy(attributes = f(component.attributes)) + case Component.Lazy(eval, hash) => + Component.Lazy(eval.map(updateAttributes(_, f)), hash) + case Component.Fragment(children) => + Component.Fragment( + children.map((_, child) => updateAttributes(child, f)) + ) + case component: Component.Text => component + } - def text[A](value: String): Widget[A] = - Widget(Component.Text(value), Styles.Empty) + final def updateListeners[A]( + widget: Widget[A, Context, Payload], + f: Listeners[A] => Listeners[A] + ): Widget[A, Context, Payload] = + Widget.component(widget) { + case component: Component.Element[Widget[A, Context, Payload], A] => + component.copy(listeners = f(component.listeners)) + case Component.Lazy(eval, hash) => + Component.Lazy(eval.map(updateListeners(_, f)), hash) + case Component.Fragment(children) => + Component.Fragment( + children.map((_, child) => updateListeners(child, f)) + ) + case component: Component.Text => component + } - def a[A]: NodeBuilder[A] = node("a") - def abbr[A]: NodeBuilder[A] = node("abbr") - def address[A]: NodeBuilder[A] = node("address") - def area[A]: NodeBuilder[A] = node("area") - def article[A]: NodeBuilder[A] = node("article") - def aside[A]: NodeBuilder[A] = node("aside") - def audio[A]: NodeBuilder[A] = node("audio") - def b[A]: NodeBuilder[A] = node("b") - def base[A]: NodeBuilder[A] = node("base") - def blockquote[A]: NodeBuilder[A] = node("blockquote") - def body[A]: NodeBuilder[A] = node("body") - def br[A]: NodeBuilder[A] = node("br") - def button[A]: NodeBuilder[A] = node("button") - def canvas[A]: NodeBuilder[A] = node("canvas") - def caption[A]: NodeBuilder[A] = node("caption") - def cite[A]: NodeBuilder[A] = node("cite") - def code[A]: NodeBuilder[A] = node("code") - def col[A]: NodeBuilder[A] = node("col") - def colgroup[A]: NodeBuilder[A] = node("colgroup") - def command[A]: NodeBuilder[A] = node("command") - def data[A]: NodeBuilder[A] = node("data") - def datalist[A]: NodeBuilder[A] = node("datalist") - def dd[A]: NodeBuilder[A] = node("dd") - def details[A]: NodeBuilder[A] = node("details") - def dfn[A]: NodeBuilder[A] = node("dfn") - def div[A]: NodeBuilder[A] = node("div") - def dl[A]: NodeBuilder[A] = node("dl") - def dt[A]: NodeBuilder[A] = node("dt") - def em[A]: NodeBuilder[A] = node("em") - def embed[A]: NodeBuilder[A] = node("embed") - def fieldset[A]: NodeBuilder[A] = node("fieldset") - def figcaption[A]: NodeBuilder[A] = node("figcaption") - def figure[A]: NodeBuilder[A] = node("figure") - def footer[A]: NodeBuilder[A] = node("footer") - def form[A]: NodeBuilder[A] = node("form") - def h1[A]: NodeBuilder[A] = node("h1") - def h2[A]: NodeBuilder[A] = node("h2") - def h3[A]: NodeBuilder[A] = node("h3") - def h4[A]: NodeBuilder[A] = node("h4") - def h5[A]: NodeBuilder[A] = node("h5") - def h6[A]: NodeBuilder[A] = node("h6") - def head[A]: NodeBuilder[A] = node("head") - def header[A]: NodeBuilder[A] = node("header") - def hr[A]: NodeBuilder[A] = node("hr") - def i[A]: NodeBuilder[A] = node("i") - def iframe[A]: NodeBuilder[A] = node("iframe") - def img[A]: NodeBuilder[A] = node("img") - def input[A]: NodeBuilder[A] = node("input") - def kbd[A]: NodeBuilder[A] = node("kbd") - def keygen[A]: NodeBuilder[A] = node("keygen") - def label[A]: NodeBuilder[A] = node("label") - def legend[A]: NodeBuilder[A] = node("legend") - def li[A]: NodeBuilder[A] = node("li") - def link[A]: NodeBuilder[A] = node("link") - def main[A]: NodeBuilder[A] = node("main") - def map[A]: NodeBuilder[A] = node("map") - def math[A]: NodeBuilder[A] = node("math") - def menu[A]: NodeBuilder[A] = node("menu") - def meta[A]: NodeBuilder[A] = node("meta") - def meter[A]: NodeBuilder[A] = node("meter") - def nav[A]: NodeBuilder[A] = node("nav") - def noscript[A]: NodeBuilder[A] = node("noscript") - def obj[A]: NodeBuilder[A] = node("object") - def ol[A]: NodeBuilder[A] = node("ol") - def optgroup[A]: NodeBuilder[A] = node("optgroup") - def option[A]: NodeBuilder[A] = node("option") - def output[A]: NodeBuilder[A] = node("output") - def p[A]: NodeBuilder[A] = node("p") - def param[A]: NodeBuilder[A] = node("param") - def pre[A]: NodeBuilder[A] = node("pre") - def progress[A]: NodeBuilder[A] = node("progress") - def q[A]: NodeBuilder[A] = node("q") - def s[A]: NodeBuilder[A] = node("s") - def samp[A]: NodeBuilder[A] = node("samp") - def script[A]: NodeBuilder[A] = node("script") - def section[A]: NodeBuilder[A] = node("section") - def select[A]: NodeBuilder[A] = node("select") - def small[A]: NodeBuilder[A] = node("small") - def source[A]: NodeBuilder[A] = node("source") - def span[A]: NodeBuilder[A] = node("span") - def strong[A]: NodeBuilder[A] = node("strong") - def sub[A]: NodeBuilder[A] = node("sub") - def summary[A]: NodeBuilder[A] = node("summary") - def sup[A]: NodeBuilder[A] = node("sup") - def svg[A]: NodeBuilder[A] = node("svg") - def table[A]: NodeBuilder[A] = node("table") - def tbody[A]: NodeBuilder[A] = node("tbody") - def td[A]: NodeBuilder[A] = node("td") - def textarea[A]: NodeBuilder[A] = node("textarea") - def tfoot[A]: NodeBuilder[A] = node("tfoot") - def th[A]: NodeBuilder[A] = node("th") - def thead[A]: NodeBuilder[A] = node("thead") - def time[A]: NodeBuilder[A] = node("time") - def title[A]: NodeBuilder[A] = node("title") - def tr[A]: NodeBuilder[A] = node("tr") - def track[A]: NodeBuilder[A] = node("track") - def u[A]: NodeBuilder[A] = node("u") - def ul[A]: NodeBuilder[A] = node("ul") - def video[A]: NodeBuilder[A] = node("video") - def wbr[A]: NodeBuilder[A] = node("wbr") + final def updateChildren[A]( + widget: Widget[A, Context, Payload], + f: Children[Widget[A, Context, Payload]] => Children[ + Widget[A, Context, Payload] + ] + ): Widget[A, Context, Payload] = Widget.component(widget) { + case component: Component.Element[Widget[A, Context, Payload], A] => + component.copy(children = f(component.children)) + case component: Component.Lazy[Widget[A, Context, Payload]] => + component.copy(eval = component.eval.map(updateChildren(_, f))) + case component: Component.Fragment[Widget[A, Context, Payload]] => + component.copy(children = f(component.children)) + case component: Component.Text => component + } + + final def updatePayload[A]( + widget: Widget[A, Context, Payload], + f: Payload => Payload + ): Widget[A, Context, Payload] = Widget.payload(widget)(f) + + // format: off + final val a: Widget[Nothing, Context, Payload] = element("a") + final val abbr: Widget[Nothing, Context, Payload] = element("abbr") + final val address: Widget[Nothing, Context, Payload] = element("address") + final val area: Widget[Nothing, Context, Payload] = element("area") + final val article: Widget[Nothing, Context, Payload] = element("article") + final val aside: Widget[Nothing, Context, Payload] = element("aside") + final val audio: Widget[Nothing, Context, Payload] = element("audio") + final val b: Widget[Nothing, Context, Payload] = element("b") + final val base: Widget[Nothing, Context, Payload] = element("base") + final val blockquote: Widget[Nothing, Context, Payload] = element("blockquote") + final val body: Widget[Nothing, Context, Payload] = element("body") + final val br: Widget[Nothing, Context, Payload] = element("br") + final val button: Widget[Nothing, Context, Payload] = element("button") + final val canvas: Widget[Nothing, Context, Payload] = element("canvas") + final val caption: Widget[Nothing, Context, Payload] = element("caption") + final val cite: Widget[Nothing, Context, Payload] = element("cite") + final val circle: Widget[Nothing, Context, Payload] = element(SVG, "circle") + final val code: Widget[Nothing, Context, Payload] = element("code") + final val col: Widget[Nothing, Context, Payload] = element("col") + final val colgroup: Widget[Nothing, Context, Payload] = element("colgroup") + final val command: Widget[Nothing, Context, Payload] = element("command") + final val data: Widget[Nothing, Context, Payload] = element("data") + final val datalist: Widget[Nothing, Context, Payload] = element("datalist") + final val dd: Widget[Nothing, Context, Payload] = element("dd") + final val details: Widget[Nothing, Context, Payload] = element("details") + final val dfn: Widget[Nothing, Context, Payload] = element("dfn") + final val div: Widget[Nothing, Context, Payload] = element("div") + final val dl: Widget[Nothing, Context, Payload] = element("dl") + final val dt: Widget[Nothing, Context, Payload] = element("dt") + final val ellipse: Widget[Nothing, Context, Payload] = element(SVG, "ellipse") + final val em: Widget[Nothing, Context, Payload] = element("em") + final val embed: Widget[Nothing, Context, Payload] = element("embed") + final val fieldset: Widget[Nothing, Context, Payload] = element("fieldset") + final val figcaption: Widget[Nothing, Context, Payload] = element("figcaption") + final val figure: Widget[Nothing, Context, Payload] = element("figure") + final val footer: Widget[Nothing, Context, Payload] = element("footer") + final val form: Widget[Nothing, Context, Payload] = element("form") + final val h1: Widget[Nothing, Context, Payload] = element("h1") + final val h2: Widget[Nothing, Context, Payload] = element("h2") + final val h3: Widget[Nothing, Context, Payload] = element("h3") + final val h4: Widget[Nothing, Context, Payload] = element("h4") + final val h5: Widget[Nothing, Context, Payload] = element("h5") + final val h6: Widget[Nothing, Context, Payload] = element("h6") + final val head: Widget[Nothing, Context, Payload] = element("head") + final val header: Widget[Nothing, Context, Payload] = element("header") + final val hr: Widget[Nothing, Context, Payload] = element("hr") + final val i: Widget[Nothing, Context, Payload] = element("i") + final val iframe: Widget[Nothing, Context, Payload] = element("iframe") + final val img: Widget[Nothing, Context, Payload] = element("img") + final val input: Widget[Nothing, Context, Payload] = element("input") + final val kbd: Widget[Nothing, Context, Payload] = element("kbd") + final val keygen: Widget[Nothing, Context, Payload] = element("keygen") + final val label: Widget[Nothing, Context, Payload] = element("label") + final val legend: Widget[Nothing, Context, Payload] = element("legend") + final val li: Widget[Nothing, Context, Payload] = element("li") + final val link: Widget[Nothing, Context, Payload] = element("link") + final val main: Widget[Nothing, Context, Payload] = element("main") + final val map: Widget[Nothing, Context, Payload] = element("map") + final val math: Widget[Nothing, Context, Payload] = element("math") + final val menu: Widget[Nothing, Context, Payload] = element("menu") + final val meta: Widget[Nothing, Context, Payload] = element("meta") + final val meter: Widget[Nothing, Context, Payload] = element("meter") + final val nav: Widget[Nothing, Context, Payload] = element("nav") + final val noscript: Widget[Nothing, Context, Payload] = element("noscript") + final val obj: Widget[Nothing, Context, Payload] = element("object") + final val ol: Widget[Nothing, Context, Payload] = element("ol") + final val optgroup: Widget[Nothing, Context, Payload] = element("optgroup") + final val option: Widget[Nothing, Context, Payload] = element("option") + final val output: Widget[Nothing, Context, Payload] = element("output") + final val p: Widget[Nothing, Context, Payload] = element("p") + final val path: Widget[Nothing, Context, Payload] = element(SVG, "path") + final val param: Widget[Nothing, Context, Payload] = element("param") + final val polygon: Widget[Nothing, Context, Payload] = element(SVG, "polygon") + final val pre: Widget[Nothing, Context, Payload] = element("pre") + final val progress: Widget[Nothing, Context, Payload] = element("progress") + final val q: Widget[Nothing, Context, Payload] = element("q") + final val rect: Widget[Nothing, Context, Payload] = element(SVG, "rect") + final val s: Widget[Nothing, Context, Payload] = element("s") + final val samp: Widget[Nothing, Context, Payload] = element("samp") + final val script: Widget[Nothing, Context, Payload] = element("script") + final val section: Widget[Nothing, Context, Payload] = element("section") + final val select: Widget[Nothing, Context, Payload] = element("select") + final val small: Widget[Nothing, Context, Payload] = element("small") + final val source: Widget[Nothing, Context, Payload] = element("source") + final val span: Widget[Nothing, Context, Payload] = element("span") + final val strong: Widget[Nothing, Context, Payload] = element("strong") + final val sub: Widget[Nothing, Context, Payload] = element("sub") + final val summary: Widget[Nothing, Context, Payload] = element("summary") + final val sup: Widget[Nothing, Context, Payload] = element("sup") + final val svg: Widget[Nothing, Context, Payload] = element(SVG, "svg") + final val table: Widget[Nothing, Context, Payload] = element("table") + final val tbody: Widget[Nothing, Context, Payload] = element("tbody") + final val td: Widget[Nothing, Context, Payload] = element("td") + final val textarea: Widget[Nothing, Context, Payload] = element("textarea") + final val tfoot: Widget[Nothing, Context, Payload] = element("tfoot") + final val th: Widget[Nothing, Context, Payload] = element("th") + final val thead: Widget[Nothing, Context, Payload] = element("thead") + final val time: Widget[Nothing, Context, Payload] = element("time") + final val title: Widget[Nothing, Context, Payload] = element("title") + final val tr: Widget[Nothing, Context, Payload] = element("tr") + final val track: Widget[Nothing, Context, Payload] = element("track") + final val u: Widget[Nothing, Context, Payload] = element("u") + final val ul: Widget[Nothing, Context, Payload] = element("ul") + final val video: Widget[Nothing, Context, Payload] = element("video") + final val wbr: Widget[Nothing, Context, Payload] = element("wbr") + // format: on } diff --git a/dsl/src/main/scala/io/taig/schelm/dsl/package.scala b/dsl/src/main/scala/io/taig/schelm/dsl/package.scala index bb6fe4d0..0e4bc4e9 100644 --- a/dsl/src/main/scala/io/taig/schelm/dsl/package.scala +++ b/dsl/src/main/scala/io/taig/schelm/dsl/package.scala @@ -2,29 +2,8 @@ package io.taig.schelm import io.taig.schelm.css._ -package object dsl extends CssDsl with PropertiesDsl with WidgetDsl { +package object dsl { type DeclarationOrPseudo = Either[Declaration, PseudoDeclaration] - private[dsl] def split[A]( - properties: Iterable[Property[A]] - ): (Attributes, Listeners[A], Styles) = - // format: off - properties.foldLeft((Attributes.Empty, Listeners.empty[A], Styles.Empty)) { - case ((attributes, listeners, styles), Property.Attribute(attribute)) => - (attributes + attribute, listeners, styles) - case ((attributes, listeners, styles), property: Property.Listener[A]) => - (attributes, listeners + property.value, styles) - case ((attributes, listeners, styles), Property.Optional(property)) => - val (x, y, z) = split(property) - (attributes ++ x, listeners ++ y, styles ++ z) - case ((attributes, listeners, styles), Property.Styles(values)) => - (attributes, listeners, styles ++ values) - } - // format: on - - private[dsl] def reduce(declarations: Iterable[DeclarationOrPseudo]): Style = - declarations.foldLeft(Style.Empty) { - case (style, Left(declaration)) => style :+ declaration - case (style, Right(declaration)) => style :+ declaration - } + val widget: StyledHtmlDsl = StyledHtmlDsl } diff --git a/playground/js/src/main/scala/io/taig/schelm/Playground.scala b/playground/js/src/main/scala/io/taig/schelm/Playground.scala index 393c9f23..daf7e7d5 100644 --- a/playground/js/src/main/scala/io/taig/schelm/Playground.scala +++ b/playground/js/src/main/scala/io/taig/schelm/Playground.scala @@ -14,7 +14,7 @@ object Playground extends IOApp { _ <- schelm.start( "main", State(), - (state: State) => toStyledHtml(App.widget(state)), + (state: State) => toStylesheetWidget(App.widget(state)), App.events, App.commands, Stream.empty diff --git a/playground/shared/src/main/scala/io/taig/schelm/playground/App.scala b/playground/shared/src/main/scala/io/taig/schelm/playground/App.scala index 472d591c..a5ef80bd 100644 --- a/playground/shared/src/main/scala/io/taig/schelm/playground/App.scala +++ b/playground/shared/src/main/scala/io/taig/schelm/playground/App.scala @@ -5,40 +5,34 @@ import cats.effect.IO import cats.implicits._ import io.taig.schelm._ import io.taig.schelm.css._ -import io.taig.schelm.dsl._ +import io.taig.schelm.dsl.widget._ import scala.concurrent.ExecutionContext import scala.concurrent.duration._ object App { - def widget(state: State): Widget[Event] = - div( - id("asdf"), - stylesheet( - if (state.clicks % 2 == 0) backgroundColor("greenyellow") - else backgroundColor("yellow"), - maxWidth(500.px), - padding(5.px), - &.after( - backgroundColor("orangered"), - content("''"), - height(100.px), - position(absolute), - width(100.%%) - ) - ) - )( - p("Hello World"), - br(id("yolo")), - button( - style(cursor(pointer)), - id("yolo").some, - if (state.clicks < 5) onClick(Event.Increment(1)) - else onClick(Event.Increment(5)) - )( - s"Does this work?: ${state.clicks}" - ) - ) + def widget(state: State): Widget[Event, Unit, Styles] = + Widget.local(identity[Unit]) { + Widget { context => + div + .attributes(id("yolo")) + .styles( + if (state.clicks % 2 == 0) backgroundColor("greenyellow") + else backgroundColor("yellow"), + maxWidth(500.px), + padding(5.px) + ) + .children( + button + .listeners( + if (state.clicks < 5) onClick(Event.Increment(1)) + else onClick(Event.Increment(5)) + ) + .children(text("Click to play")), + text(s"Does this work?: ${state.clicks}") + ) + } + } val events: EventHandler[State, Event, Command] = { case (state, Event.Increment(value)) =>