diff --git a/packages/desktop/headless_tests/utils.rs b/packages/desktop/headless_tests/utils.rs index d8bd3fb2d..343e76467 100644 --- a/packages/desktop/headless_tests/utils.rs +++ b/packages/desktop/headless_tests/utils.rs @@ -1,3 +1,5 @@ +#![allow(unused)] // for whatever reason, the compiler is not recognizing the use of these functions + use dioxus::prelude::*; use dioxus_core::Element; diff --git a/packages/desktop/js/prevent_file_upload.js b/packages/desktop/js/prevent_file_upload.js index 73b2e7794..935415178 100644 --- a/packages/desktop/js/prevent_file_upload.js +++ b/packages/desktop/js/prevent_file_upload.js @@ -11,7 +11,7 @@ let target_id = find_real_id(target); if (target_id !== null) { const send = (event_name) => { - const message = window.interpreter.serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), directory: target.getAttribute("webkitdirectory") === "true", multiple: target.hasAttribute("multiple"), target: parseInt(target_id), bubbles: event_bubbles(event_name), event: event_name }); + const message = window.interpreter.serializeIpcMessage("file_dialog", { accept: target.getAttribute("accept"), directory: target.getAttribute("webkitdirectory") === "true", multiple: target.hasAttribute("multiple"), target: parseInt(target_id), bubbles: event_bubbles(event_name), event: event_name }); window.ipc.postMessage(message); }; send("change&input"); diff --git a/packages/desktop/src/ipc.rs b/packages/desktop/src/ipc.rs index c8810c63a..464b80423 100644 --- a/packages/desktop/src/ipc.rs +++ b/packages/desktop/src/ipc.rs @@ -49,7 +49,7 @@ impl IpcMessage { pub(crate) fn method(&self) -> IpcMethod { match self.method.as_str() { // todo: this is a misspelling, needs to be fixed - "file_diolog" => IpcMethod::FileDialog, + "file_dialog" => IpcMethod::FileDialog, "user_event" => IpcMethod::UserEvent, "query" => IpcMethod::Query, "browser_open" => IpcMethod::BrowserOpen, diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index ba349f61c..033d44fbd 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -1,5 +1,5 @@ use crate::{assets::*, edits::EditQueue}; -use dioxus_interpreter_js::unified_bindings::{native_js, SLEDGEHAMMER_JS}; +use dioxus_interpreter_js::unified_bindings::native_js; use std::path::{Path, PathBuf}; use wry::{ http::{status::StatusCode, Request, Response}, diff --git a/packages/interpreter/src/js/hash.txt b/packages/interpreter/src/js/hash.txt index 134f6fe87..a6b01b52c 100644 --- a/packages/interpreter/src/js/hash.txt +++ b/packages/interpreter/src/js/hash.txt @@ -1 +1 @@ -4429706825984325407 \ No newline at end of file +3599957386864841107 \ No newline at end of file diff --git a/packages/interpreter/src/js/native.js b/packages/interpreter/src/js/native.js index 7a03ae59f..20ab039a9 100644 --- a/packages/interpreter/src/js/native.js +++ b/packages/interpreter/src/js/native.js @@ -11,13 +11,16 @@ class Interpreter { this.handler = handler; this.initialize(root); } - initialize(root) { + initialize(root, handler = null) { this.global = {}; this.local = {}; this.root = root; this.nodes = [root]; this.stack = [root]; this.templates = {}; + if (handler) { + this.handler = handler; + } } createListener(event_name, element, bubbles) { if (bubbles) { diff --git a/packages/interpreter/src/js/web.js b/packages/interpreter/src/js/web.js index 77bc50da9..1de671893 100644 --- a/packages/interpreter/src/js/web.js +++ b/packages/interpreter/src/js/web.js @@ -11,13 +11,16 @@ class Interpreter { this.handler = handler; this.initialize(root); } - initialize(root) { + initialize(root, handler = null) { this.global = {}; this.local = {}; this.root = root; this.nodes = [root]; this.stack = [root]; this.templates = {}; + if (handler) { + this.handler = handler; + } } createListener(event_name, element, bubbles) { if (bubbles) { @@ -73,6 +76,86 @@ class Interpreter { } } +// src/ts/set_attribute.ts +function setAttributeInner(node, field, value, ns) { + if (ns === "style") { + node.style.setProperty(field, value); + return; + } + if (!!ns) { + node.setAttributeNS(ns, field, value); + return; + } + switch (field) { + case "value": + if (node.value !== value) { + node.value = value; + } + break; + case "initial_value": + node.defaultValue = value; + break; + case "checked": + node.checked = truthy(value); + break; + case "initial_checked": + node.defaultChecked = truthy(value); + break; + case "selected": + node.selected = truthy(value); + break; + case "initial_selected": + node.defaultSelected = truthy(value); + break; + case "dangerous_inner_html": + node.innerHTML = value; + break; + default: + if (!truthy(value) && isBoolAttr(field)) { + node.removeAttribute(field); + } else { + node.setAttribute(field, value); + } + } +} +var truthy = function(val) { + return val === "true" || val === true; +}; +var isBoolAttr = function(field) { + switch (field) { + case "allowfullscreen": + case "allowpaymentrequest": + case "async": + case "autofocus": + case "autoplay": + case "checked": + case "controls": + case "default": + case "defer": + case "disabled": + case "formnovalidate": + case "hidden": + case "ismap": + case "itemscope": + case "loop": + case "multiple": + case "muted": + case "nomodule": + case "novalidate": + case "open": + case "playsinline": + case "readonly": + case "required": + case "reversed": + case "selected": + case "truespeed": + case "webkitdirectory": + return true; + default: + return false; + } +}; + // src/ts/interpreter_web.ts class PlatformInterpreter extends Interpreter { m; @@ -126,5 +209,6 @@ class PlatformInterpreter extends Interpreter { } } export { + setAttributeInner, PlatformInterpreter }; diff --git a/packages/interpreter/src/lib.rs b/packages/interpreter/src/lib.rs index d7112aec2..1db7cda86 100644 --- a/packages/interpreter/src/lib.rs +++ b/packages/interpreter/src/lib.rs @@ -11,6 +11,12 @@ mod write_native_mutations; #[cfg(all(feature = "binary-protocol", feature = "sledgehammer"))] pub use write_native_mutations::*; +#[cfg(feature = "sledgehammer")] +pub mod unified_bindings; + +#[cfg(feature = "sledgehammer")] +pub use unified_bindings::*; + // Common bindings for minimal usage. #[cfg(all(feature = "minimal_bindings", feature = "webonly"))] pub mod minimal_bindings { @@ -28,9 +34,3 @@ pub mod minimal_bindings { pub fn collectFormValues(node: JsValue) -> JsValue; } } - -#[cfg(feature = "sledgehammer")] -pub mod unified_bindings; - -#[cfg(feature = "sledgehammer")] -pub use unified_bindings::*; diff --git a/packages/interpreter/src/ts/interpreter_core.ts b/packages/interpreter/src/ts/interpreter_core.ts index ade777fb7..11b0c83f8 100644 --- a/packages/interpreter/src/ts/interpreter_core.ts +++ b/packages/interpreter/src/ts/interpreter_core.ts @@ -28,7 +28,7 @@ export class Interpreter { this.initialize(root); } - initialize(root: HTMLElement) { + initialize(root: HTMLElement, handler: EventListener | null = null) { this.global = {}; this.local = {}; this.root = root; @@ -36,6 +36,10 @@ export class Interpreter { this.nodes = [root]; this.stack = [root]; this.templates = {}; + + if (handler) { + this.handler = handler; + } } createListener(event_name: string, element: HTMLElement, bubbles: boolean) { diff --git a/packages/interpreter/src/ts/interpreter_web.ts b/packages/interpreter/src/ts/interpreter_web.ts index 3f4eade17..86f195446 100644 --- a/packages/interpreter/src/ts/interpreter_web.ts +++ b/packages/interpreter/src/ts/interpreter_web.ts @@ -5,6 +5,7 @@ // We're using sledgehammer directly import { Interpreter } from "./interpreter_core"; +export { setAttributeInner } from "./set_attribute"; export class PlatformInterpreter extends Interpreter { m: any; diff --git a/packages/interpreter/src/unified_bindings.rs b/packages/interpreter/src/unified_bindings.rs index 36e28b5b9..d1e3b2b0d 100644 --- a/packages/interpreter/src/unified_bindings.rs +++ b/packages/interpreter/src/unified_bindings.rs @@ -6,40 +6,13 @@ use wasm_bindgen::prelude::wasm_bindgen; use sledgehammer_bindgen::bindgen; +/// Combine the interpreter class with the sledgehammer_bindgen generated methods. pub fn native_js() -> String { format!("{}\n{}", include_str!("./js/native.js"), GENERATED_JS,) } pub const SLEDGEHAMMER_JS: &str = GENERATED_JS; -/// Extensions to the interpreter that are specific to the web platform. -#[cfg(feature = "webonly")] -#[wasm_bindgen(module = "src/js/web.js")] -extern "C" { - pub type WebInterpreter; - - #[wasm_bindgen(method, js_name = "saveTemplate")] - pub fn save_template(this: &WebInterpreter, nodes: Vec, tmpl_id: u16); - - #[wasm_bindgen(method)] - pub fn hydrate(this: &WebInterpreter, ids: Vec); - - #[wasm_bindgen(method, js_name = "getNode")] - pub fn get_node(this: &WebInterpreter, id: u32) -> Node; -} - -#[cfg(feature = "webonly")] -type PlatformInterpreter = WebInterpreter; - -#[cfg(feature = "webonly")] -impl Interpreter { - /// Convert the interpreter to a web interpreter, enabling methods like hydrate and save_template. - pub fn as_web(&self) -> &WebInterpreter { - use wasm_bindgen::prelude::JsCast; - &self.js_channel().unchecked_ref() - } -} - #[bindgen(module)] mod js { /// The interpreter extends the core interpreter which contains the state for the interpreter along with some functions that all platforms use like `AppendChildren`. @@ -222,3 +195,34 @@ mod js { "{this.els = this.stack.splice(this.stack.length - $n$); let node = this.LoadChild($array$); node.replaceWith(...this.els);}" } } + +/// Extensions to the interpreter that are specific to the web platform. +#[cfg(feature = "webonly")] +#[wasm_bindgen(module = "src/js/web.js")] +extern "C" { + pub type WebInterpreter; + + #[wasm_bindgen(method)] + pub fn initialize(this: &WebInterpreter, root: Node, handler: &js_sys::Function); + + #[wasm_bindgen(method, js_name = "saveTemplate")] + pub fn save_template(this: &WebInterpreter, nodes: Vec, tmpl_id: u16); + + #[wasm_bindgen(method)] + pub fn hydrate(this: &WebInterpreter, ids: Vec); + + #[wasm_bindgen(method, js_name = "getNode")] + pub fn get_node(this: &WebInterpreter, id: u32) -> Node; +} + +#[cfg(feature = "webonly")] +type PlatformInterpreter = WebInterpreter; + +#[cfg(feature = "webonly")] +impl Interpreter { + /// Convert the interpreter to a web interpreter, enabling methods like hydrate and save_template. + pub fn as_web(&self) -> &WebInterpreter { + use wasm_bindgen::prelude::JsCast; + &self.js_channel().unchecked_ref() + } +} diff --git a/packages/interpreter/tsconfig.native.json b/packages/interpreter/tsconfig.native.json deleted file mode 100644 index 57feec085..000000000 --- a/packages/interpreter/tsconfig.native.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - // extends the base - "extends": "./tsconfig.json", - "compilerOptions": { - "outFile": "src/js/native.js" - }, - "files": [ - "src/ts/interpreter_native.ts" - ], -} diff --git a/packages/interpreter/tsconfig.web.json b/packages/interpreter/tsconfig.web.json deleted file mode 100644 index ac1961b32..000000000 --- a/packages/interpreter/tsconfig.web.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - // extends the base - "extends": "./tsconfig.json", - "compilerOptions": { - "outFile": "src/js/web.js" - }, - "files": [ - "src/ts/interpreter_web.ts" - ], -} diff --git a/packages/liveview/src/lib.rs b/packages/liveview/src/lib.rs index 9ed7b85e8..121f0245c 100644 --- a/packages/liveview/src/lib.rs +++ b/packages/liveview/src/lib.rs @@ -31,7 +31,7 @@ pub enum LiveViewError { } fn handle_edits_code() -> String { - use dioxus_interpreter_js::binary_protocol::SLEDGEHAMMER_JS; + use dioxus_interpreter_js::unified_bindings::SLEDGEHAMMER_JS; use minify_js::{minify, Session, TopLevelMode}; let serialize_file_uploads = r#"if ( diff --git a/packages/plasmo/src/hooks.rs b/packages/plasmo/src/hooks.rs index 81f6558b6..0c0ca1c21 100644 --- a/packages/plasmo/src/hooks.rs +++ b/packages/plasmo/src/hooks.rs @@ -18,7 +18,6 @@ use dioxus_html::input_data::keyboard_types::{Code, Key, Location, Modifiers}; use dioxus_html::input_data::{ MouseButton as DioxusMouseButton, MouseButtonSet as DioxusMouseButtons, }; -use dioxus_html::FormValue; use dioxus_html::{event_bubbles, prelude::*}; use std::any::Any; use std::collections::HashMap; @@ -67,7 +66,7 @@ impl EventData { pub struct FormData { pub(crate) value: String, - pub values: HashMap, + pub values: HashMap, pub(crate) files: Option, } @@ -77,7 +76,7 @@ impl HasFormData for FormData { self.value.clone() } - fn values(&self) -> HashMap { + fn values(&self) -> HashMap { self.values.clone() } diff --git a/packages/web/ric_raf/README.md b/packages/web/ric_raf/README.md new file mode 100644 index 000000000..a1bc20e82 --- /dev/null +++ b/packages/web/ric_raf/README.md @@ -0,0 +1,3 @@ +requestIdleCallback and requestAnimationFrame implemenation + +These currently actually slow down our DOM patching and thus are temporarily removed. Technically we can schedule around rIC and rAF but choose not to. diff --git a/packages/web/src/ric_raf.rs b/packages/web/ric_raf/ric_raf.rs similarity index 100% rename from packages/web/src/ric_raf.rs rename to packages/web/ric_raf/ric_raf.rs diff --git a/packages/web/src/ricpolyfill.js b/packages/web/ric_raf/ricpolyfill.js similarity index 100% rename from packages/web/src/ricpolyfill.js rename to packages/web/ric_raf/ricpolyfill.js diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index f6add78a4..ab5521053 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -8,7 +8,7 @@ use dioxus_core::ElementId; use dioxus_html::PlatformEventData; -use dioxus_interpreter_js::unified_bindings::{Interpreter, InterpreterInterface}; +use dioxus_interpreter_js::{unified_bindings::Interpreter, WebInterpreter}; use futures_channel::mpsc; use rustc_hash::FxHashMap; use wasm_bindgen::{closure::Closure, JsCast}; @@ -17,14 +17,16 @@ use web_sys::{Document, Element, Event}; use crate::{load_document, virtual_event_from_websys_event, Config, WebEventConverter}; pub struct WebsysDom { - pub(crate) document: Document, #[allow(dead_code)] pub(crate) root: Element, + pub(crate) document: Document, pub(crate) templates: FxHashMap, pub(crate) max_template_id: u16, - pub(crate) interpreter: InterpreterInterface, + pub(crate) interpreter: Interpreter, + #[cfg(feature = "mounted")] pub(crate) event_channel: mpsc::UnboundedSender, + #[cfg(feature = "mounted")] pub(crate) queued_mounted_events: Vec, } @@ -64,7 +66,7 @@ impl WebsysDom { } }; - let interpreter = InterpreterInterface::default(); + let interpreter = Interpreter::default(); let handler: Closure = Closure::wrap(Box::new({ let event_channel = event_channel.clone(); @@ -72,42 +74,45 @@ impl WebsysDom { let name = event.type_(); let element = walk_event_for_id(event); let bubbles = dioxus_html::event_bubbles(name.as_str()); - if let Some((element, target)) = element { - let prevent_event; - if let Some(prevent_requests) = target - .get_attribute("dioxus-prevent-default") - .as_deref() - .map(|f| f.split_whitespace()) - { - prevent_event = prevent_requests - .map(|f| f.trim_start_matches("on")) - .any(|f| f == name); - } else { - prevent_event = false; - } - // Prevent forms from submitting and redirecting - if name == "submit" { - // On forms the default behavior is not to submit, if prevent default is set then we submit the form - if !prevent_event { - event.prevent_default(); - } - } else if prevent_event { + let Some((element, target)) = element else { + return; + }; + + let prevent_event; + if let Some(prevent_requests) = target + .get_attribute("dioxus-prevent-default") + .as_deref() + .map(|f| f.split_whitespace()) + { + prevent_event = prevent_requests + .map(|f| f.trim_start_matches("on")) + .any(|f| f == name); + } else { + prevent_event = false; + } + + // Prevent forms from submitting and redirecting + if name == "submit" { + // On forms the default behavior is not to submit, if prevent default is set then we submit the form + if !prevent_event { event.prevent_default(); } - - let data = virtual_event_from_websys_event(event.clone(), target); - let _ = event_channel.unbounded_send(UiEvent { - name, - bubbles, - element, - data, - }); + } else if prevent_event { + event.prevent_default(); } + + let data = virtual_event_from_websys_event(event.clone(), target); + let _ = event_channel.unbounded_send(UiEvent { + name, + bubbles, + element, + data, + }); } })); - let _interpreter: &Interpreter = interpreter.as_ref(); + let _interpreter: &WebInterpreter = interpreter.as_web(); _interpreter.initialize( root.clone().unchecked_into(), handler.as_ref().unchecked_ref(), diff --git a/packages/web/src/event.rs b/packages/web/src/event.rs index f68487925..1765fd38a 100644 --- a/packages/web/src/event.rs +++ b/packages/web/src/event.rs @@ -4,7 +4,6 @@ use dioxus_html::{ point_interaction::{ InteractionElementOffset, InteractionLocation, ModifiersInteraction, PointerInteraction, }, - prelude::FormValue, DragData, FileEngine, FormData, HasDragData, HasFileData, HasFormData, HasImageData, HasMouseData, HtmlEventConverter, ImageData, MountedData, PlatformEventData, ScrollData, }; @@ -385,24 +384,14 @@ impl HasFormData for WebFormData { .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener") } - fn values(&self) -> HashMap { + fn values(&self) -> HashMap { let mut values = HashMap::new(); - fn insert_value(map: &mut HashMap, key: String, new_value: String) { - match map.entry(key) { - std::collections::hash_map::Entry::Occupied(mut o) => { - let first_value = match o.get_mut() { - FormValue::Text(data) => std::mem::take(data), - FormValue::VecText(vec) => { - vec.push(new_value); - return; - } - }; - let _ = o.insert(FormValue::VecText(vec![first_value, new_value])); - } - std::collections::hash_map::Entry::Vacant(v) => { - let _ = v.insert(FormValue::Text(new_value)); - } + fn insert_value(map: &mut HashMap, key: String, new_value: String) { + if let Some(value) = map.get(&key) { + map.insert(key, format!("{},{}", value, new_value)); + } else { + map.insert(key, new_value); } } @@ -425,8 +414,8 @@ impl HasFormData for WebFormData { } } else if let Some(select) = self.element.dyn_ref::() { // try to fill in select element values - let options = get_select_data(select); - values.insert("options".to_string(), FormValue::VecText(options)); + let options = get_select_data(select).join(","); + values.insert("options".to_string(), options); } values diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index 1acbdeb87..d949263f5 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -30,16 +30,21 @@ use futures_util::{pin_mut, select, FutureExt, StreamExt}; mod cfg; mod dom; -#[cfg(feature = "eval")] -mod eval; + mod event; pub mod launch; mod mutations; pub use event::*; + +#[cfg(feature = "eval")] +mod eval; + #[cfg(feature = "file_engine")] mod file_engine; + #[cfg(all(feature = "hot_reload", debug_assertions))] mod hot_reload; + #[cfg(feature = "hydrate")] mod rehydrate; @@ -49,7 +54,7 @@ mod rehydrate; /// /// # Example /// -/// ```ignore +/// ```rust, ignore /// fn main() { /// let app_fut = dioxus_web::run_with_props(App, RootProps { name: String::from("joe") }); /// wasm_bindgen_futures::spawn_local(app_fut); @@ -61,12 +66,7 @@ pub async fn run(virtual_dom: VirtualDom, web_config: Config) { let mut dom = virtual_dom; #[cfg(feature = "eval")] - { - // Eval - dom.in_runtime(|| { - eval::init_eval(); - }); - } + dom.in_runtime(|| eval::init_eval()); #[cfg(feature = "panic_hook")] if web_config.default_panic_hook { @@ -109,13 +109,12 @@ pub async fn run(virtual_dom: VirtualDom, web_config: Config) { websys_dom.mount(); loop { - tracing::trace!("waiting for work"); - // if virtual dom has nothing, wait for it to have something before requesting idle time // if there is work then this future resolves immediately. let (mut res, template) = { let work = dom.wait_for_work().fuse(); pin_mut!(work); + let mut rx_next = rx.select_next_some(); #[cfg(all(feature = "hot_reload", debug_assertions))] @@ -127,6 +126,7 @@ pub async fn run(virtual_dom: VirtualDom, web_config: Config) { evt = rx_next => (Some(evt), None), } } + #[cfg(not(all(feature = "hot_reload", debug_assertions)))] select! { _ = work => (None, None), diff --git a/packages/web/src/mutations.rs b/packages/web/src/mutations.rs index c3c2a8147..19139e1ed 100644 --- a/packages/web/src/mutations.rs +++ b/packages/web/src/mutations.rs @@ -5,9 +5,7 @@ use dioxus_core::WriteMutations; use dioxus_core::{AttributeValue, ElementId}; use dioxus_html::event_bubbles; use dioxus_html::PlatformEventData; -use dioxus_interpreter_js::get_node; use dioxus_interpreter_js::minimal_bindings; -use dioxus_interpreter_js::save_template; use wasm_bindgen::JsCast; use wasm_bindgen::JsValue; @@ -58,19 +56,23 @@ impl WebsysDom { pub fn flush_edits(&mut self) { self.interpreter.flush(); - #[cfg(feature = "mounted")] + // Now that we've flushed the edits and the dom nodes exist, we can send the mounted events. - { - for id in self.queued_mounted_events.drain(..) { - let node = get_node(self.interpreter.js_channel(), id.0 as u32); - if let Some(element) = node.dyn_ref::() { - let _ = self.event_channel.unbounded_send(UiEvent { - name: "mounted".to_string(), - bubbles: false, - element: id, - data: PlatformEventData::new(Box::new(element.clone())), - }); - } + #[cfg(feature = "mounted")] + self.flush_queued_mounted_events(); + } + + #[cfg(feature = "mounted")] + fn flush_queued_mounted_events(&mut self) { + for id in self.queued_mounted_events.drain(..) { + let node = self.interpreter.as_web().get_node(id.0 as u32); + if let Some(element) = node.dyn_ref::() { + let _ = self.event_channel.unbounded_send(UiEvent { + name: "mounted".to_string(), + bubbles: false, + element: id, + data: PlatformEventData::new(Box::new(element.clone())), + }); } } } @@ -84,14 +86,14 @@ impl WebsysDom { impl WriteMutations for WebsysDom { fn register_template(&mut self, template: Template) { let mut roots = vec![]; - for root in template.roots { roots.push(self.create_template_node(root)) } - self.templates .insert(template.name.to_owned(), self.max_template_id); - save_template(self.interpreter.js_channel(), roots, self.max_template_id); + self.interpreter + .as_web() + .save_template(roots, self.max_template_id); self.max_template_id += 1 } @@ -184,30 +186,24 @@ impl WriteMutations for WebsysDom { } fn create_event_listener(&mut self, name: &'static str, id: ElementId) { - match name { - // mounted events are fired immediately after the element is mounted. - "mounted" => { - #[cfg(feature = "mounted")] - self.send_mount_event(id); - } - _ => { - self.interpreter - .new_event_listener(name, id.0 as u32, event_bubbles(name) as u8); - } + // mounted events are fired immediately after the element is mounted. + if name == "mounted" { + #[cfg(feature = "mounted")] + self.send_mount_event(id); + return; } + + self.interpreter + .new_event_listener(name, id.0 as u32, event_bubbles(name) as u8); } fn remove_event_listener(&mut self, name: &'static str, id: ElementId) { - match name { - "mounted" => {} - _ => { - self.interpreter.remove_event_listener( - name, - id.0 as u32, - event_bubbles(name) as u8, - ); - } + if name == "mounted" { + return; } + + self.interpreter + .remove_event_listener(name, id.0 as u32, event_bubbles(name) as u8); } fn remove_node(&mut self, id: ElementId) { diff --git a/packages/web/src/rehydrate.rs b/packages/web/src/rehydrate.rs index 271b3daab..3627ad0aa 100644 --- a/packages/web/src/rehydrate.rs +++ b/packages/web/src/rehydrate.rs @@ -3,7 +3,6 @@ use dioxus_core::prelude::*; use dioxus_core::AttributeValue; use dioxus_core::WriteMutations; use dioxus_core::{DynamicNode, ElementId, ScopeState, TemplateNode, VNode, VirtualDom}; -use dioxus_interpreter_js::save_template; #[derive(Debug)] pub enum RehydrationError { @@ -23,7 +22,7 @@ impl WebsysDom { // Recursively rehydrate the dom from the VirtualDom self.rehydrate_scope(root_scope, dom, &mut ids, &mut to_mount)?; - dioxus_interpreter_js::hydrate(self.interpreter.js_channel(), ids); + self.interpreter.as_web().hydrate(ids); #[cfg(feature = "mounted")] for id in to_mount { @@ -40,8 +39,7 @@ impl WebsysDom { ids: &mut Vec, to_mount: &mut Vec, ) -> Result<(), RehydrationError> { - let vnode = scope.root_node(); - self.rehydrate_vnode(dom, vnode, ids, to_mount) + self.rehydrate_vnode(dom, scope.root_node(), ids, to_mount) } fn rehydrate_vnode( @@ -168,11 +166,10 @@ impl WriteMutations for OnlyWriteTemplates<'_> { self.0 .templates .insert(template.name.to_owned(), self.0.max_template_id); - save_template( - self.0.interpreter.js_channel(), - roots, - self.0.max_template_id, - ); + self.0 + .interpreter + .as_web() + .save_template(roots, self.0.max_template_id); self.0.max_template_id += 1 }