lib.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #![doc = include_str!("../README.md")]
  2. #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
  3. #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
  4. mod element;
  5. mod events;
  6. use std::{
  7. any::Any,
  8. ops::Deref,
  9. rc::Rc,
  10. sync::{Arc, RwLock},
  11. };
  12. use dioxus_core::{Element, ElementId, ScopeId, VirtualDom};
  13. use dioxus_html::PlatformEventData;
  14. use dioxus_native_core::dioxus::{DioxusState, NodeImmutableDioxusExt};
  15. use dioxus_native_core::prelude::*;
  16. use element::DioxusTUIMutationWriter;
  17. pub use plasmo::{query::Query, Config, RenderingMode, Size, TuiContext};
  18. use plasmo::{render, Driver};
  19. pub fn launch(app: fn() -> Element) {
  20. launch_cfg(app, Config::default())
  21. }
  22. pub fn launch_cfg(app: fn() -> Element, cfg: Config) {
  23. launch_vdom_cfg(VirtualDom::new(app), cfg)
  24. }
  25. pub fn launch_vdom_cfg(vdom: VirtualDom, cfg: Config) {
  26. dioxus_html::set_event_converter(Box::new(events::SerializedHtmlEventConverter));
  27. render(cfg, |rdom, taffy, event_tx| {
  28. let dioxus_state = {
  29. let mut rdom = rdom.write().unwrap();
  30. DioxusState::create(&mut rdom)
  31. };
  32. let dioxus_state = Rc::new(RwLock::new(dioxus_state));
  33. let vdom = vdom
  34. .with_root_context(TuiContext::new(event_tx))
  35. .with_root_context(Query::new(rdom.clone(), taffy.clone()))
  36. .with_root_context(DioxusElementToNodeId {
  37. mapping: dioxus_state.clone(),
  38. });
  39. let queued_events = Vec::new();
  40. let mut myself = DioxusRenderer {
  41. vdom,
  42. dioxus_state,
  43. queued_events,
  44. #[cfg(all(feature = "hot-reload", debug_assertions))]
  45. hot_reload_rx: {
  46. let (hot_reload_tx, hot_reload_rx) =
  47. tokio::sync::mpsc::unbounded_channel::<dioxus_hot_reload::HotReloadMsg>();
  48. dioxus_hot_reload::connect(move |msg| {
  49. let _ = hot_reload_tx.send(msg);
  50. });
  51. hot_reload_rx
  52. },
  53. };
  54. {
  55. let mut rdom = rdom.write().unwrap();
  56. let mut dioxus_state = myself.dioxus_state.write().unwrap();
  57. let mut writer = DioxusTUIMutationWriter {
  58. query: myself
  59. .vdom
  60. .in_runtime(|| ScopeId::ROOT.consume_context().unwrap()),
  61. events: &mut myself.queued_events,
  62. native_core_writer: dioxus_state.create_mutation_writer(&mut rdom),
  63. };
  64. // Find any mount events
  65. myself.vdom.rebuild(&mut writer);
  66. }
  67. myself
  68. })
  69. .unwrap();
  70. }
  71. struct DioxusRenderer {
  72. vdom: VirtualDom,
  73. dioxus_state: Rc<RwLock<DioxusState>>,
  74. // Events that are queued up to be sent to the vdom next time the vdom is polled
  75. queued_events: Vec<(ElementId, &'static str, Box<dyn Any>, bool)>,
  76. #[cfg(all(feature = "hot-reload", debug_assertions))]
  77. hot_reload_rx: tokio::sync::mpsc::UnboundedReceiver<dioxus_hot_reload::HotReloadMsg>,
  78. }
  79. impl Driver for DioxusRenderer {
  80. fn update(&mut self, rdom: &Arc<RwLock<RealDom>>) {
  81. let mut rdom = rdom.write().unwrap();
  82. let mut dioxus_state = self.dioxus_state.write().unwrap();
  83. let mut writer = DioxusTUIMutationWriter {
  84. query: self
  85. .vdom
  86. .in_runtime(|| ScopeId::ROOT.consume_context().unwrap()),
  87. events: &mut self.queued_events,
  88. native_core_writer: dioxus_state.create_mutation_writer(&mut rdom),
  89. };
  90. // Find any mount events
  91. self.vdom.render_immediate(&mut writer);
  92. }
  93. fn handle_event(
  94. &mut self,
  95. rdom: &Arc<RwLock<RealDom>>,
  96. id: NodeId,
  97. event: &str,
  98. value: Rc<plasmo::EventData>,
  99. bubbles: bool,
  100. ) {
  101. let id = { rdom.read().unwrap().get(id).unwrap().mounted_id() };
  102. if let Some(id) = id {
  103. let inner_value = value.deref().clone();
  104. let boxed_event = Box::new(inner_value);
  105. let platform_event = PlatformEventData::new(boxed_event);
  106. self.vdom
  107. .handle_event(event, Rc::new(platform_event), id, bubbles);
  108. }
  109. }
  110. fn poll_async(&mut self) -> std::pin::Pin<Box<dyn futures::Future<Output = ()> + '_>> {
  111. // Add any queued events
  112. for (id, event, value, bubbles) in self.queued_events.drain(..) {
  113. let platform_event = PlatformEventData::new(value);
  114. self.vdom
  115. .handle_event(event, Rc::new(platform_event), id, bubbles);
  116. }
  117. #[cfg(all(feature = "hot-reload", debug_assertions))]
  118. return Box::pin(async {
  119. let hot_reload_wait = self.hot_reload_rx.recv();
  120. let mut hot_reload_msg = None;
  121. let wait_for_work = self.vdom.wait_for_work();
  122. tokio::select! {
  123. Some(msg) = hot_reload_wait => {
  124. #[cfg(all(feature = "hot-reload", debug_assertions))]
  125. {
  126. hot_reload_msg = Some(msg);
  127. }
  128. #[cfg(not(all(feature = "hot-reload", debug_assertions)))]
  129. let () = msg;
  130. }
  131. _ = wait_for_work => {}
  132. }
  133. // if we have a new template, replace the old one
  134. if let Some(msg) = hot_reload_msg {
  135. match msg {
  136. dioxus_hot_reload::HotReloadMsg::UpdateTemplate(template) => {
  137. self.vdom.replace_template(template);
  138. }
  139. dioxus_hot_reload::HotReloadMsg::Shutdown => {
  140. std::process::exit(0);
  141. }
  142. }
  143. }
  144. });
  145. #[cfg(not(all(feature = "hot-reload", debug_assertions)))]
  146. Box::pin(self.vdom.wait_for_work())
  147. }
  148. }
  149. #[derive(Clone)]
  150. pub struct DioxusElementToNodeId {
  151. mapping: Rc<RwLock<DioxusState>>,
  152. }
  153. impl DioxusElementToNodeId {
  154. pub fn get_node_id(&self, element_id: ElementId) -> Option<NodeId> {
  155. self.mapping
  156. .read()
  157. .unwrap()
  158. .try_element_to_node_id(element_id)
  159. }
  160. }