mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-27 20:06:53 -06:00
M6: default Vue instance swaps and keep text out of attribute detection
A Vue component's instance-swap prop now defaults to its component reference in withDefaults, so the dynamic component renders the design default. Attribute detection only applies inside an unfinished opening tag, so text like `Total = {title}` stays text instead of becoming a quoted attribute value.
This commit is contained in:
@@ -184,10 +184,38 @@ fn expr(doc: &Document, c: &Component, p: &Param, v: &Value, lang: CodeLang) ->
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether `s` ends inside an unclosed opening tag (no `>` outside quotes since the last `<`).
|
||||
fn inside_open_tag(s: &str) -> bool {
|
||||
let mut in_tag = false;
|
||||
let mut quote = None;
|
||||
let mut chars = s.chars().peekable();
|
||||
while let Some(c) = chars.next() {
|
||||
match quote {
|
||||
Some(q) => {
|
||||
if c == q {
|
||||
quote = None;
|
||||
}
|
||||
}
|
||||
None => match c {
|
||||
'<' if !in_tag && chars.peek().is_some_and(|ch| ch.is_ascii_alphabetic() || matches!(*ch, '/' | '!' | '?')) => {
|
||||
in_tag = true;
|
||||
}
|
||||
'>' if in_tag => in_tag = false,
|
||||
'"' | '\'' if in_tag => quote = Some(c),
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
in_tag
|
||||
}
|
||||
|
||||
/// Where a placeholder sits in a Vue template: whether the attribute is bound, and the quote the
|
||||
/// template already opened (if any). `None` when it isn't in an attribute at all.
|
||||
fn vue_attribute(out: &str) -> Option<(bool, Option<char>)> {
|
||||
let end = out.trim_end();
|
||||
if !inside_open_tag(end) {
|
||||
return None;
|
||||
}
|
||||
let (after, quote) = match end.chars().last() {
|
||||
Some(q @ ('"' | '\'')) => (&end[..end.len() - q.len_utf8()], Some(q)),
|
||||
_ => (end, None),
|
||||
|
||||
@@ -237,6 +237,10 @@ fn vue_links_are_a_default_import_with_quoted_bindings() {
|
||||
ex(&mut s, "instance.setProperties", json!({"ids": [i], "properties": {"Title": "Say \"hi\""}}));
|
||||
ex(&mut s, "codeConnect.set", json!({"id": i, "language": "vue", "template": "<Card title=\"{title} {title}\" />"}));
|
||||
assert_eq!(code(&mut s, i, "vue"), "import Card from \"./Card.vue\";\n\n<Card title=\"Say "hi" Say "hi"\" />\n");
|
||||
// Text after a completed tag is text, even when it contains `=`.
|
||||
ex(&mut s, "instance.setProperties", json!({"ids": [i], "properties": {"Title": "Buy"}}));
|
||||
ex(&mut s, "codeConnect.set", json!({"id": i, "language": "vue", "template": "<p>Total = {title}</p>"}));
|
||||
assert_eq!(code(&mut s, i, "vue"), "import Card from \"./Card.vue\";\n\n<p>Total = Buy</p>\n");
|
||||
// Vue is linkable; a language that isn't stays refused.
|
||||
assert!(s.execute("codeConnect.set", &json!({"id": c, "language": "css"})).is_err(), "not a code language");
|
||||
assert!(s.execute("codeConnect.set", &json!({"id": c, "language": "vue", "importPath": "a b"})).is_err(), "no spaces in a path");
|
||||
|
||||
@@ -823,10 +823,7 @@ fn vue(doc: &Document, c: &Component) -> String {
|
||||
}
|
||||
out.push_str(" }>(),\n {\n");
|
||||
for p in &props {
|
||||
// A component-valued prop has no literal to default to.
|
||||
if matches!(p.kind, ParamKind::InstanceSwap | ParamKind::Slot) {
|
||||
continue;
|
||||
}
|
||||
// An instance swap defaults to its component reference; a slot isn't in `props`.
|
||||
out.push_str(&format!(" {}: {},\n", p.ident, value_expr(doc, c, p, &p.default, CodeLang::Vue)));
|
||||
}
|
||||
out.push_str(" },\n);\n\n</script>\n\n");
|
||||
|
||||
@@ -228,6 +228,7 @@ fn instance_swap_properties_take_views() {
|
||||
assert!(leptos.contains("{icon.run()}"), "{leptos}");
|
||||
let vue = code(&mut s, chip, "vue");
|
||||
assert!(vue.contains(" icon?: unknown;"), "{vue}");
|
||||
assert!(vue.contains(" icon: HeartIcon,"), "the swap defaults to its component: {vue}");
|
||||
assert!(vue.contains("<component :is=\"icon\" />"), "a swap is a component, not an element: {vue}");
|
||||
let i = idv(&ex(&mut s, "instance.create", json!({"component": chip, "x": 0, "y": 100})));
|
||||
ex(&mut s, "instance.setProperties", json!({"ids": [i], "properties": {"Icon": star}}));
|
||||
|
||||
Reference in New Issue
Block a user