feat(lang): L11 views and templates - the UI is markup, not code
A `view Name { field = x; function q(..); on e(..) }` declaration is the one bridge between a
program and its UI: it writes view_<name>() -> UiView, whose model is a Value of every field and
whose call runs a query or an event by name.
ludic.ui is a template runtime:
- HTML-shaped XML screens and components, loaded at run time;
- {expression} bindings, if/else/each, props, slots, per-instance state;
- on-press / onclick actions (event, set, emit);
- component libraries (export="true", <import src as>).
Styling:
- stylesheets in <style> or importable .lss files (@import);
- CSS selectors (#id, .class, [attr=v], descendant and > combinators, :hover, :disabled,
:first-child, :last-child, :nth-child, :not) weighed by specificity;
- the box model and flex under CSS's property names.
Also:
- default parameters, and positional-then-named calls;
- Value gains a float kind;
- a function shadowing a runtime one is refused;
- an index is evaluated before the slice is read;
- runtime errors name the right file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
334469ef61
commit
66a2bc2214
64 changed files with 74806 additions and 63975 deletions
68
packages/ludic.ui/build.ludic
Normal file
68
packages/ludic.ui/build.ludic
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# build.ludic - a template and the model, made into this frame's nodes. <if>/<else> and
|
||||
# <each in= as= index=> are the template's own; a tag its file linked to a component is that one,
|
||||
# given its attributes as props, its on-* as what `emit` runs, and its content as <slot/>.
|
||||
function bd_kids(kids: []UiTpl, e: UiEnv, key: string, out: []UiNode) -> void {
|
||||
var last_if = true
|
||||
for i in 0 .. len(kids) {
|
||||
let k = kids[i]
|
||||
let ck = `{key}/{i}`
|
||||
if k.tag == "state" { continue }
|
||||
if k.tag == "if" {
|
||||
last_if = bd_test(k, e)
|
||||
if last_if { bd_kids(k.kids, e, ck, out) }
|
||||
} else if k.tag == "else" {
|
||||
if not last_if { bd_kids(k.kids, e, ck, out) }
|
||||
last_if = true
|
||||
} else if k.tag == "each" { bd_each(k, e, ck, out) } else if k.tag == "slot" { bd_slot(e, ck, out) } else if not bd_comp(k, e, ck, out) { push(out, bd_elem(k, e, ck)) }
|
||||
}
|
||||
}
|
||||
function bd_test(k: UiTpl, e: UiEnv) -> bool {
|
||||
let t = tpl_attr(k, "test")
|
||||
if t == null {
|
||||
ui_err("<if> needs a test=\"{...}\"")
|
||||
return false
|
||||
}
|
||||
return ui_eval_bool(t, e)
|
||||
}
|
||||
function bd_name(k: UiTpl, attr: string, dflt: string) -> string {
|
||||
let x = tpl_attr(k, attr)
|
||||
if x == null or x.op != X_LIT { return dflt }
|
||||
return Value.as_str(x.v)
|
||||
}
|
||||
function bd_each(k: UiTpl, e: UiEnv, key: string, out: []UiNode) -> void {
|
||||
let src = tpl_attr(k, "in")
|
||||
if src == null {
|
||||
ui_err("<each> needs an in=\"{...}\"")
|
||||
return
|
||||
}
|
||||
let list = ui_eval(src, e)
|
||||
let as_name = bd_name(k, "as", "item")
|
||||
let at_name = bd_name(k, "index", "index")
|
||||
for j in 0 .. Value.count(list) {
|
||||
let le = env_new(e)
|
||||
env_bind(le, as_name, Value.at(list, j))
|
||||
env_bind(le, at_name, Value.int(j))
|
||||
bd_kids(k.kids, le, `{key}#{j}`, out)
|
||||
}
|
||||
}
|
||||
function bd_slot(e: UiEnv, key: string, out: []UiNode) -> void {
|
||||
var at = e
|
||||
while at != null and at.slot == null { at = at.parent }
|
||||
if at != null { bd_kids(at.slot.kids, at.slot_env, key, out) }
|
||||
}
|
||||
function bd_comp(k: UiTpl, e: UiEnv, key: string, out: []UiNode) -> bool {
|
||||
if k.comp == null { return false }
|
||||
let c = k.comp
|
||||
let ce = env_new(null)
|
||||
ce.model = e.model
|
||||
for i in 0 .. len(k.keys) { env_bind(ce, k.keys[i], ui_eval(k.vals[i], e)) }
|
||||
ce.on_names = k.on_keys
|
||||
ce.on_acts = k.on_acts
|
||||
ce.on_envs = new []UiEnv
|
||||
for i in 0 .. len(k.on_keys) { push(ce.on_envs, e) }
|
||||
ce.slot = k
|
||||
ce.slot_env = e
|
||||
ce.state = st_for(key, c, ce)
|
||||
bd_kids(c.kids, ce, key, out)
|
||||
return true
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue