diff --git a/packages/core/benches/jsframework.rs b/packages/core/benches/jsframework.rs index b9dff6bb6..294a9a952 100644 --- a/packages/core/benches/jsframework.rs +++ b/packages/core/benches/jsframework.rs @@ -45,7 +45,7 @@ fn create_rows(c: &mut Criterion) { c.bench_function("create rows", |b| { b.iter(|| { let mut dom = VirtualDom::new(App); - let g = dom.rebuild().unwrap(); + let g = dom.rebuild(); assert!(g.edits.len() > 1); }) }); diff --git a/packages/core/examples/jsframework.rs b/packages/core/examples/jsframework.rs index 84be02832..79400afd1 100644 --- a/packages/core/examples/jsframework.rs +++ b/packages/core/examples/jsframework.rs @@ -6,7 +6,7 @@ use std::fmt::Display; fn main() { let mut dom = VirtualDom::new(App); - let g = dom.rebuild().unwrap(); + let g = dom.rebuild(); assert!(g.edits.len() > 1); } diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 0702830a3..1646219aa 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -153,7 +153,7 @@ impl<'bump> DiffMachine<'bump> { /// This method implements a depth-first iterative tree traversal. /// /// We do depth-first to maintain high cache locality (nodes were originally generated recursively). - pub async fn work(&mut self) -> Result<()> { + pub async fn work(&mut self) { // defer to individual functions so the compiler produces better code // large functions tend to be difficult for the compiler to work with while let Some(instruction) = self.stack.pop() { @@ -190,8 +190,6 @@ impl<'bump> DiffMachine<'bump> { } }; } - - Ok(()) } fn mount(&mut self, and: MountType<'bump>) { diff --git a/packages/core/src/events.rs b/packages/core/src/events.rs index 6c3d7c1d0..5c56f953e 100644 --- a/packages/core/src/events.rs +++ b/packages/core/src/events.rs @@ -602,8 +602,31 @@ pub mod on { } pub trait KeyboardEventInner { + fn alt_key(&self) -> bool; + fn char_code(&self) -> u32; + /// Identify which "key" was entered. + /// + /// This is the best method to use for all languages. They key gets mapped to a String sequence which you can match on. + /// The key isn't an enum because there are just so many context-dependent keys. + /// + /// A full list on which keys to use is available at: + /// + /// + /// # Example + /// + /// ```rust + /// match event.key().as_str() { + /// "Esc" | "Escape" => {} + /// "ArrowDown" => {} + /// "ArrowLeft" => {} + /// _ => {} + /// } + /// ``` + /// + fn key(&self) -> String; + /// Get the key code as an enum Variant. /// /// This is intended for things like arrow keys, escape keys, function keys, and other non-international keys. @@ -627,35 +650,14 @@ pub mod on { /// Check if the ctrl key was pressed down fn ctrl_key(&self) -> bool; - /// Identify which "key" was entered. - /// - /// This is the best method to use for all languages. They key gets mapped to a String sequence which you can match on. - /// The key isn't an enum because there are just so many context-dependent keys. - /// - /// A full list on which keys to use is available at: - /// - /// - /// # Example - /// - /// ```rust - /// match event.key().as_str() { - /// "Esc" | "Escape" => {} - /// "ArrowDown" => {} - /// "ArrowLeft" => {} - /// _ => {} - /// } - /// ``` - /// - fn key(&self) -> String; + fn get_modifier_state(&self, key_code: &str) -> bool; - // fn key(&self) -> String; fn locale(&self) -> String; fn location(&self) -> usize; fn meta_key(&self) -> bool; fn repeat(&self) -> bool; fn shift_key(&self) -> bool; fn which(&self) -> usize; - fn get_modifier_state(&self, key_code: usize) -> bool; } pub trait FocusEventInner { diff --git a/packages/core/src/mutations.rs b/packages/core/src/mutations.rs index afefc1cf0..7b00b2fd0 100644 --- a/packages/core/src/mutations.rs +++ b/packages/core/src/mutations.rs @@ -139,8 +139,8 @@ impl<'a> Mutations<'a> { // refs are only assigned once pub struct NodeRefMutation<'a> { - element: &'a mut Option>>, - element_id: ElementId, + pub element: &'a mut Option>>, + pub element_id: ElementId, } impl<'a> std::fmt::Debug for NodeRefMutation<'a> { diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 2718aa222..5506b5f03 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -124,26 +124,12 @@ impl VirtualDom { } } - pub fn launch_in_place(root: FC<()>) -> Self { - let mut s = Self::new(root); - s.rebuild().unwrap(); - s - } - - /// Creates a new virtualdom and immediately rebuilds it in place, not caring about the RealDom to write into. - /// - pub fn launch_with_props_in_place(root: FC

, root_props: P) -> Self { - let mut s = Self::new_with_props(root, root_props); - s.rebuild().unwrap(); - s - } - pub fn base_scope(&self) -> &Scope { - unsafe { self.shared.get_scope(self.base_scope).unwrap() } + self.shared.get_scope(self.base_scope).unwrap() } pub fn get_scope(&self, id: ScopeId) -> Option<&Scope> { - unsafe { self.shared.get_scope(id) } + self.shared.get_scope(id) } /// Performs a *full* rebuild of the virtual dom, returning every edit required to generate the actual dom rom scratch @@ -152,7 +138,7 @@ impl VirtualDom { /// /// Events like garabge collection, application of refs, etc are not handled by this method and can only be progressed /// through "run". We completely avoid the task scheduler infrastructure. - pub fn rebuild<'s>(&'s mut self) -> Result> { + pub fn rebuild<'s>(&'s mut self) -> Mutations<'s> { let mut fut = self.rebuild_async().boxed_local(); loop { @@ -163,7 +149,11 @@ impl VirtualDom { } /// Rebuild the dom from the ground up - pub async fn rebuild_async<'s>(&'s mut self) -> Result> { + /// + /// This method is asynchronous to prevent the application from blocking while the dom is being rebuilt. Computing + /// the diff and creating nodes can be expensive, so we provide this method to avoid blocking the main thread. This + /// method can be useful when needing to perform some crucial periodic tasks. + pub async fn rebuild_async<'s>(&'s mut self) -> Mutations<'s> { let mut diff_machine = DiffMachine::new(Mutations::new(), self.base_scope, &self.shared); let cur_component = self @@ -176,7 +166,7 @@ impl VirtualDom { diff_machine .stack .create_node(cur_component.frames.fin_head(), MountType::Append); - diff_machine.work().await.unwrap(); + diff_machine.work().await; } else { // todo: should this be a hard error? log::warn!( @@ -185,11 +175,20 @@ impl VirtualDom { ); } - Ok(diff_machine.mutations) + diff_machine.mutations } - // diff the dom with itself - pub async fn diff_async<'s>(&'s mut self) -> Result> { + pub fn diff_sync<'s>(&'s mut self) -> Mutations<'s> { + let mut fut = self.diff_async().boxed_local(); + + loop { + if let Some(edits) = (&mut fut).now_or_never() { + break edits; + } + } + } + + pub async fn diff_async<'s>(&'s mut self) -> Mutations<'s> { let mut diff_machine = DiffMachine::new(Mutations::new(), self.base_scope, &self.shared); let cur_component = self @@ -204,15 +203,15 @@ impl VirtualDom { new: cur_component.frames.fin_head(), }); - diff_machine.work().await.unwrap(); + diff_machine.work().await; - Ok(diff_machine.mutations) + diff_machine.mutations } /// Runs the virtualdom immediately, not waiting for any suspended nodes to complete. /// /// This method will not wait for any suspended nodes to complete. - pub fn run_immediate<'s>(&'s mut self) -> Result> { + pub fn run_immediate<'s>(&'s mut self) -> Mutations<'s> { todo!() // use futures_util::FutureExt; // let mut is_ready = || false; diff --git a/packages/core/tests/create_iterative.rs b/packages/core/tests/create_iterative.rs index cbd4068a0..e6303e31e 100644 --- a/packages/core/tests/create_iterative.rs +++ b/packages/core/tests/create_iterative.rs @@ -22,7 +22,7 @@ fn test_original_diff() { }; let mut dom = VirtualDom::new(App); - let mutations = dom.rebuild().unwrap(); + let mutations = dom.rebuild(); assert_eq!( mutations.edits, [ @@ -61,7 +61,7 @@ async fn create() { test_logging::set_up_logging(LOGGING_ENABLED); let mut dom = VirtualDom::new(App); - let mutations = dom.rebuild_async().await.unwrap(); + let mutations = dom.rebuild_async().await; assert_eq!( mutations.edits, [ @@ -103,7 +103,7 @@ async fn create_list() { test_logging::set_up_logging(LOGGING_ENABLED); let mut dom = VirtualDom::new(App); - let mutations = dom.rebuild_async().await.unwrap(); + let mutations = dom.rebuild_async().await; // copilot wrote this test :P assert_eq!( @@ -146,7 +146,7 @@ async fn create_simple() { test_logging::set_up_logging(LOGGING_ENABLED); let mut dom = VirtualDom::new(App); - let mutations = dom.rebuild_async().await.unwrap(); + let mutations = dom.rebuild_async().await; // copilot wrote this test :P assert_eq!( @@ -182,7 +182,7 @@ async fn create_components() { test_logging::set_up_logging(LOGGING_ENABLED); let mut dom = VirtualDom::new(App); - let mutations = dom.rebuild_async().await.unwrap(); + let mutations = dom.rebuild_async().await; assert_eq!( mutations.edits, @@ -228,7 +228,7 @@ async fn anchors() { test_logging::set_up_logging(LOGGING_ENABLED); let mut dom = VirtualDom::new(App); - let mutations = dom.rebuild_async().await.unwrap(); + let mutations = dom.rebuild_async().await; assert_eq!( mutations.edits, [ @@ -254,7 +254,7 @@ async fn suspended() { test_logging::set_up_logging(LOGGING_ENABLED); let mut dom = VirtualDom::new(App); - let mutations = dom.rebuild_async().await.unwrap(); + let mutations = dom.rebuild_async().await; assert_eq!( mutations.edits, diff --git a/packages/core/tests/diff_iterative.rs b/packages/core/tests/diff_iterative.rs index be1c02992..e4d247031 100644 --- a/packages/core/tests/diff_iterative.rs +++ b/packages/core/tests/diff_iterative.rs @@ -40,9 +40,9 @@ async fn test_iterative_create_components() { let mut dom = VirtualDom::new(App); - let mutations = dom.rebuild_async().await.unwrap(); + let mutations = dom.rebuild_async().await; dbg!(mutations); - let mutations = dom.diff_async().await.unwrap(); + let mutations = dom.diff_async().await; dbg!(mutations); } diff --git a/packages/core/tests/eventsystem.rs b/packages/core/tests/eventsystem.rs index 919b0a447..677f9445b 100644 --- a/packages/core/tests/eventsystem.rs +++ b/packages/core/tests/eventsystem.rs @@ -14,7 +14,7 @@ async fn event_queue_works() { }; let mut dom = VirtualDom::new(App); - let edits = dom.rebuild().unwrap(); + let edits = dom.rebuild(); async_std::task::spawn_local(async move { match dom.run_unbounded().await { diff --git a/packages/core/tests/vdom_rebuild.rs b/packages/core/tests/vdom_rebuild.rs index a3c1fdb3b..3cd985f11 100644 --- a/packages/core/tests/vdom_rebuild.rs +++ b/packages/core/tests/vdom_rebuild.rs @@ -19,7 +19,7 @@ fn app_runs() { cx.render(rsx!( div{"hello"} )) }; let mut vdom = VirtualDom::new(App); - let edits = vdom.rebuild().unwrap(); + let edits = vdom.rebuild(); dbg!(edits); } @@ -32,7 +32,7 @@ fn fragments_work() { )) }; let mut vdom = VirtualDom::new(App); - let edits = vdom.rebuild().unwrap(); + let edits = vdom.rebuild(); // should result in a final "appendchildren n=2" dbg!(edits); } @@ -46,7 +46,7 @@ fn lists_work() { )) }; let mut vdom = VirtualDom::new(App); - let edits = vdom.rebuild().unwrap(); + let edits = vdom.rebuild(); dbg!(edits); } @@ -61,7 +61,7 @@ fn conditional_rendering() { }; let mut vdom = VirtualDom::new(App); - let mutations = vdom.rebuild().unwrap(); + let mutations = vdom.rebuild(); dbg!(&mutations); // the "false" fragment should generate an empty placeholder to re-visit assert!(mutations.edits[mutations.edits.len() - 2].is("CreatePlaceholder")); @@ -82,7 +82,7 @@ fn child_components() { )) }; let mut vdom = VirtualDom::new(App); - let edits = vdom.rebuild().unwrap(); + let edits = vdom.rebuild(); dbg!(edits); } @@ -94,6 +94,6 @@ fn suspended_works() { }; let mut vdom = VirtualDom::new(App); - let edits = vdom.rebuild().unwrap(); + let edits = vdom.rebuild(); dbg!(edits); } diff --git a/packages/core/tests/work_sync.rs b/packages/core/tests/work_sync.rs index ed9269bc7..ba2d785d3 100644 --- a/packages/core/tests/work_sync.rs +++ b/packages/core/tests/work_sync.rs @@ -22,7 +22,7 @@ fn worksync() { let mutations = loop { let g = (&mut fut).now_or_never(); if g.is_some() { - break g.unwrap().unwrap(); + break g.unwrap(); } }; diff --git a/packages/ssr/examples/basic.rs b/packages/ssr/examples/basic.rs index b3bfb6ca5..ece077759 100644 --- a/packages/ssr/examples/basic.rs +++ b/packages/ssr/examples/basic.rs @@ -5,7 +5,7 @@ use dioxus_html as dioxus_elements; fn main() { let mut dom = VirtualDom::new(App); - dom.rebuild().unwrap(); + dom.rebuild(); println!( "{}", dioxus_ssr::render_vdom(&dom, |c| c.newline(true).indent(true)) diff --git a/packages/ssr/examples/tide.rs b/packages/ssr/examples/tide.rs index 26f742bcf..9fc58d2be 100644 --- a/packages/ssr/examples/tide.rs +++ b/packages/ssr/examples/tide.rs @@ -19,7 +19,9 @@ async fn main() -> Result<(), std::io::Error> { .map(|f| f.parse().unwrap_or("...?".to_string())) .unwrap_or("...?".to_string()); - let dom = VirtualDom::launch_with_props_in_place(Example, ExampleProps { initial_name }); + let mut dom = VirtualDom::new_with_props(Example, ExampleProps { initial_name }); + + dom.rebuild(); Ok(Response::builder(200) .body(format!("{}", dioxus_ssr::render_vdom(&dom, |c| c))) diff --git a/packages/ssr/examples/tofile.rs b/packages/ssr/examples/tofile.rs index 09b710486..ec72532d0 100644 --- a/packages/ssr/examples/tofile.rs +++ b/packages/ssr/examples/tofile.rs @@ -13,7 +13,8 @@ fn main() { let mut file = File::create("example.html").unwrap(); let mut dom = VirtualDom::new(App); - dom.rebuild().expect("failed to run virtualdom"); + + dom.rebuild(); file.write_fmt(format_args!( "{}", diff --git a/packages/ssr/src/lib.rs b/packages/ssr/src/lib.rs index 866acf0a9..00c028cd1 100644 --- a/packages/ssr/src/lib.rs +++ b/packages/ssr/src/lib.rs @@ -286,28 +286,28 @@ mod tests { #[test] fn to_string_works() { let mut dom = VirtualDom::new(SIMPLE_APP); - dom.rebuild().expect("failed to run virtualdom"); + dom.rebuild(); dbg!(render_vdom(&dom, |c| c)); } #[test] fn hydration() { let mut dom = VirtualDom::new(NESTED_APP); - dom.rebuild().expect("failed to run virtualdom"); + dom.rebuild(); dbg!(render_vdom(&dom, |c| c.pre_render(true))); } #[test] fn nested() { let mut dom = VirtualDom::new(NESTED_APP); - dom.rebuild().expect("failed to run virtualdom"); + dom.rebuild(); dbg!(render_vdom(&dom, |c| c)); } #[test] fn fragment_app() { let mut dom = VirtualDom::new(FRAGMENT_APP); - dom.rebuild().expect("failed to run virtualdom"); + dom.rebuild(); dbg!(render_vdom(&dom, |c| c)); } @@ -319,7 +319,7 @@ mod tests { let mut file = File::create("index.html").unwrap(); let mut dom = VirtualDom::new(SLIGHTLY_MORE_COMPLEX); - dom.rebuild().expect("failed to run virtualdom"); + dom.rebuild(); file.write_fmt(format_args!( "{}", @@ -337,7 +337,7 @@ mod tests { }; let mut dom = VirtualDom::new(STLYE_APP); - dom.rebuild().expect("failed to run virtualdom"); + dom.rebuild(); dbg!(render_vdom(&dom, |c| c)); } } diff --git a/packages/web/examples/basic.rs b/packages/web/examples/basic.rs index 35d82daae..0fbecec7c 100644 --- a/packages/web/examples/basic.rs +++ b/packages/web/examples/basic.rs @@ -1,19 +1,17 @@ //! Basic example that renders a simple VNode to the browser. +// all these imports are done automatically with the `dioxus` crate and `prelude` +// need to do them manually for this example use dioxus::events::on::MouseEvent; use dioxus_core as dioxus; use dioxus_core::prelude::*; use dioxus_hooks::*; use dioxus_html as dioxus_elements; -// use wasm_timer; - -use std::future::Future; - -use std::{pin::Pin, time::Duration}; use dioxus::prelude::*; - use dioxus_web::*; +use std::future::Future; +use std::{pin::Pin, time::Duration}; fn main() { // Setup logging @@ -21,17 +19,33 @@ fn main() { console_error_panic_hook::set_once(); // Run the app - dioxus_web::launch(App, |c| c) + dioxus_web::launch(APP, |c| c) } -static App: FC<()> = |cx| { +static APP: FC<()> = |cx| { let mut count = use_state(cx, || 3); cx.render(rsx! { div { - button { - "add" - onclick: move |_| count += 1 + button { onclick: move |_| count += 1, "add" } + div { + div { + div { + div { + div { + Fragment { + a {"wo"} + p {"wo"} + li {"wo"} + em {"wo"} + } + } + } + Child {} + } + Child {} + } + Child {} } ul { {(0..*count).map(|f| rsx!{ @@ -43,3 +57,15 @@ static App: FC<()> = |cx| { } }) }; + +static Child: FC<()> = |cx| { + cx.render(rsx! { + div { + div { + div { + "hello child" + } + } + } + }) +}; diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index 8d06a6f5f..d36e6e2d8 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -2,6 +2,7 @@ use std::{collections::HashMap, rc::Rc, sync::Arc}; use dioxus_core::{ events::{EventTrigger, VirtualEvent}, + mutations::NodeRefMutation, DomEdit, ElementId, ScopeId, }; use fxhash::FxHashMap; @@ -77,6 +78,18 @@ impl WebsysDom { } } + pub fn apply_refs(&mut self, refs: &[NodeRefMutation]) { + for item in refs { + if let Some(bla) = &item.element { + let node = self.nodes[item.element_id.as_u64() as usize] + .as_ref() + .unwrap() + .clone(); + bla.set(Box::new(node)).unwrap(); + } + } + } + pub fn process_edits(&mut self, edits: &mut Vec) { for edit in edits.drain(..) { log::info!("Handling edit: {:#?}", edit); @@ -92,12 +105,13 @@ impl WebsysDom { DomEdit::CreateElementNs { tag, id, ns } => self.create_element(tag, Some(ns), id), DomEdit::CreatePlaceholder { id } => self.create_placeholder(id), DomEdit::NewEventListener { - event_name: event, + event_name, scope, - mounted_node_id: node, - } => self.new_event_listener(event, scope, node), + mounted_node_id, + } => self.new_event_listener(event_name, scope, mounted_node_id), DomEdit::RemoveEventListener { event } => todo!(), + DomEdit::SetText { text } => self.set_text(text), DomEdit::SetAttribute { field, value, ns } => self.set_attribute(field, value, ns), DomEdit::RemoveAttribute { name } => self.remove_attribute(name), @@ -118,6 +132,7 @@ impl WebsysDom { self.stack.push(real_node); } + // drop the node off the stack fn pop(&mut self) { self.stack.pop(); @@ -154,44 +169,21 @@ impl WebsysDom { } fn replace_with(&mut self, m: u32, root: u64) { - let mut new_nodes = vec![]; - for _ in 0..m { - new_nodes.push(self.stack.pop()); - } - let old = self.nodes[root as usize].as_ref().unwrap(); - let arr: js_sys::Array = new_nodes.iter().collect(); - let el = old.dyn_ref::().unwrap(); - el.replace_with_with_node(&arr).unwrap(); - // let arr = js_sys::Array::from(); + let arr: js_sys::Array = self + .stack + .list + .drain((self.stack.list.len() - m as usize)..) + .collect(); - // TODO: use different-sized replace withs - // if m == 1 { - // if old_node.has_type::() { - // old_node - // .dyn_ref::() - // .unwrap() - // .replace_with_with_node_1(&new_node) - // .unwrap(); - // } else if old_node.has_type::() { - // old_node - // .dyn_ref::() - // .unwrap() - // .replace_with_with_node_1(&new_node) - // .unwrap(); - // } else if old_node.has_type::() { - // old_node - // .dyn_ref::() - // .unwrap() - // .replace_with_with_node_1(&new_node) - // .unwrap(); - // } else { - // panic!("Cannot replace node: {:?}", old_node); - // } - // } - - // self.stack.push(new_node); + if let Some(el) = old.dyn_ref::() { + el.replace_with_with_node(&arr).unwrap(); + } else if let Some(el) = old.dyn_ref::() { + el.replace_with_with_node(&arr).unwrap(); + } else if let Some(el) = old.dyn_ref::() { + el.replace_with_with_node(&arr).unwrap(); + } } fn remove(&mut self, root: u64) { @@ -213,22 +205,22 @@ impl WebsysDom { self.create_element("pre", None, id); self.set_attribute("hidden", "", None); } - fn create_text_node(&mut self, text: &str, id: u64) { - // let nid = self.node_counter.next(); + fn create_text_node(&mut self, text: &str, id: u64) { let textnode = self .document .create_text_node(text) .dyn_into::() .unwrap(); - let id = id as usize; self.stack.push(textnode.clone()); - self.nodes[id] = Some(textnode); + + self.nodes[(id as usize)] = Some(textnode); } fn create_element(&mut self, tag: &str, ns: Option<&'static str>, id: u64) { let tag = wasm_bindgen::intern(tag); + let el = match ns { Some(ns) => self .document @@ -243,17 +235,12 @@ impl WebsysDom { .dyn_into::() .unwrap(), }; - let id = id as usize; self.stack.push(el.clone()); - self.nodes[id] = Some(el); - // let nid = self.node_counter.?next(); - // let nid = self.nodes.insert(el).data().as_ffi(); - // ElementId::new(nid) + self.nodes[(id as usize)] = Some(el); } fn new_event_listener(&mut self, event: &'static str, scope: ScopeId, real_id: u64) { - // let (_on, event) = event.split_at(2); let event = wasm_bindgen::intern(event); // attach the correct attributes to the element @@ -313,7 +300,8 @@ impl WebsysDom { } fn set_attribute(&mut self, name: &str, value: &str, ns: Option<&str>) { - if let Some(el) = self.stack.top().dyn_ref::() { + let node = self.stack.top(); + if let Some(el) = node.dyn_ref::() { match ns { // inline style support Some("style") => { @@ -323,11 +311,20 @@ impl WebsysDom { } _ => el.set_attribute(name, value).unwrap(), } - match name { - "value" => {} - "checked" => {} - "selected" => {} - _ => {} + } + + if let Some(node) = node.dyn_ref::() { + if name == "value" { + node.set_value(value); + } + if name == "checked" { + node.set_checked(true); + } + } + + if let Some(node) = node.dyn_ref::() { + if name == "selected" { + node.set_selected(true); } } } @@ -355,35 +352,50 @@ impl WebsysDom { } fn insert_after(&mut self, n: u32, root: u64) { - let mut new_nodes = vec![]; - for _ in 0..n { - new_nodes.push(self.stack.pop()); + let old = self.nodes[root as usize].as_ref().unwrap(); + + let arr: js_sys::Array = self + .stack + .list + .drain((self.stack.list.len() - n as usize)..) + .collect(); + + if let Some(el) = old.dyn_ref::() { + el.after_with_node(&arr).unwrap(); + } else if let Some(el) = old.dyn_ref::() { + el.after_with_node(&arr).unwrap(); + } else if let Some(el) = old.dyn_ref::() { + el.after_with_node(&arr).unwrap(); } - - let after = self.stack.top().clone(); - let arr: js_sys::Array = new_nodes.iter().collect(); - - let el = after.dyn_into::().unwrap(); - el.after_with_node(&arr).unwrap(); - // let mut old_nodes = vec![]; - // for _ in 0..n { - // old_nodes.push(self.stack.pop()); - // } - - // let el = self.stack.top(); } fn insert_before(&mut self, n: u32, root: u64) { - let n = n as usize; - let root = self - .stack - .list - .get(self.stack.list.len() - n) - .unwrap() - .clone(); - for _ in 0..n { - let el = self.stack.pop(); - root.insert_before(&el, None).unwrap(); + let after = self.nodes[root as usize].as_ref().unwrap(); + + if n == 1 { + let before = self.stack.pop(); + + after + .parent_node() + .unwrap() + .insert_before(&before, Some(&after)) + .unwrap(); + + after.insert_before(&before, None).unwrap(); + } else { + let arr: js_sys::Array = self + .stack + .list + .drain((self.stack.list.len() - n as usize)..) + .collect(); + + if let Some(el) = after.dyn_ref::() { + el.before_with_node(&arr).unwrap(); + } else if let Some(el) = after.dyn_ref::() { + el.before_with_node(&arr).unwrap(); + } else if let Some(el) = after.dyn_ref::() { + el.before_with_node(&arr).unwrap(); + } } } } @@ -447,46 +459,50 @@ fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent { "keydown" | "keypress" | "keyup" => { struct Event(web_sys::KeyboardEvent); impl KeyboardEventInner for Event { + fn alt_key(&self) -> bool { + self.0.alt_key() + } fn char_code(&self) -> u32 { - todo!() + self.0.char_code() } - fn key_code(&self) -> KeyCode { - todo!() - } - fn ctrl_key(&self) -> bool { - todo!() + fn key(&self) -> String { + self.0.key() } - fn key(&self) -> String { - todo!() + fn key_code(&self) -> KeyCode { + KeyCode::from_raw_code(self.0.key_code() as u8) + } + + fn ctrl_key(&self) -> bool { + self.0.ctrl_key() + } + + fn get_modifier_state(&self, key_code: &str) -> bool { + self.0.get_modifier_state(key_code) } fn locale(&self) -> String { - todo!() + todo!("Locale is currently not supported. :(") } fn location(&self) -> usize { - todo!() + self.0.location() as usize } fn meta_key(&self) -> bool { - todo!() + self.0.meta_key() } fn repeat(&self) -> bool { - todo!() + self.0.repeat() } fn shift_key(&self) -> bool { - todo!() + self.0.shift_key() } fn which(&self) -> usize { - todo!() - } - - fn get_modifier_state(&self, key_code: usize) -> bool { - todo!() + self.0.which() as usize } } let evt: web_sys::KeyboardEvent = event.clone().dyn_into().unwrap(); diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index 2adfb6b1c..aa482b294 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -137,7 +137,7 @@ pub async fn run_with_props( let mut websys_dom = dom::WebsysDom::new(root_el, cfg, sender_callback); - let mut mutations = dom.rebuild().unwrap(); + let mut mutations = dom.rebuild(); log::info!("Mutations: {:#?}", mutations); // hydrating is simply running the dom for a single render. If the page is already written, then the corresponding