ludic/packages/ludic.ui/cascade_merge.ludic
Orkuncakilkaya 7d8f34de17 feat(ui): flex-shrink, text that wraps beside its siblings, calc(), order, and 0 as a size
- flex-shrink: a line whose children want more room than it has takes it back from those that
  shrink, in proportion to shrink times size and never below a min size, a fixed size or the
  content. A scroll box shrinks (and scrolls), and a box in a column shrinks as far as the scroll
  boxes inside it let it, so a list in a column takes the room its siblings leave with no height.
  `flex: grow shrink`, and `flex-shrink` by name.
- A row wider than its room measures its texts (and boxes without a width) again in the room the
  rest leave them, so a line wraps beside an icon.
- calc() with + - * / and brackets over px, %, em, rem, vw, vh, plain numbers and var(); a width
  or height keeps its percentage, taken of the room it is given. Lengths lists (padding, margin)
  keep a calc()'s spaces.
- `order` places a box's children without touching the tree.
- width: 0 and height: 0 are 0: an unset size is UI_AUTO now, not 0.
- A component root that is itself a component takes each user's class, style and id in turn (the
  outermost's id wins), and the rules of all their sheets are weighed by specificity together; a
  user's rule wins a tie. The parent's sheet used to override the child's whatever its specificity,
  and a middle component's sheet was lost.
- The default sheet lays .ui-track out as a row, so a range's fill is as tall as its track and a
  checked box's knob goes right; a range's thumb is centred on the fill's end.
- ui_boxes.ludic.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 19:54:14 +03:00

53 lines
1.9 KiB
Text

# cascade_merge.ludic - a component's root is styled by its own sheet and by the sheet of every user
# that passed a class down to it, all at once: the rules that match, from all of them, ordered by
# specificity as one sheet's are. On a tie the user's rule wins (the outermost user's last), as a
# later rule does. Then `order`, which rearranges a flex box's children without touching the tree.
function cs_merged(n: UiNode) -> void {
let rules = new []UiRule
let envs = new []UiEnv
let seen = new []UiSheet
if n.sheet != null { cs_gather(n, n.sheet, n.env, rules, envs, seen) }
for i in 0 .. len(n.ups) {
if n.ups[i].sheet != null { cs_gather(n, n.ups[i].sheet, n.ups[i].env, rules, envs, seen) }
}
for i in 0 .. len(rules) { cs_rule_in(n, rules[i], envs[i]) }
}
# a sheet's matching rules into the list, each after every rule at most as specific (stable)
function cs_gather(n: UiNode, sh: UiSheet, e: UiEnv, rules: []UiRule, envs: []UiEnv, seen: []UiSheet) -> void {
for i in 0 .. len(seen) {
if seen[i] == sh { return }
}
push(seen, sh)
for i in 0 .. len(sh.rules) {
let r = sh.rules[i]
if md_ok(r) and sel_match(r.sel, n) {
push(rules, r)
push(envs, e)
var j = len(rules) - 1
while j > 0 and rules[j - 1].spec > r.spec {
rules[j] = rules[j - 1]
envs[j] = envs[j - 1]
j -= 1
}
rules[j] = r
envs[j] = e
}
}
}
# CSS's order: the children placed by it, lowest first, the tree's order kept between equals
function cs_order(n: UiNode) -> void {
var any = false
for i in 0 .. len(n.children) {
if ly_order(n.children[i]) != 0 { any = true }
}
if not any { return }
for i in 1 .. len(n.children) {
let c = n.children[i]
var j = i
while j > 0 and ly_order(n.children[j - 1]) > ly_order(c) {
n.children[j] = n.children[j - 1]
j -= 1
}
n.children[j] = c
}
}