Packages

Signals-first Gleam bindings for Preact with @preact/signals integration, shorthand HTML constructors, and Result/Option-aware rendering.

Current section

Files

Jump to
pream src pream.gleam
Raw

src/pream.gleam

import gleam/option.{type Option}
import pream/vnode.{type VNode}
/// https://npmx.dev/package-docs/preact/v/10.29.2#class-ComponentChildren
@external(javascript, "preact", "ComponentChildren")
pub type PreactComponent
/// https://npmx.dev/package-docs/preact/v/10.29.2#function-h
/// converts a vnode tree into a preact
/// `ComponentChildren` value, ready to pass to
/// preact's `render()`
@external(javascript, "./pream/component_ffi.mjs", "h")
pub fn to_preact(from node: VNode) -> PreactComponent
/// unwraps a `Result`-returning render function.
/// an `Error` is silently coerced into an empty
/// vnode — useful when a component is allowed to
/// fail without taking down the whole tree
pub fn unwrap(
render component: fn(p) -> Result(VNode, b),
with props: p,
) -> VNode {
case component(props) {
Ok(node) -> node
Error(_) -> vnode.empty()
}
}
/// unwraps an `Option`-returning render function.
/// `None` is silently coerced into an empty vnode
pub fn unwrap_option(
render component: fn(p) -> Option(VNode),
with props: p,
) -> VNode {
case component(props) {
option.Some(node) -> node
option.None -> vnode.empty()
}
}
/// typed component record — wraps a props-to-vnode
/// render function so it can be named, composed,
/// and passed around explicitly
pub type Component(p) {
Component(render: fn(p) -> VNode)
}
/// construct a component from a render function
pub fn component(render: fn(p) -> VNode) -> Component(p) {
Component(render:)
}
/// render a component with the given props
pub fn render_component(comp: Component(p), props: p) -> VNode {
comp.render(props)
}
/// render a component and convert directly to a
/// preact component, ready for `render()`
pub fn to_preact_component(comp: Component(p), props: p) -> PreactComponent {
comp.render(props) |> to_preact
}
/// Wraps a `Component` so it only re-renders when its props
/// change (shallow equality). In a signals-first app, this
/// skips the VNode build when a parent re-renders but props
/// haven't changed.
@external(javascript, "./pream/component_ffi.mjs", "memo")
pub fn memo(comp: Component(p)) -> Component(p)
/// Like `memo` but with a custom comparison function for props.
@external(javascript, "./pream/component_ffi.mjs", "memo_custom")
pub fn memo_custom(
comp: Component(p),
compare: fn(p, p) -> Bool,
) -> Component(p)