events.rs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. use crate::{runtime::with_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> Event<T> {
  29. /// Map the event data to a new type
  30. ///
  31. /// # Example
  32. ///
  33. /// ```rust, ignore
  34. /// rsx! {
  35. /// button {
  36. /// onclick: move |evt: Event<FormData>| {
  37. /// let data = evt.map(|data| data.value());
  38. /// assert_eq!(data.inner(), "hello world");
  39. /// }
  40. /// }
  41. /// }
  42. /// ```
  43. pub fn map<U: 'static, F: FnOnce(&T) -> U>(&self, f: F) -> Event<U> {
  44. Event {
  45. data: Rc::new(f(&self.data)),
  46. propagates: self.propagates.clone(),
  47. }
  48. }
  49. /// Prevent this event from continuing to bubble up the tree to parent elements.
  50. ///
  51. /// # Example
  52. ///
  53. /// ```rust, ignore
  54. /// rsx! {
  55. /// button {
  56. /// onclick: move |evt: Event<MouseData>| {
  57. /// evt.cancel_bubble();
  58. /// }
  59. /// }
  60. /// }
  61. /// ```
  62. #[deprecated = "use stop_propagation instead"]
  63. pub fn cancel_bubble(&self) {
  64. self.propagates.set(false);
  65. }
  66. /// Prevent this event from continuing to bubble up the tree to parent elements.
  67. ///
  68. /// # Example
  69. ///
  70. /// ```rust, ignore
  71. /// rsx! {
  72. /// button {
  73. /// onclick: move |evt: Event<MouseData>| {
  74. /// evt.stop_propagation();
  75. /// }
  76. /// }
  77. /// }
  78. /// ```
  79. pub fn stop_propagation(&self) {
  80. self.propagates.set(false);
  81. }
  82. /// Get a reference to the inner data from this event
  83. ///
  84. /// ```rust, ignore
  85. /// rsx! {
  86. /// button {
  87. /// onclick: move |evt: Event<MouseData>| {
  88. /// let data = evt.inner.clone();
  89. /// cx.spawn(async move {
  90. /// println!("{:?}", data);
  91. /// });
  92. /// }
  93. /// }
  94. /// }
  95. /// ```
  96. pub fn inner(&self) -> &Rc<T> {
  97. &self.data
  98. }
  99. }
  100. impl<T: ?Sized> Clone for Event<T> {
  101. fn clone(&self) -> Self {
  102. Self {
  103. propagates: self.propagates.clone(),
  104. data: self.data.clone(),
  105. }
  106. }
  107. }
  108. impl<T> std::ops::Deref for Event<T> {
  109. type Target = Rc<T>;
  110. fn deref(&self) -> &Self::Target {
  111. &self.data
  112. }
  113. }
  114. impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
  115. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  116. f.debug_struct("UiEvent")
  117. .field("bubble_state", &self.propagates)
  118. .field("data", &self.data)
  119. .finish()
  120. }
  121. }
  122. /// The callback type generated by the `rsx!` macro when an `on` field is specified for components.
  123. ///
  124. /// This makes it possible to pass `move |evt| {}` style closures into components as property fields.
  125. ///
  126. ///
  127. /// # Example
  128. ///
  129. /// ```rust, ignore
  130. /// rsx!{
  131. /// MyComponent { onclick: move |evt| tracing::debug!("clicked") }
  132. /// }
  133. ///
  134. /// #[derive(Props)]
  135. /// struct MyProps<'a> {
  136. /// onclick: EventHandler<'a, MouseEvent>,
  137. /// }
  138. ///
  139. /// fn MyComponent(cx: Scope<'a, MyProps<'a>>) -> Element {
  140. /// cx.render(rsx!{
  141. /// button {
  142. /// onclick: move |evt| cx.props.onclick.call(evt),
  143. /// }
  144. /// })
  145. /// }
  146. ///
  147. /// ```
  148. pub struct EventHandler<'bump, T = ()> {
  149. pub(crate) origin: ScopeId,
  150. pub(super) callback: RefCell<Option<ExternalListenerCallback<'bump, T>>>,
  151. }
  152. impl<T> Default for EventHandler<'_, T> {
  153. fn default() -> Self {
  154. Self {
  155. origin: ScopeId::ROOT,
  156. callback: Default::default(),
  157. }
  158. }
  159. }
  160. type ExternalListenerCallback<'bump, T> = bumpalo::boxed::Box<'bump, dyn FnMut(T) + 'bump>;
  161. impl<T> EventHandler<'_, T> {
  162. /// Call this event handler with the appropriate event type
  163. ///
  164. /// This borrows the event using a RefCell. Recursively calling a listener will cause a panic.
  165. pub fn call(&self, event: T) {
  166. if let Some(callback) = self.callback.borrow_mut().as_mut() {
  167. with_runtime(|rt| {
  168. rt.scope_stack.borrow_mut().push(self.origin);
  169. });
  170. callback(event);
  171. with_runtime(|rt| {
  172. rt.scope_stack.borrow_mut().pop();
  173. });
  174. }
  175. }
  176. /// Forcibly drop the internal handler callback, releasing memory
  177. ///
  178. /// This will force any future calls to "call" to not doing anything
  179. pub fn release(&self) {
  180. self.callback.replace(None);
  181. }
  182. }