Skip to content

Instantly share code, notes, and snippets.

@atooni
Created January 5, 2022 11:44
Show Gist options
  • Save atooni/08af14f0ec8a5c3dac991e0d5808aace to your computer and use it in GitHub Desktop.
Save atooni/08af14f0ec8a5c3dac991e0d5808aace to your computer and use it in GitHub Desktop.
Very simple Web Component ScalaJS 1.8/Scala 3.1/Laminar
package zio.insight.webapp
import scala.scalajs.js
import scala.scalajs.js.Dynamic.literal
import scala.scalajs.js.annotation.JSGlobal
import com.raquo.laminar.api.L._
import com.raquo.laminar.builders.HtmlTag
import com.raquo.laminar.nodes.ReactiveElement
import org.scalajs.dom
@js.native
trait CustomElementsRegistry extends js.Any:
def define(name: String, definition: Any): Unit = js.native
end CustomElementsRegistry
object CustomElementsRegistry:
def customElements =
js.Dynamic.global.window.asInstanceOf[Window].customElements
end CustomElementsRegistry
@js.native
@JSGlobal
class Window extends dom.Window:
val customElements: CustomElementsRegistry = js.native
end Window
@js.native
@JSGlobal
class HTMLTemplateElement extends HTMLElement:
val content: HTMLElement = js.native
end HTMLTemplateElement
@js.native
@JSGlobal
class HTMLElement extends dom.HTMLEmbedElement:
def attachShadow(options: js.Any): dom.HTMLEmbedElement = js.native
end HTMLElement
class ParagraphElement extends HTMLElement:
private lazy val template = dom.document.getElementById("my-paragraph").asInstanceOf[HTMLTemplateElement]
private lazy val shadow = this.attachShadow(literal(mode = "closed"))
shadow.appendChild(template.content.cloneNode(true))
end ParagraphElement
object MainView:
def render =
div(
MyParagraph()
)
end MainView
object MyParagraph:
type El = ReactiveElement[ParagraphElement]
type ModFunction = MyParagraph.type => Mod[El]
private val tag = new HtmlTag[ParagraphElement]("my-paragraph", void = false)
def apply(mods: ModFunction*): El =
tag(mods.map(_(MyParagraph)): _*)
end MyParagraph
object HelloWorld:
def main(args: Array[String]) =
val _ = documentEvents.onDomContentLoaded.foreach { _ =>
CustomElementsRegistry.customElements.define("my-paragraph", js.constructorOf[ParagraphElement])
val appContainer = dom.document.getElementById("app")
appContainer.innerHTML = ""
val _ = render(appContainer, MainView.render)
}(unsafeWindowOwner)
end HelloWorld
<html>
<head>
<script src="insight.js"></script>
</head>
<body>
<!-- The placeholder for the actual application -->
<div id="app"></div>
</body>
<template id="my-paragraph">
<h1>A cool title without changing code</h1>
<p style="background-color: lightcyan;">Hello from my first Laminar component !</p>
</template>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment