diff --git a/packages/core/src/context.rs b/packages/core/src/context.rs index 6a959f00f..0c8879eae 100644 --- a/packages/core/src/context.rs +++ b/packages/core/src/context.rs @@ -205,13 +205,13 @@ Any function prefixed with "use" should not be called conditionally. /// /// /// - pub fn use_context_provider(self, init: F) -> &'src Rc + pub fn use_provide_context(self, init: F) -> &'src Rc where T: 'static, F: FnOnce() -> T, { - let mut cxs = self.scope.shared_contexts.borrow_mut(); let ty = TypeId::of::(); + let contains_key = self.scope.shared_contexts.borrow().contains_key(&ty); let is_initialized = self.use_hook( |_| false, @@ -223,18 +223,29 @@ Any function prefixed with "use" should not be called conditionally. |_| {}, ); - match (is_initialized, cxs.contains_key(&ty)) { + match (is_initialized, contains_key) { // Do nothing, already initialized and already exists (true, true) => {} // Needs to be initialized (false, false) => { log::debug!("Initializing context..."); - cxs.insert(ty, Rc::new(init())); + let initialized = Rc::new(init()); + let p = self + .scope + .shared_contexts + .borrow_mut() + .insert(ty, initialized); + log::info!( + "There are now {} shared contexts for scope {:?}", + self.scope.shared_contexts.borrow().len(), + self.scope.our_arena_idx, + ); } _ => debug_assert!(false, "Cannot initialize two contexts of the same type"), }; + self.use_context::() } @@ -264,9 +275,17 @@ Any function prefixed with "use" should not be called conditionally. "Searching {:#?} for valid shared_context", inner.our_arena_idx ); - let shared_contexts = inner.shared_contexts.borrow(); + let shared_ctx = { + let shared_contexts = inner.shared_contexts.borrow(); - if let Some(shared_cx) = shared_contexts.get(&ty) { + log::debug!( + "This component has {} shared contexts", + shared_contexts.len() + ); + shared_contexts.get(&ty).map(|f| f.clone()) + }; + + if let Some(shared_cx) = shared_ctx { log::debug!("found matching cx"); let rc = shared_cx .clone() diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 7247ef5a4..a91a81cdc 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -50,6 +50,7 @@ use crate::{arena::SharedArena, innerlude::*, tasks::TaskQueue}; use fxhash::FxHashSet; +use smallvec::{smallvec, SmallVec}; use std::any::Any; @@ -74,7 +75,7 @@ pub struct DiffMachine<'real, 'bump, Dom: RealDom<'bump>> { pub edits: DomEditor<'real, 'bump>, pub components: &'bump SharedArena, pub task_queue: &'bump TaskQueue, - pub cur_idx: ScopeId, + pub cur_idxs: SmallVec<[ScopeId; 5]>, pub diffed: FxHashSet, pub event_queue: EventQueue, pub seen_nodes: FxHashSet, @@ -96,7 +97,7 @@ where edits: DomEditor::new(edits), components, dom, - cur_idx, + cur_idxs: smallvec![cur_idx], event_queue, task_queue, diffed: FxHashSet::default(), @@ -156,6 +157,7 @@ where log::warn!("diffing components? {:#?}", new.user_fc); if old.user_fc == new.user_fc { // Make sure we're dealing with the same component (by function pointer) + self.cur_idxs.push(old.ass_scope.get().unwrap()); // Make sure the new component vnode is referencing the right scope id let scope_id = old.ass_scope.get(); @@ -181,6 +183,7 @@ where } else { // } + self.cur_idxs.pop(); self.seen_nodes.insert(scope_id.unwrap()); } else { @@ -399,10 +402,10 @@ where log::debug!("Mounting a new component"); let caller = vcomponent.caller.clone(); - let parent_idx = self.cur_idx; + let parent_idx = self.cur_idxs.last().unwrap().clone(); // Insert a new scope into our component list - let idx = self + let new_idx = self .components .with(|components| { components.insert_with_key(|new_idx| { @@ -435,20 +438,22 @@ where // TODO: abstract this unsafe into the arena abstraction let inner: &'bump mut _ = unsafe { &mut *self.components.components.get() }; - let new_component = inner.get_mut(idx).unwrap(); + let new_component = inner.get_mut(new_idx).unwrap(); // Actually initialize the caller's slot with the right address - vcomponent.ass_scope.set(Some(idx)); + vcomponent.ass_scope.set(Some(new_idx)); // Run the scope for one iteration to initialize it new_component.run_scope().unwrap(); // TODO: we need to delete (IE relcaim this node, otherwise the arena will grow infinitely) let nextnode = new_component.next_frame(); + self.cur_idxs.push(new_idx); let meta = self.create(nextnode); + self.cur_idxs.pop(); // Finally, insert this node as a seen node. - self.seen_nodes.insert(idx); + self.seen_nodes.insert(new_idx); CreateMeta::new(vcomponent.is_static, meta.added_to_stack) } diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 07acedf1e..d6db0a637 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -533,6 +533,17 @@ impl<'a> IntoVNode<'a> for Option> { } } +impl IntoVNode<'_> for &'static str { + fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> { + NodeFactory::static_text(self) + } +} +impl IntoVNode<'_> for Arguments<'_> { + fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> { + cx.text(self) + } +} + impl Debug for NodeFactory<'_> { fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Ok(()) diff --git a/packages/desktop/src/index.html b/packages/desktop/src/index.html index 44a9f0d19..e67dee623 100644 --- a/packages/desktop/src/index.html +++ b/packages/desktop/src/index.html @@ -51,8 +51,7 @@ const node = self.stack.pop(); node.remove(); } - RemoveAllChildren(self, edit) { - } + RemoveAllChildren(self, edit) {} CreateTextNode(self, edit) { self.stack.push(document.createTextNode(edit.text)); } @@ -62,24 +61,32 @@ self.stack.push(document.createElement(tagName)); } CreateElementNs(self, edit) { + const tagName = edit.tag; + console.log(`creating namespaced element: `, edit); self.stack.push(document.createElementNS(edit.ns, edit.tag)); } CreatePlaceholder(self, edit) { const a = `self.stack.push(document.createElement("pre"))`; self.stack.push(document.createComment("vroot")); } - NewEventListener(self, edit) { - } - RemoveEventListener(self, edit) { - } + NewEventListener(self, edit) {} + RemoveEventListener(self, edit) {} SetText(self, edit) { self.top().textContent = edit.text; } SetAttribute(self, edit) { const name = edit.field; const value = edit.value; + const ns = edit.ns; + const node = self.top(self.stack); - node.setAttribute(name, value); + if (ns == "style") { + node.style[name] = value; + } else if (ns !== undefined) { + node.setAttributeNS(ns, name, value); + } else { + node.setAttribute(name, value); + } if ((name === "value", self)) { node.value = value; @@ -94,6 +101,7 @@ RemoveAttribute(self, edit) { const name = edit.field; const node = self.top(self.stack); + node.removeAttribute(name); if ((name === "value", self)) { diff --git a/packages/hooks/src/usestate.rs b/packages/hooks/src/usestate.rs index 7eecfc01d..397ed202d 100644 --- a/packages/hooks/src/usestate.rs +++ b/packages/hooks/src/usestate.rs @@ -2,13 +2,13 @@ use dioxus_core::prelude::Context; use std::{ cell::{Cell, Ref, RefCell, RefMut}, fmt::Display, - ops::{Deref, DerefMut}, + ops::{Deref, DerefMut, Not}, rc::Rc, }; /// Store state between component renders! /// -/// ## The "King" of state hooks +/// ## The "Pinnacle" of state hooks /// /// The Dioxus version of `useState` is the "king daddy" of state management. It allows you to ergonomically store and /// modify state between component renders. When the state is updated, the component will re-render. @@ -129,6 +129,10 @@ impl<'a, T: 'static> UseState<'a, T> { wip: self.inner.wip.clone(), } } + + pub fn split_for_async(&'a self) -> (&'a Self, AsyncUseState) { + (self, self.for_async()) + } } impl<'a, T: 'static + ToOwned> UseState<'a, T> { @@ -147,15 +151,15 @@ impl<'a, T: 'static + ToOwned> UseState<'a, T> { } } -impl<'a, T: 'static> std::ops::Deref for UseState<'a, T> { +impl<'a, T> std::ops::Deref for UseState<'a, T> { type Target = T; fn deref(&self) -> &Self::Target { - &self.inner.current_val + self.get() } } -use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; impl<'a, T: Copy + Add> Add for UseState<'a, T> { type Output = T; @@ -208,6 +212,18 @@ impl<'a, T: Copy + Div> DivAssign for UseState<'a, T> { self.set(self.inner.current_val.div(rhs)); } } +impl<'a, T: PartialEq> PartialEq for UseState<'a, T> { + fn eq(&self, other: &T) -> bool { + self.get() == other + } +} +impl<'a, O, T: Not + Copy> Not for UseState<'a, T> { + type Output = O; + + fn not(self) -> Self::Output { + !*self.get() + } +} // enable displaty for the handle impl<'a, T: 'static + Display> std::fmt::Display for UseState<'a, T> { @@ -233,4 +249,7 @@ impl AsyncUseState { slot.as_mut().unwrap() }) } + pub fn set(&mut self, val: T) { + *self.wip.borrow_mut() = Some(val); + } } diff --git a/packages/ssr/src/lib.rs b/packages/ssr/src/lib.rs index 68826ae54..dbae758e6 100644 --- a/packages/ssr/src/lib.rs +++ b/packages/ssr/src/lib.rs @@ -12,8 +12,8 @@ use dioxus_core::*; pub fn render_vnode(vnode: &VNode, string: &mut String) {} -pub fn render_vdom(vdom: &VirtualDom) -> String { - format!("{:}", TextRenderer::from_vdom(vdom)) +pub fn render_vdom(dom: &VirtualDom) -> String { + format!("{:}", TextRenderer::from_vdom(dom)) } pub fn render_vdom_scope(vdom: &VirtualDom, scope: ScopeId) -> Option { diff --git a/packages/web/Cargo.toml b/packages/web/Cargo.toml index e802d4a0c..9de645a68 100644 --- a/packages/web/Cargo.toml +++ b/packages/web/Cargo.toml @@ -17,7 +17,6 @@ wasm-bindgen-futures = "0.4.20" wasm-logger = "0.2.0" log = "0.4.14" fxhash = "0.2.1" -pretty_env_logger = "0.4.0" console_error_panic_hook = "0.1.6" generational-arena = "0.2.8" wasm-bindgen-test = "0.3.21" @@ -60,6 +59,8 @@ features = [ "CompositionEvent", "DocumentType", "CharacterData", + "SvgElement", + "SvgAnimatedString", "HtmlOptionElement", ] diff --git a/packages/web/src/new.rs b/packages/web/src/new.rs index fb1a3e5e6..e1138206a 100644 --- a/packages/web/src/new.rs +++ b/packages/web/src/new.rs @@ -294,8 +294,20 @@ impl WebsysDom { fn set_attribute(&mut self, name: &str, value: &str, ns: Option<&str>) { if name == "class" { - if let Some(el) = self.stack.top().dyn_ref::() { - el.set_class_name(value); + match ns { + Some("http://www.w3.org/2000/svg") => { + // + if let Some(el) = self.stack.top().dyn_ref::() { + let r: web_sys::SvgAnimatedString = el.class_name(); + r.set_base_val(value); + // el.set_class_name(value); + } + } + _ => { + if let Some(el) = self.stack.top().dyn_ref::() { + el.set_class_name(value); + } + } } } else { if let Some(el) = self.stack.top().dyn_ref::() {