README

mizchi/luna/core does not have a README file

#
StaticDomAttr

type StaticDomAttr = Attr[Unit, String]

Static DOM attribute - no event handlers, string values

#
StaticDomNode

type StaticDomNode = Node[Unit, String]

Static DOM node - no event handlers, string attributes Use for SSR, static site generation, or pre-rendering

#
Attr

pub(all) enum Attr[E, A] {
VStatic(A)
VDynamic(() -> A)
VHandler(EventHandler[E])
VAction(String)
}

Attribute value that can be static or dynamic (signal-based) Type parameter A represents the attribute value type:
  • Web: A = String (HTML attributes are strings)
  • TUI: A = TuiAttrValue (typed values like Dimension, Color)

#
ComponentRef

pub(all) struct ComponentRef[T] {
url : String
props : T
trigger : TriggerType
}

Component reference for type-safe Island embedding Represents a client-side Web Components Island that can be embedded in server-rendered HTML
  • url: Path to the client JavaScript (e.g., "/static/counter.js")
  • props: Component props (must be ToJson serializable)
  • trigger: When to hydrate the component

#
EventHandler

pub struct EventHandler[E] {
callback : (E) -> Unit
}

Event handler type - newtype wrapper for callback function

#
EventHandler::get_callback

fn[E] EventHandler::get_callback(self : EventHandler[E]) -> ((E) -> Unit)

Get the callback function

#
MatchCase

pub struct MatchCase[E, A] {
when : () -> Bool
render : () -> Node[E, A]
}

Match case for Switch - pairs a condition with content

#
Node

pub(all) enum Node[E, A] {
Element(VElement[E, A])
Text(String)
DynamicText(() -> String)
Fragment(Array[Node[E, A]])
Show(condition~ : () -> Bool, child~ : () -> Node[E, A])
For(render~ : () -> Array[Node[E, A]])
Component(render~ : () -> Node[E, A])
WcIsland(VWcIsland[E, A])
Async(VAsync[E, A])
ErrorBoundary(VErrorBoundary[E, A])
Switch(VSwitch[E, A])
InternalRef(VInternalRef[E, A])
RawHtml(String)
}

Virtual DOM node types Type parameter A represents the attribute value type (see Attr[E, A])

#
TriggerType

#alias(Trigger)
pub(all) enum TriggerType {
Load
Idle
Visible
Media(String)
None
}

Hydration trigger types - when to hydrate a component

#
TriggerType::parse

fn TriggerType::parse(s : String) -> TriggerType

Parse TriggerType from string.
test {
// Round-trip test: parse then to_string
inspect(TriggerType::parse("load").to_string(), content="load")
inspect(TriggerType::parse("idle").to_string(), content="idle")
inspect(TriggerType::parse("visible").to_string(), content="visible")
inspect(TriggerType::parse("none").to_string(), content="none")
inspect(
TriggerType::parse("media:(min-width: 1024px)").to_string(),
content="media:(min-width: 1024px)",
)
}

#
TriggerType::to_string

fn TriggerType::to_string(self : TriggerType) -> String

Convert TriggerType to attribute value.
test {
inspect(TriggerType::Load.to_string(), content="load")
inspect(TriggerType::Idle.to_string(), content="idle")
inspect(TriggerType::Visible.to_string(), content="visible")
inspect(
TriggerType::Media("(max-width: 768px)").to_string(),
content="media:(max-width: 768px)",
)
inspect(TriggerType::None.to_string(), content="none")
}

#
TrustedHtml

pub(all) struct TrustedHtml {
content : String
}

Explicit wrapper for HTML that has already been trusted by the caller.

#
TrustedHtml::to_string

fn TrustedHtml::to_string(self : TrustedHtml) -> String

#
VAsync

pub struct VAsync[E, A] {
render : async () -> Node[E, A]
fallback : () -> Node[E, A]
on_error : (Error) -> Node[E, A]?
}

Virtual Async node for async rendering with error handling Note: async functions implicitly raise Error, no need for raise? annotation

#
VElement

pub struct VElement[E, A] {
tag : String
attrs : Array[(String, Attr[E, A])]
children : Array[Node[E, A]]
}

Virtual element node

#
VErrorBoundary

pub struct VErrorBoundary[E, A] {
children : () -> Node[E, A] raise
fallback : (Error, () -> Unit) -> Node[E, A] raise
}

Virtual ErrorBoundary node for catching rendering errors Similar to Solid.js ErrorBoundary - catches errors during:
  • Child component rendering
  • Effects and memos within children Does NOT catch:
  • Event handler errors
  • Async errors outside render cycle

#
VInternalRef

pub struct VInternalRef[E, A] {
url : String
state : String
trigger : TriggerType
styles : String
children : Array[Node[E, A]]
}

Virtual Internal Reference node for type-safe Island embedding

#
VSwitch

pub struct VSwitch[E, A] {
cases : Array[MatchCase[E, A]]
fallback : () -> Node[E, A]?
}

Virtual Switch node - renders first matching case Similar to Solid.js /
  • cases: array of condition-content pairs, evaluated in order
  • fallback: optional content when no case matches

#
VWcIsland

pub struct VWcIsland[E, A] {
name : String
url : String
styles : String
state : String
trigger : TriggerType
children : Array[Node[E, A]]
}

Virtual Web Components Island node - Web Components based hydration unit Uses Declarative Shadow DOM for SSR and DOM Parts for partial updates

#
action

fn[E, V, Act : Show] action(a : Act) -> Attr[E, V]

Create an action attribute value - dispatches named action on event Used for declarative event handling with enum types: ("onclick", action(Increment)) // requires derive(Show)

Example:
pub enum MyAction { Increment; Decrement } derive(Show) h("button", [("onclick", action(Increment))], [...])

#
async_

fn[E, A] async_(render~ : async () -> Node[E, A], fallback~ : () -> Node[E, A], on_error? : (Error) -> Node[E, A]?) -> Node[E, A]

Create an async VNode with fallback
  • render: async function that produces the content (may raise errors)
  • fallback: shown while loading or on error (if no on_error handler)
  • on_error: optional custom error UI handler

#
attr_dynamic

fn[E, A] attr_dynamic(getter : () -> A) -> Attr[E, A]

Create a dynamic attribute value. The value is computed lazily on each render.
test {
let mut count = 0
let attr : Attr[Unit, String] = attr_dynamic(fn() {
"count-" + count.to_string()
})
guard attr is VDynamic(getter) else { fail("expected VDynamic") }
inspect(getter(), content="count-0")
count = 5
inspect(getter(), content="count-5")
}

#
attr_dynamic_style

fn[E] attr_dynamic_style(getter : () -> String) -> Attr[E, String]

Create a dynamic style attribute value Note: For Web (A = String), the getter returns a style string

#
attr_handler

fn[E, A] attr_handler(handler : EventHandler[E]) -> Attr[E, A]

Create a handler attribute value

#
attr_static

fn[E, A] attr_static(value : A) -> Attr[E, A]

Create a static attribute value.
test {
let attr : Attr[Unit, String] = attr_static("my-class")
guard attr is VStatic(v) else { fail("expected VStatic") }
inspect(v, content="my-class")
}

#
attr_style

fn[E] attr_style(style : String) -> Attr[E, String]

Create a style attribute value (string form, e.g. "color: red; margin: 10px") Note: For Web (A = String), pass the style string directly

#
component

fn[E, A] component(render : () -> Node[E, A]) -> Node[E, A]

Create a component VNode. Wraps a render function as a component boundary.
test {
let node : Node[Unit, String] = component(fn() {
h("div", [], [text("Component")])
})
guard node is Component(render~) else { fail("expected Component") }
guard render() is Element(el) else { fail("expected Element") }
inspect(el.tag, content="div")
}

#
component_ref

fn[T] component_ref(url : String, props : T, trigger? : TriggerType) -> ComponentRef[T]

Create a ComponentRef for a Web Components Island

#
error_boundary

fn[E, A] error_boundary(children~ : () -> Node[E, A] raise, fallback~ : (Error, () -> Unit) -> Node[E, A] raise) -> Node[E, A]

Create an error boundary VNode Catches errors during child rendering and displays fallback UI
  • children: lazy function that produces child content (may throw)
  • fallback: function receiving (error, reset) that produces fallback UI
    • error: the caught Error
    • reset: function to retry rendering children

Example:
error_boundary( children=fn() { risky_component() }, fallback=fn(err, reset) { h("div", [], [ text("Error: " + err.to_string()), h("button", [("onclick", handler(fn(_) { reset() }))], [text("Retry")]) ]) } )

#
event_handler

fn event_handler() -> EventHandler[Unit]

Create a placeholder event handler for SSR (noop)

#
for_each

fn[E, A] for_each(items : () -> Array[Node[E, A]]) -> Node[E, A]

Create a list VNode. Renders a dynamic list of nodes.
test {
let items = ["a", "b", "c"]
let node : Node[Unit, String] = for_each(fn() { items.map(fn(s) { text(s) }) })
guard node is For(render~) else { fail("expected For") }
inspect(render().length(), content="3")
}

#
fragment

fn[E, A] fragment(children : Array[Node[E, A]]) -> Node[E, A]

Create a fragment VNode. Groups multiple nodes without a wrapper element.
test {
let node : Node[Unit, String] = fragment([
text("Hello"),
text(" "),
text("World"),
])
guard node is Fragment(children) else { fail("expected Fragment") }
inspect(children.length(), content="3")
}
fn[E, A] h(tag : String, attrs : Array[(String, Attr[E, A])], children : Array[Node[E, A]]) -> Node[E, A]

Create a VNode element. The main building block for creating virtual DOM elements.
test {
let node : Node[Unit, String] = h(
"div",
[("class", attr_static("container"))],
[text("Hello")],
)
guard node is Element(el) else { fail("expected Element") }
inspect(el.tag, content="div")
}

#
handler

fn[E] handler(f : (E) -> Unit) -> EventHandler[E]

Create an event handler from a callback.
test {
let h : EventHandler[Int] = handler(fn(x) { let _ = x * 2 })
inspect(h.get_callback()(5), content="()")
}

#
handler_from_callback

fn handler_from_callback(f : () -> Unit) -> EventHandler[Unit]

Create an event handler from a simple callback (ignores event, for SSR compatibility)

#
has_dynamic_content

fn[E, A] has_dynamic_content(attrs : Array[(String, Attr[E, A])]) -> Bool

Check if element has dynamic content that needs hydration

#
internal_ref

fn[E, A] internal_ref(url : String, state : String, trigger? : TriggerType, styles? : String, children? : Array[Node[E, A]]) -> Node[E, A]

Create an internal reference VNode (for server_dom.wc_island())

#
match_case

fn[E, A] match_case(when~ : () -> Bool, render~ : () -> Node[E, A]) -> MatchCase[E, A]

Create a match case for Switch
  • when: condition function, evaluated lazily
  • render: content to render when condition is true

#
raw_html

fn[E, A] raw_html(content : String) -> Node[E, A]

Create a raw HTML VNode (content is not escaped). Use with caution: content should be trusted or sanitized.
test {
let node : Node[Unit, String] = raw_html("<strong>Bold</strong>")
guard node is RawHtml(html) else { fail("expected RawHtml") }
inspect(html, content="<strong>Bold</strong>")
}

#
raw_trusted_html

fn[E, A] raw_trusted_html(content : TrustedHtml) -> Node[E, A]

Create a raw HTML VNode from an explicit trusted wrapper.

#
show

fn[E, A] show(when : () -> Bool, child : () -> Node[E, A]) -> Node[E, A]

Create a conditional VNode. Only renders the child when the condition is true.
test {
let visible = true
let node : Node[Unit, String] = show(fn() { visible }, fn() {
text("Visible!")
})
guard node is Show(condition~, ..) else { fail("expected Show") }
inspect(condition(), content="true")
}

#
switch_

fn[E, A] switch_(cases~ : Array[MatchCase[E, A]], fallback? : () -> Node[E, A]?) -> Node[E, A]

Create a switch VNode - renders first matching case Similar to Solid.js /

Example:
switch_( cases=[ match_case(when=fn() { state.get() == 1 }, render=fn() { text("One") }), match_case(when=fn() { state.get() == 2 }, render=fn() { text("Two") }), ], fallback=Some(fn() { text("Other") }) )

#
text

fn[E, A] text(content : String) -> Node[E, A]

Create a text VNode.
test {
let node : Node[Unit, String] = text("Hello World")
guard node is Text(s) else { fail("expected Text") }
inspect(s, content="Hello World")
}

#
text_dyn

fn[E, A] text_dyn(content : () -> String) -> Node[E, A]

Create a dynamic text VNode. The content is computed lazily on each render.
test {
let mut count = 5
let node : Node[Unit, String] = text_dyn(fn() { count.to_string() })
guard node is DynamicText(getter) else { fail("expected DynamicText") }
inspect(getter(), content="5")
count = 10
inspect(getter(), content="10")
}

#
unsafe_trusted_html

fn unsafe_trusted_html(content : String) -> TrustedHtml

#
wc_component_ref

fn[T] wc_component_ref(url : String, props : T, trigger? : TriggerType) -> ComponentRef[T]

Alias for component_ref — kept for backward source compatibility within the workspace.

#
wc_island

fn[E, A] wc_island(name : String, url : String, styles : String, state : String, children : Array[Node[E, A]], trigger? : TriggerType) -> Node[E, A]

Create a Web Components island VNode for partial hydration Uses Declarative Shadow DOM for SSR