|
@@ -3,21 +3,21 @@ use crate::events::{BlitzKeyboardData, NativeClickData, NativeConverter, NativeF
|
|
|
use crate::mutation_writer::{DioxusState, MutationWriter};
|
|
|
use crate::qual_name;
|
|
|
use crate::NodeId;
|
|
|
-
|
|
|
-use blitz_dom::Attribute;
|
|
|
use blitz_dom::{
|
|
|
- net::Resource, BaseDocument, Document, EventDriver, EventHandler, Node, DEFAULT_CSS,
|
|
|
+ net::Resource, Attribute, BaseDocument, Document, EventDriver, EventHandler, Node, DEFAULT_CSS,
|
|
|
};
|
|
|
use blitz_traits::{
|
|
|
events::{DomEvent, DomEventData, EventState, UiEvent},
|
|
|
net::NetProvider,
|
|
|
shell::{ColorScheme, Viewport},
|
|
|
};
|
|
|
-
|
|
|
use dioxus_core::{ElementId, Event, VirtualDom};
|
|
|
use dioxus_html::{set_event_converter, PlatformEventData};
|
|
|
+use futures_util::task::noop_waker;
|
|
|
use futures_util::{pin_mut, FutureExt};
|
|
|
use std::ops::{Deref, DerefMut};
|
|
|
+use std::sync::LazyLock;
|
|
|
+use std::task::{Context as TaskContext, Waker};
|
|
|
use std::{any::Any, collections::HashMap, rc::Rc, sync::Arc};
|
|
|
|
|
|
fn wrap_event_data<T: Any>(value: T) -> Rc<dyn Any> {
|
|
@@ -34,6 +34,30 @@ fn get_dioxus_id(node: &Node) -> Option<ElementId> {
|
|
|
.map(ElementId)
|
|
|
}
|
|
|
|
|
|
+/// Integrates [`BaseDocument`] from [`blitz-dom`](blitz_dom) with [`VirtualDom`] from [`dioxus-core`](dioxus_core)
|
|
|
+///
|
|
|
+/// ### Example
|
|
|
+///
|
|
|
+/// ```rust
|
|
|
+/// // Example Dioxus app
|
|
|
+/// fn app() -> Element {
|
|
|
+/// rsx! {
|
|
|
+/// div { "Hello, world!" }
|
|
|
+/// }
|
|
|
+/// }
|
|
|
+///
|
|
|
+/// fn main() {
|
|
|
+/// let vdom = VirtualDom::new(app);
|
|
|
+/// let mut doc = DioxusDocument::new(vdom, None);
|
|
|
+/// doc.set_viewport(Viewport::new(WIDTH, HEIGHT, SCALE_FACTOR, COLOR_SCHEME));
|
|
|
+/// doc.inital_build();
|
|
|
+///
|
|
|
+/// }
|
|
|
+/// ```
|
|
|
+///
|
|
|
+/// You can just push events into the [`DioxusDocument`] with [`doc.handle_ui_event(..)`](Self::handle_ui_event)
|
|
|
+/// and then flush the changes with [`doc.poll(..)`](Self::poll)
|
|
|
+
|
|
|
pub struct DioxusDocument {
|
|
|
pub inner: BaseDocument,
|
|
|
pub vdom: VirtualDom,
|
|
@@ -50,16 +74,33 @@ pub struct DioxusDocument {
|
|
|
}
|
|
|
|
|
|
impl DioxusDocument {
|
|
|
+ /// Create a new [`DioxusDocument`] from a [`VirtualDom`].
|
|
|
pub fn new(vdom: VirtualDom, net_provider: Option<Arc<dyn NetProvider<Resource>>>) -> Self {
|
|
|
let viewport = Viewport::new(0, 0, 1.0, ColorScheme::Light);
|
|
|
let mut doc = BaseDocument::new(viewport);
|
|
|
|
|
|
+ // Set base_url
|
|
|
+ doc.set_base_url("dioxus://index.html");
|
|
|
+
|
|
|
// Set net provider
|
|
|
if let Some(net_provider) = net_provider {
|
|
|
doc.set_net_provider(net_provider);
|
|
|
}
|
|
|
|
|
|
+ // Include default stylesheet
|
|
|
+ doc.add_user_agent_stylesheet(DEFAULT_CSS);
|
|
|
+
|
|
|
// Create some minimal HTML to render the app into.
|
|
|
+ // HTML is equivalent to:
|
|
|
+ //
|
|
|
+ // <html>
|
|
|
+ // <head></head>
|
|
|
+ // <body>
|
|
|
+ // <div id="main"></div>
|
|
|
+ // </body>
|
|
|
+ // </html>
|
|
|
+ //
|
|
|
+ // TODO: Support arbitrary "index.html" templates
|
|
|
|
|
|
// Create the html element
|
|
|
let mut mutr = doc.mutate();
|
|
@@ -84,11 +125,8 @@ impl DioxusDocument {
|
|
|
|
|
|
drop(mutr);
|
|
|
|
|
|
- // Include default and user-specified stylesheets
|
|
|
- doc.add_user_agent_stylesheet(DEFAULT_CSS);
|
|
|
-
|
|
|
let vdom_state = DioxusState::create(main_element_id);
|
|
|
- let mut doc = Self {
|
|
|
+ Self {
|
|
|
vdom,
|
|
|
vdom_state,
|
|
|
inner: doc,
|
|
@@ -96,20 +134,18 @@ impl DioxusDocument {
|
|
|
head_element_id,
|
|
|
body_element_id,
|
|
|
main_element_id,
|
|
|
- };
|
|
|
-
|
|
|
- doc.inner.set_base_url("dioxus://index.html");
|
|
|
- //doc.initial_build();
|
|
|
- doc.inner.print_tree();
|
|
|
-
|
|
|
- doc
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ /// Run an initial build of the Dioxus vdom
|
|
|
pub fn initial_build(&mut self) {
|
|
|
let mut writer = MutationWriter::new(&mut self.inner, &mut self.vdom_state);
|
|
|
self.vdom.rebuild(&mut writer);
|
|
|
}
|
|
|
|
|
|
+ /// Used to respond to a `CreateHeadElement` event generated by Dioxus. These
|
|
|
+ /// events allow Dioxus to create elements in the `<head>` of the document.
|
|
|
+ #[doc(hidden)]
|
|
|
pub fn create_head_element(
|
|
|
&mut self,
|
|
|
name: &str,
|
|
@@ -150,11 +186,13 @@ impl Document for DioxusDocument {
|
|
|
self
|
|
|
}
|
|
|
|
|
|
- fn poll(&mut self, mut cx: std::task::Context) -> bool {
|
|
|
+ fn poll(&mut self, cx: Option<TaskContext>) -> bool {
|
|
|
{
|
|
|
let fut = self.vdom.wait_for_work();
|
|
|
pin_mut!(fut);
|
|
|
|
|
|
+ static NOOP_WAKER: LazyLock<Waker> = LazyLock::new(noop_waker);
|
|
|
+ let mut cx = cx.unwrap_or_else(|| TaskContext::from_waker(&NOOP_WAKER));
|
|
|
match fut.poll_unpin(&mut cx) {
|
|
|
std::task::Poll::Ready(_) => {}
|
|
|
std::task::Poll::Pending => return false,
|
|
@@ -167,7 +205,7 @@ impl Document for DioxusDocument {
|
|
|
true
|
|
|
}
|
|
|
|
|
|
- fn handle_event(&mut self, event: UiEvent) {
|
|
|
+ fn handle_ui_event(&mut self, event: UiEvent) {
|
|
|
set_event_converter(Box::new(NativeConverter {}));
|
|
|
let handler = DioxusEventHandler {
|
|
|
vdom: &mut self.vdom,
|