feat: allow spreading of both attributes and event handlers (#2432)
This commit is contained in:
parent
fc537c14c4
commit
119c9ea23f
|
@ -22,7 +22,7 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Sember Checks
|
||||
- name: Semver Checks
|
||||
uses: obi1kenobi/cargo-semver-checks-action@v2
|
||||
with:
|
||||
rust-toolchain: nightly-2024-03-31
|
||||
|
|
|
@ -75,6 +75,13 @@ check-examples`.
|
|||
We have a fairly extensive CI setup that runs both lints (like `rustfmt` and `clippy`)
|
||||
and tests on PRs. You can run most of these locally if you have `cargo-make` installed.
|
||||
|
||||
Note that some of the `rustfmt` settings used require usage of the nightly compiler.
|
||||
Formatting the code using the stable toolchain may result in a wrong code format and
|
||||
subsequently CI errors.
|
||||
Run `cargo +nightly fmt` if you want to keep the stable toolchain active.
|
||||
You may want to let your IDE automatically use the `+nightly` parameter when a
|
||||
"format on save" action is used.
|
||||
|
||||
If you added an example, make sure to add it to the list in `examples/Makefile.toml`.
|
||||
|
||||
From the root directory of the repo, run
|
||||
|
|
|
@ -10,7 +10,6 @@ CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = [
|
|||
"counter",
|
||||
"counter_isomorphic",
|
||||
"counters",
|
||||
"counters_stable",
|
||||
"counter_url_query",
|
||||
"counter_without_macros",
|
||||
"directives",
|
||||
|
@ -29,6 +28,7 @@ CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = [
|
|||
"server_fns_axum",
|
||||
"session_auth_axum",
|
||||
"slots",
|
||||
"spread",
|
||||
"sso_auth_axum",
|
||||
"ssr_modes",
|
||||
"ssr_modes_axum",
|
||||
|
|
|
@ -17,10 +17,12 @@ You can also run any of the examples using [`cargo-make`](https://github.com/sag
|
|||
Follow these steps to get any example up and running.
|
||||
|
||||
1. `cd` to the example you want to run
|
||||
2. Run `cargo make ci` to setup and test the example
|
||||
3. Run `cargo make start` to run the example
|
||||
4. Open the client URL in the console output (<http://127.0.0.1:8080> or <http://127.0.0.1:3000> by default)
|
||||
5. Run `cargo make stop` to end any processes started by `cargo make start`.
|
||||
2. Make sure `cargo-make` is installed (for example by running `cargo install cargo-make`)
|
||||
3. Make sure `rustup target add wasm32-unknown-unknown` was executed for the currently selected toolchain.
|
||||
4. Run `cargo make ci` to setup and test the example
|
||||
5. Run `cargo make start` to run the example
|
||||
6. Open the client URL in the console output (<http://127.0.0.1:8080> or <http://127.0.0.1:3000> by default)
|
||||
7. Run `cargo make stop` to end any processes started by `cargo make start`.
|
||||
|
||||
Here are a few additional notes:
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "spread"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["csr", "nightly"] }
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
|
@ -0,0 +1,4 @@
|
|||
extend = [
|
||||
{ path = "../cargo-make/main.toml" },
|
||||
{ path = "../cargo-make/trunk_server.toml" },
|
||||
]
|
|
@ -0,0 +1,13 @@
|
|||
# Leptos Attribute and EventHandler spreading Example
|
||||
|
||||
This example creates a simple element in a client side rendered app with Rust and WASM!
|
||||
|
||||
Dynamic sets of attributes and event handler are spread onto the element with little effort.
|
||||
|
||||
## Getting Started
|
||||
|
||||
See the [Examples README](../README.md) for setup and run instructions.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Run `trunk serve --open` to run this example.
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link data-trunk rel="rust" data-wasm-opt="z"/>
|
||||
<link data-trunk rel="icon" type="image/ico" href="/public/favicon.ico"/>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,2 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-01-29"
|
|
@ -0,0 +1,57 @@
|
|||
use leptos::*;
|
||||
|
||||
/// Demonstrates how attributes and event handlers can be spread onto elements.
|
||||
#[component]
|
||||
pub fn SpreadingExample() -> impl IntoView {
|
||||
fn alert(msg: impl AsRef<str>) {
|
||||
let _ = window().alert_with_message(msg.as_ref());
|
||||
}
|
||||
|
||||
let attrs_only: Vec<(&'static str, Attribute)> =
|
||||
vec![("data-foo", "42".into_attribute())];
|
||||
|
||||
let event_handlers_only: Vec<EventHandlerFn> =
|
||||
vec![EventHandlerFn::Click(Box::new(|_e: ev::MouseEvent| {
|
||||
alert("event_handlers_only clicked");
|
||||
}))];
|
||||
|
||||
let combined: Vec<Binding> = vec![
|
||||
("data-foo", "123".into_attribute()).into(),
|
||||
EventHandlerFn::Click(Box::new(|_e: ev::MouseEvent| {
|
||||
alert("combined clicked");
|
||||
}))
|
||||
.into(),
|
||||
];
|
||||
|
||||
let partial_attrs: Vec<(&'static str, Attribute)> =
|
||||
vec![("data-foo", "11".into_attribute())];
|
||||
|
||||
let partial_event_handlers: Vec<EventHandlerFn> =
|
||||
vec![EventHandlerFn::Click(Box::new(|_e: ev::MouseEvent| {
|
||||
alert("partial_event_handlers clicked");
|
||||
}))];
|
||||
|
||||
view! {
|
||||
<div {..attrs_only}>
|
||||
"<div {..attrs_only} />"
|
||||
</div>
|
||||
|
||||
<div {..event_handlers_only}>
|
||||
"<div {..event_handlers_only} />"
|
||||
</div>
|
||||
|
||||
<div {..combined}>
|
||||
"<div {..combined} />"
|
||||
</div>
|
||||
|
||||
<div {..partial_attrs} {..partial_event_handlers}>
|
||||
"<div {..partial_attrs} {..partial_event_handlers} />"
|
||||
</div>
|
||||
|
||||
// Overwriting an event handler, here on:click, will result in a panic in debug builds. In release builds, the initial handler is kept.
|
||||
// If spreading is used, prefer manually merging event handlers in the binding list instead.
|
||||
//<div {..mixed} on:click=|_e| { alert("I will never be seen..."); }>
|
||||
// "with overwritten click handler"
|
||||
//</div>
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
use leptos::*;
|
||||
use spread::SpreadingExample;
|
||||
|
||||
pub fn main() {
|
||||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
mount_to_body(|| {
|
||||
view! {
|
||||
<SpreadingExample/>
|
||||
}
|
||||
})
|
||||
}
|
|
@ -27,8 +27,6 @@
|
|||
//! the code that Leptos generates.
|
||||
//! - [`counters`](https://github.com/leptos-rs/leptos/tree/main/examples/counters) introduces parent-child
|
||||
//! communication via contexts, and the `<For/>` component for efficient keyed list updates.
|
||||
//! - [`counters_stable`](https://github.com/leptos-rs/leptos/tree/main/examples/counters_stable) adapts the `counters` example
|
||||
//! to show how to use Leptos with `stable` Rust.
|
||||
//! - [`error_boundary`](https://github.com/leptos-rs/leptos/tree/main/examples/error_boundary) shows how to use
|
||||
//! `Result` types to handle errors.
|
||||
//! - [`parent_child`](https://github.com/leptos-rs/leptos/tree/main/examples/parent_child) shows four different
|
||||
|
@ -39,6 +37,7 @@
|
|||
//! - [`router`](https://github.com/leptos-rs/leptos/tree/main/examples/router) shows how to use Leptos’s nested router
|
||||
//! to enable client-side navigation and route-specific, reactive data loading.
|
||||
//! - [`slots`](https://github.com/leptos-rs/leptos/tree/main/examples/slots) shows how to use slots on components.
|
||||
//! - [`spread`](https://github.com/leptos-rs/leptos/tree/main/examples/spread) shows how the spread syntax can be used to spread data and/or event handlers onto elements.
|
||||
//! - [`counter_isomorphic`](https://github.com/leptos-rs/leptos/tree/main/examples/counter_isomorphic) shows
|
||||
//! different methods of interaction with a stateful server, including server functions, server actions, forms,
|
||||
//! and server-sent events (SSE).
|
||||
|
@ -162,9 +161,11 @@ pub use leptos_dom::{
|
|||
set_interval_with_handle, set_timeout, set_timeout_with_handle,
|
||||
window_event_listener, window_event_listener_untyped,
|
||||
},
|
||||
html, math, mount_to, mount_to_body, nonce, svg, window, Attribute, Class,
|
||||
CollectView, Errors, Fragment, HtmlElement, IntoAttribute, IntoClass,
|
||||
IntoProperty, IntoStyle, IntoView, NodeRef, Property, View,
|
||||
html,
|
||||
html::Binding,
|
||||
math, mount_to, mount_to_body, nonce, svg, window, Attribute, Class,
|
||||
CollectView, Errors, EventHandlerFn, Fragment, HtmlElement, IntoAttribute,
|
||||
IntoClass, IntoProperty, IntoStyle, IntoView, NodeRef, Property, View,
|
||||
};
|
||||
/// Utilities for simple isomorphic logging to the console or terminal.
|
||||
pub mod logging {
|
||||
|
|
|
@ -167,6 +167,86 @@ impl DOMEventResponder for crate::View {
|
|||
}
|
||||
}
|
||||
|
||||
/// A statically typed event handler.
|
||||
pub enum EventHandlerFn {
|
||||
/// `keydown` event handler.
|
||||
Keydown(Box<dyn FnMut(KeyboardEvent)>),
|
||||
/// `keyup` event handler.
|
||||
Keyup(Box<dyn FnMut(KeyboardEvent)>),
|
||||
/// `keypress` event handler.
|
||||
Keypress(Box<dyn FnMut(KeyboardEvent)>),
|
||||
|
||||
/// `click` event handler.
|
||||
Click(Box<dyn FnMut(MouseEvent)>),
|
||||
/// `dblclick` event handler.
|
||||
Dblclick(Box<dyn FnMut(MouseEvent)>),
|
||||
/// `mousedown` event handler.
|
||||
Mousedown(Box<dyn FnMut(MouseEvent)>),
|
||||
/// `mouseup` event handler.
|
||||
Mouseup(Box<dyn FnMut(MouseEvent)>),
|
||||
/// `mouseenter` event handler.
|
||||
Mouseenter(Box<dyn FnMut(MouseEvent)>),
|
||||
/// `mouseleave` event handler.
|
||||
Mouseleave(Box<dyn FnMut(MouseEvent)>),
|
||||
/// `mouseout` event handler.
|
||||
Mouseout(Box<dyn FnMut(MouseEvent)>),
|
||||
/// `mouseover` event handler.
|
||||
Mouseover(Box<dyn FnMut(MouseEvent)>),
|
||||
/// `mousemove` event handler.
|
||||
Mousemove(Box<dyn FnMut(MouseEvent)>),
|
||||
|
||||
/// `wheel` event handler.
|
||||
Wheel(Box<dyn FnMut(WheelEvent)>),
|
||||
|
||||
/// `touchstart` event handler.
|
||||
Touchstart(Box<dyn FnMut(TouchEvent)>),
|
||||
/// `touchend` event handler.
|
||||
Touchend(Box<dyn FnMut(TouchEvent)>),
|
||||
/// `touchcancel` event handler.
|
||||
Touchcancel(Box<dyn FnMut(TouchEvent)>),
|
||||
/// `touchmove` event handler.
|
||||
Touchmove(Box<dyn FnMut(TouchEvent)>),
|
||||
|
||||
/// `pointerenter` event handler.
|
||||
Pointerenter(Box<dyn FnMut(PointerEvent)>),
|
||||
/// `pointerleave` event handler.
|
||||
Pointerleave(Box<dyn FnMut(PointerEvent)>),
|
||||
/// `pointerdown` event handler.
|
||||
Pointerdown(Box<dyn FnMut(PointerEvent)>),
|
||||
/// `pointerup` event handler.
|
||||
Pointerup(Box<dyn FnMut(PointerEvent)>),
|
||||
/// `pointercancel` event handler.
|
||||
Pointercancel(Box<dyn FnMut(PointerEvent)>),
|
||||
/// `pointerout` event handler.
|
||||
Pointerout(Box<dyn FnMut(PointerEvent)>),
|
||||
/// `pointerover` event handler.
|
||||
Pointerover(Box<dyn FnMut(PointerEvent)>),
|
||||
/// `pointermove` event handler.
|
||||
Pointermove(Box<dyn FnMut(PointerEvent)>),
|
||||
|
||||
/// `drag` event handler.
|
||||
Drag(Box<dyn FnMut(DragEvent)>),
|
||||
/// `dragend` event handler.
|
||||
Dragend(Box<dyn FnMut(DragEvent)>),
|
||||
/// `dragenter` event handler.
|
||||
Dragenter(Box<dyn FnMut(DragEvent)>),
|
||||
/// `dragleave` event handler.
|
||||
Dragleave(Box<dyn FnMut(DragEvent)>),
|
||||
/// `dragstart` event handler.
|
||||
Dragstart(Box<dyn FnMut(DragEvent)>),
|
||||
/// `drop` event handler.
|
||||
Drop(Box<dyn FnMut(DragEvent)>),
|
||||
|
||||
/// `blur` event handler.
|
||||
Blur(Box<dyn FnMut(FocusEvent)>),
|
||||
/// `focusout` event handler.
|
||||
Focusout(Box<dyn FnMut(FocusEvent)>),
|
||||
/// `focus` event handler.
|
||||
Focus(Box<dyn FnMut(FocusEvent)>),
|
||||
/// `focusin` event handler.
|
||||
Focusin(Box<dyn FnMut(FocusEvent)>),
|
||||
}
|
||||
|
||||
/// Type that can be used to handle DOM events
|
||||
pub trait EventHandler {
|
||||
/// Attaches event listener to any target that can respond to DOM events
|
||||
|
|
|
@ -63,7 +63,7 @@ cfg_if! {
|
|||
|
||||
use crate::{
|
||||
create_node_ref,
|
||||
ev::EventDescriptor,
|
||||
ev::{EventDescriptor, EventHandlerFn},
|
||||
hydration::HydrationCtx,
|
||||
macro_helpers::{
|
||||
Attribute, IntoAttribute, IntoClass, IntoProperty, IntoStyle,
|
||||
|
@ -366,6 +366,33 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Bind data through attributes, or behavior through event handlers, to an element.
|
||||
/// A value of any type able to provide an iterator of bindings (like a: `Vec<Binding>`),
|
||||
/// can be spread onto an element using the spread syntax `view! { <div {..bindings} /> }`.
|
||||
pub enum Binding {
|
||||
/// A statically named attribute.
|
||||
Attribute {
|
||||
/// Name of the attribute.
|
||||
name: &'static str,
|
||||
/// Value of the attribute, possibly reactive.
|
||||
value: Attribute,
|
||||
},
|
||||
/// A statically typed event handler.
|
||||
EventHandler(EventHandlerFn),
|
||||
}
|
||||
|
||||
impl From<(&'static str, Attribute)> for Binding {
|
||||
fn from((name, value): (&'static str, Attribute)) -> Self {
|
||||
Self::Attribute { name, value }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EventHandlerFn> for Binding {
|
||||
fn from(handler: EventHandlerFn) -> Self {
|
||||
Self::EventHandler(handler)
|
||||
}
|
||||
}
|
||||
|
||||
impl<El: ElementDescriptor + 'static> HtmlElement<El> {
|
||||
pub(crate) fn new(element: El) -> Self {
|
||||
cfg_if! {
|
||||
|
@ -651,7 +678,7 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Adds multiple attributes to the element
|
||||
/// Adds multiple attributes to the element.
|
||||
#[track_caller]
|
||||
pub fn attrs(
|
||||
mut self,
|
||||
|
@ -663,6 +690,133 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Adds multiple bindings (attributes or event handlers) to the element.
|
||||
#[track_caller]
|
||||
pub fn bindings<B: Into<Binding>>(
|
||||
mut self,
|
||||
bindings: impl std::iter::IntoIterator<Item = B>,
|
||||
) -> Self {
|
||||
for binding in bindings {
|
||||
self = self.binding(binding.into());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a single binding (attribute or event handler) to the element.
|
||||
#[track_caller]
|
||||
fn binding(self, binding: Binding) -> Self {
|
||||
match binding {
|
||||
Binding::Attribute { name, value } => self.attr(name, value),
|
||||
Binding::EventHandler(handler) => match handler {
|
||||
EventHandlerFn::Keydown(handler) => {
|
||||
self.on(crate::events::typed::keydown, handler)
|
||||
}
|
||||
EventHandlerFn::Keyup(handler) => {
|
||||
self.on(crate::events::typed::keyup, handler)
|
||||
}
|
||||
EventHandlerFn::Keypress(handler) => {
|
||||
self.on(crate::events::typed::keypress, handler)
|
||||
}
|
||||
EventHandlerFn::Click(handler) => {
|
||||
self.on(crate::events::typed::click, handler)
|
||||
}
|
||||
EventHandlerFn::Dblclick(handler) => {
|
||||
self.on(crate::events::typed::dblclick, handler)
|
||||
}
|
||||
EventHandlerFn::Mousedown(handler) => {
|
||||
self.on(crate::events::typed::mousedown, handler)
|
||||
}
|
||||
EventHandlerFn::Mouseup(handler) => {
|
||||
self.on(crate::events::typed::mouseup, handler)
|
||||
}
|
||||
EventHandlerFn::Mouseenter(handler) => {
|
||||
self.on(crate::events::typed::mouseenter, handler)
|
||||
}
|
||||
EventHandlerFn::Mouseleave(handler) => {
|
||||
self.on(crate::events::typed::mouseleave, handler)
|
||||
}
|
||||
EventHandlerFn::Mouseout(handler) => {
|
||||
self.on(crate::events::typed::mouseout, handler)
|
||||
}
|
||||
EventHandlerFn::Mouseover(handler) => {
|
||||
self.on(crate::events::typed::mouseover, handler)
|
||||
}
|
||||
EventHandlerFn::Mousemove(handler) => {
|
||||
self.on(crate::events::typed::mousemove, handler)
|
||||
}
|
||||
EventHandlerFn::Wheel(handler) => {
|
||||
self.on(crate::events::typed::wheel, handler)
|
||||
}
|
||||
EventHandlerFn::Touchstart(handler) => {
|
||||
self.on(crate::events::typed::touchstart, handler)
|
||||
}
|
||||
EventHandlerFn::Touchend(handler) => {
|
||||
self.on(crate::events::typed::touchend, handler)
|
||||
}
|
||||
EventHandlerFn::Touchcancel(handler) => {
|
||||
self.on(crate::events::typed::touchcancel, handler)
|
||||
}
|
||||
EventHandlerFn::Touchmove(handler) => {
|
||||
self.on(crate::events::typed::touchmove, handler)
|
||||
}
|
||||
EventHandlerFn::Pointerenter(handler) => {
|
||||
self.on(crate::events::typed::pointerenter, handler)
|
||||
}
|
||||
EventHandlerFn::Pointerleave(handler) => {
|
||||
self.on(crate::events::typed::pointerleave, handler)
|
||||
}
|
||||
EventHandlerFn::Pointerdown(handler) => {
|
||||
self.on(crate::events::typed::pointerdown, handler)
|
||||
}
|
||||
EventHandlerFn::Pointerup(handler) => {
|
||||
self.on(crate::events::typed::pointerup, handler)
|
||||
}
|
||||
EventHandlerFn::Pointercancel(handler) => {
|
||||
self.on(crate::events::typed::pointercancel, handler)
|
||||
}
|
||||
EventHandlerFn::Pointerout(handler) => {
|
||||
self.on(crate::events::typed::pointerout, handler)
|
||||
}
|
||||
EventHandlerFn::Pointerover(handler) => {
|
||||
self.on(crate::events::typed::pointerover, handler)
|
||||
}
|
||||
EventHandlerFn::Pointermove(handler) => {
|
||||
self.on(crate::events::typed::pointermove, handler)
|
||||
}
|
||||
EventHandlerFn::Drag(handler) => {
|
||||
self.on(crate::events::typed::drag, handler)
|
||||
}
|
||||
EventHandlerFn::Dragend(handler) => {
|
||||
self.on(crate::events::typed::dragend, handler)
|
||||
}
|
||||
EventHandlerFn::Dragenter(handler) => {
|
||||
self.on(crate::events::typed::dragenter, handler)
|
||||
}
|
||||
EventHandlerFn::Dragleave(handler) => {
|
||||
self.on(crate::events::typed::dragleave, handler)
|
||||
}
|
||||
EventHandlerFn::Dragstart(handler) => {
|
||||
self.on(crate::events::typed::dragstart, handler)
|
||||
}
|
||||
EventHandlerFn::Drop(handler) => {
|
||||
self.on(crate::events::typed::drop, handler)
|
||||
}
|
||||
EventHandlerFn::Blur(handler) => {
|
||||
self.on(crate::events::typed::blur, handler)
|
||||
}
|
||||
EventHandlerFn::Focusout(handler) => {
|
||||
self.on(crate::events::typed::focusout, handler)
|
||||
}
|
||||
EventHandlerFn::Focus(handler) => {
|
||||
self.on(crate::events::typed::focus, handler)
|
||||
}
|
||||
EventHandlerFn::Focusin(handler) => {
|
||||
self.on(crate::events::typed::focusin, handler)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a class to an element.
|
||||
///
|
||||
/// **Note**: In the builder syntax, this will be overwritten by the `class`
|
||||
|
|
|
@ -36,7 +36,10 @@ pub use directive::*;
|
|||
pub use events::add_event_helper;
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use events::{add_event_listener, add_event_listener_undelegated};
|
||||
pub use events::{typed as ev, typed::EventHandler};
|
||||
pub use events::{
|
||||
typed as ev,
|
||||
typed::{EventHandler, EventHandlerFn},
|
||||
};
|
||||
pub use html::HtmlElement;
|
||||
use html::{AnyElement, ElementDescriptor};
|
||||
pub use hydration::{HydrationCtx, HydrationKey};
|
||||
|
|
|
@ -223,7 +223,7 @@ pub(crate) fn element_to_tokens(
|
|||
None
|
||||
}
|
||||
});
|
||||
let spread_attrs = node.attributes().iter().filter_map(|node| {
|
||||
let bindings = node.attributes().iter().filter_map(|node| {
|
||||
use rstml::node::NodeBlock;
|
||||
use syn::{Expr, ExprRange, RangeLimits, Stmt};
|
||||
|
||||
|
@ -237,7 +237,9 @@ pub(crate) fn element_to_tokens(
|
|||
..
|
||||
}),
|
||||
_,
|
||||
) => Some(quote! { .attrs(#[allow(unused_brace)] {#end}) }),
|
||||
) => Some(
|
||||
quote! { .bindings(#[allow(unused_brace)] {#end}) },
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
|
@ -356,7 +358,7 @@ pub(crate) fn element_to_tokens(
|
|||
#(#ide_helper_close_tag)*
|
||||
#name
|
||||
#(#attrs)*
|
||||
#(#spread_attrs)*
|
||||
#(#bindings)*
|
||||
#(#class_attrs)*
|
||||
#(#style_attrs)*
|
||||
#global_class_expr
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
//! ## Example
|
||||
//!
|
||||
//! ```rust
|
||||
//!
|
||||
//! use leptos::*;
|
||||
//! use leptos_router::*;
|
||||
//!
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
# Stable options
|
||||
edition = "2021"
|
||||
imports_granularity = "Crate"
|
||||
max_width = 80
|
||||
|
||||
# Unstable options
|
||||
imports_granularity = "Crate"
|
||||
format_strings = true
|
||||
group_imports = "One"
|
||||
format_code_in_doc_comments = true
|
||||
|
|
Loading…
Reference in New Issue