wip: overhaul event system

This commit is contained in:
Jonathan Kelley committed 2022-11-15 16:05:22 -08:00
1 parent c44bd11fe5
commit 47d0f51e00
48 files changed
+3175 -2597

No files matched your search

+61 -47
View File
@@ -1,50 +1,5 @@
use crate::{arena::ElementId, virtual_dom::VirtualDom, Attribute, AttributeValue};
use std::cell::Cell;
/// User Events are events that are shuttled from the renderer into the [`VirtualDom`] through the scheduler channel.
///
/// These events will be passed to the appropriate Element given by `mounted_dom_id` and then bubbled up through the tree
/// where each listener is checked and fired if the event name matches.
///
/// It is the expectation that the event name matches the corresponding event listener, otherwise Dioxus will panic in
/// attempting to downcast the event data.
///
/// Because Event Data is sent across threads, it must be `Send + Sync`. We are hoping to lift the `Sync` restriction but
/// `Send` will not be lifted. The entire `UserEvent` must also be `Send + Sync` due to its use in the scheduler channel.
///
/// # Example
/// ```rust, ignore
/// fn App(cx: Scope) -> Element {
/// render!(div {
/// onclick: move |_| println!("Clicked!")
/// })
/// }
///
/// let mut dom = VirtualDom::new(App);
/// let mut scheduler = dom.get_scheduler_channel();
/// scheduler.unbounded_send(SchedulerMsg::UiEvent(
/// UserEvent {
/// scope_id: None,
/// priority: EventPriority::Medium,
/// name: "click",
/// element: Some(ElementId(0)),
/// data: Arc::new(ClickEvent { .. })
/// }
/// )).unwrap();
/// ```
#[derive(Debug)]
pub struct UiEvent<T> {
/// The priority of the event to be scheduled around ongoing work
pub priority: EventPriority,
/// The optional real node associated with the trigger
pub element: ElementId,
/// The event type IE "onclick" or "onmouseover"
pub name: &'static str,
pub bubble: Cell<bool>,
pub event: T,
}
use bumpalo::boxed::Box as BumpBox;
use std::{any::Any, cell::RefCell};
/// Priority of Event Triggers.
///
@@ -108,6 +63,65 @@ pub fn is_path_ascendant(small: &[u8], big: &[u8]) -> bool {
small == &big[..small.len()]
}
pub type InternalHandler<'bump> = &'bump RefCell<Option<InternalListenerCallback<'bump>>>;
type InternalListenerCallback<'bump> = BumpBox<'bump, dyn FnMut(&'bump dyn Any) + 'bump>;
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<Option<ExternalListenerCallback<'bump, T>>>,
}
impl<'a, T> Default for EventHandler<'a, T> {
fn default() -> Self {
Self {
callback: RefCell::new(None),
}
}
}
impl<T> 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);
}
}
#[test]
fn matches_slice() {
let left = &[1, 2, 3];