//! This module provides a set of common events for all Dioxus apps to target, regardless of host platform. //! ------------------------------------------------------------------------------------------------------- //! //! 3rd party renderers are responsible for converting their native events into these virtual event types. Events might //! be heavy or need to interact through FFI, so the events themselves are designed to be lazy. use std::rc::Rc; use crate::{innerlude::ScopeIdx, virtual_dom::RealDomNode}; #[derive(Debug)] pub struct EventTrigger { pub component_id: ScopeIdx, pub real_node_id: RealDomNode, pub event: VirtualEvent, } impl EventTrigger { pub fn new(event: VirtualEvent, scope: ScopeIdx, mounted_dom_id: RealDomNode) -> Self { Self { component_id: scope, real_node_id: mounted_dom_id, event, } } } #[derive(Debug)] pub enum VirtualEvent { // Real events ClipboardEvent(Rc), CompositionEvent(Rc), KeyboardEvent(Rc), FocusEvent(Rc), FormEvent(Rc), SelectionEvent(Rc), TouchEvent(Rc), UIEvent(Rc), WheelEvent(Rc), MediaEvent(Rc), AnimationEvent(Rc), TransitionEvent(Rc), ToggleEvent(Rc), MouseEvent(Rc), PointerEvent(Rc), // Whenever a task is ready (complete) Dioxus produces this "FiberEvent" FiberEvent { task_id: u16 }, // image event has conflicting method types // ImageEvent(event_data::ImageEvent), OtherEvent, } pub mod on { //! This module defines the synthetic events that all Dioxus apps enable. No matter the platform, every dioxus renderer //! will implement the same events and same behavior (bubbling, cancelation, etc). //! //! Synthetic events are immutable and wrapped in Arc. It is the intention for Dioxus renderers to re-use the underyling //! Arc allocation through "get_mut" //! //! //! #![allow(unused)] use std::{fmt::Debug, ops::Deref, rc::Rc}; use crate::{ builder::ElementBuilder, builder::NodeCtx, innerlude::{Attribute, Listener, RealDomNode, VNode}, }; use std::cell::Cell; use super::VirtualEvent; macro_rules! event_directory { ( $( $eventdata:ident: [ $( $name:ident )* ]; )* ) => { $( $( pub fn $name<'a>( c: &'_ NodeCtx<'a>, callback: impl Fn(Rc) + 'a, ) -> Listener<'a> { let bump = &c.bump(); Listener { event: stringify!($name), mounted_node: bump.alloc(Cell::new(RealDomNode::empty())), scope: c.scope_ref.arena_idx, callback: bump.alloc(move |evt: VirtualEvent| match evt { VirtualEvent::$eventdata(event) => callback(event), _ => unreachable!("Downcasted VirtualEvent to wrong event type - this is an internal bug!") }), } } )* )* }; } event_directory! { ClipboardEvent: [copy cut paste]; CompositionEvent: [compositionend compositionstart compositionupdate]; KeyboardEvent: [keydown keypress keyup]; FocusEvent: [focus blur]; FormEvent: [change input invalid reset submit]; MouseEvent: [ click contextmenu doubleclick drag dragend dragenter dragexit dragleave dragover dragstart drop mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup ]; PointerEvent: [ pointerdown pointermove pointerup pointercancel gotpointercapture lostpointercapture pointerenter pointerleave pointerover pointerout ]; SelectionEvent: [select]; TouchEvent: [touchcancel touchend touchmove touchstart]; UIEvent: [scroll]; WheelEvent: [wheel]; MediaEvent: [ abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting ]; AnimationEvent: [animationstart animationend animationiteration]; TransitionEvent: [transitionend]; ToggleEvent: [toggle]; } trait GenericEvent { /// Returns whether or not a specific event is a bubbling event fn bubbles(&self) -> bool; /// Sets or returns whether the event should propagate up the hierarchy or not fn cancel_bubble(&self); /// Returns whether or not an event can have its default action prevented fn cancelable(&self) -> bool; /// Returns whether the event is composed or not fn composed(&self) -> bool; /// Returns the event's path fn composed_path(&self) -> String; /// Returns the element whose event listeners triggered the event fn current_target(&self); /// Returns whether or not the preventDefault method was called for the event fn default_prevented(&self) -> bool; /// Returns which phase of the event flow is currently being evaluated fn event_phase(&self) -> usize; /// Returns whether or not an event is trusted fn is_trusted(&self) -> bool; /// Cancels the event if it is cancelable, meaning that the default action that belongs to the event will fn prevent_default(&self); /// Prevents other listeners of the same event from being called fn stop_immediate_propagation(&self); /// Prevents further propagation of an event during event flow fn stop_propagation(&self); /// Returns the element that triggered the event fn target(&self); /// Returns the time (in milliseconds relative to the epoch) at which the event was created fn time_stamp(&self) -> usize; } pub trait ClipboardEvent: Debug { // DOMDataTransfer clipboardData } pub trait CompositionEvent: Debug { fn data(&self) -> String; } pub trait KeyboardEvent: Debug { fn char_code(&self) -> usize; fn ctrl_key(&self) -> bool; fn key(&self) -> String; fn key_code(&self) -> usize; fn locale(&self) -> String; fn location(&self) -> usize; fn meta_key(&self) -> bool; fn repeat(&self) -> bool; fn shift_key(&self) -> bool; fn which(&self) -> usize; fn get_modifier_state(&self, key_code: usize) -> bool; } pub trait FocusEvent: Debug { /* DOMEventTarget relatedTarget */ } pub trait FormEvent: Debug { fn value(&self) -> String; } pub trait MouseEvent: Debug { fn alt_key(&self) -> bool; fn button(&self) -> i16; fn buttons(&self) -> u16; fn client_x(&self) -> i32; fn client_y(&self) -> i32; fn ctrl_key(&self) -> bool; fn meta_key(&self) -> bool; fn page_x(&self) -> i32; fn page_y(&self) -> i32; fn screen_x(&self) -> i32; fn screen_y(&self) -> i32; fn shift_key(&self) -> bool; fn get_modifier_state(&self, key_code: &str) -> bool; } pub trait PointerEvent: Debug { // Mouse only fn alt_key(&self) -> bool; fn button(&self) -> usize; fn buttons(&self) -> usize; fn client_x(&self) -> i32; fn client_y(&self) -> i32; fn ctrl_key(&self) -> bool; fn meta_key(&self) -> bool; fn page_x(&self) -> i32; fn page_y(&self) -> i32; fn screen_x(&self) -> i32; fn screen_y(&self) -> i32; fn shift_key(&self) -> bool; fn get_modifier_state(&self, key_code: usize) -> bool; fn pointer_id(&self) -> usize; fn width(&self) -> usize; fn height(&self) -> usize; fn pressure(&self) -> usize; fn tangential_pressure(&self) -> usize; fn tilt_x(&self) -> i32; fn tilt_y(&self) -> i32; fn twist(&self) -> i32; fn pointer_type(&self) -> String; fn is_primary(&self) -> bool; } pub trait SelectionEvent: Debug {} pub trait TouchEvent: Debug { fn alt_key(&self) -> bool; fn ctrl_key(&self) -> bool; fn meta_key(&self) -> bool; fn shift_key(&self) -> bool; fn get_modifier_state(&self, key_code: usize) -> bool; // changedTouches: DOMTouchList, // targetTouches: DOMTouchList, // touches: DOMTouchList, } pub trait UIEvent: Debug { // DOMAbstractView view fn detail(&self) -> i32; } pub trait WheelEvent: Debug { fn delta_mode(&self) -> i32; fn delta_x(&self) -> i32; fn delta_y(&self) -> i32; fn delta_z(&self) -> i32; } pub trait MediaEvent: Debug {} pub trait ImageEvent: Debug { // load error } pub trait AnimationEvent: Debug { fn animation_name(&self) -> String; fn pseudo_element(&self) -> String; fn elapsed_time(&self) -> f32; } pub trait TransitionEvent: Debug { fn property_name(&self) -> String; fn pseudo_element(&self) -> String; fn elapsed_time(&self) -> f32; } pub trait ToggleEvent: Debug {} } mod tests { use std::rc::Rc; use crate as dioxus; use crate::events::on::MouseEvent; use crate::prelude::*; fn autocomplete() { // let v = move |evt| { // let r = evt.alt_key(); // }; let g = rsx! { button { onclick: move |evt| { let r = evt.alt_key(); } } }; } }