From 7dfe89c9581f45a445f17f9fe4bb94e61f67e971 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sat, 24 Jul 2021 02:52:05 -0400 Subject: [PATCH] feat: wire up event delegator for webview --- examples/basic.rs | 7 +- examples/calculator.rs | 3 +- examples/model.rs | 1 + examples/webview.rs | 1 + packages/core-macro/src/htm.rs | 12 +- packages/core-macro/src/lib.rs | 1 - packages/core-macro/src/rsx/body.rs | 1 - packages/core-macro/src/rsx/element.rs | 3 +- packages/core-macro/src/util.rs | 179 ------------------------- packages/core/src/arena.rs | 3 +- packages/core/src/diff.rs | 11 +- packages/core/src/events.rs | 7 +- packages/core/src/lib.rs | 6 +- packages/core/src/nodes.rs | 3 +- packages/core/src/scope.rs | 2 + packages/core/src/virtual_dom.rs | 6 +- packages/desktop/Cargo.toml | 2 +- packages/desktop/src/events.rs | 85 ++++++++++++ packages/desktop/src/index.html | 153 ++++++++++++++------- packages/desktop/src/lib.rs | 47 +++++-- packages/hooks/src/usestate.rs | 4 +- 21 files changed, 265 insertions(+), 272 deletions(-) delete mode 100644 packages/core-macro/src/util.rs create mode 100644 packages/desktop/src/events.rs diff --git a/examples/basic.rs b/examples/basic.rs index 63ab7d3fc..12958072a 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -5,10 +5,9 @@ fn main() { use dioxus_elements::{GlobalAttributes, SvgAttributes}; __cx.element( dioxus_elements::button, - __cx.bump() - .alloc([dioxus::events::on::onclick(__cx, move |_| {})]), - __cx.bump().alloc([]), - __cx.bump().alloc([]), + [dioxus::events::on::onclick(__cx, move |_| {})], + [], + [], None, ) }); diff --git a/examples/calculator.rs b/examples/calculator.rs index 67dc79be4..2dbbde02b 100644 --- a/examples/calculator.rs +++ b/examples/calculator.rs @@ -5,6 +5,7 @@ // use dioxus::prelude::*; fn main() { + env_logger::init(); dioxus::desktop::launch(App, |cfg| cfg); } @@ -23,7 +24,7 @@ const App: FC<()> = |cx| { let operator = use_state(cx, || None as Option); let display_value = use_state(cx, || "".to_string()); - let clear_display = display_value.eq("0"); + let clear_display = display_value == "0"; let clear_text = if clear_display { "C" } else { "AC" }; let input_digit = move |num: u8| display_value.get_mut().push_str(num.to_string().as_str()); diff --git a/examples/model.rs b/examples/model.rs index 7ddd36854..bc5185b32 100644 --- a/examples/model.rs +++ b/examples/model.rs @@ -20,6 +20,7 @@ use dioxus::prelude::*; const STYLE: &str = include_str!("./assets/calculator.css"); fn main() { + env_logger::init(); dioxus::desktop::launch(App, |cfg| cfg.with_title("Calculator Demo")) .expect("failed to launch dioxus app"); } diff --git a/examples/webview.rs b/examples/webview.rs index 2d51f2ead..f10117908 100644 --- a/examples/webview.rs +++ b/examples/webview.rs @@ -12,6 +12,7 @@ use dioxus::prelude::*; fn main() { + env_logger::init(); dioxus::desktop::launch(App, |c| c); } diff --git a/packages/core-macro/src/htm.rs b/packages/core-macro/src/htm.rs index 068a8009d..a5f6dbd8b 100644 --- a/packages/core-macro/src/htm.rs +++ b/packages/core-macro/src/htm.rs @@ -13,8 +13,6 @@ //! //! -use crate::util::is_valid_svg_tag; - use { proc_macro::TokenStream, proc_macro2::{Span, TokenStream as TokenStream2}, @@ -163,11 +161,11 @@ impl ToTokens for ToToksCtx<&Element> { self.recurse(attr).to_tokens(tokens); } - if is_valid_svg_tag(&name.to_string()) { - tokens.append_all(quote! { - .namespace(Some("http://www.w3.org/2000/svg")) - }); - } + // if is_valid_svg_tag(&name.to_string()) { + // tokens.append_all(quote! { + // .namespace(Some("http://www.w3.org/2000/svg")) + // }); + // } match &self.inner.children { MaybeExpr::Expr(expr) => tokens.append_all(quote! { diff --git a/packages/core-macro/src/lib.rs b/packages/core-macro/src/lib.rs index 8c3c00bf1..8d124800a 100644 --- a/packages/core-macro/src/lib.rs +++ b/packages/core-macro/src/lib.rs @@ -7,7 +7,6 @@ pub(crate) mod htm; pub(crate) mod ifmt; pub(crate) mod props; pub(crate) mod rsx; -pub(crate) mod util; #[proc_macro] pub fn format_args_f(input: TokenStream) -> TokenStream { diff --git a/packages/core-macro/src/rsx/body.rs b/packages/core-macro/src/rsx/body.rs index 9ea37585d..8e0e97d46 100644 --- a/packages/core-macro/src/rsx/body.rs +++ b/packages/core-macro/src/rsx/body.rs @@ -1,4 +1,3 @@ -use crate::util::is_valid_tag; use proc_macro2::TokenStream as TokenStream2; use quote::{quote, ToTokens, TokenStreamExt}; use syn::{ diff --git a/packages/core-macro/src/rsx/element.rs b/packages/core-macro/src/rsx/element.rs index 45c391831..6250cb123 100644 --- a/packages/core-macro/src/rsx/element.rs +++ b/packages/core-macro/src/rsx/element.rs @@ -273,8 +273,7 @@ fn parse_rsx_element_field( let ty: AttrType = match name_str.as_str() { // short circuit early if style is using the special syntax - "style" if stream.peek(Token![:]) => { - stream.parse::().unwrap(); + "style" if stream.peek(token::Brace) => { let inner; syn::braced!(inner in stream); diff --git a/packages/core-macro/src/util.rs b/packages/core-macro/src/util.rs deleted file mode 100644 index 1e595f8f8..000000000 --- a/packages/core-macro/src/util.rs +++ /dev/null @@ -1,179 +0,0 @@ -// use lazy_static::lazy_static; -use once_cell::sync::Lazy; -use std::collections::hash_set::HashSet; -use syn::{parse::ParseBuffer, Expr}; - -pub fn try_parse_bracketed(stream: &ParseBuffer) -> syn::Result { - let content; - syn::braced!(content in stream); - content.parse() -} - -/// rsx! and html! macros support the html namespace as well as svg namespace -static HTML_TAGS: Lazy> = Lazy::new(|| { - [ - "a", - "abbr", - "address", - "area", - "article", - "aside", - "audio", - "b", - "base", - "bdi", - "bdo", - "big", - "blockquote", - "body", - "br", - "button", - "canvas", - "caption", - "cite", - "code", - "col", - "colgroup", - "command", - "data", - "datalist", - "dd", - "del", - "details", - "dfn", - "dialog", - "div", - "dl", - "dt", - "em", - "embed", - "fieldset", - "figcaption", - "figure", - "footer", - "form", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "head", - "header", - "hr", - "html", - "i", - "iframe", - "img", - "input", - "ins", - "kbd", - "keygen", - "label", - "legend", - "li", - "link", - "main", - "map", - "mark", - "menu", - "menuitem", - "meta", - "meter", - "nav", - "noscript", - "object", - "ol", - "optgroup", - "option", - "output", - "p", - "param", - "picture", - "pre", - "progress", - "q", - "rp", - "rt", - "ruby", - "s", - "samp", - "script", - "section", - "select", - "small", - "source", - "span", - "strong", - "style", - "sub", - "summary", - "sup", - "table", - "tbody", - "td", - "textarea", - "tfoot", - "th", - "thead", - "time", - "title", - "tr", - "track", - "u", - "ul", - "var", - "video", - "wbr", - ] - .iter() - .cloned() - .collect() -}); - -static SVG_TAGS: Lazy> = Lazy::new(|| { - [ - // SVTG - "svg", "path", "g", "text", - ] - .iter() - .cloned() - .collect() -}); - -// these tags are reserved by dioxus for any reason -// They might not all be used -static RESERVED_TAGS: Lazy> = Lazy::new(|| { - [ - // a fragment - "fragment", - ] - .iter() - .cloned() - .collect() -}); - -/// Whether or not this tag is valid -/// -/// ``` -/// use html_validation::is_valid_tag; -/// -/// assert_eq!(is_valid_tag("br"), true); -/// -/// assert_eq!(is_valid_tag("random"), false); -/// ``` -pub fn is_valid_tag(tag: &str) -> bool { - is_valid_html_tag(tag) || is_valid_svg_tag(tag) || is_valid_reserved_tag(tag) -} - -pub fn is_valid_html_tag(tag: &str) -> bool { - HTML_TAGS.contains(tag) -} - -pub fn is_valid_svg_tag(tag: &str) -> bool { - SVG_TAGS.contains(tag) -} - -pub fn is_valid_reserved_tag(tag: &str) -> bool { - RESERVED_TAGS.contains(tag) -} diff --git a/packages/core/src/arena.rs b/packages/core/src/arena.rs index 2fd1f1d2f..0b6f41c1a 100644 --- a/packages/core/src/arena.rs +++ b/packages/core/src/arena.rs @@ -20,8 +20,7 @@ pub struct ElementId(pub usize); impl ElementId { pub fn as_u64(self) -> u64 { - todo!() - // self.0.as_ffi() + self.0 as u64 } } diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 1ce705e4d..3a43d7a1c 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -85,7 +85,7 @@ impl<'r, 'b> DiffMachine<'r, 'b> { pub fn get_scope_mut(&mut self, id: &ScopeId) -> Option<&'b mut Scope> { // ensure we haven't seen this scope before // if we have, then we're trying to alias it, which is not allowed - debug_assert!(!self.seen_nodes.contains(id)); + // debug_assert!(!self.seen_nodes.contains(id)); unsafe { self.vdom.get_scope_mut(*id) } } pub fn get_scope(&mut self, id: &ScopeId) -> Option<&'b Scope> { @@ -120,10 +120,11 @@ impl<'real, 'bump> DiffMachine<'real, 'bump> { // // each function call assumes the stack is fresh (empty). pub fn diff_node(&mut self, old_node: &'bump VNode<'bump>, new_node: &'bump VNode<'bump>) { - let root = old_node - .dom_id - .get() - .expect("Should not be diffing old nodes that were never assigned"); + // currently busted for components - need to fid + let root = old_node.dom_id.get().expect(&format!( + "Should not be diffing old nodes that were never assigned, {:#?}", + old_node + )); match (&old_node.kind, &new_node.kind) { // Handle the "sane" cases first. diff --git a/packages/core/src/events.rs b/packages/core/src/events.rs index 45ceabf53..33874b219 100644 --- a/packages/core/src/events.rs +++ b/packages/core/src/events.rs @@ -125,6 +125,8 @@ pub enum VirtualEvent { hook_idx: usize, domnode: Rc>>, }, + // TOOD: make garbage collection its own dedicated event + // GarbageCollection {} } pub mod on { @@ -183,6 +185,7 @@ pub mod on { where F: FnMut($wrapper) + 'a { let bump = &c.bump(); + let cb: &mut dyn FnMut(VirtualEvent) = bump.alloc(move |evt: VirtualEvent| match evt { VirtualEvent::$wrapper(event) => callback(event), _ => unreachable!("Downcasted VirtualEvent to wrong event type - this is an internal bug!") @@ -190,8 +193,10 @@ pub mod on { let callback: BumpBox = unsafe { BumpBox::from_raw(cb) }; + let event_name = stringify!($name); + let shortname: &'static str = &event_name[2..]; Listener { - event: stringify!($name), + event: shortname, mounted_node: Cell::new(None), scope: c.scope.our_arena_idx, callback: RefCell::new(callback), diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 5d36787e2..fa9f4e221 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -10,9 +10,9 @@ //! pub use crate::innerlude::{ - format_args_f, html, rsx, Context, DioxusElement, DomEdit, DomTree, ElementId, EventTrigger, - LazyNodes, NodeFactory, Properties, RealDom, ScopeId, VNode, VNodeKind, VirtualDom, - VirtualEvent, FC, + format_args_f, html, rsx, Context, DioxusElement, DomEdit, DomTree, ElementId, EventPriority, + EventTrigger, LazyNodes, NodeFactory, Properties, RealDom, ScopeId, VNode, VNodeKind, + VirtualDom, VirtualEvent, FC, }; pub mod prelude { diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 36fce44b8..f439a080b 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -249,13 +249,12 @@ impl<'a> NodeFactory<'a> { // We take the references directly from the bump arena // - // // TODO: this code shouldn't necessarily be here of all places // It would make more sense to do this in diffing let mut queue = self.scope.listeners.borrow_mut(); for listener in listeners.iter() { - let long_listener: &Listener<'static> = unsafe { std::mem::transmute(listener) }; + let long_listener: &'a Listener<'static> = unsafe { std::mem::transmute(listener) }; queue.push(long_listener as *const _) } diff --git a/packages/core/src/scope.rs b/packages/core/src/scope.rs index 1a70fc13f..4f15f150d 100644 --- a/packages/core/src/scope.rs +++ b/packages/core/src/scope.rs @@ -108,6 +108,8 @@ impl Scope { let next_frame = self.frames.prev_frame_mut(); next_frame.bump.reset(); + // make sure we call the drop implementation on all the listeners + // this is important to not leak memory self.listeners.borrow_mut().clear(); unsafe { self.hooks.reset() }; diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index f82026a8d..243b4c5d4 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -258,10 +258,10 @@ 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 async fn progress_with_event<'s>( + pub async fn progress_with_event<'a, 's>( &'s mut self, - realdom: &'s mut dyn RealDom<'s>, - edits: &mut Vec>, + realdom: &'a mut dyn RealDom<'s>, + edits: &'a mut Vec>, ) -> Result<()> { let trigger = self.triggers.borrow_mut().pop().expect("failed"); diff --git a/packages/desktop/Cargo.toml b/packages/desktop/Cargo.toml index 4c44aecb1..2c12663ba 100644 --- a/packages/desktop/Cargo.toml +++ b/packages/desktop/Cargo.toml @@ -20,13 +20,13 @@ log = "0.4.13" fern = { version = "0.6.0", features = ["colored"] } html-escape = "0.2.9" wry = "0.11.0" +async-std = { version = "1.9.0", features = ["attributes"] } [dev-dependencies] dioxus-html = { path = "../html" } tide = "0.15.0" tide-websockets = "0.3.0" -async-std = { version = "1.9.0", features = ["attributes"] } # thiserror = "1.0.23" # log = "0.4.13" diff --git a/packages/desktop/src/events.rs b/packages/desktop/src/events.rs new file mode 100644 index 000000000..308726f51 --- /dev/null +++ b/packages/desktop/src/events.rs @@ -0,0 +1,85 @@ +//! Convert a serialized event to an event Trigger +//! + +use std::rc::Rc; + +use dioxus_core::{ + events::{ + on::{MouseEvent, MouseEventInner}, + VirtualEvent, + }, + ElementId, EventPriority, EventTrigger, ScopeId, +}; + +#[derive(serde::Serialize, serde::Deserialize)] +struct ImEvent { + event: String, + mounted_dom_id: u64, + scope: u64, +} +pub fn trigger_from_serialized(val: serde_json::Value) -> EventTrigger { + let mut data: Vec = serde_json::from_value(val).unwrap(); + let data = data.drain(..).next().unwrap(); + + let event = VirtualEvent::MouseEvent(MouseEvent(Rc::new(WebviewMouseEvent))); + let scope = ScopeId(data.scope as usize); + let mounted_dom_id = Some(ElementId(data.mounted_dom_id as usize)); + let priority = EventPriority::High; + EventTrigger::new(event, scope, mounted_dom_id, priority) +} + +#[derive(Debug)] +struct WebviewMouseEvent; +impl MouseEventInner for WebviewMouseEvent { + fn alt_key(&self) -> bool { + todo!() + } + + fn button(&self) -> i16 { + todo!() + } + + fn buttons(&self) -> u16 { + todo!() + } + + fn client_x(&self) -> i32 { + todo!() + } + + fn client_y(&self) -> i32 { + todo!() + } + + fn ctrl_key(&self) -> bool { + todo!() + } + + fn meta_key(&self) -> bool { + todo!() + } + + fn page_x(&self) -> i32 { + todo!() + } + + fn page_y(&self) -> i32 { + todo!() + } + + fn screen_x(&self) -> i32 { + todo!() + } + + fn screen_y(&self) -> i32 { + todo!() + } + + fn shift_key(&self) -> bool { + todo!() + } + + fn get_modifier_state(&self, key_code: &str) -> bool { + todo!() + } +} diff --git a/packages/desktop/src/index.html b/packages/desktop/src/index.html index 584685419..c734af71c 100644 --- a/packages/desktop/src/index.html +++ b/packages/desktop/src/index.html @@ -5,10 +5,13 @@