Lcl · Core · Packages · Libraries
DomA declarative DOM library for Lcl in the browser: describe the page
as a tree of plain values, let Dom:: render it and, when
the description changes, patch the real DOM to match. The same trees
render to HTML text with Dom::html, so the description
is equally at home on a server.
LCL_BUILD_JS=ON
(rendering goes through Js::); Dom::h and Dom::html are pure Lcl and
run anywhere.A node is a dict #{tag ... attrs #{...} children (...)}
built by Dom::h or by the tag
procedures in Html:: (Html::div,
Html::p, … one per common HTML element). Strings and
numbers are text nodes. Children are ordinary arguments; a list argument
is spliced, so [List::map $items $render_item] drops
straight in, and an empty string is skipped, so
[if $cond { ... } else { "" }] is a conditional child.
eval [Dom::html_tags] ;; div, p, ul, ... as bare names
proc view {todos} {
div #{class app} \
[h1 "Todos ([len $todos])"] \
[ul [List::map $todos [lambda {t} { li #{key $t} $t }]]] \
[if [== [len $todos] 0] { p #{class empty} "Nothing to do" } else { "" }]
}Attributes are a dict given first. class,
value, checked, disabled,
selected and readonly set the element’s
property; style takes a dict of CSS properties;
on<event> takes a procedure that receives the event
(as a Js::ref) – take a rest parameter if you do not need
it; key identifies a child across renders so reordering
moves elements instead of rewriting them; everything else is
setAttribute.
Dom::mount renders a
node into a container and returns a mount handle; Dom::update patches what is
mounted to a new node, touching only what changed. Dom::app wraps the common
shape – some state, a render procedure, re-render on Dom::set_state:
Dom::app [Js::global document body] #{count 0} [lambda {state app} {
let n [get $state count]
div [h1 "Clicked $n times"] \
[button #{onclick [lambda {*_} { Dom::set_state $app #{count [+ $n 1]} }]} "+1"]
}]Examples:
>> Dom::h p #{class note} "hi " [Dom::h b "there"]
#{"children" ("hi " #{"children" ("there") "tag" "b" "attrs" #{}}) "tag" "p" "attrs" #{"class" "note"}}
>> Dom::html [Dom::h ul [List::map (a b) [lambda {x} { Dom::h li $x }]]]
"<ul><li>a</li><li>b</li></ul>"Dom::node? vIs v an element node (as opposed to text)?
Examples:
>> Dom::node? [Dom::h p]
1
>> Dom::node? "text"
0Dom::h tag *argsBuild an element node: tag, an optional attribute dict,
then children – nodes, text, or lists of either (spliced). Numbers
become text; empty strings are dropped.
Examples:
>> Dom::h br
#{"children" () "tag" "br" "attrs" #{}}
>> get [Dom::h a #{href /x} "link"] attrs
#{"href" "/x"}
>> get [Dom::h p "n = " 42 "" ("x" "y")] children
("n = " "42" "x" "y")Dom::TAGSThe common HTML elements, defined as procedures in
Html::.
Dom::html_tags (names "")Lcl source that defines the Html:: tag procedures as
bare names in the scope that evaluates it –
eval [Dom::html_tags] at the top of a file, or
[Dom::html_tags (div p ul li)] for a chosen few. Bare
a, b, i, s,
u and q are deliberately short; take only what
you use if that bites.
Examples:
>> eval [Dom::html_tags (article p)]
>> Dom::html [article [p "one"] [p "two"]]
"<article><p>one</p><p>two</p></article>"Dom::escape sHTML-escape text.
Examples:
>> Dom::escape {a < b & "c"}
"a < b & "c""Dom::html nodeRender a node to HTML text: attributes in sorted order,
style dicts as CSS text, event handlers and
key omitted, void elements unclosed, text escaped.
Examples:
>> Dom::html [Dom::h input #{type text value "a<b" disabled 1}]
"<input disabled=\"1\" type=\"text\" value=\"a<b\">"
>> Dom::html [Dom::h div #{style #{color red margin 0} onclick x key k} "t"]
"<div style=\"color:red;margin:0\">t</div>"
>> Dom::html "1 < 2"
"1 < 2"Dom::mount container nodeRender node into container (a
Js::ref element, appended after whatever is there) and
return a mount handle.
let m [Dom::mount [Js::global document body] [Html::p "hello"]]
Dom::update $m [Html::p "hello again"]Dom::update handle nodePatch a mount to show node, changing only what differs
from the node it currently shows.
Dom::unmount handleRemove a mount’s element from the document.
Dom::element handleThe element a mount rendered (a Js::ref).
Dom::app container state renderMount [apply $render $state $app] into
container, where app is the handle returned;
Dom::set_state
re-renders with new state and Dom::refresh with the
same. render receives the state and the handle.
Dom::set_state handle stateReplace an app’s state and re-render.
Dom::state handleAn app’s current state.
Dom::refresh handleRe-render an app from its current state.
Html