diff --git a/Cargo.toml b/Cargo.toml index 9d609e50f..2d8e2b064 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ members = [ "packages/core", "packages/html-namespace", "packages/web", + "packages/webview" # "packages/cli", # "packages/atoms", # "packages/ssr", diff --git a/packages/core/examples/html.rs b/packages/core/examples/html.rs new file mode 100644 index 000000000..67c56e856 --- /dev/null +++ b/packages/core/examples/html.rs @@ -0,0 +1,108 @@ +use bumpalo::Bump; + +fn main() {} + +fn build(factory: Factory) { + factory.text(); + div::new(factory) + .r#class() + .r#tag() + .r#type() + .add_children() + .iter_children() + .finish(); +} + +/// # The `div` element +/// +/// +/// The
HTML element is the generic container for flow content. It has no effect on the content or layout until +/// styled in some way using CSS (e.g. styling is directly applied to it, or some kind of layout model like Flexbox is +/// applied to its parent element). +/// +/// As a "pure" container, the
element does not inherently represent anything. Instead, it's used to group content +/// so it can be easily styled using the class or id attributes, marking a section of a document as being written in a +/// different language (using the lang attribute), and so on. +/// +/// ## Usage +/// ``` +/// rsx!{ +/// div { class: "tall", id: "unique id" +/// h1 {} +/// p {} +/// } +/// } +/// +/// ``` +/// +/// ## Specifications +/// - Content categories: Flow content, palpable content. +/// - Permitted content: Flow content. +/// - Permitted parents: Any element that accepts flow content. +#[allow(non_camel_case_types)] +struct div {} + +struct h1 {} + +struct h2 {} + +trait BasicElement: Sized { + const TagName: &'static str; + fn get_bump(&self) -> &Bump; + fn new(factory: Factory) -> Self; + fn add_children(self) -> Self { + self + } + fn iter_children(self) -> Self { + self + } + fn finish(self) -> Self { + self + } +} + +impl BasicElement for div { + const TagName: &'static str = "div"; + + fn get_bump(&self) -> &Bump { + todo!() + } + + fn new(factory: Factory) -> Self { + todo!() + } +} + +impl div { + fn class(self) -> Self { + self + } + fn tag(self) -> Self { + self + } + fn r#type(self) -> Self { + self + } +} + +#[derive(Clone, Copy)] +struct Factory<'a> { + bump: &'a bumpalo::Bump, +} + +impl<'a> Factory<'a> { + fn text(&self) -> &str { + todo!() + } + fn new_el(&'a self, tag: &'static str) -> ElementBuilder<'a> { + ElementBuilder { + bump: self.bump, + tag, + } + } +} + +struct ElementBuilder<'a> { + tag: &'static str, + bump: &'a bumpalo::Bump, +} diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index 210a04c4e..4340b7eec 100644 --- a/packages/core/src/arena.rs +++ b/packages/core/src/arena.rs @@ -21,6 +21,75 @@ enum MutStatus { Mut, } +// impl ScopeArenaInner { +// pub fn new(arena: Arena) -> Self { +// ScopeArenaInner { +// arena: UnsafeCell::new(arena), +// locks: Default::default(), +// } +// } + +// /// THIS METHOD IS CURRENTLY UNSAFE +// /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS +// pub fn try_get(&self, idx: ScopeIdx) -> Result<&Scope> { +// let inner = unsafe { &*self.arena.get() }; +// let scope = inner.get(idx); +// scope.ok_or_else(|| Error::FatalInternal("Scope not found")) +// } + +// /// THIS METHOD IS CURRENTLY UNSAFE +// /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS +// pub fn try_get_mut(&self, idx: ScopeIdx) -> Result<&mut Scope> { +// let inner = unsafe { &mut *self.arena.get() }; +// let scope = inner.get_mut(idx); +// scope.ok_or_else(|| Error::FatalInternal("Scope not found")) +// } + +// fn inner(&self) -> &Arena { +// todo!() +// } + +// fn inner_mut(&mut self) -> &mut Arena { +// todo!() +// } + +// /// THIS METHOD IS CURRENTLY UNSAFE +// /// THERE ARE NO CHECKS TO VERIFY THAT WE ARE ALLOWED TO DO THIS +// pub fn with(&self, f: impl FnOnce(&mut Arena) -> T) -> Result { +// let inner = unsafe { &mut *self.arena.get() }; +// Ok(f(inner)) +// // todo!() +// } + +// pub fn with_scope<'b, O: 'static>( +// &'b self, +// id: ScopeIdx, +// f: impl FnOnce(&'b mut Scope) -> O, +// ) -> Result { +// todo!() +// } + +// // return a bumpframe with a lifetime attached to the arena borrow +// // this is useful for merging lifetimes +// pub fn with_scope_vnode<'b>( +// &self, +// id: ScopeIdx, +// f: impl FnOnce(&mut Scope) -> &VNode<'b>, +// ) -> Result<&VNode<'b>> { +// todo!() +// } + +// pub fn try_remove(&mut self, id: ScopeIdx) -> Result { +// let inner = unsafe { &mut *self.arena.get() }; +// inner +// .remove(id) +// .ok_or_else(|| Error::FatalInternal("Scope not found")) +// } + +// unsafe fn inner_unchecked<'s>() -> &'s mut Arena { +// todo!() +// } +// } impl ScopeArena { pub fn new(arena: Arena) -> Self { ScopeArena(Rc::new(RefCell::new(ScopeArenaInner { @@ -79,7 +148,7 @@ impl ScopeArena { todo!() } - pub fn try_remove(&mut self, id: ScopeIdx) -> Result { + pub fn try_remove(&self, id: ScopeIdx) -> Result { let inner = unsafe { &mut *self.0.borrow().arena.get() }; inner .remove(id) diff --git a/packages/core/src/debug_renderer.rs b/packages/core/src/debug_renderer.rs index 82eb10538..13486bb4a 100644 --- a/packages/core/src/debug_renderer.rs +++ b/packages/core/src/debug_renderer.rs @@ -38,9 +38,9 @@ impl DebugRenderer { Ok(()) } - pub fn step(&mut self, machine: &mut DiffMachine) -> Result<()> { - Ok(()) - } + // pub fn step(&mut self, machine: &mut DiffMachine) -> Result<()> { + // Ok(()) + // } // this does a "holy" compare - if something is missing in the rhs, it doesn't complain. // it only complains if something shows up that's not in the lhs, *or* if a value is different. diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 399720991..5d7265e35 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -22,13 +22,17 @@ //! More info on how to improve this diffing algorithm: //! - https://hacks.mozilla.org/2019/03/fast-bump-allocated-virtual-doms-with-rust-and-wasm/ -use crate::{arena::ScopeArena, innerlude::*}; +use crate::{ + arena::{ScopeArena, ScopeArenaInner}, + innerlude::*, +}; use fxhash::{FxHashMap, FxHashSet}; use std::{ any::Any, cell::Cell, cmp::Ordering, + marker::PhantomData, rc::{Rc, Weak}, }; @@ -42,7 +46,7 @@ use std::{ /// will receive modifications. However, instead of using child-based methods for descending through the tree, we instead /// ask the RealDom to either push or pop real nodes onto the stack. This saves us the indexing cost while working on a /// single node -pub trait RealDom { +pub trait RealDom<'a> { // Navigation fn push_root(&mut self, root: RealDomNode); @@ -55,27 +59,27 @@ pub trait RealDom { fn remove_all_children(&mut self); // Create - fn create_text_node(&mut self, text: &str) -> RealDomNode; - fn create_element(&mut self, tag: &str) -> RealDomNode; - fn create_element_ns(&mut self, tag: &str, namespace: &str) -> RealDomNode; + fn create_text_node(&mut self, text: &'a str) -> RealDomNode; + fn create_element(&mut self, tag: &'static str) -> RealDomNode; + fn create_element_ns(&mut self, tag: &'static str, namespace: &'static str) -> RealDomNode; // placeholders are nodes that don't get rendered but still exist as an "anchor" in the real dom fn create_placeholder(&mut self) -> RealDomNode; // events fn new_event_listener( &mut self, - event: &str, + event: &'static str, scope: ScopeIdx, element_id: usize, realnode: RealDomNode, ); // fn new_event_listener(&mut self, event: &str); - fn remove_event_listener(&mut self, event: &str); + fn remove_event_listener(&mut self, event: &'static str); // modify - fn set_text(&mut self, text: &str); - fn set_attribute(&mut self, name: &str, value: &str, is_namespaced: bool); - fn remove_attribute(&mut self, name: &str); + fn set_text(&mut self, text: &'a str); + fn set_attribute(&mut self, name: &'static str, value: &'a str, is_namespaced: bool); + fn remove_attribute(&mut self, name: &'static str); // node ref fn raw_node_as_any_mut(&self) -> &mut dyn Any; @@ -93,19 +97,19 @@ pub trait RealDom { /// The order of these re-entrances is stored in the DiffState itself. The DiffState comes pre-loaded with a set of components /// that were modified by the eventtrigger. This prevents doubly evaluating components if they were both updated via /// subscriptions and props changes. -pub struct DiffMachine<'a, Dom: RealDom> { - pub dom: &'a mut Dom, +pub struct DiffMachine<'real, 'bump, Dom: RealDom<'bump>> { + pub dom: &'real mut Dom, + pub components: &'bump ScopeArena, pub cur_idx: ScopeIdx, pub diffed: FxHashSet, - pub components: ScopeArena, pub event_queue: EventQueue, pub seen_nodes: FxHashSet, } -impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { +impl<'real, 'bump, Dom: RealDom<'bump>> DiffMachine<'real, 'bump, Dom> { pub fn new( - dom: &'a mut Dom, - components: ScopeArena, + dom: &'real mut Dom, + components: &'bump ScopeArena, cur_idx: ScopeIdx, event_queue: EventQueue, ) -> Self { @@ -128,8 +132,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // // The change list stack is in the same state when this function exits. // In the case of Fragments, the parent node is on the stack - pub fn diff_node(&mut self, old_node: &VNode<'a>, new_node: &VNode<'a>) { - // pub fn diff_node(&self, old: &VNode<'a>, new: &VNode<'a>) { + pub fn diff_node(&mut self, old_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>) { /* For each valid case, we "commit traversal", meaning we save this current position in the tree. Then, we diff and queue an edit event (via chagelist). s single trees - when components show up, we save that traversal and then re-enter later. @@ -326,7 +329,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // When this function returns, the new node is on top of the change list stack: // // [... node] - fn create(&mut self, node: &VNode<'a>) { + fn create(&mut self, node: &'bump VNode<'bump>) { // debug_assert!(self.dom.traversal_is_committed()); match node { VNode::Text(text) => { @@ -434,7 +437,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // yaaaaay lifetimes out of thin air // really tho, we're merging the frame lifetimes together - let inner: &'a mut _ = unsafe { &mut *self.components.0.borrow().arena.get() }; + let inner: &'bump mut _ = unsafe { &mut *self.components.0.borrow().arena.get() }; let new_component = inner.get_mut(idx).unwrap(); // Actually initialize the caller's slot with the right address @@ -467,7 +470,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { } } -impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { +impl<'a, 'bump, Dom: RealDom<'bump>> DiffMachine<'a, 'bump, Dom> { /// Destroy a scope and all of its descendents. /// /// Calling this will run the destuctors on all hooks in the tree. @@ -559,8 +562,8 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // The change list stack is left unchanged. fn diff_attr( &mut self, - old: &'a [Attribute<'a>], - new: &'a [Attribute<'a>], + old: &'bump [Attribute<'bump>], + new: &'bump [Attribute<'bump>], is_namespaced: bool, ) { // Do O(n^2) passes to add/update and remove attributes, since @@ -613,7 +616,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // [... parent] // // the change list stack is in the same state when this function returns. - fn diff_children(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) { + fn diff_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) { if new.is_empty() { if !old.is_empty() { // self.dom.commit_traversal(); @@ -693,11 +696,11 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // [... parent] // // Upon exiting, the change list stack is in the same state. - fn diff_keyed_children(&self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) { + fn diff_keyed_children(&self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) { // todo!(); if cfg!(debug_assertions) { let mut keys = fxhash::FxHashSet::default(); - let mut assert_unique_keys = |children: &'a [VNode<'a>]| { + let mut assert_unique_keys = |children: &'bump [VNode<'bump>]| { keys.clear(); for child in children { let key = child.key(); @@ -777,7 +780,11 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // [... parent] // // Upon exit, the change list stack is the same. - fn diff_keyed_prefix(&self, old: &[VNode<'a>], new: &[VNode<'a>]) -> KeyedPrefixResult { + fn diff_keyed_prefix( + &self, + old: &'bump [VNode<'bump>], + new: &'bump [VNode<'bump>], + ) -> KeyedPrefixResult { todo!() // self.dom.go_down(); // let mut shared_prefix_count = 0; @@ -831,8 +838,8 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // Upon exit from this function, it will be restored to that same state. fn diff_keyed_middle( &self, - old: &[VNode<'a>], - mut new: &[VNode<'a>], + old: &[VNode<'bump>], + mut new: &[VNode<'bump>], shared_prefix_count: usize, shared_suffix_count: usize, old_shared_suffix_start: usize, @@ -1059,8 +1066,8 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // When this function exits, the change list stack remains the same. fn diff_keyed_suffix( &self, - old: &[VNode<'a>], - new: &[VNode<'a>], + old: &[VNode<'bump>], + new: &[VNode<'bump>], new_shared_suffix_start: usize, ) { todo!() @@ -1088,7 +1095,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // [... parent] // // the change list stack is in the same state when this function returns. - fn diff_non_keyed_children(&mut self, old: &'a [VNode<'a>], new: &'a [VNode<'a>]) { + fn diff_non_keyed_children(&mut self, old: &'bump [VNode<'bump>], new: &'bump [VNode<'bump>]) { // Handled these cases in `diff_children` before calling this function. debug_assert!(!new.is_empty()); debug_assert!(!old.is_empty()); @@ -1163,7 +1170,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // [... parent] // // When this function returns, the change list stack is in the same state. - pub fn remove_all_children(&mut self, old: &[VNode<'a>]) { + pub fn remove_all_children(&mut self, old: &'bump [VNode<'bump>]) { // debug_assert!(self.dom.traversal_is_committed()); log::debug!("REMOVING CHILDREN"); for _child in old { @@ -1182,7 +1189,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // [... parent] // // When this function returns, the change list stack is in the same state. - pub fn create_and_append_children(&mut self, new: &[VNode<'a>]) { + pub fn create_and_append_children(&mut self, new: &'bump [VNode<'bump>]) { // debug_assert!(self.dom.traversal_is_committed()); for child in new { // self.create_and_append(node, parent) @@ -1200,7 +1207,7 @@ impl<'a, Dom: RealDom> DiffMachine<'a, Dom> { // After the function returns, the child is no longer on the change list stack: // // [... parent] - pub fn remove_self_and_next_siblings(&self, old: &[VNode<'a>]) { + pub fn remove_self_and_next_siblings(&self, old: &[VNode<'bump>]) { // debug_assert!(self.dom.traversal_is_committed()); for child in old { if let VNode::Component(vcomp) = child { diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 0ae0e6301..81f1d6b13 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -8,9 +8,9 @@ //! //! -pub mod util; pub mod arena; -pub mod component; // Logic for extending FC +pub mod component; +pub mod util; // Logic for extending FC pub mod debug_renderer; pub mod diff; diff --git a/packages/core/src/util.rs b/packages/core/src/util.rs index b5c4f86c5..f5f921685 100644 --- a/packages/core/src/util.rs +++ b/packages/core/src/util.rs @@ -8,7 +8,7 @@ impl DebugDom { Self { counter: 0 } } } -impl RealDom for DebugDom { +impl<'a> RealDom<'a> for DebugDom { fn push_root(&mut self, root: RealDomNode) {} fn append_child(&mut self) {} diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index d55790fb2..07e3476d4 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -196,10 +196,10 @@ impl VirtualDom { impl VirtualDom { /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch /// Currently this doesn't do what we want it to do - pub fn rebuild<'s, Dom: RealDom>(&'s mut self, realdom: &mut Dom) -> Result<()> { + pub fn rebuild<'s, Dom: RealDom<'s>>(&'s mut self, realdom: &mut Dom) -> Result<()> { let mut diff_machine = DiffMachine::new( realdom, - self.components.clone(), + &self.components, self.base_scope, self.event_queue.clone(), ); @@ -207,7 +207,6 @@ impl VirtualDom { // Schedule an update and then immediately call it on the root component // This is akin to a hook being called from a listener and requring a re-render // Instead, this is done on top-level component - let base = self.components.try_get(self.base_scope)?; let update = &base.event_channel; @@ -260,21 +259,17 @@ impl VirtualDom { // but the guarantees provide a safe, fast, and efficient abstraction for the VirtualDOM updating framework. // // A good project would be to remove all unsafe from this crate and move the unsafety into safer abstractions. - pub fn progress_with_event( - &mut self, - realdom: &mut Dom, + pub fn progress_with_event<'s, Dom: RealDom<'s>>( + &'s mut self, + realdom: &'_ mut Dom, trigger: EventTrigger, ) -> Result<()> { let id = trigger.component_id.clone(); self.components.try_get_mut(id)?.call_listener(trigger)?; - let mut diff_machine = DiffMachine::new( - realdom, - self.components.clone(), - id, - self.event_queue.clone(), - ); + let mut diff_machine = + DiffMachine::new(realdom, &self.components, id, self.event_queue.clone()); self.progress_completely(&mut diff_machine)?; @@ -285,9 +280,9 @@ impl VirtualDom { /// Only ever run each component once. /// /// The DiffMachine logs its progress as it goes which might be useful for certain types of renderers. - pub(crate) fn progress_completely<'s, Dom: RealDom>( - &'s mut self, - diff_machine: &'_ mut DiffMachine<'s, Dom>, + pub(crate) fn progress_completely<'a, 'bump, Dom: RealDom<'bump>>( + &'bump self, + diff_machine: &'_ mut DiffMachine<'a, 'bump, Dom>, ) -> Result<()> { // Add this component to the list of components that need to be difed // #[allow(unused_assignments)] diff --git a/packages/web/examples/jackjill.rs b/packages/web/examples/jackjill.rs index d01021a4e..0df2b2749 100644 --- a/packages/web/examples/jackjill.rs +++ b/packages/web/examples/jackjill.rs @@ -15,35 +15,35 @@ static Example: FC<()> = |cx| { log::debug!("Running component...."); cx.render(html! { -
-
-
- // Tagline - - "Dioxus Example: Jack and Jill" - +
+
+
+ // Tagline + + "Dioxus Example: Jack and Jill" + - // Header -

- "Hello, {name}" -

+ // Header +

+ "Hello, {name}" +

- // Control buttons -
- + // Control buttons +
+ - -
+
-
-
- }) +
+
+
+ }) }; diff --git a/packages/web/examples/jackjillrsx.rs b/packages/web/examples/jackjillrsx.rs new file mode 100644 index 000000000..eca2a930d --- /dev/null +++ b/packages/web/examples/jackjillrsx.rs @@ -0,0 +1,37 @@ +use dioxus::prelude::*; +use dioxus_core as dioxus; +use dioxus_web::WebsysRenderer; + +fn main() { + wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); + console_error_panic_hook::set_once(); + wasm_bindgen_futures::spawn_local(WebsysRenderer::start(Example)) +} + +static Example: FC<()> = |cx| { + let (name, set_name) = use_state(&cx, || "...?"); + cx.render(rsx! { + section { class: "py-12 px-4 text-center" + div { class: "w-full max-w-2xl mx-auto" + span { class: "text-sm font-semibold" + "Dioxus Example: Jack and Jill" + } + h2 { class: "text-5xl mt-2 mb-6 leading-tight font-semibold font-heading" + "Hello, {name}" + } + div { + button { + class:"inline-block py-4 px-8 m-2 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow" + onclick: move |_| set_name("jack") + "Jack!" + } + button { + class:"inline-block py-4 px-8 m-2 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow" + onclick: move |_| set_name("jill") + "Jill!" + } + } + } + } + }) +}; diff --git a/packages/webview/src/dom.rs b/packages/webview/src/dom.rs new file mode 100644 index 000000000..dd6156a3b --- /dev/null +++ b/packages/webview/src/dom.rs @@ -0,0 +1,173 @@ +//! webview dom + +use dioxus_core as dioxus; +use dioxus_core::prelude::*; +use dioxus_core::{ + diff::RealDom, + prelude::ScopeIdx, + virtual_dom::{RealDomNode, VirtualDom}, +}; +use serde::{Deserialize, Serialize}; + +fn test() { + const App: FC<()> = |cx| cx.render(rsx! { div {}}); + let mut vi = VirtualDom::new(App); + let mut real = WebviewDom { + edits: Vec::new(), + node_counter: 0, + }; + vi.rebuild(&mut real); +} + +pub struct WebviewDom<'bump> { + pub edits: Vec>, + pub node_counter: u64, +} +impl WebviewDom<'_> { + pub fn new() -> Self { + Self { + edits: Vec::new(), + node_counter: 0, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum SerializedDom<'bump> { + PushRoot { + root: u64, + }, + AppendChild, + ReplaceWith, + Remove, + RemoveAllChildren, + CreateTextNode { + text: &'bump str, + id: u64, + }, + CreateElement { + tag: &'bump str, + id: u64, + }, + CreateElementNs { + tag: &'bump str, + id: u64, + ns: &'bump str, + }, + CreatePlaceholder { + id: u64, + }, + NewEventListener { + scope: ScopeIdx, + node: u64, + idx: usize, + }, + + RemoveEventListener { + event: &'bump str, + }, + SetText { + text: &'bump str, + }, + SetAttribute { + field: &'bump str, + value: &'bump str, + }, + RemoveAttribute { + name: &'bump str, + }, +} + +use SerializedDom::*; +impl<'bump> RealDom<'bump> for WebviewDom<'bump> { + fn push_root(&mut self, root: dioxus_core::virtual_dom::RealDomNode) { + self.edits.push(PushRoot { root: root.0 }); + } + + fn append_child(&mut self) { + self.edits.push(AppendChild {}); + } + + fn replace_with(&mut self) { + self.edits.push(ReplaceWith); + } + + fn remove(&mut self) { + self.edits.push(Remove); + } + + fn remove_all_children(&mut self) { + self.edits.push(RemoveAllChildren); + } + + fn create_text_node(&mut self, text: &'bump str) -> dioxus_core::virtual_dom::RealDomNode { + self.node_counter += 1; + let id = RealDomNode::new(self.node_counter); + self.edits.push(CreateTextNode { text, id: id.0 }); + id + } + + fn create_element(&mut self, tag: &'bump str) -> dioxus_core::virtual_dom::RealDomNode { + self.node_counter += 1; + let id = RealDomNode::new(self.node_counter); + self.edits.push(CreateElement { id: id.0, tag }); + id + } + + fn create_element_ns( + &mut self, + tag: &'static str, + namespace: &'static str, + ) -> dioxus_core::virtual_dom::RealDomNode { + self.node_counter += 1; + let id = RealDomNode::new(self.node_counter); + self.edits.push(CreateElementNs { + id: id.0, + ns: namespace, + tag, + }); + id + } + + fn create_placeholder(&mut self) -> dioxus_core::virtual_dom::RealDomNode { + self.node_counter += 1; + let id = RealDomNode::new(self.node_counter); + self.edits.push(CreatePlaceholder { id: id.0 }); + id + } + + fn new_event_listener( + &mut self, + event: &str, + scope: dioxus_core::prelude::ScopeIdx, + element_id: usize, + realnode: dioxus_core::virtual_dom::RealDomNode, + ) { + self.edits.push(NewEventListener { + scope, + idx: element_id, + node: realnode.0, + }); + } + + fn remove_event_listener(&mut self, event: &'static str) { + self.edits.push(RemoveEventListener { event }); + } + + fn set_text(&mut self, text: &'bump str) { + self.edits.push(SetText { text }); + } + + fn set_attribute(&mut self, field: &'static str, value: &'bump str, is_namespaced: bool) { + self.edits.push(SetAttribute { field, value }); + } + + fn remove_attribute(&mut self, name: &'static str) { + self.edits.push(RemoveAttribute { name }); + } + + fn raw_node_as_any_mut(&self) -> &mut dyn std::any::Any { + todo!() + // self.edits.push(PushRoot { root }); + } +} diff --git a/packages/webview/src/lib.rs b/packages/webview/src/lib.rs index 61877c36e..71b090a32 100644 --- a/packages/webview/src/lib.rs +++ b/packages/webview/src/lib.rs @@ -5,6 +5,7 @@ use dioxus_core::prelude::*; use dioxus_core::virtual_dom::VirtualDom; use web_view::Handle; use web_view::{WVResult, WebView, WebViewBuilder}; +mod dom; static HTML_CONTENT: &'static str = include_str!("./../../liveview/index.html"); @@ -22,6 +23,7 @@ pub struct WebviewRenderer { /// The root component used to render the Webview root: FC, } + enum InnerEvent { Initiate(Handle<()>), } @@ -68,8 +70,10 @@ impl WebviewRenderer { .unwrap(); let mut vdom = VirtualDom::new_with_props(root, props); - let edits = vdom.rebuild()?; - let ref_edits = Arc::new(serde_json::to_string(&edits)?); + let mut real_dom = dom::WebviewDom::new(); + vdom.rebuild(&mut real_dom)?; + + let ref_edits = Arc::new(serde_json::to_string(&real_dom.edits)?); loop { view.step()