dioxus_native/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3//! A native renderer for Dioxus.
4//!
5//! ## Feature flags
6//!  - `default`: Enables the features listed below.
7//!  - `accessibility`: Enables [`accesskit`](https://docs.rs/accesskit/latest/accesskit/) accessibility support.
8//!  - `hot-reload`: Enables hot-reloading of Dioxus RSX.
9//!  - `menu`: Enables the [`muda`](https://docs.rs/muda/latest/muda/) menubar.
10//!  - `tracing`: Enables tracing support.
11
12mod assets;
13mod contexts;
14mod dioxus_application;
15mod dioxus_document;
16mod events;
17mod mutation_writer;
18
19use blitz_dom::{ns, Atom, QualName};
20pub use dioxus_application::{DioxusNativeApplication, DioxusNativeEvent};
21pub use dioxus_document::DioxusDocument;
22
23use blitz_shell::{create_default_event_loop, BlitzShellEvent, Config, WindowConfig};
24use dioxus_core::{ComponentFunction, Element, VirtualDom};
25use std::any::Any;
26
27type NodeId = usize;
28
29/// Launch an interactive HTML/CSS renderer driven by the Dioxus virtualdom
30pub fn launch(app: fn() -> Element) {
31    launch_cfg(app, vec![], vec![])
32}
33
34pub fn launch_cfg(
35    app: fn() -> Element,
36    contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
37    cfg: Vec<Box<dyn Any>>,
38) {
39    launch_cfg_with_props(app, (), contexts, cfg)
40}
41
42// todo: props shouldn't have the clone bound - should try and match dioxus-desktop behavior
43pub fn launch_cfg_with_props<P: Clone + 'static, M: 'static>(
44    app: impl ComponentFunction<P, M>,
45    props: P,
46    contexts: Vec<Box<dyn Fn() -> Box<dyn Any> + Send + Sync>>,
47    _cfg: Vec<Box<dyn Any>>,
48) {
49    let _cfg = _cfg
50        .into_iter()
51        .find_map(|cfg| cfg.downcast::<Config>().ok())
52        .unwrap_or_default();
53    let event_loop = create_default_event_loop::<BlitzShellEvent>();
54
55    // Turn on the runtime and enter it
56    let rt = tokio::runtime::Builder::new_multi_thread()
57        .enable_all()
58        .build()
59        .unwrap();
60    let _guard = rt.enter();
61
62    // Setup hot-reloading if enabled.
63    #[cfg(all(
64        feature = "hot-reload",
65        debug_assertions,
66        not(target_os = "android"),
67        not(target_os = "ios")
68    ))]
69    {
70        let proxy = event_loop.create_proxy();
71        dioxus_devtools::connect(move |event| {
72            let dxn_event = DioxusNativeEvent::DevserverEvent(event);
73            let _ = proxy.send_event(BlitzShellEvent::embedder_event(dxn_event));
74        })
75    }
76
77    // Spin up the virtualdom
78    // We're going to need to hit it with a special waker
79    // Note that we are delaying the initialization of window-specific contexts (net provider, document, etc)
80    let mut vdom = VirtualDom::new_with_props(app, props);
81
82    // Add contexts
83    for context in contexts {
84        vdom.insert_any_root_context(context());
85    }
86
87    // Create application
88    let mut application = DioxusNativeApplication::new(event_loop.create_proxy(), vdom);
89
90    // Run event loop
91    event_loop.run_app(&mut application).unwrap();
92}
93
94pub(crate) fn qual_name(local_name: &str, namespace: Option<&str>) -> QualName {
95    QualName {
96        prefix: None,
97        ns: namespace.map(Atom::from).unwrap_or(ns!(html)),
98        local: Atom::from(local_name),
99    }
100}
101
102// Syntax sugar to make tracing calls less noisy in function below
103macro_rules! trace {
104    ($pattern:literal) => {{
105        #[cfg(feature = "tracing")]
106        tracing::info!($pattern);
107    }};
108    ($pattern:literal, $item1:expr) => {{
109        #[cfg(feature = "tracing")]
110        tracing::info!($pattern, $item1);
111    }};
112    ($pattern:literal, $item1:expr, $item2:expr) => {{
113        #[cfg(feature = "tracing")]
114        tracing::info!($pattern, $item1, $item2);
115    }};
116    ($pattern:literal, $item1:expr, $item2:expr, $item3:expr) => {{
117        #[cfg(feature = "tracing")]
118        tracing::info!($pattern, $item1, $item2);
119    }};
120    ($pattern:literal, $item1:expr, $item2:expr, $item3:expr, $item4:expr) => {{
121        #[cfg(feature = "tracing")]
122        tracing::info!($pattern, $item1, $item2, $item3, $item4);
123    }};
124}
125pub(crate) use trace;