Upgrade Blitz to 0.1.0-rc.1 (#4452)
* Update to newer version of blitz_dom::Document trait Signed-off-by: Nico Burns <nico@nicoburns.com> * Native: use DocumentConfig parameter Signed-off-by: Nico Burns <nico@nicoburns.com> * Native: set event converter less often Signed-off-by: Nico Burns <nico@nicoburns.com> * Native: count event handlers and skip events if none Signed-off-by: Nico Burns <nico@nicoburns.com> * Upgrade to Blitz 0.1.0-rc.1 * Fix typo Signed-off-by: Nico Burns <nico@nicoburns.com> * Fix native-headless example Signed-off-by: Nico Burns <nico@nicoburns.com> * Use workspace deps for native-headless-in-bevy example Signed-off-by: Nico Burns <nico@nicoburns.com> * Fix native-headless-in-bevy example (for blitz 0.1.0-rc.1) * Fix native-dom-document doc tests --------- Signed-off-by: Nico Burns <nico@nicoburns.com>
This commit is contained in:
1 parent
18fe6de9a0
commit
6524f55462
12 files changed
+163
-88
No files matched your search
@@ -19,8 +19,8 @@ autofocus = []
|
||||
|
||||
[dependencies]
|
||||
# Blitz dependencies
|
||||
blitz-dom = { version = "=0.1.0-alpha.5", default-features = false }
|
||||
blitz-traits = { version = "=0.1.0-alpha.5" }
|
||||
blitz-dom = { workspace = true, default-features = false }
|
||||
blitz-traits = { workspace = true }
|
||||
|
||||
# DioxusLabs dependencies
|
||||
dioxus-core = { workspace = true }
|
||||
@@ -35,6 +35,9 @@ tracing = { workspace = true, optional = true }
|
||||
rustc-hash = { workspace = true }
|
||||
futures-util = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
dioxus = { workspace = true }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
@@ -3,22 +3,18 @@ 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,
|
||||
Attribute, BaseDocument, Document, DocumentConfig, EventDriver, EventHandler, Node, DEFAULT_CSS,
|
||||
};
|
||||
use blitz_traits::{
|
||||
events::{DomEvent, DomEventData, EventState, UiEvent},
|
||||
net::NetProvider,
|
||||
shell::{ColorScheme, Viewport},
|
||||
};
|
||||
|
||||
use blitz_traits::events::{DomEvent, DomEventData, EventState, UiEvent};
|
||||
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::{any::Any, collections::HashMap, rc::Rc, sync::Arc};
|
||||
use std::sync::LazyLock;
|
||||
use std::task::{Context as TaskContext, Waker};
|
||||
use std::{any::Any, collections::HashMap, rc::Rc};
|
||||
|
||||
fn wrap_event_data<T: Any>(value: T) -> Rc<dyn Any> {
|
||||
Rc::new(PlatformEventData::new(Box::new(value)))
|
||||
@@ -34,6 +30,34 @@ 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
|
||||
/// use blitz_traits::shell::{Viewport, ColorScheme};
|
||||
/// use dioxus_native_dom::{DioxusDocument, DocumentConfig};
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// // Example Dioxus app
|
||||
/// fn app() -> Element {
|
||||
/// rsx! {
|
||||
/// div { "Hello, world!" }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let vdom = VirtualDom::new(app);
|
||||
/// let mut doc = DioxusDocument::new(vdom, DocumentConfig {
|
||||
/// viewport: Some(Viewport::new(800, 600, 1.0, ColorScheme::Light)),
|
||||
/// ..Default::default()
|
||||
/// });
|
||||
/// doc.initial_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,32 @@ pub struct DioxusDocument {
|
||||
}
|
||||
|
||||
impl DioxusDocument {
|
||||
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);
|
||||
/// Create a new [`DioxusDocument`] from a [`VirtualDom`].
|
||||
pub fn new(vdom: VirtualDom, mut config: DocumentConfig) -> Self {
|
||||
// Only really needs to happen once
|
||||
set_event_converter(Box::new(NativeConverter {}));
|
||||
|
||||
// Set net provider
|
||||
if let Some(net_provider) = net_provider {
|
||||
doc.set_net_provider(net_provider);
|
||||
}
|
||||
config.base_url = Some(
|
||||
config
|
||||
.base_url
|
||||
.unwrap_or_else(|| String::from("dioxus://index.html")),
|
||||
);
|
||||
let mut doc = BaseDocument::new(config);
|
||||
|
||||
// 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 +124,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 +133,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 +185,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,8 +204,7 @@ impl Document for DioxusDocument {
|
||||
true
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, event: UiEvent) {
|
||||
set_event_converter(Box::new(NativeConverter {}));
|
||||
fn handle_ui_event(&mut self, event: UiEvent) {
|
||||
let handler = DioxusEventHandler {
|
||||
vdom: &mut self.vdom,
|
||||
vdom_state: &mut self.vdom_state,
|
||||
@@ -209,6 +245,14 @@ impl EventHandler for DioxusEventHandler<'_> {
|
||||
mutr: &mut blitz_dom::DocumentMutator<'_>,
|
||||
event_state: &mut EventState,
|
||||
) {
|
||||
// As an optimisation we maintain a count of the total number event handlers of a given type
|
||||
// If this count is zero then we can skip handling that kind of event entirely.
|
||||
let event_kind_idx = event.data.discriminant() as usize;
|
||||
let event_kind_count = self.vdom_state.event_handler_counts[event_kind_idx];
|
||||
if event_kind_count == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let event_data = match &event.data {
|
||||
DomEventData::MouseMove(mevent)
|
||||
| DomEventData::MouseDown(mevent)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
mod dioxus_document;
|
||||
mod events;
|
||||
mod mutation_writer;
|
||||
pub use blitz_dom::DocumentConfig;
|
||||
pub use dioxus_document::DioxusDocument;
|
||||
|
||||
use blitz_dom::{ns, LocalName, Namespace, QualName};
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
//! Integration between Dioxus and Blitz
|
||||
use crate::{qual_name, trace, NodeId};
|
||||
use blitz_dom::{Attribute, BaseDocument, DocumentMutator};
|
||||
use blitz_traits::events::DomEventKind;
|
||||
use dioxus_core::{
|
||||
AttributeValue, ElementId, Template, TemplateAttribute, TemplateNode, WriteMutations,
|
||||
};
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::str::FromStr as _;
|
||||
|
||||
/// The state of the Dioxus integration with the RealDom
|
||||
#[derive(Debug)]
|
||||
pub struct DioxusState {
|
||||
/// Store of templates keyed by unique name
|
||||
templates: FxHashMap<Template, Vec<NodeId>>,
|
||||
pub(crate) templates: FxHashMap<Template, Vec<NodeId>>,
|
||||
/// Stack machine state for applying dioxus mutations
|
||||
stack: Vec<NodeId>,
|
||||
pub(crate) stack: Vec<NodeId>,
|
||||
/// Mapping from vdom ElementId -> rdom NodeId
|
||||
node_id_mapping: Vec<Option<NodeId>>,
|
||||
pub(crate) node_id_mapping: Vec<Option<NodeId>>,
|
||||
/// Count of each handler type
|
||||
pub(crate) event_handler_counts: [u32; 32],
|
||||
}
|
||||
|
||||
impl DioxusState {
|
||||
@@ -24,6 +28,7 @@ impl DioxusState {
|
||||
templates: FxHashMap::default(),
|
||||
stack: vec![root_id],
|
||||
node_id_mapping: vec![Some(root_id)],
|
||||
event_handler_counts: [0; 32],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,10 +259,18 @@ impl WriteMutations for MutationWriter<'_> {
|
||||
self.set_attribute("data-dioxus-id", None, &value, id);
|
||||
|
||||
// node.add_event_listener(name);
|
||||
|
||||
if let Ok(kind) = DomEventKind::from_str(name) {
|
||||
let idx = kind.discriminant() as usize;
|
||||
self.state.event_handler_counts[idx] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_event_listener(&mut self, _name: &'static str, _id: ElementId) {
|
||||
// node.remove_event_listener(name);
|
||||
fn remove_event_listener(&mut self, name: &'static str, _id: ElementId) {
|
||||
if let Ok(kind) = DomEventKind::from_str(name) {
|
||||
let idx = kind.discriminant() as usize;
|
||||
self.state.event_handler_counts[idx] -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@ autofocus = []
|
||||
|
||||
[dependencies]
|
||||
# Blitz dependencies
|
||||
anyrender = { version = "0.4", default-features = false }
|
||||
anyrender_vello = { version = "0.4", default-features = false }
|
||||
blitz-dom = { workspace = true, default-features = false }
|
||||
anyrender = { workspace = true }
|
||||
anyrender_vello = { workspace = true }
|
||||
blitz-dom = { workspace = true }
|
||||
blitz-net = { workspace = true, optional = true }
|
||||
blitz-paint = { workspace = true, optional = true }
|
||||
blitz-traits = { workspace = true }
|
||||
blitz-shell = { workspace = true, default-features = false }
|
||||
blitz-shell = { workspace = true }
|
||||
|
||||
# DioxusLabs dependencies
|
||||
dioxus-core = { workspace = true }
|
||||
|
||||
@@ -124,7 +124,13 @@ pub fn launch_cfg_with_props<P: Clone + 'static, M: 'static>(
|
||||
let net_provider = None;
|
||||
|
||||
// Create document + window from the baked virtualdom
|
||||
let doc = DioxusDocument::new(vdom, net_provider);
|
||||
let doc = DioxusDocument::new(
|
||||
vdom,
|
||||
DocumentConfig {
|
||||
net_provider,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
let renderer = DioxusNativeWindowRenderer::with_features_and_limits(features, limits);
|
||||
let config = WindowConfig::with_attributes(
|
||||
Box::new(doc) as _,
|
||||
|
||||
Reference in new issue
Block a user