Allow on-, class-, prop-, and attr- as equivalent to on:, class:, prop:, and attr: to get around a syn-rsx parsing limitation on mixing colons and dashes in an attribute name
This commit is contained in:
parent
c8545f47cb
commit
47fad9a042
|
@ -81,3 +81,33 @@ fn test_classes() {
|
|||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
|
||||
#[test]
|
||||
fn test_dash_prefixes() {
|
||||
use leptos_dom::*;
|
||||
use leptos_macro::view;
|
||||
use leptos_reactive::{create_signal, run_scope};
|
||||
|
||||
let colons = run_scope(|cx| {
|
||||
let (value, set_value) = create_signal(cx, 5);
|
||||
view! {
|
||||
cx,
|
||||
<div class="my big" class:a={move || value() > 10} class:red=true class:car={move || value() > 1} attr:id="id"></div>
|
||||
}
|
||||
});
|
||||
|
||||
let dashes = run_scope(|cx| {
|
||||
let (value, set_value) = create_signal(cx, 5);
|
||||
view! {
|
||||
cx,
|
||||
<div class="my big" class-a={move || value() > 10} class-red=true class-car={move || value() > 1} attr-id="id"></div>
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(colons, dashes);
|
||||
assert_eq!(
|
||||
dashes,
|
||||
"<div data-hk=\"0-0\" class=\"my big red car\" id=\"id\"></div>"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ mod server;
|
|||
/// # });
|
||||
/// ```
|
||||
///
|
||||
/// 5. Event handlers can be added with `on:` attributes
|
||||
/// 5. Event handlers can be added with `on:` attributes. If the event name contains a dash, you should use `on-` as the prefix instead.
|
||||
/// ```rust
|
||||
/// # use leptos_reactive::*; use leptos_dom::*; use leptos_macro::view; use leptos_dom::wasm_bindgen::JsCast;
|
||||
/// # run_scope(|cx| {
|
||||
|
@ -124,7 +124,7 @@ mod server;
|
|||
/// ```
|
||||
///
|
||||
/// 6. DOM properties can be set with `prop:` attributes, which take any primitive type or `JsValue` (or a signal
|
||||
/// that returns a primitive or JsValue).
|
||||
/// that returns a primitive or JsValue). If your property name contains a dash, you should use `prop-` as the prefix instead.
|
||||
/// ```rust
|
||||
/// # use leptos_reactive::*; use leptos_dom::*; use leptos_macro::view; use leptos_dom::wasm_bindgen::JsCast;
|
||||
/// # run_scope(|cx| {
|
||||
|
@ -147,6 +147,7 @@ mod server;
|
|||
/// ```
|
||||
///
|
||||
/// 7. Classes can be toggled with `class:` attributes, which take a `bool` (or a signal that returns a `bool`).
|
||||
/// If your class name contains a dash, you should use `class-` as the prefix instead.
|
||||
/// ```rust
|
||||
/// # use leptos_reactive::*; use leptos_dom::*; use leptos_macro::view; use leptos_dom::wasm_bindgen::JsCast;
|
||||
/// # run_scope(|cx| {
|
||||
|
|
|
@ -214,8 +214,14 @@ fn element_to_tokens(
|
|||
.iter()
|
||||
.filter_map(|node| {
|
||||
node.name_as_string().and_then(|name| {
|
||||
if name.starts_with("class:") {
|
||||
let name = name.replacen("class:", "", 1);
|
||||
if name.starts_with("class:") || name.starts_with("class-") {
|
||||
let name = if name.starts_with("class:") {
|
||||
name.replacen("class:", "", 1)
|
||||
} else if name.starts_with("class-") {
|
||||
name.replacen("class-", "", 1)
|
||||
} else {
|
||||
name
|
||||
};
|
||||
let value = node.value.as_ref().expect("class: attributes need values");
|
||||
let span = node.name_span().expect("missing span for class name");
|
||||
Some(quote_spanned! {
|
||||
|
@ -400,6 +406,13 @@ fn attr_to_tokens(
|
|||
} else {
|
||||
name
|
||||
};
|
||||
let name = if name.starts_with("attr:") {
|
||||
name.replacen("attr:", "", 1)
|
||||
} else if name.starts_with("attr-") {
|
||||
name.replacen("attr-", "", 1)
|
||||
} else {
|
||||
name
|
||||
};
|
||||
let value = match &node.value {
|
||||
Some(expr) => match expr {
|
||||
syn::Expr::Lit(expr_lit) => {
|
||||
|
@ -456,16 +469,20 @@ fn attr_to_tokens(
|
|||
}
|
||||
}
|
||||
// Event Handlers
|
||||
else if name.starts_with("on:") {
|
||||
else if name.starts_with("on:") || name.starts_with("on-") {
|
||||
let handler = node
|
||||
.value
|
||||
.as_ref()
|
||||
.expect("event listener attributes need a value");
|
||||
|
||||
if mode != Mode::Ssr {
|
||||
let event_name = name.replacen("on:", "", 1);
|
||||
let name = if name.starts_with("on:") {
|
||||
name.replacen("on:", "", 1)
|
||||
} else {
|
||||
name.replacen("on-", "", 1)
|
||||
};
|
||||
expressions.push(quote_spanned! {
|
||||
span => add_event_listener(#el_id.unchecked_ref(), #event_name, #handler);
|
||||
span => add_event_listener(#el_id.unchecked_ref(), #name, #handler);
|
||||
});
|
||||
} else {
|
||||
// this is here to avoid warnings about unused signals
|
||||
|
@ -476,10 +493,9 @@ fn attr_to_tokens(
|
|||
}
|
||||
}
|
||||
// Properties
|
||||
else if name.starts_with("prop:") {
|
||||
else if name.starts_with("prop:") || name.starts_with("prop-") {
|
||||
// can't set properties in SSR
|
||||
if mode != Mode::Ssr {
|
||||
let name = name.replacen("prop:", "", 1);
|
||||
if mode != Mode::Ssr {
|
||||
let value = node.value.as_ref().expect("prop: blocks need values");
|
||||
expressions.push(quote_spanned! {
|
||||
span => leptos_dom::property(#cx, #el_id.unchecked_ref(), #name, #value.into_property(#cx))
|
||||
|
@ -487,11 +503,10 @@ fn attr_to_tokens(
|
|||
}
|
||||
}
|
||||
// Classes
|
||||
else if name.starts_with("class:") {
|
||||
else if name.starts_with("class:") || name.starts_with("class-") {
|
||||
if mode == Mode::Ssr {
|
||||
// handled separately because they need to be merged
|
||||
} else {
|
||||
let name = name.replacen("class:", "", 1);
|
||||
let value = node.value.as_ref().expect("class: attributes need values");
|
||||
expressions.push(quote_spanned! {
|
||||
span => leptos_dom::class(#cx, #el_id.unchecked_ref(), #name, #value.into_class(#cx))
|
||||
|
@ -875,9 +890,13 @@ fn create_component(cx: &Ident, node: &Node, mode: Mode) -> TokenStream {
|
|||
let props = node.attributes.iter().filter_map(|attr| {
|
||||
let attr_name = attr.name_as_string().unwrap_or_default();
|
||||
if attr_name.starts_with("on:")
|
||||
|| attr_name.starts_with("on-")
|
||||
|| attr_name.starts_with("prop:")
|
||||
|| attr_name.starts_with("prop-")
|
||||
|| attr_name.starts_with("class:")
|
||||
|| attr_name.starts_with("class-")
|
||||
|| attr_name.starts_with("attr:")
|
||||
|| attr_name.starts_with("attr-")
|
||||
{
|
||||
None
|
||||
} else {
|
||||
|
@ -896,12 +915,23 @@ fn create_component(cx: &Ident, node: &Node, mode: Mode) -> TokenStream {
|
|||
|
||||
let mut other_attrs = node.attributes.iter().filter_map(|attr| {
|
||||
let attr_name = attr.name_as_string().unwrap_or_default();
|
||||
// Event Listeners
|
||||
if let Some(event_name) = attr_name.strip_prefix("on:") {
|
||||
let span = attr.name_span().unwrap();
|
||||
let handler = attr
|
||||
.value
|
||||
.as_ref()
|
||||
.expect("event listener attributes need a value");
|
||||
.expect("on: event listener attributes need a value");
|
||||
Some(quote_spanned! {
|
||||
span => add_event_listener(#component_name.unchecked_ref(), #event_name, #handler)
|
||||
})
|
||||
}
|
||||
else if let Some(event_name) = attr_name.strip_prefix("on-") {
|
||||
let span = attr.name_span().unwrap();
|
||||
let handler = attr
|
||||
.value
|
||||
.as_ref()
|
||||
.expect("on- event listener attributes need a value");
|
||||
Some(quote_spanned! {
|
||||
span => add_event_listener(#component_name.unchecked_ref(), #event_name, #handler)
|
||||
})
|
||||
|
@ -913,6 +943,12 @@ fn create_component(cx: &Ident, node: &Node, mode: Mode) -> TokenStream {
|
|||
span => leptos_dom::property(#cx, #component_name.unchecked_ref(), #name, #value.into_property(#cx))
|
||||
})
|
||||
}
|
||||
else if let Some(name) = attr_name.strip_prefix("prop-") {
|
||||
let value = attr.value.as_ref().expect("prop- attributes need values");
|
||||
Some(quote_spanned! {
|
||||
span => leptos_dom::property(#cx, #component_name.unchecked_ref(), #name, #value.into_property(#cx))
|
||||
})
|
||||
}
|
||||
// Classes
|
||||
else if let Some(name) = attr_name.strip_prefix("class:") {
|
||||
let value = attr.value.as_ref().expect("class: attributes need values");
|
||||
|
@ -920,10 +956,21 @@ fn create_component(cx: &Ident, node: &Node, mode: Mode) -> TokenStream {
|
|||
span => leptos_dom::class(#cx, #component_name.unchecked_ref(), #name, #value.into_class(#cx))
|
||||
})
|
||||
}
|
||||
else if let Some(name) = attr_name.strip_prefix("class-") {
|
||||
let value = attr.value.as_ref().expect("class: attributes need values");
|
||||
Some(quote_spanned! {
|
||||
span => leptos_dom::class(#cx, #component_name.unchecked_ref(), #name, #value.into_class(#cx))
|
||||
})
|
||||
}
|
||||
// Attributes
|
||||
else if let Some(name) = attr_name.strip_prefix("attr:") {
|
||||
let value = attr.value.as_ref().expect("attr: attributes need values");
|
||||
let name = name.replace('_', "-");
|
||||
Some(quote_spanned! {
|
||||
span => leptos_dom::attribute(#cx, #component_name.unchecked_ref(), #name, #value.into_attribute(#cx))
|
||||
})
|
||||
}
|
||||
else if let Some(name) = attr_name.strip_prefix("attr-") {
|
||||
let value = attr.value.as_ref().expect("attr- attributes need values");
|
||||
Some(quote_spanned! {
|
||||
span => leptos_dom::attribute(#cx, #component_name.unchecked_ref(), #name, #value.into_attribute(#cx))
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue