mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
feat: allow spreading of both attributes and event handlers (#2432)
This commit is contained in:
parent
fc537c14c4
commit
119c9ea23f
20 changed files with 386 additions and 25 deletions
2
.github/workflows/ci-semver.yml
vendored
2
.github/workflows/ci-semver.yml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Sember Checks
|
- name: Semver Checks
|
||||||
uses: obi1kenobi/cargo-semver-checks-action@v2
|
uses: obi1kenobi/cargo-semver-checks-action@v2
|
||||||
with:
|
with:
|
||||||
rust-toolchain: nightly-2024-03-31
|
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`)
|
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.
|
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`.
|
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
|
From the root directory of the repo, run
|
||||||
|
|
|
@ -10,7 +10,6 @@ CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = [
|
||||||
"counter",
|
"counter",
|
||||||
"counter_isomorphic",
|
"counter_isomorphic",
|
||||||
"counters",
|
"counters",
|
||||||
"counters_stable",
|
|
||||||
"counter_url_query",
|
"counter_url_query",
|
||||||
"counter_without_macros",
|
"counter_without_macros",
|
||||||
"directives",
|
"directives",
|
||||||
|
@ -29,6 +28,7 @@ CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = [
|
||||||
"server_fns_axum",
|
"server_fns_axum",
|
||||||
"session_auth_axum",
|
"session_auth_axum",
|
||||||
"slots",
|
"slots",
|
||||||
|
"spread",
|
||||||
"sso_auth_axum",
|
"sso_auth_axum",
|
||||||
"ssr_modes",
|
"ssr_modes",
|
||||||
"ssr_modes_axum",
|
"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.
|
Follow these steps to get any example up and running.
|
||||||
|
|
||||||
1. `cd` to the example you want to run
|
1. `cd` to the example you want to run
|
||||||
2. Run `cargo make ci` to setup and test the example
|
2. Make sure `cargo-make` is installed (for example by running `cargo install cargo-make`)
|
||||||
3. Run `cargo make start` to run the example
|
3. Make sure `rustup target add wasm32-unknown-unknown` was executed for the currently selected toolchain.
|
||||||
4. Open the client URL in the console output (<http://127.0.0.1:8080> or <http://127.0.0.1:3000> by default)
|
4. Run `cargo make ci` to setup and test the example
|
||||||
5. Run `cargo make stop` to end any processes started by `cargo make start`.
|
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:
|
Here are a few additional notes:
|
||||||
|
|
||||||
|
|
14
examples/spread/Cargo.toml
Normal file
14
examples/spread/Cargo.toml
Normal file
|
@ -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"
|
4
examples/spread/Makefile.toml
Normal file
4
examples/spread/Makefile.toml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
extend = [
|
||||||
|
{ path = "../cargo-make/main.toml" },
|
||||||
|
{ path = "../cargo-make/trunk_server.toml" },
|
||||||
|
]
|
13
examples/spread/README.md
Normal file
13
examples/spread/README.md
Normal file
|
@ -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.
|
8
examples/spread/index.html
Normal file
8
examples/spread/index.html
Normal file
|
@ -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>
|
BIN
examples/spread/public/favicon.ico
Normal file
BIN
examples/spread/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
2
examples/spread/rust-toolchain.toml
Normal file
2
examples/spread/rust-toolchain.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "nightly-2024-01-29"
|
57
examples/spread/src/lib.rs
Normal file
57
examples/spread/src/lib.rs
Normal file
|
@ -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>
|
||||||
|
}
|
||||||
|
}
|
12
examples/spread/src/main.rs
Normal file
12
examples/spread/src/main.rs
Normal file
|
@ -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.
|
//! the code that Leptos generates.
|
||||||
//! - [`counters`](https://github.com/leptos-rs/leptos/tree/main/examples/counters) introduces parent-child
|
//! - [`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.
|
//! 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
|
//! - [`error_boundary`](https://github.com/leptos-rs/leptos/tree/main/examples/error_boundary) shows how to use
|
||||||
//! `Result` types to handle errors.
|
//! `Result` types to handle errors.
|
||||||
//! - [`parent_child`](https://github.com/leptos-rs/leptos/tree/main/examples/parent_child) shows four different
|
//! - [`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
|
//! - [`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.
|
//! 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.
|
//! - [`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
|
//! - [`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,
|
//! different methods of interaction with a stateful server, including server functions, server actions, forms,
|
||||||
//! and server-sent events (SSE).
|
//! and server-sent events (SSE).
|
||||||
|
@ -162,9 +161,11 @@ pub use leptos_dom::{
|
||||||
set_interval_with_handle, set_timeout, set_timeout_with_handle,
|
set_interval_with_handle, set_timeout, set_timeout_with_handle,
|
||||||
window_event_listener, window_event_listener_untyped,
|
window_event_listener, window_event_listener_untyped,
|
||||||
},
|
},
|
||||||
html, math, mount_to, mount_to_body, nonce, svg, window, Attribute, Class,
|
html,
|
||||||
CollectView, Errors, Fragment, HtmlElement, IntoAttribute, IntoClass,
|
html::Binding,
|
||||||
IntoProperty, IntoStyle, IntoView, NodeRef, Property, View,
|
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.
|
/// Utilities for simple isomorphic logging to the console or terminal.
|
||||||
pub mod logging {
|
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
|
/// Type that can be used to handle DOM events
|
||||||
pub trait EventHandler {
|
pub trait EventHandler {
|
||||||
/// Attaches event listener to any target that can respond to DOM events
|
/// Attaches event listener to any target that can respond to DOM events
|
||||||
|
|
|
@ -63,7 +63,7 @@ cfg_if! {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
create_node_ref,
|
create_node_ref,
|
||||||
ev::EventDescriptor,
|
ev::{EventDescriptor, EventHandlerFn},
|
||||||
hydration::HydrationCtx,
|
hydration::HydrationCtx,
|
||||||
macro_helpers::{
|
macro_helpers::{
|
||||||
Attribute, IntoAttribute, IntoClass, IntoProperty, IntoStyle,
|
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> {
|
impl<El: ElementDescriptor + 'static> HtmlElement<El> {
|
||||||
pub(crate) fn new(element: El) -> Self {
|
pub(crate) fn new(element: El) -> Self {
|
||||||
cfg_if! {
|
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]
|
#[track_caller]
|
||||||
pub fn attrs(
|
pub fn attrs(
|
||||||
mut self,
|
mut self,
|
||||||
|
@ -663,6 +690,133 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
|
||||||
self
|
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.
|
/// Adds a class to an element.
|
||||||
///
|
///
|
||||||
/// **Note**: In the builder syntax, this will be overwritten by the `class`
|
/// **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;
|
pub use events::add_event_helper;
|
||||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||||
use events::{add_event_listener, add_event_listener_undelegated};
|
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;
|
pub use html::HtmlElement;
|
||||||
use html::{AnyElement, ElementDescriptor};
|
use html::{AnyElement, ElementDescriptor};
|
||||||
pub use hydration::{HydrationCtx, HydrationKey};
|
pub use hydration::{HydrationCtx, HydrationKey};
|
||||||
|
|
|
@ -223,7 +223,7 @@ pub(crate) fn element_to_tokens(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let spread_attrs = node.attributes().iter().filter_map(|node| {
|
let bindings = node.attributes().iter().filter_map(|node| {
|
||||||
use rstml::node::NodeBlock;
|
use rstml::node::NodeBlock;
|
||||||
use syn::{Expr, ExprRange, RangeLimits, Stmt};
|
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,
|
_ => None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -356,7 +358,7 @@ pub(crate) fn element_to_tokens(
|
||||||
#(#ide_helper_close_tag)*
|
#(#ide_helper_close_tag)*
|
||||||
#name
|
#name
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#(#spread_attrs)*
|
#(#bindings)*
|
||||||
#(#class_attrs)*
|
#(#class_attrs)*
|
||||||
#(#style_attrs)*
|
#(#style_attrs)*
|
||||||
#global_class_expr
|
#global_class_expr
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
//! ## Example
|
//! ## Example
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//!
|
|
||||||
//! use leptos::*;
|
//! use leptos::*;
|
||||||
//! use leptos_router::*;
|
//! use leptos_router::*;
|
||||||
//!
|
//!
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
# Stable options
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
imports_granularity = "Crate"
|
|
||||||
max_width = 80
|
max_width = 80
|
||||||
|
|
||||||
|
# Unstable options
|
||||||
|
imports_granularity = "Crate"
|
||||||
format_strings = true
|
format_strings = true
|
||||||
group_imports = "One"
|
group_imports = "One"
|
||||||
format_code_in_doc_comments = true
|
format_code_in_doc_comments = true
|
||||||
|
|
Loading…
Reference in a new issue