module

Hecr

Constants

VERSION = "0.0.1"

Class methods

attr(io : IO, name : String, value : Bool) : Nil
Source
attr(io : IO, name : String, value : Nil) : Nil
Source
attr(io : IO, name : String, value : Safe) : Nil
Source
attr(io : IO, name : String, value : Array) : Nil
Source
attr(io : IO, name : String, value) : Nil
Source
attrs(io : IO, pairs) : Nil
Source
class_list(*parts : String | Bool | Nil) : String

Joins class-name parts for the :class attribute (generated code). nil/false parts drop (conditional classes), whitespace-separated tokens within a part dedupe preserving first occurrence — scoped values from CSS modules repeat shared composes bases.

Source
escape(value) : String

Escapes to a String (convenience; generated code uses escape_to).

Source
escape_to(io : IO, value : Safe) : Nil

Writes value HTML-escaped to io. Safe values pass through verbatim, nil renders as nothing, numbers and booleans need no escaping.

Source
escape_to(io : IO, value : Nil) : Nil
Source
escape_to(io : IO, value : String) : Nil
Source
escape_to(io : IO, value : Number | Bool) : Nil
Source
escape_to(io : IO, value) : Nil
Source
raw(value : Safe) : Safe

Marks a string as already-safe HTML. raw is the only escape hatch from escaped-by-default interpolation.

Source
raw(value : Nil) : Safe
Source
raw(value) : Safe
Source
slot_sink(io : IO) : IO

Uniform default-slot protocol: generated component calls without named slot entries pass a block receiving one object and write rendered content to Hecr.slot_sink(obj). For IO-protocol components that's the IO itself; for slot-builder components (Hecr.slots) the content is captured as the builder's inner entry.

Source
slot_sink(builder) : IO
Source

Macros

embed(path, io_name)

Renders a template file by appending to an existing IO variable — streaming mode, no intermediate string:

Hecr.embed "page.hecr", response_io

Source
embed_templates(glob, styles = nil)

Defines one function component per template file matching glob (relative to the calling file). Every file must open with a contract directive — a verbatim Crystal def head whose name matches the file basename (decision D10):

<%@ def card(title : String, footer : String? = nil) %>

styles: names a CSS modules provider (a module exposing a .styles(path, name:) macro, e.g. LightningCSSModules). Each template is then paired with its colocated <basename>.module.css (or the file named by its <%@ styles "..." %> directive), and the template's :class attribute resolves class names through the generated styles module — misspelled classes fail the build (decision D12):

Hecr.embed_templates "components/*.hecr", styles: LightningCSSModules

Source
render(template)

Renders an inline template (use a RAW heredoc so Crystal doesn't interpolate #{} in the template — see docs/dialect.md):

def button(label : String) : Hecr::Safe Hecr.render <<-'HECR' <button class="btn">{label}</button> HECR end

Source
slots(decl, &block)

Generates a slot-builder struct from a declaration (decision D6). The builder is yielded to the component's block; each named slot entry is stored as a typed proc plus its attributes. Generic type parameters flow from the component's arguments into :let bindings with no annotations at the call site (spike 04).

Hecr.slots TableSlots(T) do col label : String, let : T footer end

def table(rows : Array(T), & : TableSlots(T) ->) : Hecr::Safe forall T slots = TableSlots(T).new yield slots Hecr.render <<-'HECR' ...<th :for={c <- slots.col}>{c.label}...{c.render(row)}... HECR end

For every slot name the struct gets:

  • name — getter returning the entries collected so far
  • add_name(attrs...) { |io, let| } — adder (used by generated code)
  • add_name(attrs...) — body-less adder (<:name attrs/>) and each entry exposes its attrs, its body proc, and render(let) : Hecr::Safe.

The reserved let parameter declares the type yielded to the entry's block (use a Tuple type for multiple values). An inner slot (the default slot) is generated automatically unless declared explicitly — declare it to give the default slot a let type. render_inner(let) renders all default-slot entries in order.

Source
template(path)

Renders a template file (path relative to the calling file) and returns Hecr::Safe.

Source

Nested types