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>
This commit is contained in:
parent
9ad6347044
commit
7d8f34de17
23 changed files with 609 additions and 94 deletions
94
packages/ludic.ui/attr_more.ludic
Normal file
94
packages/ludic.ui/attr_more.ludic
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# attr_more.ludic - width and height (where 0 is 0 and calc() may hold a percentage), the flex
|
||||
# shorthand, flex-shrink, order and text-shadow
|
||||
function el_more(n: UiNode, key: string, v: Val) -> bool {
|
||||
let s = vl_text(v)
|
||||
if key == "shrink" { nx(n).shrink = Math.max(el_num(s), 0.0) } else if key == "order" { nx(n).order = int(el_num(s)) } else if key == "text-shadow" { el_text_shadow(n, s) } else { return false }
|
||||
return true
|
||||
}
|
||||
# width or height: a length (0 included), fill, a percentage, calc(), or auto/fit (none)
|
||||
function el_dim(n: UiNode, wide: bool, v: Val) -> void {
|
||||
let s = vl_text(v)
|
||||
var fixed = UI_AUTO
|
||||
var pct = 0.0
|
||||
var off = 0.0
|
||||
if ca_is(s) {
|
||||
if ca_eval(s) {
|
||||
pct = ca_pct
|
||||
off = ca_px
|
||||
if pct <= 0.0 { fixed = Math.max(ca_px, 0.0) }
|
||||
}
|
||||
} else if s == "fill" { fixed = UI_FILL } else if len(s) > 1 and s[len(s) - 1] == 37 {
|
||||
pct = el_num(s)
|
||||
if pct <= 0.0 { fixed = 0.0 }
|
||||
} else if s != "auto" and s != "fit" and s != "" { fixed = el_len(v) }
|
||||
if pct <= 0.0 { off = 0.0 }
|
||||
if n.ex != null or off != 0.0 {
|
||||
if wide { nx(n).w_off = off } else { nx(n).h_off = off }
|
||||
}
|
||||
if wide {
|
||||
n.w = fixed
|
||||
n.w_pct = Math.max(pct, 0.0)
|
||||
} else {
|
||||
n.h = fixed
|
||||
n.h_pct = Math.max(pct, 0.0)
|
||||
}
|
||||
}
|
||||
# a length out of calc(); a percentage has nothing to be a share of here
|
||||
function el_calc_len(s: string) -> float {
|
||||
if not ca_eval(s) { return 0.0 }
|
||||
if ca_pct != 0.0 { ui_err(`{el_key}: {s} - a percentage in calc() is for a width or a height`) }
|
||||
return ca_px
|
||||
}
|
||||
# flex: 1 | flex: 1 0 | flex: 2 1 auto | flex: none - the grow, then the shrink
|
||||
function el_flex_short(n: UiNode, s: string) -> void {
|
||||
let parts = el_words(s)
|
||||
if s == "none" {
|
||||
n.grow = 0.0
|
||||
nx(n).shrink = 0.0
|
||||
return
|
||||
}
|
||||
if len(parts) > 0 { n.grow = el_num(parts[0]) }
|
||||
if len(parts) > 1 and len(parts[1]) > 0 and parts[1][0] >= 48 and parts[1][0] <= 57 { nx(n).shrink = el_num(parts[1]) }
|
||||
}
|
||||
# words apart by spaces, a bracket's own spaces kept: "calc(1em + 2px) 4px" is two
|
||||
function el_words(s: string) -> []string {
|
||||
let out = new []string
|
||||
var at = 0
|
||||
var depth = 0
|
||||
for i in 0 .. len(s) {
|
||||
if s[i] == 40 { depth += 1 }
|
||||
if s[i] == 41 { depth -= 1 }
|
||||
if s[i] == 32 and depth == 0 {
|
||||
if i > at { push(out, s[at..i]) }
|
||||
at = i + 1
|
||||
}
|
||||
}
|
||||
if len(s) > at { push(out, s[at..len(s)]) }
|
||||
return out
|
||||
}
|
||||
# text-shadow: 1px 2px 3px rgba(0, 0, 0, 0.6) - x, y, a blur drawn sharp, the colour; or none
|
||||
function el_text_shadow(n: UiNode, s: string) -> void {
|
||||
let x = nx(n)
|
||||
x.tsh_set = true
|
||||
x.tsh_c = -2
|
||||
if tpl_words(s) == "none" { return }
|
||||
let parts = el_words(s)
|
||||
var nums = 0
|
||||
var col = ""
|
||||
for i in 0 .. len(parts) {
|
||||
let p = parts[i]
|
||||
if col == "" and ((p[0] >= 48 and p[0] <= 57) or p[0] == 45 or p[0] == 46) {
|
||||
if nums == 0 { x.tsh_x = el_unit(p) }
|
||||
if nums == 1 { x.tsh_y = el_unit(p) }
|
||||
nums += 1
|
||||
} else if col == "" { col = p } else { col = col + " " + p }
|
||||
}
|
||||
if col == "" { col = "rgba(0,0,0,0.6)" }
|
||||
x.tsh_c = ui_color(col)
|
||||
x.tsh_a = cl_alpha
|
||||
}
|
||||
# one word of a list of lengths (padding: calc(1em / 4) 2px)
|
||||
function el_word_len(w: string) -> float {
|
||||
if ca_is(w) { return el_calc_len(w) }
|
||||
return el_unit(w)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue