, T>(mut _f: impl FnMut(::dioxus_core::Event<$data>) -> E + 'static) -> ::dioxus_core::Attribute {
::dioxus_core::Attribute::new(
@@ -356,6 +369,15 @@ pub fn event_bubbles(evt: &str) -> bool {
}
#[doc(hidden)]
+#[rustversion::attr(
+ since(1.78.0),
+ diagnostic::on_unimplemented(
+ message = "`EventHandlerReturn` is not implemented for `{Self}`",
+ label = "Return Value",
+ note = "Event handlers in dioxus need to return either: nothing (the unit type `()`), or an async block that dioxus will automatically spawn",
+ note = "You likely need to add a semicolon to the end of the event handler to make it return nothing",
+ )
+)]
pub trait EventReturn: Sized {
fn spawn(self) {}
}
diff --git a/packages/html/src/events/mounted.rs b/packages/html/src/events/mounted.rs
index 8962766e15..d6166e3ee5 100644
--- a/packages/html/src/events/mounted.rs
+++ b/packages/html/src/events/mounted.rs
@@ -44,6 +44,7 @@ impl RenderedElementBacking for () {
/// The way that scrolling should be performed
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
+#[doc(alias = "ScrollIntoViewOptions")]
pub enum ScrollBehavior {
/// Scroll to the element immediately
#[cfg_attr(feature = "serialize", serde(rename = "instant"))]
@@ -80,6 +81,7 @@ impl MountedData {
}
/// Scroll to make the element visible
+ #[doc(alias = "scrollIntoView")]
pub fn scroll_to(
&self,
behavior: ScrollBehavior,
@@ -88,6 +90,8 @@ impl MountedData {
}
/// Set the focus on the element
+ #[doc(alias = "focus")]
+ #[doc(alias = "blur")]
pub fn set_focus(&self, focus: bool) -> Pin>>> {
self.inner.set_focus(focus)
}
@@ -105,7 +109,64 @@ pub type MountedEvent = Event;
impl_event! [
MountedData;
- /// mounted
+ #[doc(alias = "ref")]
+ #[doc(alias = "createRef")]
+ #[doc(alias = "useRef")]
+ /// The onmounted event is fired when the element is first added to the DOM. This event gives you a [`MountedData`] object and lets you interact with the raw DOM element.
+ ///
+ /// This event is fired once per element. If you need to access the element multiple times, you can store the [`MountedData`] object in a [`use_signal`] hook and use it as needed.
+ ///
+ /// # Examples
+ ///
+ /// ```rust, no_run
+ /// # use dioxus::prelude::*;
+ /// fn App() -> Element {
+ /// let mut header_element = use_signal(|| None);
+ ///
+ /// rsx! {
+ /// div {
+ /// h1 {
+ /// // The onmounted event will run the first time the h1 element is mounted
+ /// onmounted: move |element| header_element.set(Some(element.data())),
+ /// "Scroll to top example"
+ /// }
+ ///
+ /// for i in 0..100 {
+ /// div { "Item {i}" }
+ /// }
+ ///
+ /// button {
+ /// // When you click the button, if the header element has been mounted, we scroll to that element
+ /// onclick: move |_| async move {
+ /// if let Some(header) = header_element.cloned() {
+ /// let _ = header.scroll_to(ScrollBehavior::Smooth).await;
+ /// }
+ /// },
+ /// "Scroll to top"
+ /// }
+ /// }
+ /// }
+ /// }
+ /// ```
+ ///
+ /// The `MountedData` struct contains cross platform APIs that work on the desktop, mobile, liveview and web platforms. For the web platform, you can also downcast the `MountedData` event to the `web-sys::Element` type for more web specific APIs:
+ ///
+ /// ```rust, no_run
+ /// # use dioxus::prelude::*;
+ /// # use dioxus_web::WebEventExt;
+ /// fn App() -> Element {
+ /// rsx! {
+ /// div {
+ /// id: "some-id",
+ /// onmounted: move |element| {
+ /// // You can use the web_event trait to downcast the element to a web specific event. For the mounted event, this will be a web_sys::Element
+ /// let web_sys_element = element.web_event();
+ /// assert_eq!(web_sys_element.id(), "some-id");
+ /// }
+ /// }
+ /// }
+ /// }
+ /// ```
onmounted
];
diff --git a/packages/html/src/global_attributes.rs b/packages/html/src/global_attributes.rs
index cbac1d87e9..243b76251d 100644
--- a/packages/html/src/global_attributes.rs
+++ b/packages/html/src/global_attributes.rs
@@ -29,12 +29,21 @@ macro_rules! trait_method_mapping {
(
$matching:ident;
$(#[$attr:meta])*
- $name:ident: $lit:literal, $ns:literal;
+ $name:ident: $lit:literal in $ns:literal;
) => {
if $matching == stringify!($name) {
return Some(($lit, Some($ns)));
}
};
+ (
+ $matching:ident;
+ $(#[$attr:meta])*
+ $name:ident in $ns:literal;
+ ) => {
+ if $matching == stringify!($name) {
+ return Some((stringify!($name), Some($ns)));
+ }
+ };
}
#[cfg(feature = "html-to-rsx")]
@@ -60,12 +69,21 @@ macro_rules! html_to_rsx_attribute_mapping {
(
$matching:ident;
$(#[$attr:meta])*
- $name:ident: $lit:literal, $ns:literal;
+ $name:ident: $lit:literal in $ns:literal;
) => {
if $matching == stringify!($lit) {
return Some(stringify!($name));
}
};
+ (
+ $matching:ident;
+ $(#[$attr:meta])*
+ $name:ident in $ns:literal;
+ ) => {
+ if $matching == stringify!($name) {
+ return Some(stringify!($name));
+ }
+ };
}
macro_rules! trait_methods {
@@ -77,7 +95,7 @@ macro_rules! trait_methods {
$fn_html_to_rsx:ident;
$(
$(#[$attr:meta])*
- $name:ident $(: $($arg:literal),*)*;
+ $name:ident $(: $js_name:literal)? $(in $ns:literal)?;
)+
) => {
$(#[$trait_attr])*
@@ -93,7 +111,7 @@ macro_rules! trait_methods {
$(
trait_method_mapping! {
attr;
- $name$(: $($arg),*)*;
+ $name $(: $js_name)? $(in $ns)?;
}
)*
None
@@ -105,7 +123,7 @@ macro_rules! trait_methods {
$(
html_to_rsx_attribute_mapping! {
html;
- $name$(: $($arg),*)*;
+ $name $(: $js_name)? $(in $ns)?;
}
)*
None
@@ -115,7 +133,10 @@ macro_rules! trait_methods {
};
// Rename the incoming ident and apply a custom namespace
- ( $name:ident: $lit:literal, $ns:literal; ) => { ($lit, Some($ns), false) };
+ ( $name:ident: $lit:literal in $ns:literal; ) => { ($lit, Some($ns), false) };
+
+ // Custom namespace
+ ( $name:ident in $ns:literal; ) => { (stringify!($name), Some($ns), false) };
// Rename the incoming ident
( $name:ident: $lit:literal; ) => { ($lit, None, false ) };
@@ -139,11 +160,11 @@ trait_methods! {
///
- accesskey: "accesskey";
+ accesskey;
///
- autocapitalize: "autocapitalize";
+ autocapitalize;
///
@@ -158,25 +179,38 @@ trait_methods! {
/// Classes allow CSS and Javascript to select and access specific elements via the class selectors or
/// functions like the DOM method document.getElementsByClassName.
///
- /// ## Example
+ /// ## Multiple Classes
///
- /// ### HTML:
- /// ```html
- /// Above point sounds a bit obvious. Remove/rewrite?
+ /// If you include multiple classes in a single element dioxus will automatically join them with a space.
+ ///
+ /// ```rust
+ /// # use dioxus::prelude::*;
+ /// rsx! {
+ /// div {
+ /// class: "my-class",
+ /// class: "my-other-class"
+ /// }
+ /// };
/// ```
///
- /// ### CSS:
- /// ```css
- /// .note {
- /// font-style: italic;
- /// font-weight: bold;
- /// }
+ /// ## Optional Classes
+ ///
+ /// You can include optional attributes with an unterminated if statement as the value of the attribute. This is very useful for conditionally applying css classes:
///
- /// .editorial {
- /// background: rgb(255, 0, 0, .25);
- /// padding: 10px;
- /// }
+ /// ```rust
+ /// # use dioxus::prelude::*;
+ /// rsx! {
+ /// div {
+ /// class: if true {
+ /// "my-class"
+ /// },
+ /// class: if false {
+ /// "my-other-class"
+ /// }
+ /// }
+ /// };
/// ```
+ ///
///
class;
@@ -270,1222 +304,1222 @@ trait_methods! {
// This roughly follows the html spec
///
- align_content: "align-content", "style";
+ align_content: "align-content" in "style";
///
- align_items: "align-items", "style";
+ align_items: "align-items" in "style";
///
- align_self: "align-self", "style";
+ align_self: "align-self" in "style";
///
- alignment_adjust: "alignment-adjust", "style";
+ alignment_adjust: "alignment-adjust" in "style";
///
- alignment_baseline: "alignment-baseline", "style";
+ alignment_baseline: "alignment-baseline" in "style";
///
- all: "all", "style";
+ all in "style";
///
- alt: "alt", "style";
+ alt in "style";
///
- animation: "animation", "style";
+ animation in "style";
///
- animation_delay: "animation-delay", "style";
+ animation_delay: "animation-delay" in "style";
///
- animation_direction: "animation-direction", "style";
+ animation_direction: "animation-direction" in "style";
///
- animation_duration: "animation-duration", "style";
+ animation_duration: "animation-duration" in "style";
///
- animation_fill_mode: "animation-fill-mode", "style";
+ animation_fill_mode: "animation-fill-mode" in "style";
///
- animation_iteration_count: "animation-iteration-count", "style";
+ animation_iteration_count: "animation-iteration-count" in "style";
///
- animation_name: "animation-name", "style";
+ animation_name: "animation-name" in "style";
///
- animation_play_state: "animation-play-state", "style";
+ animation_play_state: "animation-play-state" in "style";
///
- animation_timing_function: "animation-timing-function", "style";
+ animation_timing_function: "animation-timing-function" in "style";
///
- azimuth: "azimuth", "style";
+ azimuth in "style";
///
- backdrop_filter: "backdrop-filter", "style";
+ backdrop_filter: "backdrop-filter" in "style";
///
- backface_visibility: "backface-visibility", "style";
+ backface_visibility: "backface-visibility" in "style";
///
- background: "background", "style";
+ background in "style";
///
- background_attachment: "background-attachment", "style";
+ background_attachment: "background-attachment" in "style";
///
- background_clip: "background-clip", "style";
+ background_clip: "background-clip" in "style";
///
- background_color: "background-color", "style";
+ background_color: "background-color" in "style";
///
- background_image: "background-image", "style";
+ background_image: "background-image" in "style";
///
- background_origin: "background-origin", "style";
+ background_origin: "background-origin" in "style";
///
- background_position: "background-position", "style";
+ background_position: "background-position" in "style";
///
- background_repeat: "background-repeat", "style";
+ background_repeat: "background-repeat" in "style";
///
- background_size: "background-size", "style";
+ background_size: "background-size" in "style";
///
- background_blend_mode: "background-blend-mode", "style";
+ background_blend_mode: "background-blend-mode" in "style";
///
- baseline_shift: "baseline-shift", "style";
+ baseline_shift: "baseline-shift" in "style";
///
- bleed: "bleed", "style";
+ bleed in "style";
///
- bookmark_label: "bookmark-label", "style";
+ bookmark_label: "bookmark-label" in "style";
///
- bookmark_level: "bookmark-level", "style";
+ bookmark_level: "bookmark-level" in "style";
///
- bookmark_state: "bookmark-state", "style";
+ bookmark_state: "bookmark-state" in "style";
///
- border: "border", "style";
+ border in "style";
///
- border_color: "border-color", "style";
+ border_color: "border-color" in "style";
///
- border_style: "border-style", "style";
+ border_style: "border-style" in "style";
///
- border_width: "border-width", "style";
+ border_width: "border-width" in "style";
///
- border_bottom: "border-bottom", "style";
+ border_bottom: "border-bottom" in "style";
///
- border_bottom_color: "border-bottom-color", "style";
+ border_bottom_color: "border-bottom-color" in "style";
///
- border_bottom_style: "border-bottom-style", "style";
+ border_bottom_style: "border-bottom-style" in "style";
///
- border_bottom_width: "border-bottom-width", "style";
+ border_bottom_width: "border-bottom-width" in "style";
///
- border_left: "border-left", "style";
+ border_left: "border-left" in "style";
///
- border_left_color: "border-left-color", "style";
+ border_left_color: "border-left-color" in "style";
///
- border_left_style: "border-left-style", "style";
+ border_left_style: "border-left-style" in "style";
///
- border_left_width: "border-left-width", "style";
+ border_left_width: "border-left-width" in "style";
///
- border_right: "border-right", "style";
+ border_right: "border-right" in "style";
///
- border_right_color: "border-right-color", "style";
+ border_right_color: "border-right-color" in "style";
///
- border_right_style: "border-right-style", "style";
+ border_right_style: "border-right-style" in "style";
///
- border_right_width: "border-right-width", "style";
+ border_right_width: "border-right-width" in "style";
///
- border_top: "border-top", "style";
+ border_top: "border-top" in "style";
///
- border_top_color: "border-top-color", "style";
+ border_top_color: "border-top-color" in "style";
///
- border_top_style: "border-top-style", "style";
+ border_top_style: "border-top-style" in "style";
///
- border_top_width: "border-top-width", "style";
+ border_top_width: "border-top-width" in "style";
///
- border_collapse: "border-collapse", "style";
+ border_collapse: "border-collapse" in "style";
///
- border_image: "border-image", "style";
+ border_image: "border-image" in "style";
///
- border_image_outset: "border-image-outset", "style";
+ border_image_outset: "border-image-outset" in "style";
///
- border_image_repeat: "border-image-repeat", "style";
+ border_image_repeat: "border-image-repeat" in "style";
///
- border_image_slice: "border-image-slice", "style";
+ border_image_slice: "border-image-slice" in "style";
///
- border_image_source: "border-image-source", "style";
+ border_image_source: "border-image-source" in "style";
///
- border_image_width: "border-image-width", "style";
+ border_image_width: "border-image-width" in "style";
///
- border_radius: "border-radius", "style";
+ border_radius: "border-radius" in "style";
///
- border_bottom_left_radius: "border-bottom-left-radius", "style";
+ border_bottom_left_radius: "border-bottom-left-radius" in "style";
///
- border_bottom_right_radius: "border-bottom-right-radius", "style";
+ border_bottom_right_radius: "border-bottom-right-radius" in "style";
///
- border_top_left_radius: "border-top-left-radius", "style";
+ border_top_left_radius: "border-top-left-radius" in "style";
///
- border_top_right_radius: "border-top-right-radius", "style";
+ border_top_right_radius: "border-top-right-radius" in "style";
///
- border_spacing: "border-spacing", "style";
+ border_spacing: "border-spacing" in "style";
///