import gleam/dynamic/decode.{type Dynamic} import gleam/list import gleam/option import plinth/browser/event import pream/dom import pream/format import pream/signal /// virtual dom node — same shape as the output /// of preact's `h()`. built up via small composable /// helpers below, then handed to `pream.to_preact` pub opaque type VNode { VNode(tag: String, props: List(Prop), children: List(VChild)) } /// child of a vnode — one of four variants: /// static element, static text, reactive element, /// or reactive text. use the constructors below /// (e.g. `text`, `element`, `reactive`, `reactive_text`) /// to build values of this type. pub type VChild { Element(VNode) Text(String) Reactive(signal.Signal(VNode)) ReactiveText(signal.Signal(String)) } /// vnode property — either an attribute (any gleam /// value, serialized downstream in ffi) or an /// event handler. handlers are camelCased and /// prefixed with `on_` in ffi pub type Prop { /// NOTE: a prop can be any gleam value /// we're swallowing the type here and handle /// it downstram in ffi. this is done to make /// the render API simple Attr(key: String, value: dom.Native) Handler(event: String, handle: fn(event.Event(Dynamic)) -> Nil) } // ── Construction ──────────────────────────────────────── /// https://npmx.dev/package-docs/preact/v/10.29.2#function-h /// creates an empty vnode with the given tag and /// no props or children — equivalent to `` pub fn new(tag: String) -> VNode { VNode(tag: tag, props: [], children: []) } /// renders nothing — mapped to preact's `null` in ffi pub fn empty() -> VNode { VNode("$NULL", [], []) } /// https://npmx.dev/package-docs/preact/v/10.29.2#function-fragment /// a fragment vnode — used to return multiple /// sibling children without a wrapper element pub fn fragment() -> VNode { VNode("$FRAGMENT", [], []) } // ── HTML shorthand constructors ─ /// Creates a `
` vnode. pub fn div() -> VNode { new("div") } /// Creates a `` vnode. pub fn span() -> VNode { new("span") } /// Creates a `

` vnode. pub fn p() -> VNode { new("p") } /// Creates an `

` vnode. pub fn h1() -> VNode { new("h1") } /// Creates an `

` vnode. pub fn h2() -> VNode { new("h2") } /// Creates an `

` vnode. pub fn h3() -> VNode { new("h3") } /// Creates an `

` vnode. pub fn h4() -> VNode { new("h4") } /// Creates an `

` vnode. pub fn h5() -> VNode { new("h5") } /// Creates an `
` vnode. pub fn h6() -> VNode { new("h6") } /// Creates a `