events.rs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. use crate::{global_context::current_scope_id, Runtime, ScopeId};
  2. use std::{
  3. cell::{Cell, RefCell},
  4. rc::Rc,
  5. };
  6. /// A wrapper around some generic data that handles the event's state
  7. ///
  8. ///
  9. /// Prevent this event from continuing to bubble up the tree to parent elements.
  10. ///
  11. /// # Example
  12. ///
  13. /// ```rust, ignore
  14. /// rsx! {
  15. /// button {
  16. /// onclick: move |evt: Event<MouseData>| {
  17. /// evt.cancel_bubble();
  18. ///
  19. /// }
  20. /// }
  21. /// }
  22. /// ```
  23. pub struct Event<T: 'static + ?Sized> {
  24. /// The data associated with this event
  25. pub data: Rc<T>,
  26. pub(crate) propagates: Rc<Cell<bool>>,
  27. }
  28. impl<T: ?Sized + 'static> Event<T> {
  29. pub(crate) fn new(data: Rc<T>, bubbles: bool) -> Self {
  30. Self {
  31. data,
  32. propagates: Rc::new(Cell::new(bubbles)),
  33. }
  34. }
  35. }
  36. impl<T> Event<T> {
  37. /// Map the event data to a new type
  38. ///
  39. /// # Example
  40. ///
  41. /// ```rust, ignore
  42. /// rsx! {
  43. /// button {
  44. /// onclick: move |evt: Event<FormData>| {
  45. /// let data = evt.map(|data| data.value());
  46. /// assert_eq!(data.inner(), "hello world");
  47. /// }
  48. /// }
  49. /// }
  50. /// ```
  51. pub fn map<U: 'static, F: FnOnce(&T) -> U>(&self, f: F) -> Event<U> {
  52. Event {
  53. data: Rc::new(f(&self.data)),
  54. propagates: self.propagates.clone(),
  55. }
  56. }
  57. /// Prevent this event from continuing to bubble up the tree to parent elements.
  58. ///
  59. /// # Example
  60. ///
  61. /// ```rust, ignore
  62. /// rsx! {
  63. /// button {
  64. /// onclick: move |evt: Event<MouseData>| {
  65. /// evt.cancel_bubble();
  66. /// }
  67. /// }
  68. /// }
  69. /// ```
  70. #[deprecated = "use stop_propagation instead"]
  71. pub fn cancel_bubble(&self) {
  72. self.propagates.set(false);
  73. }
  74. /// Prevent this event from continuing to bubble up the tree to parent elements.
  75. ///
  76. /// # Example
  77. ///
  78. /// ```rust, ignore
  79. /// rsx! {
  80. /// button {
  81. /// onclick: move |evt: Event<MouseData>| {
  82. /// evt.stop_propagation();
  83. /// }
  84. /// }
  85. /// }
  86. /// ```
  87. pub fn stop_propagation(&self) {
  88. self.propagates.set(false);
  89. }
  90. /// Get a reference to the inner data from this event
  91. ///
  92. /// ```rust, ignore
  93. /// rsx! {
  94. /// button {
  95. /// onclick: move |evt: Event<MouseData>| {
  96. /// let data = evt.inner.clone();
  97. /// cx.spawn(async move {
  98. /// println!("{:?}", data);
  99. /// });
  100. /// }
  101. /// }
  102. /// }
  103. /// ```
  104. pub fn data(&self) -> Rc<T> {
  105. self.data.clone()
  106. }
  107. }
  108. impl<T: ?Sized> Clone for Event<T> {
  109. fn clone(&self) -> Self {
  110. Self {
  111. propagates: self.propagates.clone(),
  112. data: self.data.clone(),
  113. }
  114. }
  115. }
  116. impl<T> std::ops::Deref for Event<T> {
  117. type Target = Rc<T>;
  118. fn deref(&self) -> &Self::Target {
  119. &self.data
  120. }
  121. }
  122. impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
  123. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  124. f.debug_struct("UiEvent")
  125. .field("bubble_state", &self.propagates)
  126. .field("data", &self.data)
  127. .finish()
  128. }
  129. }
  130. /// The callback type generated by the `rsx!` macro when an `on` field is specified for components.
  131. ///
  132. /// This makes it possible to pass `move |evt| {}` style closures into components as property fields.
  133. ///
  134. ///
  135. /// # Example
  136. ///
  137. /// ```rust, ignore
  138. /// rsx!{
  139. /// MyComponent { onclick: move |evt| tracing::debug!("clicked") }
  140. /// }
  141. ///
  142. /// #[derive(Props)]
  143. /// struct MyProps {
  144. /// onclick: EventHandler<MouseEvent>,
  145. /// }
  146. ///
  147. /// fn MyComponent(cx: MyProps) -> Element {
  148. /// rsx!{
  149. /// button {
  150. /// onclick: move |evt| cx.onclick.call(evt),
  151. /// }
  152. /// }
  153. /// }
  154. ///
  155. /// ```
  156. pub struct EventHandler<T = ()> {
  157. pub(crate) origin: ScopeId,
  158. pub(super) callback: Rc<RefCell<Option<ExternalListenerCallback<T>>>>,
  159. }
  160. impl<T> Clone for EventHandler<T> {
  161. fn clone(&self) -> Self {
  162. Self {
  163. origin: self.origin,
  164. callback: self.callback.clone(),
  165. }
  166. }
  167. }
  168. impl<T> PartialEq for EventHandler<T> {
  169. fn eq(&self, other: &Self) -> bool {
  170. Rc::ptr_eq(&self.callback, &other.callback)
  171. }
  172. }
  173. impl<T> Default for EventHandler<T> {
  174. fn default() -> Self {
  175. Self {
  176. origin: ScopeId::ROOT,
  177. callback: Default::default(),
  178. }
  179. }
  180. }
  181. type ExternalListenerCallback<T> = Box<dyn FnMut(T)>;
  182. impl<T> EventHandler<T> {
  183. /// Create a new [`EventHandler`] from an [`FnMut`]
  184. pub fn new(mut f: impl FnMut(T) + 'static) -> EventHandler<T> {
  185. let callback = Rc::new(RefCell::new(Some(Box::new(move |event: T| {
  186. f(event);
  187. }) as Box<dyn FnMut(T)>)));
  188. EventHandler {
  189. callback,
  190. origin: current_scope_id().expect("to be in a dioxus runtime"),
  191. }
  192. }
  193. /// Call this event handler with the appropriate event type
  194. ///
  195. /// This borrows the event using a RefCell. Recursively calling a listener will cause a panic.
  196. pub fn call(&self, event: T) {
  197. if let Some(callback) = self.callback.borrow_mut().as_mut() {
  198. Runtime::with(|rt| rt.scope_stack.borrow_mut().push(self.origin));
  199. callback(event);
  200. Runtime::with(|rt| rt.scope_stack.borrow_mut().pop());
  201. }
  202. }
  203. /// Forcibly drop the internal handler callback, releasing memory
  204. ///
  205. /// This will force any future calls to "call" to not doing anything
  206. pub fn release(&self) {
  207. self.callback.replace(None);
  208. }
  209. }