Fix autofill event downcast - ignore events of the wrong type (#5379)
* fix autofill events * ignore the wrong type of event like we do in desktop * check the event type before dispatch instead of panicing on downcast * clean up conversion * remove example * pull out shared event list * pull in deserialize_raw * unified event list * prettier comment * restore test * restore alias * normal doc comments * move over comments * minimize diff * remove alias, was moved into the macro
This commit is contained in:
1 parent
610ee8107f
commit
d8026f8824
27 files changed
+596
-960
No files matched your search
@@ -130,16 +130,3 @@ pub trait HasAnimationData: std::any::Any {
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! [
|
||||
AnimationData;
|
||||
|
||||
/// onanimationstart
|
||||
onanimationstart
|
||||
|
||||
/// onanimationend
|
||||
onanimationend
|
||||
|
||||
/// onanimationiteration
|
||||
onanimationiteration
|
||||
];
|
||||
@@ -79,10 +79,3 @@ pub trait HasCancelData: std::any::Any {
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! {
|
||||
CancelData;
|
||||
|
||||
/// oncancel
|
||||
oncancel
|
||||
}
|
||||
@@ -79,16 +79,3 @@ pub trait HasClipboardData: std::any::Any {
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event![
|
||||
ClipboardData;
|
||||
|
||||
/// oncopy
|
||||
oncopy
|
||||
|
||||
/// oncut
|
||||
oncut
|
||||
|
||||
/// onpaste
|
||||
onpaste
|
||||
];
|
||||
@@ -94,16 +94,3 @@ pub trait HasCompositionData: std::any::Any {
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! [
|
||||
CompositionData;
|
||||
|
||||
/// oncompositionstart
|
||||
oncompositionstart
|
||||
|
||||
/// oncompositionend
|
||||
oncompositionend
|
||||
|
||||
/// oncompositionupdate
|
||||
oncompositionupdate
|
||||
];
|
||||
@@ -226,31 +226,3 @@ pub trait HasDragData: HasMouseData + crate::HasFileData + crate::HasDataTransfe
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! {
|
||||
DragData;
|
||||
|
||||
/// ondrag
|
||||
ondrag
|
||||
|
||||
/// ondragend
|
||||
ondragend
|
||||
|
||||
/// ondragenter
|
||||
ondragenter
|
||||
|
||||
/// ondragexit
|
||||
ondragexit
|
||||
|
||||
/// ondragleave
|
||||
ondragleave
|
||||
|
||||
/// ondragover
|
||||
ondragover
|
||||
|
||||
/// ondragstart
|
||||
ondragstart
|
||||
|
||||
/// ondrop
|
||||
ondrop
|
||||
}
|
||||
@@ -79,19 +79,3 @@ pub trait HasFocusData: std::any::Any {
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! [
|
||||
FocusData;
|
||||
|
||||
/// onfocus
|
||||
onfocus
|
||||
|
||||
// onfocusout
|
||||
onfocusout
|
||||
|
||||
// onfocusin
|
||||
onfocusin
|
||||
|
||||
/// onblur
|
||||
onblur
|
||||
];
|
||||
@@ -346,65 +346,3 @@ mod serialize {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_event! {
|
||||
FormData;
|
||||
|
||||
/// onchange
|
||||
onchange
|
||||
|
||||
/// The `oninput` event is fired when the value of a `<input>`, `<select>`, or `<textarea>` element is changed.
|
||||
///
|
||||
/// There are two main approaches to updating your input element:
|
||||
/// 1) Controlled inputs directly update the value of the input element as the user interacts with the element
|
||||
///
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// fn App() -> Element {
|
||||
/// let mut value = use_signal(|| "hello world".to_string());
|
||||
///
|
||||
/// rsx! {
|
||||
/// input {
|
||||
/// // We directly set the value of the input element to our value signal
|
||||
/// value: "{value}",
|
||||
/// // The `oninput` event handler will run every time the user changes the value of the input element
|
||||
/// // We can set the `value` signal to the new value of the input element
|
||||
/// oninput: move |event| value.set(event.value())
|
||||
/// }
|
||||
/// // Since this is a controlled input, we can also update the value of the input element directly
|
||||
/// button {
|
||||
/// onclick: move |_| value.write().clear(),
|
||||
/// "Clear"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// 2) Uncontrolled inputs just read the value of the input element as it changes
|
||||
///
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// fn App() -> Element {
|
||||
/// rsx! {
|
||||
/// input {
|
||||
/// // In uncontrolled inputs, we don't set the value of the input element directly
|
||||
/// // But you can still read the value of the input element
|
||||
/// oninput: move |event| println!("{}", event.value()),
|
||||
/// }
|
||||
/// // Since we don't directly control the value of the input element, we can't easily modify it
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
oninput
|
||||
|
||||
/// oninvalid
|
||||
oninvalid
|
||||
|
||||
/// onreset
|
||||
onreset
|
||||
|
||||
/// onsubmit
|
||||
onsubmit
|
||||
}
|
||||
@@ -0,0 +1,448 @@
|
||||
use super::*;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! with_html_event_groups {
|
||||
($macro:ident) => {
|
||||
$macro! {
|
||||
enum Event {
|
||||
#[convert = convert_animation_data]
|
||||
#[events = [
|
||||
onanimationstart => animationstart,
|
||||
onanimationend => animationend,
|
||||
onanimationiteration => animationiteration,
|
||||
]]
|
||||
Animation(AnimationData),
|
||||
|
||||
#[convert = convert_cancel_data]
|
||||
#[events = [
|
||||
oncancel => cancel,
|
||||
]]
|
||||
Cancel(CancelData),
|
||||
|
||||
#[convert = convert_clipboard_data]
|
||||
#[events = [
|
||||
oncopy => copy,
|
||||
oncut => cut,
|
||||
onpaste => paste,
|
||||
]]
|
||||
Clipboard(ClipboardData),
|
||||
|
||||
#[convert = convert_composition_data]
|
||||
#[events = [
|
||||
oncompositionstart => compositionstart,
|
||||
oncompositionend => compositionend,
|
||||
oncompositionupdate => compositionupdate,
|
||||
]]
|
||||
Composition(CompositionData),
|
||||
|
||||
#[convert = convert_drag_data]
|
||||
#[events = [
|
||||
ondrag => drag,
|
||||
ondragend => dragend,
|
||||
ondragenter => dragenter,
|
||||
ondragexit => dragexit,
|
||||
ondragleave => dragleave,
|
||||
ondragover => dragover,
|
||||
ondragstart => dragstart,
|
||||
ondrop => drop,
|
||||
]]
|
||||
Drag(DragData),
|
||||
|
||||
#[convert = convert_focus_data]
|
||||
#[events = [
|
||||
onfocus => focus,
|
||||
onfocusout => focusout,
|
||||
onfocusin => focusin,
|
||||
onblur => blur,
|
||||
]]
|
||||
Focus(FocusData),
|
||||
|
||||
#[convert = convert_form_data]
|
||||
#[events = [
|
||||
onchange => change,
|
||||
/// The `oninput` event is fired when the value of a `<input>`, `<select>`, or `<textarea>` element is changed.
|
||||
///
|
||||
/// There are two main approaches to updating your input element:
|
||||
/// 1) Controlled inputs directly update the value of the input element as the user interacts with the element
|
||||
///
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// fn App() -> Element {
|
||||
/// let mut value = use_signal(|| "hello world".to_string());
|
||||
///
|
||||
/// rsx! {
|
||||
/// input {
|
||||
/// value: "{value}",
|
||||
/// oninput: move |event| value.set(event.value())
|
||||
/// }
|
||||
/// button {
|
||||
/// onclick: move |_| value.write().clear(),
|
||||
/// "Clear"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// 2) Uncontrolled inputs just read the value of the input element as it changes
|
||||
///
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// fn App() -> Element {
|
||||
/// rsx! {
|
||||
/// input {
|
||||
/// oninput: move |event| println!("{}", event.value()),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
oninput => input,
|
||||
oninvalid => invalid,
|
||||
onreset => reset,
|
||||
onsubmit => submit,
|
||||
]]
|
||||
Form(FormData),
|
||||
|
||||
#[convert = convert_image_data]
|
||||
#[events = [
|
||||
onerror => error,
|
||||
onload => load,
|
||||
]]
|
||||
Image(ImageData),
|
||||
|
||||
#[convert = convert_keyboard_data]
|
||||
#[events = [
|
||||
onkeydown => keydown,
|
||||
onkeypress => keypress,
|
||||
onkeyup => keyup,
|
||||
]]
|
||||
Keyboard(KeyboardData),
|
||||
|
||||
#[convert = convert_media_data]
|
||||
#[events = [
|
||||
onabort => abort,
|
||||
oncanplay => canplay,
|
||||
oncanplaythrough => canplaythrough,
|
||||
ondurationchange => durationchange,
|
||||
onemptied => emptied,
|
||||
onencrypted => encrypted,
|
||||
onended => ended,
|
||||
onloadeddata => loadeddata,
|
||||
onloadedmetadata => loadedmetadata,
|
||||
onloadstart => loadstart,
|
||||
onpause => pause,
|
||||
onplay => play,
|
||||
onplaying => playing,
|
||||
onprogress => progress,
|
||||
onratechange => ratechange,
|
||||
onseeked => seeked,
|
||||
onseeking => seeking,
|
||||
onstalled => stalled,
|
||||
onsuspend => suspend,
|
||||
ontimeupdate => timeupdate,
|
||||
onvolumechange => volumechange,
|
||||
onwaiting => waiting,
|
||||
]]
|
||||
#[raw = [interruptbegin, interruptend, loadend, timeout]]
|
||||
Media(MediaData),
|
||||
|
||||
#[convert = convert_mounted_data]
|
||||
#[events = [
|
||||
#[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`](https://docs.rs/dioxus-hooks/latest/dioxus_hooks/fn.use_signal.html) 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, ignore
|
||||
/// use dioxus::prelude::*;
|
||||
/// use dioxus_web::WebEventExt; // provides [`as_web_event()`] method
|
||||
///
|
||||
/// 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.as_web_event();
|
||||
/// assert_eq!(web_sys_element.id(), "some-id");
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
onmounted => mounted,
|
||||
]]
|
||||
Mounted(MountedData),
|
||||
|
||||
#[convert = convert_mouse_data]
|
||||
#[events = [
|
||||
/// Execute a callback when a button is clicked.
|
||||
///
|
||||
/// ## Description
|
||||
///
|
||||
/// An element receives a click event when a pointing device button (such as a mouse's primary mouse button)
|
||||
/// is both pressed and released while the pointer is located inside the element.
|
||||
///
|
||||
/// - Bubbles: Yes
|
||||
/// - Cancelable: Yes
|
||||
/// - Interface(InteData): [`MouseEvent`]
|
||||
///
|
||||
/// If the button is pressed on one element and the pointer is moved outside the element before the button
|
||||
/// is released, the event is fired on the most specific ancestor element that contained both elements.
|
||||
/// `click` fires after both the `mousedown` and `mouseup` events have fired, in that order.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```rust, ignore
|
||||
/// rsx!( button { onclick: move |_| tracing::info!("Clicked!"), "click me" } )
|
||||
/// ```
|
||||
///
|
||||
/// ## Reference
|
||||
/// - <https://www.w3schools.com/tags/ev_onclick.asp>
|
||||
/// - <https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event>
|
||||
onclick => click,
|
||||
oncontextmenu => contextmenu,
|
||||
#[deprecated(since = "0.5.0", note = "use ondoubleclick instead")]
|
||||
ondblclick => dblclick,
|
||||
#[doc(alias = "ondblclick")]
|
||||
ondoubleclick => dblclick,
|
||||
onmousedown => mousedown,
|
||||
onmouseenter => mouseenter,
|
||||
onmouseleave => mouseleave,
|
||||
onmousemove => mousemove,
|
||||
onmouseout => mouseout,
|
||||
/// Triggered when the users's mouse hovers over an element.
|
||||
onmouseover => mouseover,
|
||||
onmouseup => mouseup,
|
||||
]]
|
||||
#[raw = [doubleclick]]
|
||||
Mouse(MouseData),
|
||||
|
||||
#[convert = convert_pointer_data]
|
||||
#[events = [
|
||||
onpointerdown => pointerdown,
|
||||
onpointermove => pointermove,
|
||||
onpointerup => pointerup,
|
||||
onpointercancel => pointercancel,
|
||||
ongotpointercapture => gotpointercapture,
|
||||
onlostpointercapture => lostpointercapture,
|
||||
onpointerenter => pointerenter,
|
||||
onpointerleave => pointerleave,
|
||||
onpointerover => pointerover,
|
||||
onpointerout => pointerout,
|
||||
onauxclick => auxclick,
|
||||
]]
|
||||
#[raw = [pointerlockchange, pointerlockerror]]
|
||||
Pointer(PointerData),
|
||||
|
||||
#[convert = convert_resize_data]
|
||||
#[events = [
|
||||
onresize => resize,
|
||||
]]
|
||||
Resize(ResizeData),
|
||||
|
||||
#[convert = convert_scroll_data]
|
||||
#[events = [
|
||||
onscroll => scroll,
|
||||
onscrollend => scrollend,
|
||||
]]
|
||||
Scroll(ScrollData),
|
||||
|
||||
#[convert = convert_selection_data]
|
||||
#[events = [
|
||||
onselect => select,
|
||||
onselectstart => selectstart,
|
||||
onselectionchange => selectionchange,
|
||||
]]
|
||||
Selection(SelectionData),
|
||||
|
||||
#[convert = convert_toggle_data]
|
||||
#[events = [
|
||||
ontoggle => toggle,
|
||||
onbeforetoggle => beforetoggle,
|
||||
]]
|
||||
Toggle(ToggleData),
|
||||
|
||||
#[convert = convert_touch_data]
|
||||
#[events = [
|
||||
ontouchstart => touchstart,
|
||||
ontouchmove => touchmove,
|
||||
ontouchend => touchend,
|
||||
ontouchcancel => touchcancel,
|
||||
]]
|
||||
Touch(TouchData),
|
||||
|
||||
#[convert = convert_transition_data]
|
||||
#[events = [
|
||||
ontransitionend => transitionend,
|
||||
]]
|
||||
Transition(TransitionData),
|
||||
|
||||
#[convert = convert_visible_data]
|
||||
#[events = [
|
||||
onvisible => visible,
|
||||
]]
|
||||
Visible(VisibleData),
|
||||
|
||||
#[convert = convert_wheel_data]
|
||||
#[events = [
|
||||
/// Called when the mouse wheel is rotated over an element.
|
||||
onwheel => wheel,
|
||||
]]
|
||||
Wheel(WheelData),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! expand_html_event_converter {
|
||||
(
|
||||
enum Event {
|
||||
$(
|
||||
#[convert = $converter:ident]
|
||||
#[events = [
|
||||
$(
|
||||
$( #[$attr:meta] )*
|
||||
$name:ident => $raw:ident,
|
||||
)*
|
||||
]]
|
||||
$(#[raw = [$($raw_only:ident),* $(,)?]])?
|
||||
$group:ident($data:ident),
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
/// A converter between a platform specific event and a general event. All code in a renderer that has a large binary size should be placed in this trait. Each of these functions should be snipped in high levels of optimization.
|
||||
pub trait HtmlEventConverter: Send + Sync {
|
||||
$(
|
||||
fn $converter(&self, event: &PlatformEventData) -> $data;
|
||||
)*
|
||||
}
|
||||
|
||||
$(
|
||||
impl From<&PlatformEventData> for $data {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.$converter(val))
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
macro_rules! expand_html_event_deserialize {
|
||||
(
|
||||
enum Event {
|
||||
$(
|
||||
#[convert = $converter:ident]
|
||||
#[events = [
|
||||
$(
|
||||
$( #[$attr:meta] )*
|
||||
$name:ident => $raw:ident,
|
||||
)*
|
||||
]]
|
||||
$(#[raw = [$($raw_only:ident),* $(,)?]])?
|
||||
$group:ident($data:ident),
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
pub(crate) fn deserialize_raw_event(
|
||||
name: &str,
|
||||
data: &serde_json::Value,
|
||||
) -> Result<Option<crate::transit::EventData>, serde_json::Error> {
|
||||
#[inline]
|
||||
fn de<'de, F>(f: &'de serde_json::Value) -> Result<F, serde_json::Error>
|
||||
where
|
||||
F: serde::Deserialize<'de>,
|
||||
{
|
||||
F::deserialize(f)
|
||||
}
|
||||
|
||||
Ok(match name {
|
||||
$(
|
||||
$( stringify!($raw) )|* $($(| stringify!($raw_only))*)? => {
|
||||
Some(expand_html_event_deserialize!(@deserialize $group, data))
|
||||
}
|
||||
)*
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
};
|
||||
(@deserialize Mounted, $data:ident) => {
|
||||
crate::transit::EventData::Mounted
|
||||
};
|
||||
(@deserialize $group:ident, $data:ident) => {
|
||||
crate::transit::EventData::$group(de($data)?)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! expand_html_event_listeners {
|
||||
(
|
||||
enum Event {
|
||||
$(
|
||||
#[convert = $converter:ident]
|
||||
#[events = [
|
||||
$(
|
||||
$( #[$attr:meta] )*
|
||||
$name:ident => $raw:ident,
|
||||
)*
|
||||
]]
|
||||
$(#[raw = [$($raw_only:ident),* $(,)?]])?
|
||||
$group:ident($data:ident),
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
$(
|
||||
impl_event! {
|
||||
$data;
|
||||
$(
|
||||
#[doc = concat!(stringify!($name))]
|
||||
$( #[$attr] )*
|
||||
$name: concat!("on", stringify!($raw));
|
||||
)*
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
with_html_event_groups!(expand_html_event_converter);
|
||||
#[cfg(feature = "serialize")]
|
||||
with_html_event_groups!(expand_html_event_deserialize);
|
||||
with_html_event_groups!(expand_html_event_listeners);
|
||||
@@ -94,13 +94,3 @@ pub trait HasImageData: std::any::Any {
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! [
|
||||
ImageData;
|
||||
|
||||
/// onerror
|
||||
onerror
|
||||
|
||||
/// onload
|
||||
onload
|
||||
];
|
||||
@@ -226,19 +226,6 @@ impl<'de> serde::Deserialize<'de> for KeyboardData {
|
||||
}
|
||||
}
|
||||
|
||||
impl_event! {
|
||||
KeyboardData;
|
||||
|
||||
/// onkeydown
|
||||
onkeydown
|
||||
|
||||
/// onkeypress
|
||||
onkeypress
|
||||
|
||||
/// onkeyup
|
||||
onkeyup
|
||||
}
|
||||
|
||||
pub trait HasKeyboardData: ModifiersInteraction + std::any::Any {
|
||||
/// The value of the key pressed by the user, taking into consideration the state of modifier keys such as Shift as well as the keyboard locale and layout.
|
||||
fn key(&self) -> Key;
|
||||
|
||||
@@ -78,78 +78,3 @@ pub trait HasMediaData: std::any::Any {
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! [
|
||||
MediaData;
|
||||
|
||||
///abort
|
||||
onabort
|
||||
|
||||
///canplay
|
||||
oncanplay
|
||||
|
||||
///canplaythrough
|
||||
oncanplaythrough
|
||||
|
||||
///durationchange
|
||||
ondurationchange
|
||||
|
||||
///emptied
|
||||
onemptied
|
||||
|
||||
///encrypted
|
||||
onencrypted
|
||||
|
||||
///ended
|
||||
onended
|
||||
|
||||
// todo: this conflicts with Media events
|
||||
// neither have data, so it's okay
|
||||
// ///error
|
||||
// onerror
|
||||
|
||||
///loadeddata
|
||||
onloadeddata
|
||||
|
||||
///loadedmetadata
|
||||
onloadedmetadata
|
||||
|
||||
///loadstart
|
||||
onloadstart
|
||||
|
||||
///pause
|
||||
onpause
|
||||
|
||||
///play
|
||||
onplay
|
||||
|
||||
///playing
|
||||
onplaying
|
||||
|
||||
///progress
|
||||
onprogress
|
||||
|
||||
///ratechange
|
||||
onratechange
|
||||
|
||||
///seeked
|
||||
onseeked
|
||||
|
||||
///seeking
|
||||
onseeking
|
||||
|
||||
///stalled
|
||||
onstalled
|
||||
|
||||
///suspend
|
||||
onsuspend
|
||||
|
||||
///timeupdate
|
||||
ontimeupdate
|
||||
|
||||
///volumechange
|
||||
onvolumechange
|
||||
|
||||
///waiting
|
||||
onwaiting
|
||||
];
|
||||
@@ -8,7 +8,7 @@ macro_rules! impl_event {
|
||||
$data:ty;
|
||||
$(
|
||||
$( #[$attr:meta] )*
|
||||
$name:ident $(: $js_name:literal)?
|
||||
$name:ident $( : $js_name:expr )?;
|
||||
)*
|
||||
) => {
|
||||
$(
|
||||
@@ -21,9 +21,6 @@ macro_rules! impl_event {
|
||||
/// </details>
|
||||
///
|
||||
#[doc = include_str!("../../docs/common_event_handler_errors.md")]
|
||||
$(
|
||||
#[doc(alias = $js_name)]
|
||||
)?
|
||||
#[inline]
|
||||
pub fn $name<__Marker>(mut _f: impl ::dioxus_core::SuperInto<::dioxus_core::ListenerCallback<$data>, __Marker>) -> ::dioxus_core::Attribute {
|
||||
let event_handler = _f.super_into();
|
||||
@@ -60,7 +57,7 @@ macro_rules! impl_event {
|
||||
)*
|
||||
};
|
||||
|
||||
(@name $name:ident $js_name:literal) => {
|
||||
(@name $name:ident $js_name:expr) => {
|
||||
$js_name
|
||||
};
|
||||
(@name $name:ident) => {
|
||||
@@ -111,177 +108,7 @@ impl PlatformEventData {
|
||||
}
|
||||
}
|
||||
|
||||
/// A converter between a platform specific event and a general event. All code in a renderer that has a large binary size should be placed in this trait. Each of these functions should be snipped in high levels of optimization.
|
||||
pub trait HtmlEventConverter: Send + Sync {
|
||||
/// Convert a general event to an animation data event
|
||||
fn convert_animation_data(&self, event: &PlatformEventData) -> AnimationData;
|
||||
/// Convert a general event to a cancel data event
|
||||
fn convert_cancel_data(&self, event: &PlatformEventData) -> CancelData;
|
||||
/// Convert a general event to a clipboard data event
|
||||
fn convert_clipboard_data(&self, event: &PlatformEventData) -> ClipboardData;
|
||||
/// Convert a general event to a composition data event
|
||||
fn convert_composition_data(&self, event: &PlatformEventData) -> CompositionData;
|
||||
/// Convert a general event to a drag data event
|
||||
fn convert_drag_data(&self, event: &PlatformEventData) -> DragData;
|
||||
/// Convert a general event to a focus data event
|
||||
fn convert_focus_data(&self, event: &PlatformEventData) -> FocusData;
|
||||
/// Convert a general event to a form data event
|
||||
fn convert_form_data(&self, event: &PlatformEventData) -> FormData;
|
||||
/// Convert a general event to an image data event
|
||||
fn convert_image_data(&self, event: &PlatformEventData) -> ImageData;
|
||||
/// Convert a general event to a keyboard data event
|
||||
fn convert_keyboard_data(&self, event: &PlatformEventData) -> KeyboardData;
|
||||
/// Convert a general event to a media data event
|
||||
fn convert_media_data(&self, event: &PlatformEventData) -> MediaData;
|
||||
/// Convert a general event to a mounted data event
|
||||
fn convert_mounted_data(&self, event: &PlatformEventData) -> MountedData;
|
||||
/// Convert a general event to a mouse data event
|
||||
fn convert_mouse_data(&self, event: &PlatformEventData) -> MouseData;
|
||||
/// Convert a general event to a pointer data event
|
||||
fn convert_pointer_data(&self, event: &PlatformEventData) -> PointerData;
|
||||
/// Convert a general event to a resize data event
|
||||
fn convert_resize_data(&self, event: &PlatformEventData) -> ResizeData;
|
||||
/// Convert a general event to a scroll data event
|
||||
fn convert_scroll_data(&self, event: &PlatformEventData) -> ScrollData;
|
||||
/// Convert a general event to a selection data event
|
||||
fn convert_selection_data(&self, event: &PlatformEventData) -> SelectionData;
|
||||
/// Convert a general event to a toggle data event
|
||||
fn convert_toggle_data(&self, event: &PlatformEventData) -> ToggleData;
|
||||
/// Convert a general event to a touch data event
|
||||
fn convert_touch_data(&self, event: &PlatformEventData) -> TouchData;
|
||||
/// Convert a general event to a transition data event
|
||||
fn convert_transition_data(&self, event: &PlatformEventData) -> TransitionData;
|
||||
/// Convert a general event to a visible data event
|
||||
fn convert_visible_data(&self, event: &PlatformEventData) -> VisibleData;
|
||||
/// Convert a general event to a wheel data event
|
||||
fn convert_wheel_data(&self, event: &PlatformEventData) -> WheelData;
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for AnimationData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_animation_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for CancelData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_cancel_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for ClipboardData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_clipboard_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for CompositionData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_composition_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for DragData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_drag_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for FocusData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_focus_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for FormData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_form_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for ImageData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_image_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for KeyboardData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_keyboard_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for MediaData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_media_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for MountedData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_mounted_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for MouseData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_mouse_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for PointerData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_pointer_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for ResizeData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_resize_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for ScrollData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_scroll_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for SelectionData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_selection_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for ToggleData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_toggle_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for TouchData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_touch_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for TransitionData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_transition_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for VisibleData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_visible_data(val))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&PlatformEventData> for WheelData {
|
||||
fn from(val: &PlatformEventData) -> Self {
|
||||
with_event_converter(|c| c.convert_wheel_data(val))
|
||||
}
|
||||
}
|
||||
mod generated;
|
||||
|
||||
mod animation;
|
||||
mod cancel;
|
||||
@@ -312,6 +139,7 @@ pub use composition::*;
|
||||
pub use drag::*;
|
||||
pub use focus::*;
|
||||
pub use form::*;
|
||||
pub use generated::*;
|
||||
pub use image::*;
|
||||
pub use keyboard::*;
|
||||
pub use media::*;
|
||||
|
||||
@@ -213,72 +213,7 @@ use crate::geometry::{PixelsRect, PixelsSize, PixelsVector2D};
|
||||
|
||||
pub type MountedEvent = Event<MountedData>;
|
||||
|
||||
impl_event! [
|
||||
MountedData;
|
||||
|
||||
#[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`](https://docs.rs/dioxus-hooks/latest/dioxus_hooks/fn.use_signal.html) 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, ignore
|
||||
/// use dioxus::prelude::*;
|
||||
/// use dioxus_web::WebEventExt; // provides [`as_web_event()`] method
|
||||
///
|
||||
/// 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.as_web_event();
|
||||
/// assert_eq!(web_sys_element.id(), "some-id");
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
onmounted
|
||||
];
|
||||
|
||||
pub use onmounted as onmount;
|
||||
pub use super::onmounted as onmount;
|
||||
|
||||
/// The MountedResult type for the MountedData
|
||||
pub type MountedResult<T> = Result<T, MountedError>;
|
||||
|
||||
@@ -44,66 +44,6 @@ pub trait HasMouseData: PointerInteraction {
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! {
|
||||
MouseData;
|
||||
|
||||
/// Execute a callback when a button is clicked.
|
||||
///
|
||||
/// ## Description
|
||||
///
|
||||
/// An element receives a click event when a pointing device button (such as a mouse's primary mouse button)
|
||||
/// is both pressed and released while the pointer is located inside the element.
|
||||
///
|
||||
/// - Bubbles: Yes
|
||||
/// - Cancelable: Yes
|
||||
/// - Interface(InteData): [`MouseEvent`]
|
||||
///
|
||||
/// If the button is pressed on one element and the pointer is moved outside the element before the button
|
||||
/// is released, the event is fired on the most specific ancestor element that contained both elements.
|
||||
/// `click` fires after both the `mousedown` and `mouseup` events have fired, in that order.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```rust, ignore
|
||||
/// rsx!( button { onclick: move |_| tracing::info!("Clicked!"), "click me" } )
|
||||
/// ```
|
||||
///
|
||||
/// ## Reference
|
||||
/// - <https://www.w3schools.com/tags/ev_onclick.asp>
|
||||
/// - <https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event>
|
||||
onclick
|
||||
|
||||
/// oncontextmenu
|
||||
oncontextmenu
|
||||
|
||||
#[deprecated(since = "0.5.0", note = "use ondoubleclick instead")]
|
||||
ondblclick
|
||||
|
||||
ondoubleclick: "ondblclick"
|
||||
|
||||
/// onmousedown
|
||||
onmousedown
|
||||
|
||||
/// onmouseenter
|
||||
onmouseenter
|
||||
|
||||
/// onmouseleave
|
||||
onmouseleave
|
||||
|
||||
/// onmousemove
|
||||
onmousemove
|
||||
|
||||
/// onmouseout
|
||||
onmouseout
|
||||
|
||||
/// onmouseover
|
||||
///
|
||||
/// Triggered when the users's mouse hovers over an element.
|
||||
onmouseover
|
||||
|
||||
/// onmouseup
|
||||
onmouseup
|
||||
}
|
||||
|
||||
impl MouseData {
|
||||
/// Create a new instance of MouseData
|
||||
pub fn new(inner: impl HasMouseData + 'static) -> Self {
|
||||
|
||||
@@ -105,42 +105,6 @@ pub trait HasPointerData: PointerInteraction {
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event![
|
||||
PointerData;
|
||||
/// pointerdown
|
||||
onpointerdown
|
||||
|
||||
/// pointermove
|
||||
onpointermove
|
||||
|
||||
/// pointerup
|
||||
onpointerup
|
||||
|
||||
/// pointercancel
|
||||
onpointercancel
|
||||
|
||||
/// gotpointercapture
|
||||
ongotpointercapture
|
||||
|
||||
/// lostpointercapture
|
||||
onlostpointercapture
|
||||
|
||||
/// pointerenter
|
||||
onpointerenter
|
||||
|
||||
/// pointerleave
|
||||
onpointerleave
|
||||
|
||||
/// pointerover
|
||||
onpointerover
|
||||
|
||||
/// pointerout
|
||||
onpointerout
|
||||
|
||||
/// auxclick
|
||||
onauxclick
|
||||
];
|
||||
|
||||
impl PointerData {
|
||||
/// Gets the unique identifier of the pointer causing the event.
|
||||
pub fn pointer_id(&self) -> i32 {
|
||||
|
||||
@@ -132,13 +132,6 @@ use crate::geometry::PixelsSize;
|
||||
|
||||
pub type ResizeEvent = Event<ResizeData>;
|
||||
|
||||
impl_event! {
|
||||
ResizeData;
|
||||
|
||||
/// onresize
|
||||
onresize
|
||||
}
|
||||
|
||||
/// The ResizeResult type for the ResizeData
|
||||
pub type ResizeResult<T> = Result<T, ResizeError>;
|
||||
|
||||
|
||||
@@ -171,13 +171,3 @@ pub trait HasScrollData: std::any::Any {
|
||||
/// Get the viewport height
|
||||
fn client_height(&self) -> i32;
|
||||
}
|
||||
|
||||
impl_event! {
|
||||
ScrollData;
|
||||
|
||||
/// onscroll
|
||||
onscroll
|
||||
|
||||
/// onscrollend
|
||||
onscrollend
|
||||
}
|
||||
@@ -79,16 +79,3 @@ pub trait HasSelectionData: std::any::Any {
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! [
|
||||
SelectionData;
|
||||
|
||||
/// select
|
||||
onselect
|
||||
|
||||
/// selectstart
|
||||
onselectstart
|
||||
|
||||
/// selectionchange
|
||||
onselectionchange
|
||||
];
|
||||
@@ -79,13 +79,3 @@ pub trait HasToggleData: std::any::Any {
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! {
|
||||
ToggleData;
|
||||
|
||||
/// ontoggle
|
||||
ontoggle
|
||||
|
||||
/// onbeforetoggle
|
||||
onbeforetoggle
|
||||
}
|
||||
@@ -351,18 +351,3 @@ impl InteractionLocation for SerializedTouchPoint {
|
||||
PagePoint::new(self.page_x, self.page_y)
|
||||
}
|
||||
}
|
||||
|
||||
impl_event! {
|
||||
TouchData;
|
||||
/// touchstart
|
||||
ontouchstart
|
||||
|
||||
/// touchmove
|
||||
ontouchmove
|
||||
|
||||
/// touchend
|
||||
ontouchend
|
||||
|
||||
/// touchcancel
|
||||
ontouchcancel
|
||||
}
|
||||
@@ -108,10 +108,3 @@ pub trait HasTransitionData: std::any::Any {
|
||||
/// return self as Any
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl_event! {
|
||||
TransitionData;
|
||||
|
||||
/// transitionend
|
||||
ontransitionend
|
||||
}
|
||||
@@ -266,13 +266,6 @@ use crate::geometry::PixelsRect;
|
||||
|
||||
pub type VisibleEvent = Event<VisibleData>;
|
||||
|
||||
impl_event! {
|
||||
VisibleData;
|
||||
|
||||
/// onvisible
|
||||
onvisible
|
||||
}
|
||||
|
||||
/// The VisibleResult type for the VisibleData
|
||||
pub type VisibleResult<T> = Result<T, VisibleError>;
|
||||
|
||||
|
||||
@@ -223,13 +223,6 @@ impl<'de> serde::Deserialize<'de> for WheelData {
|
||||
}
|
||||
}
|
||||
|
||||
impl_event![
|
||||
WheelData;
|
||||
|
||||
/// Called when the mouse wheel is rotated over an element.
|
||||
onwheel
|
||||
];
|
||||
|
||||
pub trait HasWheelData: HasMouseData + std::any::Any {
|
||||
/// The amount of wheel movement
|
||||
fn delta(&self) -> WheelDelta;
|
||||
|
||||
@@ -53,97 +53,12 @@ impl<'de> Deserialize<'de> for HtmlEvent {
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
fn deserialize_raw(name: &str, data: &serde_json::Value) -> Result<EventData, serde_json::Error> {
|
||||
use EventData::*;
|
||||
|
||||
// a little macro-esque thing to make the code below more readable
|
||||
#[inline]
|
||||
fn de<'de, F>(f: &'de serde_json::Value) -> Result<F, serde_json::Error>
|
||||
where
|
||||
F: Deserialize<'de>,
|
||||
{
|
||||
F::deserialize(f)
|
||||
match deserialize_raw_event(name, data)? {
|
||||
Some(result) => Ok(result),
|
||||
None => Err(serde::de::Error::custom(format!(
|
||||
"Unknown event type: {name}"
|
||||
))),
|
||||
}
|
||||
|
||||
let data = match name {
|
||||
// Cancel
|
||||
"cancel" => Cancel(de(data)?),
|
||||
|
||||
// Mouse
|
||||
"click" | "contextmenu" | "dblclick" | "doubleclick" | "mousedown" | "mouseenter"
|
||||
| "mouseleave" | "mousemove" | "mouseout" | "mouseover" | "mouseup" => Mouse(de(data)?),
|
||||
|
||||
// Clipboard
|
||||
"copy" | "cut" | "paste" => Clipboard(de(data)?),
|
||||
|
||||
// Composition
|
||||
"compositionend" | "compositionstart" | "compositionupdate" => Composition(de(data)?),
|
||||
|
||||
// Keyboard
|
||||
"keydown" | "keypress" | "keyup" => Keyboard(de(data)?),
|
||||
|
||||
// Focus
|
||||
"blur" | "focus" | "focusin" | "focusout" => Focus(de(data)?),
|
||||
|
||||
// Form
|
||||
"change" | "input" | "invalid" | "reset" | "submit" => Form(de(data)?),
|
||||
|
||||
// Drag
|
||||
"drag" | "dragend" | "dragenter" | "dragexit" | "dragleave" | "dragover" | "dragstart"
|
||||
| "drop" => Drag(de(data)?),
|
||||
|
||||
// Pointer
|
||||
"pointerlockchange" | "pointerlockerror" | "pointerdown" | "pointermove" | "pointerup"
|
||||
| "pointerover" | "pointerout" | "pointerenter" | "pointerleave" | "gotpointercapture"
|
||||
| "lostpointercapture" | "auxclick" => Pointer(de(data)?),
|
||||
|
||||
// Selection
|
||||
"selectstart" | "selectionchange" | "select" => Selection(de(data)?),
|
||||
|
||||
// Touch
|
||||
"touchcancel" | "touchend" | "touchmove" | "touchstart" => Touch(de(data)?),
|
||||
|
||||
// Resize
|
||||
"resize" => Resize(de(data)?),
|
||||
|
||||
// Scroll
|
||||
"scroll" | "scrollend" => Scroll(de(data)?),
|
||||
|
||||
// Visible
|
||||
"visible" => Visible(de(data)?),
|
||||
|
||||
// Wheel
|
||||
"wheel" => Wheel(de(data)?),
|
||||
|
||||
// Media
|
||||
"abort" | "canplay" | "canplaythrough" | "durationchange" | "emptied" | "encrypted"
|
||||
| "ended" | "interruptbegin" | "interruptend" | "loadeddata" | "loadedmetadata"
|
||||
| "loadstart" | "pause" | "play" | "playing" | "progress" | "ratechange" | "seeked"
|
||||
| "seeking" | "stalled" | "suspend" | "timeupdate" | "volumechange" | "waiting"
|
||||
| "loadend" | "timeout" => Media(de(data)?),
|
||||
|
||||
// Animation
|
||||
"animationstart" | "animationend" | "animationiteration" => Animation(de(data)?),
|
||||
|
||||
// Transition
|
||||
"transitionend" => Transition(de(data)?),
|
||||
|
||||
// Toggle
|
||||
"toggle" => Toggle(de(data)?),
|
||||
|
||||
"load" | "error" => Image(de(data)?),
|
||||
|
||||
// Mounted
|
||||
"mounted" => Mounted,
|
||||
|
||||
// OtherData => "abort" | "afterprint" | "beforeprint" | "beforeunload" | "hashchange" | "languagechange" | "message" | "offline" | "online" | "pagehide" | "pageshow" | "popstate" | "rejectionhandled" | "storage" | "unhandledrejection" | "unload" | "userproximity" | "vrdisplayactivate" | "vrdisplayblur" | "vrdisplayconnect" | "vrdisplaydeactivate" | "vrdisplaydisconnect" | "vrdisplayfocus" | "vrdisplaypointerrestricted" | "vrdisplaypointerunrestricted" | "vrdisplaypresentchange";
|
||||
other => {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"Unknown event type: {other}"
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
|
||||
+11
-1
@@ -15,7 +15,9 @@ use rustc_hash::FxHashMap;
|
||||
use wasm_bindgen::{closure::Closure, JsCast};
|
||||
use web_sys::{Document, Event, Node};
|
||||
|
||||
use crate::{load_document, virtual_event_from_websys_event, Config, WebEventConverter};
|
||||
use crate::{
|
||||
event_type_matches, load_document, virtual_event_from_websys_event, Config, WebEventConverter,
|
||||
};
|
||||
|
||||
pub struct WebsysDom {
|
||||
#[allow(dead_code)]
|
||||
@@ -94,6 +96,14 @@ impl WebsysDom {
|
||||
return;
|
||||
};
|
||||
|
||||
// Some browser features (e.g. datalist autocomplete) dispatch
|
||||
// a plain Event with a typed name like "keydown" that isn't
|
||||
// actually a KeyboardEvent. Drop events whose JS type doesn't
|
||||
// match what the converters will unchecked-cast to.
|
||||
if !event_type_matches(name.as_str(), web_sys_event) {
|
||||
return;
|
||||
}
|
||||
|
||||
let data = virtual_event_from_websys_event(web_sys_event.clone(), target);
|
||||
|
||||
let event = dioxus_core::Event::new(Rc::new(data) as Rc<dyn Any>, bubbles);
|
||||
|
||||
@@ -3,12 +3,6 @@ use web_sys::Event;
|
||||
|
||||
use super::{Synthetic, WebEventExt};
|
||||
|
||||
impl From<&Event> for Synthetic<Event> {
|
||||
fn from(e: &Event) -> Self {
|
||||
Synthetic::new(e.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl HasClipboardData for Synthetic<Event> {
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
&self.event
|
||||
|
||||
+127
-199
@@ -1,6 +1,4 @@
|
||||
use dioxus_html::{
|
||||
DragData, FormData, HtmlEventConverter, ImageData, MountedData, PlatformEventData,
|
||||
};
|
||||
use dioxus_html::{DragData, FormData, HtmlEventConverter, ImageData, PlatformEventData};
|
||||
use form::WebFormData;
|
||||
use load::WebImageEvent;
|
||||
use wasm_bindgen::JsCast;
|
||||
@@ -52,170 +50,135 @@ fn downcast_event(event: &dioxus_html::PlatformEventData) -> &GenericWebSysEvent
|
||||
.expect("event should be a GenericWebSysEvent")
|
||||
}
|
||||
|
||||
impl HtmlEventConverter for WebEventConverter {
|
||||
#[inline(always)]
|
||||
fn convert_animation_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::AnimationData {
|
||||
Synthetic::<web_sys::AnimationEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_cancel_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::CancelData {
|
||||
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_clipboard_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::ClipboardData {
|
||||
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_composition_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::CompositionData {
|
||||
Synthetic::<web_sys::CompositionEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_drag_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::DragData {
|
||||
let event = downcast_event(event);
|
||||
DragData::new(Synthetic::new(
|
||||
event.raw.clone().unchecked_into::<web_sys::DragEvent>(),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_focus_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::FocusData {
|
||||
Synthetic::<web_sys::FocusEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_form_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::FormData {
|
||||
let event = downcast_event(event);
|
||||
FormData::new(WebFormData::new(event.element.clone(), event.raw.clone()))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_image_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::ImageData {
|
||||
let event = downcast_event(event);
|
||||
let error = event.raw.type_() == "error";
|
||||
ImageData::new(WebImageEvent::new(event.raw.clone(), error))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_keyboard_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::KeyboardData {
|
||||
Synthetic::<web_sys::KeyboardEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_media_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::MediaData {
|
||||
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline(always)]
|
||||
fn convert_mounted_data(&self, event: &dioxus_html::PlatformEventData) -> MountedData {
|
||||
#[cfg(feature = "mounted")]
|
||||
{
|
||||
Synthetic::new(
|
||||
event
|
||||
.downcast::<web_sys::Element>()
|
||||
.expect("event should be a web_sys::Element")
|
||||
.clone(),
|
||||
)
|
||||
.into()
|
||||
macro_rules! with_web_event_converters {
|
||||
($macro:ident) => {
|
||||
$macro! {
|
||||
convert_animation_data(AnimationData) => web_sys::AnimationEvent;
|
||||
convert_cancel_data(CancelData) => web_sys::Event;
|
||||
convert_clipboard_data(ClipboardData) => web_sys::Event;
|
||||
convert_composition_data(CompositionData) => web_sys::CompositionEvent;
|
||||
convert_drag_data(DragData) => web_sys::DragEvent => |event| {
|
||||
let event = downcast_event(event);
|
||||
DragData::new(Synthetic::new(
|
||||
event.raw.clone().unchecked_into::<web_sys::DragEvent>(),
|
||||
))
|
||||
};
|
||||
convert_focus_data(FocusData) => web_sys::FocusEvent;
|
||||
convert_form_data(FormData) => web_sys::Event => |event| {
|
||||
let event = downcast_event(event);
|
||||
FormData::new(WebFormData::new(event.element.clone(), event.raw.clone()))
|
||||
};
|
||||
convert_image_data(ImageData) => web_sys::Event => |event| {
|
||||
let event = downcast_event(event);
|
||||
ImageData::new(WebImageEvent::new(
|
||||
event.raw.clone(),
|
||||
event.raw.type_() == "error",
|
||||
))
|
||||
};
|
||||
convert_keyboard_data(KeyboardData) => web_sys::KeyboardEvent;
|
||||
convert_media_data(MediaData) => web_sys::Event;
|
||||
convert_mounted_data(MountedData) => web_sys::Element => |event| {
|
||||
#[cfg(feature = "mounted")]
|
||||
{
|
||||
Synthetic::new(
|
||||
event
|
||||
.downcast::<web_sys::Element>()
|
||||
.expect("event should be a web_sys::Element")
|
||||
.clone(),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
#[cfg(not(feature = "mounted"))]
|
||||
{
|
||||
let _ = event;
|
||||
panic!("mounted events require the `mounted` feature on dioxus-web")
|
||||
}
|
||||
};
|
||||
convert_mouse_data(MouseData) => web_sys::MouseEvent;
|
||||
convert_pointer_data(PointerData) => web_sys::PointerEvent;
|
||||
convert_resize_data(ResizeData) => web_sys::ResizeObserverEntry;
|
||||
convert_scroll_data(ScrollData) => web_sys::Event;
|
||||
convert_selection_data(SelectionData) => web_sys::Event;
|
||||
convert_toggle_data(ToggleData) => web_sys::Event;
|
||||
convert_touch_data(TouchData) => web_sys::TouchEvent;
|
||||
convert_transition_data(TransitionData) => web_sys::TransitionEvent;
|
||||
convert_visible_data(VisibleData) => web_sys::IntersectionObserverEntry;
|
||||
convert_wheel_data(WheelData) => web_sys::WheelEvent;
|
||||
}
|
||||
#[cfg(not(feature = "mounted"))]
|
||||
{
|
||||
panic!("mounted events are not supported without the mounted feature on the dioxus-web crate enabled")
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_mouse_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::MouseData {
|
||||
Synthetic::<web_sys::MouseEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_pointer_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::PointerData {
|
||||
Synthetic::<web_sys::PointerEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_resize_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::ResizeData {
|
||||
Synthetic::<web_sys::ResizeObserverEntry>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_scroll_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::ScrollData {
|
||||
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_selection_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::SelectionData {
|
||||
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_toggle_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::ToggleData {
|
||||
Synthetic::new(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_touch_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::TouchData {
|
||||
Synthetic::<web_sys::TouchEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_transition_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::TransitionData {
|
||||
Synthetic::<web_sys::TransitionEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_visible_data(
|
||||
&self,
|
||||
event: &dioxus_html::PlatformEventData,
|
||||
) -> dioxus_html::VisibleData {
|
||||
Synthetic::<web_sys::IntersectionObserverEntry>::from(downcast_event(event).raw.clone())
|
||||
.into()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn convert_wheel_data(&self, event: &dioxus_html::PlatformEventData) -> dioxus_html::WheelData {
|
||||
Synthetic::<web_sys::WheelEvent>::from(downcast_event(event).raw.clone()).into()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! expand_web_event_converter {
|
||||
(
|
||||
$(
|
||||
$converter:ident($data:ident) => $web_ty:ty $(=> |$event:ident| $body:block)?;
|
||||
)*
|
||||
) => {
|
||||
macro_rules! web_event_type_matches {
|
||||
$(
|
||||
($event_name:ident, $converter) => {
|
||||
$event_name.is_instance_of::<$web_ty>()
|
||||
};
|
||||
)*
|
||||
}
|
||||
|
||||
impl HtmlEventConverter for WebEventConverter {
|
||||
$(
|
||||
expand_web_event_converter!(@method $converter, $data, $web_ty $(, $event, $body)?);
|
||||
)*
|
||||
}
|
||||
};
|
||||
|
||||
(@method $converter:ident, $data:ident, $web_ty:ty) => {
|
||||
#[inline(always)]
|
||||
fn $converter(&self, event: &PlatformEventData) -> dioxus_html::$data {
|
||||
Synthetic::new(downcast_event(event).raw.clone().unchecked_into::<$web_ty>()).into()
|
||||
}
|
||||
};
|
||||
|
||||
(@method $converter:ident, $data:ident, $web_ty:ty, $event:ident, $body:block) => {
|
||||
#[inline(always)]
|
||||
fn $converter(&self, $event: &PlatformEventData) -> dioxus_html::$data $body
|
||||
};
|
||||
}
|
||||
|
||||
with_web_event_converters!(expand_web_event_converter);
|
||||
|
||||
macro_rules! expand_web_event_changes {
|
||||
(
|
||||
enum Event {
|
||||
$(
|
||||
#[convert = $converter:ident]
|
||||
#[events = [
|
||||
$(
|
||||
$( #[$attr:meta] )*
|
||||
$name:ident => $raw:ident,
|
||||
)*
|
||||
]]
|
||||
$(#[raw = [$($raw_only:ident),* $(,)?]])?
|
||||
$group:ident($data:ident),
|
||||
)*
|
||||
}
|
||||
) => {
|
||||
pub(crate) fn event_type_matches(name: &str, event: &web_sys::Event) -> bool {
|
||||
let m = match name {
|
||||
$(
|
||||
$( stringify!($raw) )|* $($(| stringify!($raw_only))*)? => {
|
||||
web_event_type_matches!(event, $converter)
|
||||
}
|
||||
)*
|
||||
_ => true,
|
||||
};
|
||||
if !m {
|
||||
tracing::warn!("Ignoring \"{name}\": not the expected type: {event:?}");
|
||||
}
|
||||
m
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
dioxus_html::with_html_event_groups!(expand_web_event_changes);
|
||||
|
||||
/// A extension trait for web-sys events that provides a way to get the event as a web-sys event.
|
||||
pub trait WebEventExt {
|
||||
/// The web specific event type
|
||||
@@ -262,38 +225,3 @@ pub(crate) fn load_document() -> Document {
|
||||
.document()
|
||||
.expect("should have access to the Document")
|
||||
}
|
||||
|
||||
macro_rules! uncheck_convert {
|
||||
($t:ty) => {
|
||||
impl From<Event> for Synthetic<$t> {
|
||||
#[inline]
|
||||
fn from(e: Event) -> Self {
|
||||
let e: $t = e.unchecked_into();
|
||||
Self::new(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Event> for Synthetic<$t> {
|
||||
#[inline]
|
||||
fn from(e: &Event) -> Self {
|
||||
let e: &$t = e.unchecked_ref();
|
||||
Self::new(e.clone())
|
||||
}
|
||||
}
|
||||
};
|
||||
($($t:ty),+ $(,)?) => {
|
||||
$(uncheck_convert!($t);)+
|
||||
};
|
||||
}
|
||||
|
||||
uncheck_convert![
|
||||
web_sys::CompositionEvent,
|
||||
web_sys::KeyboardEvent,
|
||||
web_sys::TouchEvent,
|
||||
web_sys::PointerEvent,
|
||||
web_sys::WheelEvent,
|
||||
web_sys::AnimationEvent,
|
||||
web_sys::TransitionEvent,
|
||||
web_sys::MouseEvent,
|
||||
web_sys::FocusEvent,
|
||||
];
|
||||
Reference in new issue
Block a user