Synchronous prevent default (#2792)

* add prevent default methods to the event

* sync prevent default almost working

* sync prevent default working

* Move event handling into the runtime

* update core tests

* restore desktop file dialog

* implement prevent default on web

* add a hint about the new prevent default method

* fix web prevent default

* Fix CTRL+click on links

* fix values memorize in place test

* Fix a few more tests

* Add a playwright test for sync prevent default

* Fix core doc tests

* create a deprecated VirtualDom::handle_event

* fix macos imports in desktop

* Fix onmounted event

* Fix liveview support

* switch to RefCell for metadata

* Remove println

* remove prevent default attribute

* remove web specific link behavior

* Fix liveview links

* more liveview fixes for link

* Fix merge conflicts

* Fix clippy

* use the new prevent default in the file upload example
This commit is contained in:
Evan Almloff authored and GitHub committed 2024-08-13 11:57:54 -07:00
1 parent 8b62b71e2d
commit cab573eefd
54 files changed
+940 -729

No files matched your search

+63 -14
View File
@@ -1,10 +1,6 @@
use crate::{global_context::current_scope_id, properties::SuperFrom, Runtime, ScopeId};
use generational_box::GenerationalBox;
use std::{
cell::{Cell, RefCell},
marker::PhantomData,
rc::Rc,
};
use std::{cell::RefCell, marker::PhantomData, rc::Rc};
/// A wrapper around some generic data that handles the event's state
///
@@ -26,19 +22,29 @@ use std::{
pub struct Event<T: 'static + ?Sized> {
/// The data associated with this event
pub data: Rc<T>,
pub(crate) propagates: Rc<Cell<bool>>,
pub(crate) metadata: Rc<RefCell<EventMetadata>>,
}
#[derive(Clone, Copy)]
pub(crate) struct EventMetadata {
pub(crate) propagates: bool,
pub(crate) prevent_default: bool,
}
impl<T: ?Sized + 'static> Event<T> {
pub(crate) fn new(data: Rc<T>, bubbles: bool) -> Self {
/// Create a new event from the inner data
pub fn new(data: Rc<T>, propagates: bool) -> Self {
Self {
data,
propagates: Rc::new(Cell::new(bubbles)),
metadata: Rc::new(RefCell::new(EventMetadata {
propagates,
prevent_default: false,
})),
}
}
}
impl<T> Event<T> {
impl<T: ?Sized> Event<T> {
/// Map the event data to a new type
///
/// # Example
@@ -57,7 +63,7 @@ impl<T> Event<T> {
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(),
metadata: self.metadata.clone(),
}
}
@@ -78,7 +84,12 @@ impl<T> Event<T> {
/// ```
#[deprecated = "use stop_propagation instead"]
pub fn cancel_bubble(&self) {
self.propagates.set(false);
self.metadata.borrow_mut().propagates = false;
}
/// Check if the event propagates up the tree to parent elements
pub fn propagates(&self) -> bool {
self.metadata.borrow().propagates
}
/// Prevent this event from continuing to bubble up the tree to parent elements.
@@ -96,7 +107,7 @@ impl<T> Event<T> {
/// };
/// ```
pub fn stop_propagation(&self) {
self.propagates.set(false);
self.metadata.borrow_mut().propagates = false;
}
/// Get a reference to the inner data from this event
@@ -117,12 +128,49 @@ impl<T> Event<T> {
pub fn data(&self) -> Rc<T> {
self.data.clone()
}
/// Prevent the default action of the event.
///
/// # Example
///
/// ```rust
/// # use dioxus::prelude::*;
/// fn App() -> Element {
/// rsx! {
/// a {
/// // You can prevent the default action of the event with `prevent_default`
/// onclick: move |event| {
/// event.prevent_default();
/// },
/// href: "https://dioxuslabs.com",
/// "don't go to the link"
/// }
/// }
/// }
/// ```
///
/// Note: This must be called synchronously when handling the event. Calling it after the event has been handled will have no effect.
///
/// <div class="warning">
///
/// This method is not available on the LiveView renderer because LiveView handles all events over a websocket which cannot block.
///
/// </div>
#[track_caller]
pub fn prevent_default(&self) {
self.metadata.borrow_mut().prevent_default = true;
}
/// Check if the default action of the event is enabled.
pub fn default_action_enabled(&self) -> bool {
!self.metadata.borrow().prevent_default
}
}
impl<T: ?Sized> Clone for Event<T> {
fn clone(&self) -> Self {
Self {
propagates: self.propagates.clone(),
metadata: self.metadata.clone(),
data: self.data.clone(),
}
}
@@ -138,7 +186,8 @@ impl<T> std::ops::Deref for Event<T> {
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("bubble_state", &self.propagates())
.field("prevent_default", &!self.default_action_enabled())
.field("data", &self.data)
.finish()
}