Merge main into #1421

apply_order takes #1458's numbering; a $var wrapper ranks 7, after boundVariables.
This commit is contained in:
bflatastic
2026-10-29 13:46:39 +07:00
138 changed files with 4903 additions and 784 deletions
+24 -9
View File
@@ -405,23 +405,37 @@ pub(crate) fn variable_prop<'a>(cmd: &str, key: &str, value: &'a Value) -> Resul
Ok(Some(name))
}
/// The order [`apply`] takes keys in: geometry first so rotation applies to the final size, style
/// links after the values so a link wins over values its style sets, variable bindings last so
/// paints set in the same call don't detach them. `$var` wrappers also win over style links.
/// The order [`apply`] takes keys in: geometry first so rotation applies to the final size, the
/// auto layout mode before the keys that tune it (an object `layout` replaces the whole auto
/// layout), style links after the values so a link wins over values its style sets, variable
/// bindings last so paints set in the same call don't detach them. `$var` wrappers also win over style links.
fn apply_order(k: &str, v: &Value) -> u8 {
if v.get("$var").is_some() {
return 6;
return 7;
}
match k {
"path" | "width" | "height" | "w" | "h" => 0,
"rotation" => 2,
"x" | "y" => 3,
"fillStyle" | "strokeStyle" | "effectStyle" | "textStyle" | "gridStyle" => 4,
"boundVariables" => 5,
_ => 1,
"layout" | "layoutMode" => 1,
"rotation" => 3,
"x" | "y" => 4,
"fillStyle" | "strokeStyle" | "effectStyle" | "textStyle" | "gridStyle" => 5,
"boundVariables" => 6,
_ => 2,
}
}
/// Auto layout keys given beside a `layout` (or `layoutMode`) that turns auto layout off: they
/// would turn it back on (`layout_mut`), so the call is refused rather than one of them losing.
fn layout_keys_beside_none(cmd: &str, props: &Map<String, Value>) -> Result<()> {
let off = ["layout", "layoutMode"]
.into_iter()
.find(|k| props.get(*k).is_some_and(|v| v.is_null() || v.as_str().is_some_and(|s| s.eq_ignore_ascii_case("none"))));
let tuning: Vec<String> = props.keys().filter(|k| LAYOUT_KEYS.contains(&k.as_str())).map(|k| format!("`{k}`")).collect();
let Some(off) = off.filter(|_| !tuning.is_empty()) else { return Ok(()) };
let (what, are) = if tuning.len() == 1 { ("an auto layout property", "is") } else { ("auto layout properties", "are") };
Err(bad(cmd, format!("{} {are} {what}, and `{off}` in the same call turns auto layout off", tuning.join(", "))))
}
/// An explicit width (`is_w`) or height makes hugging or filling on that axis fixed, like typing
/// into W or H.
fn fix_axis(doc: &mut Document, id: NodeId, is_w: bool) -> Result<()> {
@@ -1034,6 +1048,7 @@ fn apply_variable(cmd: &str, doc: &mut Document, id: NodeId, k: &str, v: &Value)
/// Apply a property map to one node. `x`/`y` are relative to the parent.
pub fn apply(cmd: &str, doc: &mut Document, id: NodeId, props: &Map<String, Value>) -> Result<()> {
layout_keys_beside_none(cmd, props)?;
let mut unknown = Vec::new();
let mut keys: Vec<(&String, &Value)> = props.iter().collect();
keys.sort_by_key(|(k, v)| apply_order(k, v));