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 `
` vnode. pub fn p() -> VNode { new("p") } /// Creates an `