123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- use crate::{global_context::current_scope_id, Runtime, ScopeId};
- use std::{
- cell::{Cell, RefCell},
- rc::Rc,
- };
- /// A wrapper around some generic data that handles the event's state
- ///
- ///
- /// Prevent this event from continuing to bubble up the tree to parent elements.
- ///
- /// # Example
- ///
- /// ```rust, ignore
- /// rsx! {
- /// button {
- /// onclick: move |evt: Event<MouseData>| {
- /// evt.cancel_bubble();
- ///
- /// }
- /// }
- /// }
- /// ```
- pub struct Event<T: 'static + ?Sized> {
- /// The data associated with this event
- pub data: Rc<T>,
- pub(crate) propagates: Rc<Cell<bool>>,
- }
- impl<T: ?Sized + 'static> Event<T> {
- pub(crate) fn new(data: Rc<T>, bubbles: bool) -> Self {
- Self {
- data,
- propagates: Rc::new(Cell::new(bubbles)),
- }
- }
- }
- impl<T> Event<T> {
- /// Map the event data to a new type
- ///
- /// # Example
- ///
- /// ```rust, ignore
- /// rsx! {
- /// button {
- /// onclick: move |evt: Event<FormData>| {
- /// let data = evt.map(|data| data.value());
- /// assert_eq!(data.inner(), "hello world");
- /// }
- /// }
- /// }
- /// ```
- pub fn map<U: 'static, F: FnOnce(&T) -> U>(&self, f: F) -> Event<U> {
- Event {
- data: Rc::new(f(&self.data)),
- propagates: self.propagates.clone(),
- }
- }
- /// Prevent this event from continuing to bubble up the tree to parent elements.
- ///
- /// # Example
- ///
- /// ```rust, ignore
- /// rsx! {
- /// button {
- /// onclick: move |evt: Event<MouseData>| {
- /// evt.cancel_bubble();
- /// }
- /// }
- /// }
- /// ```
- #[deprecated = "use stop_propagation instead"]
- pub fn cancel_bubble(&self) {
- self.propagates.set(false);
- }
- /// Prevent this event from continuing to bubble up the tree to parent elements.
- ///
- /// # Example
- ///
- /// ```rust, ignore
- /// rsx! {
- /// button {
- /// onclick: move |evt: Event<MouseData>| {
- /// evt.stop_propagation();
- /// }
- /// }
- /// }
- /// ```
- pub fn stop_propagation(&self) {
- self.propagates.set(false);
- }
- /// Get a reference to the inner data from this event
- ///
- /// ```rust, ignore
- /// rsx! {
- /// button {
- /// onclick: move |evt: Event<MouseData>| {
- /// let data = evt.inner.clone();
- /// cx.spawn(async move {
- /// println!("{:?}", data);
- /// });
- /// }
- /// }
- /// }
- /// ```
- pub fn data(&self) -> Rc<T> {
- self.data.clone()
- }
- }
- impl<T: ?Sized> Clone for Event<T> {
- fn clone(&self) -> Self {
- Self {
- propagates: self.propagates.clone(),
- data: self.data.clone(),
- }
- }
- }
- impl<T> std::ops::Deref for Event<T> {
- type Target = Rc<T>;
- fn deref(&self) -> &Self::Target {
- &self.data
- }
- }
- impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("UiEvent")
- .field("bubble_state", &self.propagates)
- .field("data", &self.data)
- .finish()
- }
- }
- /// The callback type generated by the `rsx!` macro when an `on` field is specified for components.
- ///
- /// This makes it possible to pass `move |evt| {}` style closures into components as property fields.
- ///
- ///
- /// # Example
- ///
- /// ```rust, ignore
- /// rsx!{
- /// MyComponent { onclick: move |evt| tracing::debug!("clicked") }
- /// }
- ///
- /// #[derive(Props)]
- /// struct MyProps {
- /// onclick: EventHandler<MouseEvent>,
- /// }
- ///
- /// fn MyComponent(cx: MyProps) -> Element {
- /// rsx!{
- /// button {
- /// onclick: move |evt| cx.onclick.call(evt),
- /// }
- /// }
- /// }
- ///
- /// ```
- pub struct EventHandler<T = ()> {
- pub(crate) origin: ScopeId,
- pub(super) callback: Rc<RefCell<Option<ExternalListenerCallback<T>>>>,
- }
- impl<T> Clone for EventHandler<T> {
- fn clone(&self) -> Self {
- Self {
- origin: self.origin,
- callback: self.callback.clone(),
- }
- }
- }
- impl<T> PartialEq for EventHandler<T> {
- fn eq(&self, other: &Self) -> bool {
- Rc::ptr_eq(&self.callback, &other.callback)
- }
- }
- impl<T> Default for EventHandler<T> {
- fn default() -> Self {
- Self {
- origin: ScopeId::ROOT,
- callback: Default::default(),
- }
- }
- }
- type ExternalListenerCallback<T> = Box<dyn FnMut(T)>;
- impl<T> EventHandler<T> {
- /// Create a new [`EventHandler`] from an [`FnMut`]
- pub fn new(mut f: impl FnMut(T) + 'static) -> EventHandler<T> {
- let callback = Rc::new(RefCell::new(Some(Box::new(move |event: T| {
- f(event);
- }) as Box<dyn FnMut(T)>)));
- EventHandler {
- callback,
- origin: current_scope_id().expect("to be in a dioxus runtime"),
- }
- }
- /// Call this event handler with the appropriate event type
- ///
- /// This borrows the event using a RefCell. Recursively calling a listener will cause a panic.
- pub fn call(&self, event: T) {
- if let Some(callback) = self.callback.borrow_mut().as_mut() {
- Runtime::with(|rt| rt.scope_stack.borrow_mut().push(self.origin));
- callback(event);
- Runtime::with(|rt| rt.scope_stack.borrow_mut().pop());
- }
- }
- /// Forcibly drop the internal handler callback, releasing memory
- ///
- /// This will force any future calls to "call" to not doing anything
- pub fn release(&self) {
- self.callback.replace(None);
- }
- }
|