use bumpalo::boxed::Box as BumpBox; use std::{ any::Any, cell::{Cell, RefCell}, fmt::Debug, rc::Rc, }; pub struct UiEvent { pub(crate) bubbles: Rc>, pub(crate) data: Rc, } impl UiEvent { pub fn downcast(self) -> Option> { Some(UiEvent { bubbles: self.bubbles, data: self.data.downcast().ok()?, }) } } impl Clone for UiEvent { fn clone(&self) -> Self { Self { bubbles: self.bubbles.clone(), data: self.data.clone(), } } } impl UiEvent { pub fn cancel_bubble(&self) { self.bubbles.set(false); } } impl std::ops::Deref for UiEvent { type Target = Rc; fn deref(&self) -> &Self::Target { &self.data } } impl std::fmt::Debug for UiEvent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("UiEvent") .field("bubble_state", &self.bubbles) .field("data", &self.data) .finish() } } type ExternalListenerCallback<'bump, T> = BumpBox<'bump, dyn FnMut(T) + 'bump>; /// 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| log::info!("clicked"), } /// } /// /// #[derive(Props)] /// struct MyProps<'a> { /// onclick: EventHandler<'a, MouseEvent>, /// } /// /// fn MyComponent(cx: Scope<'a, MyProps<'a>>) -> Element { /// cx.render(rsx!{ /// button { /// onclick: move |evt| cx.props.onclick.call(evt), /// } /// }) /// } /// /// ``` pub struct EventHandler<'bump, T = ()> { /// The (optional) callback that the user specified /// Uses a `RefCell` to allow for interior mutability, and FnMut closures. pub callback: RefCell>>, } impl<'a, T> Default for EventHandler<'a, T> { fn default() -> Self { Self { callback: RefCell::new(None), } } } impl EventHandler<'_, T> { /// Call this event handler with the appropriate event type pub fn call(&self, event: T) { if let Some(callback) = self.callback.borrow_mut().as_mut() { callback(event); } } /// Forcibly drop the internal handler callback, releasing memory pub fn release(&self) { self.callback.replace(None); } }