1
0
Эх сурвалжийг харах

clippy, and don't hash invisible files for ts generation

Jonathan Kelley 1 жил өмнө
parent
commit
4b2e426958

+ 0 - 1
Cargo.lock

@@ -2384,7 +2384,6 @@ version = "0.5.0-alpha.0"
 dependencies = [
  "async-trait",
  "core-foundation",
- "crossbeam-channel",
  "dioxus",
  "dioxus-cli-config",
  "dioxus-core",

+ 3 - 6
examples/assets/file_upload.css

@@ -1,14 +1,11 @@
 body {
     font-family: Arial, sans-serif;
-    margin: 0;
-    padding: 0;
+    margin: 10px;
+    padding: 10px;
     background-color: #f4f4f4;
-    display: flex;
     justify-content: center;
     align-items: center;
-    height: 100vh;
-    flex-direction: column;
-    gap: 20px;
+    min-height: 100vh;
 }
 
 #drop-zone {

+ 37 - 20
examples/file_upload.rs

@@ -12,15 +12,23 @@ fn main() {
     LaunchBuilder::desktop().launch(app);
 }
 
+struct UploadedFile {
+    name: String,
+    contents: String,
+}
+
 fn app() -> Element {
     let mut enable_directory_upload = use_signal(|| false);
-    let mut files_uploaded = use_signal(|| Vec::new() as Vec<String>);
+    let mut files_uploaded = use_signal(|| Vec::new() as Vec<UploadedFile>);
 
     let read_files = move |file_engine: Arc<dyn FileEngine>| async move {
         let files = file_engine.files();
         for file_name in &files {
-            if let Some(file) = file_engine.read_file_to_string(file_name).await {
-                files_uploaded.write().push(file);
+            if let Some(contents) = file_engine.read_file_to_string(file_name).await {
+                files_uploaded.write().push(UploadedFile {
+                    name: file_name.clone(),
+                    contents,
+                });
             }
         }
     };
@@ -40,25 +48,31 @@ fn app() -> Element {
     rsx! {
         style { {include_str!("./assets/file_upload.css")} }
 
-        input {
-            r#type: "checkbox",
-            id: "directory-upload",
-            checked: enable_directory_upload,
-            oninput: move |evt| enable_directory_upload.set(evt.checked()),
-        },
+        h1 { "File Upload Example" }
+        p { "Drop a .txt, .rs, or .js file here to read it" }
 
-        label { r#for: "directory-upload", "Enable directory upload" }
 
-        input {
-            r#type: "file",
-            accept: ".txt,.rs,.js",
-            multiple: true,
-            name: "textreader",
-            directory: enable_directory_upload,
-            onchange: upload_files,
+        div {
+            label { r#for: "directory-upload", "Enable directory upload" }
+            input {
+                r#type: "checkbox",
+                id: "directory-upload",
+                checked: enable_directory_upload,
+                oninput: move |evt| enable_directory_upload.set(evt.checked()),
+            },
         }
 
-        label { r#for: "textreader", "Upload text/rust files and read them" }
+        div {
+            label { r#for: "textreader", "Upload text/rust files and read them" }
+            input {
+                r#type: "file",
+                accept: ".txt,.rs,.js",
+                multiple: true,
+                name: "textreader",
+                directory: enable_directory_upload,
+                onchange: upload_files,
+            }
+        }
 
         div {
             // cheating with a little bit of JS...
@@ -71,8 +85,11 @@ fn app() -> Element {
         }
 
         ul {
-            for file in files_uploaded.read().iter() {
-                li { "{file}" }
+            for file in files_uploaded.read().iter().rev() {
+                li {
+                    span { "{file.name}" }
+                    pre  { "{file.contents}"  }
+                }
             }
         }
     }

+ 2 - 2
examples/form.rs

@@ -11,8 +11,8 @@ fn main() {
 }
 
 fn app() -> Element {
-    let mut values = use_signal(|| HashMap::new());
-    let mut submitted_values = use_signal(|| HashMap::new());
+    let mut values = use_signal(HashMap::new);
+    let mut submitted_values = use_signal(HashMap::new);
 
     rsx! {
         div { style: "display: flex",

+ 0 - 2
packages/desktop/Cargo.toml

@@ -46,11 +46,9 @@ dunce = "1.0.2"
 slab = { workspace = true }
 rustc-hash = { workspace = true }
 dioxus-hooks = { workspace = true }
-
 futures-util = { workspace = true }
 urlencoding = "2.1.2"
 async-trait = "0.1.68"
-crossbeam-channel = "0.5.8"
 tao = { version = "0.24.0", features = ["rwh_05"] }
 
 [target.'cfg(any(target_os = "windows",target_os = "macos",target_os = "linux",target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))'.dependencies]

+ 2 - 2
packages/desktop/headless_tests/events.rs

@@ -437,7 +437,7 @@ fn test_focus_out_div() -> Element {
 }
 
 fn test_form_input() -> Element {
-    let mut values = use_signal(|| HashMap::new());
+    let mut values = use_signal(HashMap::new);
 
     utils::mock_event_with_extra(
         "form-username",
@@ -489,7 +489,7 @@ fn test_form_input() -> Element {
 }
 
 fn test_form_submit() -> Element {
-    let mut values = use_signal(|| HashMap::new());
+    let mut values = use_signal(HashMap::new);
 
     utils::mock_event_with_extra(
         "form-submitter",

+ 1 - 1
packages/desktop/headless_tests/rendering.rs

@@ -14,7 +14,7 @@ fn use_inner_html(id: &'static str) -> Option<String> {
 
     use_effect(move || {
         spawn(async move {
-            tokio::time::sleep(std::time::Duration::from_millis(2000)).await;
+            tokio::time::sleep(std::time::Duration::from_millis(500)).await;
 
             let res = eval(&format!(
                 r#"let element = document.getElementById('{}');

+ 1 - 1
packages/desktop/headless_tests/utils.rs

@@ -36,7 +36,7 @@ pub fn mock_event_with_extra(id: &'static str, value: &'static str, extra: &'sta
         EXPECTED_EVENTS.with_mut(|x| *x += 1);
 
         spawn(async move {
-            tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
+            tokio::time::sleep(std::time::Duration::from_millis(500)).await;
 
             let js = format!(
                 r#"

+ 38 - 32
packages/desktop/src/app.rs

@@ -3,12 +3,11 @@ use crate::{
     element::DesktopElement,
     event_handlers::WindowEventHandlers,
     file_upload::{DesktopFileDragEvent, DesktopFileUploadForm, FileDialogRequest},
-    ipc::{EventData, IpcMessage, UserWindowEvent},
+    ipc::{IpcMessage, UserWindowEvent},
     query::QueryResult,
     shortcut::{GlobalHotKeyEvent, ShortcutRegistry},
     webview::WebviewInstance,
 };
-use crossbeam_channel::Receiver;
 use dioxus_core::ElementId;
 use dioxus_core::VirtualDom;
 use dioxus_html::{native_bind::NativeFileEngine, HasFileData, HtmlEvent, PlatformEventData};
@@ -50,7 +49,6 @@ pub(crate) struct SharedContext {
     pub(crate) event_handlers: WindowEventHandlers,
     pub(crate) pending_webviews: RefCell<Vec<WebviewInstance>>,
     pub(crate) shortcut_manager: ShortcutRegistry,
-    pub(crate) global_hotkey_channel: Receiver<GlobalHotKeyEvent>,
     pub(crate) proxy: EventLoopProxy<UserWindowEvent>,
     pub(crate) target: EventLoopWindowTarget<UserWindowEvent>,
 }
@@ -70,7 +68,6 @@ impl App {
                 event_handlers: WindowEventHandlers::default(),
                 pending_webviews: Default::default(),
                 shortcut_manager: ShortcutRegistry::new(),
-                global_hotkey_channel: GlobalHotKeyEvent::receiver().clone(),
                 proxy: event_loop.create_proxy(),
                 target: event_loop.clone(),
             }),
@@ -79,6 +76,9 @@ impl App {
         // Set the event converter
         dioxus_html::set_event_converter(Box::new(crate::events::SerializedHtmlEventConverter));
 
+        // Wire up the global hotkey handler
+        app.set_global_hotkey_handler();
+
         // Allow hotreloading to work - but only in debug mode
         #[cfg(all(feature = "hot-reload", debug_assertions))]
         app.connect_hotreload();
@@ -88,14 +88,13 @@ impl App {
 
     pub fn tick(&mut self, window_event: &Event<'_, UserWindowEvent>) {
         self.control_flow = ControlFlow::Wait;
-
         self.shared
             .event_handlers
             .apply_event(window_event, &self.shared.target);
+    }
 
-        if let Ok(event) = self.shared.global_hotkey_channel.try_recv() {
-            self.shared.shortcut_manager.call_handlers(event);
-        }
+    pub fn handle_global_hotkey(&self, event: GlobalHotKeyEvent) {
+        self.shared.shortcut_manager.call_handlers(event);
     }
 
     #[cfg(all(feature = "hot-reload", debug_assertions))]
@@ -103,10 +102,7 @@ impl App {
         dioxus_hot_reload::connect({
             let proxy = self.shared.proxy.clone();
             move |template| {
-                let _ = proxy.send_event(UserWindowEvent(
-                    EventData::HotReloadEvent(template),
-                    unsafe { WindowId::dummy() },
-                ));
+                let _ = proxy.send_event(UserWindowEvent::HotReloadEvent(template));
             }
         });
     }
@@ -115,10 +111,7 @@ impl App {
         for handler in self.shared.pending_webviews.borrow_mut().drain(..) {
             let id = handler.desktop_context.window.id();
             self.webviews.insert(id, handler);
-            _ = self
-                .shared
-                .proxy
-                .send_event(UserWindowEvent(EventData::Poll, id));
+            _ = self.shared.proxy.send_event(UserWindowEvent::Poll(id));
         }
     }
 
@@ -168,11 +161,6 @@ impl App {
 
         let id = webview.desktop_context.window.id();
         self.webviews.insert(id, webview);
-
-        _ = self
-            .shared
-            .proxy
-            .send_event(UserWindowEvent(EventData::Poll, id));
     }
 
     pub fn handle_browser_open(&mut self, msg: IpcMessage) {
@@ -186,19 +174,29 @@ impl App {
         }
     }
 
+    /// The webview is finally loaded
+    ///
+    /// Let's rebuild it and then start polling it
     pub fn handle_initialize_msg(&mut self, id: WindowId) {
         let view = self.webviews.get_mut(&id).unwrap();
+
         view.dom
             .rebuild(&mut *view.desktop_context.mutation_state.borrow_mut());
+
         view.desktop_context.send_edits();
+
         view.desktop_context
             .window
             .set_visible(self.is_visible_before_start);
+
+        _ = self.shared.proxy.send_event(UserWindowEvent::Poll(id));
     }
 
+    /// Todo: maybe we should poll the virtualdom asking if it has any final actions to apply before closing the webview
+    ///
+    /// Technically you can handle this with the use_window_event hook
     pub fn handle_close_msg(&mut self, id: WindowId) {
         self.webviews.remove(&id);
-
         if self.webviews.is_empty() {
             self.control_flow = ControlFlow::Exit
         }
@@ -244,16 +242,14 @@ impl App {
                 if drag.files().is_some() {
                     let file_event = recent_file.current().unwrap();
                     let paths = match file_event {
-                        wry::FileDropEvent::Hovered { paths, position } => paths,
-                        wry::FileDropEvent::Dropped { paths, position } => paths,
+                        wry::FileDropEvent::Hovered { paths, .. } => paths,
+                        wry::FileDropEvent::Dropped { paths, .. } => paths,
                         _ => vec![],
                     };
-                    let files = Arc::new(NativeFileEngine::new(paths));
-                    let event = DesktopFileDragEvent {
+                    Rc::new(PlatformEventData::new(Box::new(DesktopFileDragEvent {
                         mouse: drag.mouse.clone(),
-                        files,
-                    };
-                    Rc::new(PlatformEventData::new(Box::new(event)))
+                        files: Arc::new(NativeFileEngine::new(paths)),
+                    })))
                 } else {
                     data.into_any()
                 }
@@ -282,8 +278,6 @@ impl App {
         }
     }
 
-    pub fn handle_file_drag(&mut self, msg: IpcMessage, window: WindowId) {}
-
     pub fn handle_file_dialog_msg(&mut self, msg: IpcMessage, window: WindowId) {
         let Ok(file_dialog) = serde_json::from_value::<FileDialogRequest>(msg.params()) else {
             return;
@@ -327,6 +321,19 @@ impl App {
 
         view.poll_vdom();
     }
+
+    fn set_global_hotkey_handler(&self) {
+        let receiver = self.shared.proxy.clone();
+
+        // The event loop becomes the hotkey receiver
+        // This means we don't need to poll the receiver on every tick - we just get the events as they come in
+        // This is a bit more efficient than the previous implementation, but if someone else sets a handler, the
+        // receiver will become inert.
+        global_hotkey::GlobalHotKeyEvent::set_event_handler(Some(move |t| {
+            // todo: should we unset the event handler when the app shuts down?
+            _ = receiver.send_event(UserWindowEvent::GlobalHotKeyEvent(t));
+        }));
+    }
 }
 
 /// Different hide implementations per platform
@@ -336,7 +343,6 @@ pub fn hide_app_window(window: &wry::WebView) {
     {
         use tao::platform::windows::WindowExtWindows;
         window.set_visible(false);
-        // window.set_skip_taskbar(true);
     }
 
     #[cfg(target_os = "linux")]

+ 2 - 10
packages/desktop/src/config.rs

@@ -1,11 +1,7 @@
 use std::borrow::Cow;
 use std::path::PathBuf;
-
-use tao::window::{Icon, WindowBuilder, WindowId};
-use wry::{
-    http::{Request as HttpRequest, Response as HttpResponse},
-    FileDropEvent,
-};
+use tao::window::{Icon, WindowBuilder};
+use wry::http::{Request as HttpRequest, Response as HttpResponse};
 
 /// The behaviour of the application when the last window is closed.
 #[derive(Copy, Clone, Eq, PartialEq)]
@@ -21,7 +17,6 @@ pub enum WindowCloseBehaviour {
 /// The configuration for the desktop application.
 pub struct Config {
     pub(crate) window: WindowBuilder,
-    pub(crate) file_drop_handler: Option<DropHandler>,
     pub(crate) protocols: Vec<WryProtocol>,
     pub(crate) pre_rendered: Option<String>,
     pub(crate) disable_context_menu: bool,
@@ -35,8 +30,6 @@ pub struct Config {
     pub(crate) enable_default_menu_bar: bool,
 }
 
-type DropHandler = Box<dyn Fn(WindowId, FileDropEvent) -> bool>;
-
 pub(crate) type WryProtocol = (
     String,
     Box<dyn Fn(HttpRequest<Vec<u8>>) -> HttpResponse<Cow<'static, [u8]>> + 'static>,
@@ -56,7 +49,6 @@ impl Config {
         Self {
             window,
             protocols: Vec::new(),
-            file_drop_handler: None,
             pre_rendered: None,
             disable_context_menu: !cfg!(debug_assertions),
             resource_dir: None,

+ 5 - 11
packages/desktop/src/desktop_context.rs

@@ -3,7 +3,7 @@ use crate::{
     assets::AssetHandlerRegistry,
     edits::EditQueue,
     file_upload::NativeFileHover,
-    ipc::{EventData, UserWindowEvent},
+    ipc::UserWindowEvent,
     query::QueryEngine,
     shortcut::{HotKey, ShortcutHandle, ShortcutRegistryError},
     webview::WebviewInstance,
@@ -17,14 +17,13 @@ use dioxus_interpreter_js::MutationState;
 use std::{
     cell::RefCell,
     rc::{Rc, Weak},
-    sync::Arc,
 };
 use tao::{
     event::Event,
     event_loop::EventLoopWindowTarget,
     window::{Fullscreen as WryFullscreen, Window, WindowId},
 };
-use wry::{FileDropEvent, RequestAsyncResponder, WebView};
+use wry::{RequestAsyncResponder, WebView};
 
 #[cfg(target_os = "ios")]
 use tao::platform::ios::WindowExtIOS;
@@ -130,12 +129,7 @@ impl DesktopService {
 
         self.shared
             .proxy
-            .send_event(UserWindowEvent(EventData::NewWindow, cx.id()))
-            .unwrap();
-
-        self.shared
-            .proxy
-            .send_event(UserWindowEvent(EventData::Poll, cx.id()))
+            .send_event(UserWindowEvent::NewWindow)
             .unwrap();
 
         self.shared.pending_webviews.borrow_mut().push(window);
@@ -167,7 +161,7 @@ impl DesktopService {
         let _ = self
             .shared
             .proxy
-            .send_event(UserWindowEvent(EventData::CloseWindow, self.id()));
+            .send_event(UserWindowEvent::CloseWindow(self.id()));
     }
 
     /// Close a particular window, given its ID
@@ -175,7 +169,7 @@ impl DesktopService {
         let _ = self
             .shared
             .proxy
-            .send_event(UserWindowEvent(EventData::CloseWindow, id));
+            .send_event(UserWindowEvent::CloseWindow(id));
     }
 
     /// change window to fullscreen

+ 10 - 4
packages/desktop/src/file_upload.rs

@@ -12,7 +12,13 @@ use dioxus_html::{
 };
 use muda::accelerator::Modifiers;
 use serde::Deserialize;
-use std::{cell::Cell, path::PathBuf, rc::Rc, str::FromStr, sync::Arc};
+use std::{
+    cell::{Cell, RefCell},
+    path::PathBuf,
+    rc::Rc,
+    str::FromStr,
+    sync::Arc,
+};
 use wry::FileDropEvent;
 
 #[derive(Debug, Deserialize)]
@@ -156,15 +162,15 @@ impl HasFormData for DesktopFileUploadForm {
 
 #[derive(Default, Clone)]
 pub struct NativeFileHover {
-    event: Rc<Cell<Option<FileDropEvent>>>,
+    event: Rc<RefCell<Option<FileDropEvent>>>,
 }
 impl NativeFileHover {
     pub fn set(&self, event: FileDropEvent) {
-        self.event.set(Some(event));
+        self.event.borrow_mut().replace(event);
     }
 
     pub fn current(&self) -> Option<FileDropEvent> {
-        self.event.as_ref().clone().take()
+        self.event.borrow_mut().clone()
     }
 }
 

+ 7 - 11
packages/desktop/src/ipc.rs

@@ -1,18 +1,17 @@
+use global_hotkey::GlobalHotKeyEvent;
 use serde::{Deserialize, Serialize};
 use tao::window::WindowId;
 
-/// A pair of data
 #[derive(Debug, Clone)]
-pub struct UserWindowEvent(pub EventData, pub WindowId);
+pub enum UserWindowEvent {
+    /// A global hotkey event
+    GlobalHotKeyEvent(GlobalHotKeyEvent),
 
-/// The data that might eminate from any window/webview
-#[derive(Debug, Clone)]
-pub enum EventData {
     /// Poll the virtualdom
-    Poll,
+    Poll(WindowId),
 
     /// Handle an ipc message eminating from the window.postMessage of a given webview
-    Ipc(IpcMessage),
+    Ipc { id: WindowId, msg: IpcMessage },
 
     /// Handle a hotreload event, basically telling us to update our templates
     #[cfg(all(feature = "hot-reload", debug_assertions))]
@@ -22,7 +21,7 @@ pub enum EventData {
     NewWindow,
 
     /// Close a given window (could be any window!)
-    CloseWindow,
+    CloseWindow(WindowId),
 }
 
 /// A message struct that manages the communication between the webview and the eventloop code
@@ -42,16 +41,13 @@ pub enum IpcMethod<'a> {
     Query,
     BrowserOpen,
     Initialize,
-    FileDrag,
     Other(&'a str),
 }
 
 impl IpcMessage {
     pub(crate) fn method(&self) -> IpcMethod {
         match self.method.as_str() {
-            // todo: this is a misspelling, needs to be fixed
             "file_dialog" => IpcMethod::FileDialog,
-            "file_drag" => IpcMethod::FileDrag,
             "user_event" => IpcMethod::UserEvent,
             "query" => IpcMethod::Query,
             "browser_open" => IpcMethod::BrowserOpen,

+ 11 - 9
packages/desktop/src/launch.rs

@@ -1,7 +1,7 @@
 pub use crate::Config;
 use crate::{
     app::App,
-    ipc::{EventData, IpcMethod, UserWindowEvent},
+    ipc::{IpcMethod, UserWindowEvent},
 };
 use dioxus_core::*;
 use std::any::Any;
@@ -15,6 +15,7 @@ pub fn launch_virtual_dom_blocking(virtual_dom: VirtualDom, desktop_config: Conf
     let (event_loop, mut app) = App::new(desktop_config, virtual_dom);
 
     event_loop.run(move |window_event, _, control_flow| {
+        // Set the control flow and check if any events need to be handled in the app itself
         app.tick(&window_event);
 
         match window_event {
@@ -26,19 +27,20 @@ pub fn launch_virtual_dom_blocking(virtual_dom: VirtualDom, desktop_config: Conf
                 WindowEvent::Destroyed { .. } => app.window_destroyed(window_id),
                 _ => {}
             },
-            Event::UserEvent(UserWindowEvent(event, id)) => match event {
-                EventData::Poll => app.poll_vdom(id),
-                EventData::NewWindow => app.handle_new_window(),
-                EventData::CloseWindow => app.handle_close_msg(id),
+
+            Event::UserEvent(event) => match event {
+                UserWindowEvent::Poll(id) => app.poll_vdom(id),
+                UserWindowEvent::NewWindow => app.handle_new_window(),
+                UserWindowEvent::CloseWindow(id) => app.handle_close_msg(id),
+                UserWindowEvent::GlobalHotKeyEvent(evnt) => app.handle_global_hotkey(evnt),
                 #[cfg(all(feature = "hot-reload", debug_assertions))]
-                EventData::HotReloadEvent(msg) => app.handle_hot_reload_msg(msg),
-                EventData::Ipc(msg) => match msg.method() {
+                UserWindowEvent::HotReloadEvent(msg) => app.handle_hot_reload_msg(msg),
+                UserWindowEvent::Ipc { id, msg } => match msg.method() {
+                    IpcMethod::Initialize => app.handle_initialize_msg(id),
                     IpcMethod::FileDialog => app.handle_file_dialog_msg(msg, id),
-                    IpcMethod::FileDrag => app.handle_file_drag(msg, id),
                     IpcMethod::UserEvent => app.handle_user_event_msg(msg, id),
                     IpcMethod::Query => app.handle_query_msg(msg, id),
                     IpcMethod::BrowserOpen => app.handle_browser_open(msg),
-                    IpcMethod::Initialize => app.handle_initialize_msg(id),
                     IpcMethod::Other(_) => {}
                 },
             },

+ 0 - 6
packages/desktop/src/mobile_shortcut.rs

@@ -80,10 +80,4 @@ pub struct GlobalHotKeyEvent {
     pub id: u32,
 }
 
-impl GlobalHotKeyEvent {
-    pub fn receiver() -> crossbeam_channel::Receiver<GlobalHotKeyEvent> {
-        crossbeam_channel::unbounded().1
-    }
-}
-
 pub(crate) type Code = dioxus_html::input_data::keyboard_types::Code;

+ 1 - 0
packages/desktop/src/protocol.rs

@@ -50,6 +50,7 @@ pub(super) fn index_request(
         }
         None => assets_head(),
     };
+
     if let Some(head) = head {
         index.insert_str(index.find("</head>").expect("Head element to exist"), &head);
     }

+ 6 - 3
packages/desktop/src/query.rs

@@ -1,13 +1,17 @@
-use std::{cell::RefCell, rc::Rc};
-
 use crate::DesktopContext;
 use futures_util::{FutureExt, StreamExt};
 use generational_box::Owner;
 use serde::{de::DeserializeOwned, Deserialize};
 use serde_json::Value;
 use slab::Slab;
+use std::{cell::RefCell, rc::Rc};
 use thiserror::Error;
 
+/*
+todo:
+- write this in the interpreter itself rather than in blobs of inline javascript...
+- it could also be simpler, probably?
+*/
 const DIOXUS_CODE: &str = r#"
 let dioxus = {
     recv: function () {
@@ -43,7 +47,6 @@ let dioxus = {
 }"#;
 
 /// Tracks what query ids are currently active
-
 pub(crate) struct SharedSlab<T = ()> {
     pub slab: Rc<RefCell<Slab<T>>>,
 }

+ 2 - 2
packages/desktop/src/waker.rs

@@ -1,4 +1,4 @@
-use crate::ipc::{EventData, UserWindowEvent};
+use crate::ipc::UserWindowEvent;
 use futures_util::task::ArcWake;
 use std::sync::Arc;
 use tao::{event_loop::EventLoopProxy, window::WindowId};
@@ -24,7 +24,7 @@ pub fn tao_waker(proxy: EventLoopProxy<UserWindowEvent>, id: WindowId) -> std::t
         fn wake_by_ref(arc_self: &Arc<Self>) {
             _ = arc_self
                 .proxy
-                .send_event(UserWindowEvent(EventData::Poll, arc_self.id));
+                .send_event(UserWindowEvent::Poll(arc_self.id));
         }
     }
 

+ 21 - 28
packages/desktop/src/webview.rs

@@ -1,13 +1,7 @@
 use crate::{
-    app::SharedContext,
-    assets::AssetHandlerRegistry,
-    edits::EditQueue,
-    eval::DesktopEvalProvider,
-    file_upload::NativeFileHover,
-    ipc::{EventData, UserWindowEvent},
-    protocol,
-    waker::tao_waker,
-    Config, DesktopContext, DesktopService,
+    app::SharedContext, assets::AssetHandlerRegistry, edits::EditQueue, eval::DesktopEvalProvider,
+    file_upload::NativeFileHover, ipc::UserWindowEvent, protocol, waker::tao_waker, Config,
+    DesktopContext, DesktopService,
 };
 use dioxus_core::{ScopeId, VirtualDom};
 use dioxus_html::prelude::EvalProvider;
@@ -61,6 +55,7 @@ impl WebviewInstance {
 
         let mut web_context = WebContext::new(cfg.data_dir.clone());
         let edit_queue = EditQueue::default();
+        let file_hover = NativeFileHover::default();
         let asset_handlers = AssetHandlerRegistry::new(dom.runtime());
         let headless = !cfg.window.window.visible;
 
@@ -72,6 +67,7 @@ impl WebviewInstance {
         let asset_handlers_ = asset_handlers.clone();
         let edit_queue_ = edit_queue.clone();
         let proxy_ = shared.proxy.clone();
+        let file_hover_ = file_hover.clone();
 
         let request_handler = move |request, responder: RequestAsyncResponder| {
             // Try to serve the index file first
@@ -97,12 +93,17 @@ impl WebviewInstance {
 
         let ipc_handler = move |payload: String| {
             // defer the event to the main thread
-            if let Ok(message) = serde_json::from_str(&payload) {
-                _ = proxy_.send_event(UserWindowEvent(EventData::Ipc(message), window_id));
+            if let Ok(msg) = serde_json::from_str(&payload) {
+                _ = proxy_.send_event(UserWindowEvent::Ipc { id: window_id, msg });
             }
         };
 
-        let file_hover = NativeFileHover::default();
+        let file_drop_handler = move |evt| {
+            // Update the most recent file drop event - when the event comes in from the webview we can use the
+            // most recent event to build a new event with the files in it.
+            file_hover_.set(evt);
+            false
+        };
 
         #[cfg(any(
             target_os = "windows",
@@ -133,15 +134,7 @@ impl WebviewInstance {
             .with_navigation_handler(|var| var.contains("dioxus")) // prevent all navigations
             .with_asynchronous_custom_protocol(String::from("dioxus"), request_handler)
             .with_web_context(&mut web_context)
-            .with_file_drop_handler({
-                let file_hover = file_hover.clone();
-                move |evt| {
-                    println!("file drop: {:?}", evt);
-                    // Update the most recent file hover status
-                    file_hover.set(evt);
-                    false
-                }
-            });
+            .with_file_drop_handler(file_drop_handler);
 
         if let Some(color) = cfg.background_color {
             webview = webview.with_background_color(color);
@@ -153,15 +146,15 @@ impl WebviewInstance {
 
         const INITIALIZATION_SCRIPT: &str = r#"
         if (document.addEventListener) {
-        document.addEventListener('contextmenu', function(e) {
-            e.preventDefault();
-        }, false);
+            document.addEventListener('contextmenu', function(e) {
+                e.preventDefault();
+            }, false);
         } else {
-        document.attachEvent('oncontextmenu', function() {
-            window.event.returnValue = false;
-        });
+            document.attachEvent('oncontextmenu', function() {
+                window.event.returnValue = false;
+            });
         }
-    "#;
+        "#;
 
         if cfg.disable_context_menu {
             // in release mode, we don't want to show the dev tool or reload menus

+ 15 - 8
packages/interpreter/build.rs

@@ -6,13 +6,13 @@ use std::{
 
 fn main() {
     // If any TS changes, re-run the build script
-    println!("cargo:rerun-if-changed=src/ts/*.ts,*.json");
+    println!("cargo:rerun-if-changed=src/ts/*.ts");
 
     // Compute the hash of the ts files
-    let hash = hash_dir("src/ts");
+    let hash = hash_dir("./src/ts");
 
     // If the hash matches the one on disk, we're good and don't need to update bindings
-    if let Ok(contents) = read_to_string("src/js/hash.txt") {
+    if let Ok(contents) = read_to_string("./src/js/hash.txt") {
         if contents.trim() == hash.to_string() {
             return;
         }
@@ -34,11 +34,17 @@ fn hash_dir(dir: &str) -> u64 {
     for entry in std::fs::read_dir(dir).unwrap() {
         let entry = entry.unwrap();
         let path = entry.path();
-        let metadata = std::fs::metadata(&path).unwrap();
-        if metadata.is_file() {
-            let contents = std::fs::read(&path).unwrap();
-            contents.hash(&mut hasher);
+
+        let Some(ext) = path.extension() else {
+            continue;
+        };
+
+        if ext != "ts" {
+            continue;
         }
+
+        let contents = std::fs::read(&path).unwrap();
+        contents.hash(&mut hasher);
     }
 
     hasher.finish()
@@ -58,7 +64,8 @@ fn gen_bindings(input_name: &str, output_name: &str) {
         .arg(format!("src/ts/{input_name}.ts"))
         .arg("--outfile")
         .arg(format!("src/js/{output_name}.js"))
-        // .arg("--minify")
+        .arg("--minify-whitespace")
+        .arg("--minify-syntax")
         .status()
         .unwrap();
 

+ 1 - 99
packages/interpreter/src/js/common.js

@@ -1,99 +1 @@
-// 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/form.ts
-function retrieveFormValues(form) {
-  const formData = new FormData(form);
-  const contents = {};
-  formData.forEach((value, key) => {
-    if (contents[key]) {
-      contents[key] += "," + value;
-    } else {
-      contents[key] = value;
-    }
-  });
-  return {
-    valid: form.checkValidity(),
-    values: contents
-  };
-}
-export {
-  setAttributeInner,
-  retrieveFormValues
-};
+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===!0},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!0;default:return!1}};function retrieveFormValues(form){const formData=new FormData(form),contents={};return formData.forEach((value,key)=>{if(contents[key])contents[key]+=","+value;else contents[key]=value}),{valid:form.checkValidity(),values:contents}}export{setAttributeInner,retrieveFormValues};

+ 1 - 207
packages/interpreter/src/js/core.js

@@ -1,207 +1 @@
-// 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/core.ts
-class BaseInterpreter {
-  global;
-  local;
-  root;
-  handler;
-  nodes;
-  stack;
-  templates;
-  m;
-  constructor() {
-  }
-  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) {
-      if (this.global[event_name] === undefined) {
-        this.global[event_name] = { active: 1, callback: this.handler };
-        this.root.addEventListener(event_name, this.handler);
-      } else {
-        this.global[event_name].active++;
-      }
-    } else {
-      const id = element.getAttribute("data-dioxus-id");
-      if (!this.local[id]) {
-        this.local[id] = {};
-      }
-      element.addEventListener(event_name, this.handler);
-    }
-  }
-  removeListener(element, event_name, bubbles) {
-    if (bubbles) {
-      this.removeBubblingListener(event_name);
-    } else {
-      this.removeNonBubblingListener(element, event_name);
-    }
-  }
-  removeBubblingListener(event_name) {
-    this.global[event_name].active--;
-    if (this.global[event_name].active === 0) {
-      this.root.removeEventListener(event_name, this.global[event_name].callback);
-      delete this.global[event_name];
-    }
-  }
-  removeNonBubblingListener(element, event_name) {
-    const id = element.getAttribute("data-dioxus-id");
-    delete this.local[id][event_name];
-    if (Object.keys(this.local[id]).length === 0) {
-      delete this.local[id];
-    }
-    element.removeEventListener(event_name, this.handler);
-  }
-  removeAllNonBubblingListeners(element) {
-    const id = element.getAttribute("data-dioxus-id");
-    delete this.local[id];
-  }
-  getNode(id) {
-    return this.nodes[id];
-  }
-  appendChildren(id, many) {
-    const root = this.nodes[id];
-    const els = this.stack.splice(this.stack.length - many);
-    for (let k = 0;k < many; k++) {
-      root.appendChild(els[k]);
-    }
-  }
-  loadChild(ptr, len) {
-    let node = this.stack[this.stack.length - 1];
-    let ptr_end = ptr + len;
-    for (;ptr < ptr_end; ptr++) {
-      let end = this.m.getUint8(ptr);
-      for (node = node.firstChild;end > 0; end--) {
-        node = node.nextSibling;
-      }
-    }
-    return node;
-  }
-  saveTemplate(nodes, tmpl_id) {
-    this.templates[tmpl_id] = nodes;
-  }
-  hydrateRoot(ids) {
-    const hydrateNodes = document.querySelectorAll("[data-node-hydration]");
-    for (let i = 0;i < hydrateNodes.length; i++) {
-      const hydrateNode = hydrateNodes[i];
-      const hydration = hydrateNode.getAttribute("data-node-hydration");
-      const split = hydration.split(",");
-      const id = ids[parseInt(split[0])];
-      this.nodes[id] = hydrateNode;
-      if (split.length > 1) {
-        hydrateNode.listening = split.length - 1;
-        hydrateNode.setAttribute("data-dioxus-id", id.toString());
-        for (let j = 1;j < split.length; j++) {
-          const listener = split[j];
-          const split2 = listener.split(":");
-          const event_name = split2[0];
-          const bubbles = split2[1] === "1";
-          this.createListener(event_name, hydrateNode, bubbles);
-        }
-      }
-    }
-    const treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_COMMENT);
-    let currentNode = treeWalker.nextNode();
-    while (currentNode) {
-      const id = currentNode.textContent;
-      const split = id.split("node-id");
-      if (split.length > 1) {
-        this.nodes[ids[parseInt(split[1])]] = currentNode.nextSibling;
-      }
-      currentNode = treeWalker.nextNode();
-    }
-  }
-  setAttributeInner(node, field, value, ns) {
-    setAttributeInner(node, field, value, ns);
-  }
-}
-export {
-  BaseInterpreter
-};
+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===!0},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!0;default:return!1}};class BaseInterpreter{global;local;root;handler;nodes;stack;templates;m;constructor(){}initialize(root,handler=null){if(this.global={},this.local={},this.root=root,this.nodes=[root],this.stack=[root],this.templates={},handler)this.handler=handler}createListener(event_name,element,bubbles){if(bubbles)if(this.global[event_name]===void 0)this.global[event_name]={active:1,callback:this.handler},this.root.addEventListener(event_name,this.handler);else this.global[event_name].active++;else{const id=element.getAttribute("data-dioxus-id");if(!this.local[id])this.local[id]={};element.addEventListener(event_name,this.handler)}}removeListener(element,event_name,bubbles){if(bubbles)this.removeBubblingListener(event_name);else this.removeNonBubblingListener(element,event_name)}removeBubblingListener(event_name){if(this.global[event_name].active--,this.global[event_name].active===0)this.root.removeEventListener(event_name,this.global[event_name].callback),delete this.global[event_name]}removeNonBubblingListener(element,event_name){const id=element.getAttribute("data-dioxus-id");if(delete this.local[id][event_name],Object.keys(this.local[id]).length===0)delete this.local[id];element.removeEventListener(event_name,this.handler)}removeAllNonBubblingListeners(element){const id=element.getAttribute("data-dioxus-id");delete this.local[id]}getNode(id){return this.nodes[id]}appendChildren(id,many){const root=this.nodes[id],els=this.stack.splice(this.stack.length-many);for(let k=0;k<many;k++)root.appendChild(els[k])}loadChild(ptr,len){let node=this.stack[this.stack.length-1],ptr_end=ptr+len;for(;ptr<ptr_end;ptr++){let end=this.m.getUint8(ptr);for(node=node.firstChild;end>0;end--)node=node.nextSibling}return node}saveTemplate(nodes,tmpl_id){this.templates[tmpl_id]=nodes}hydrateRoot(ids){const hydrateNodes=document.querySelectorAll("[data-node-hydration]");for(let i=0;i<hydrateNodes.length;i++){const hydrateNode=hydrateNodes[i],split=hydrateNode.getAttribute("data-node-hydration").split(","),id=ids[parseInt(split[0])];if(this.nodes[id]=hydrateNode,split.length>1){hydrateNode.listening=split.length-1,hydrateNode.setAttribute("data-dioxus-id",id.toString());for(let j=1;j<split.length;j++){const split2=split[j].split(":"),event_name=split2[0],bubbles=split2[1]==="1";this.createListener(event_name,hydrateNode,bubbles)}}}const treeWalker=document.createTreeWalker(document.body,NodeFilter.SHOW_COMMENT);let currentNode=treeWalker.nextNode();while(currentNode){const split=currentNode.textContent.split("node-id");if(split.length>1)this.nodes[ids[parseInt(split[1])]]=currentNode.nextSibling;currentNode=treeWalker.nextNode()}}setAttributeInner(node,field,value,ns){setAttributeInner(node,field,value,ns)}}export{BaseInterpreter};

+ 1 - 1
packages/interpreter/src/js/hash.txt

@@ -1 +1 @@
-13140749608285001344
+6653358969285642234

+ 1 - 422
packages/interpreter/src/js/native.js

@@ -1,422 +1 @@
-// src/ts/form.ts
-function retriveValues(event, target) {
-  let contents = {
-    values: {}
-  };
-  let form = target.closest("form");
-  if (form) {
-    if (event.type === "input" || event.type === "change" || event.type === "submit" || event.type === "reset" || event.type === "click") {
-      contents = retrieveFormValues(form);
-    }
-  }
-  return contents;
-}
-function retrieveFormValues(form) {
-  const formData = new FormData(form);
-  const contents = {};
-  formData.forEach((value, key) => {
-    if (contents[key]) {
-      contents[key] += "," + value;
-    } else {
-      contents[key] = value;
-    }
-  });
-  return {
-    valid: form.checkValidity(),
-    values: contents
-  };
-}
-function retriveSelectValue(target) {
-  let options = target.selectedOptions;
-  let values = [];
-  for (let i = 0;i < options.length; i++) {
-    values.push(options[i].value);
-  }
-  return values;
-}
-
-// src/ts/serialize.ts
-function serializeEvent(event, target) {
-  let contents = {};
-  let extend = (obj) => contents = { ...contents, ...obj };
-  if (event instanceof WheelEvent) {
-    extend(serializeWheelEvent(event));
-  }
-  if (event instanceof MouseEvent) {
-    extend(serializeMouseEvent(event));
-  }
-  if (event instanceof KeyboardEvent) {
-    extend(serializeKeyboardEvent(event));
-  }
-  if (event instanceof InputEvent) {
-    extend(serializeInputEvent(event, target));
-  }
-  if (event instanceof PointerEvent) {
-    extend(serializePointerEvent(event));
-  }
-  if (event instanceof AnimationEvent) {
-    extend(serializeAnimationEvent(event));
-  }
-  if (event instanceof TransitionEvent) {
-    extend({ property_name: event.propertyName, elapsed_time: event.elapsedTime, pseudo_element: event.pseudoElement });
-  }
-  if (event instanceof CompositionEvent) {
-    extend({ data: event.data });
-  }
-  if (event instanceof DragEvent) {
-    extend(serializeDragEvent(event));
-  }
-  if (event instanceof FocusEvent) {
-    extend({});
-  }
-  if (event instanceof ClipboardEvent) {
-    extend({});
-  }
-  if (typeof TouchEvent !== "undefined" && event instanceof TouchEvent) {
-    extend(serializeTouchEvent(event));
-  }
-  if (event.type === "submit" || event.type === "reset" || event.type === "click" || event.type === "change" || event.type === "input") {
-    extend(serializeInputEvent(event, target));
-  }
-  if (event instanceof DragEvent) {
-  }
-  return contents;
-}
-var serializeInputEvent = function(event, target) {
-  let contents = {};
-  if (target instanceof HTMLElement) {
-    let values = retriveValues(event, target);
-    contents.values = values.values;
-    contents.valid = values.valid;
-  }
-  if (event.target instanceof HTMLInputElement) {
-    let target2 = event.target;
-    let value = target2.value ?? target2.textContent ?? "";
-    if (target2.type === "checkbox") {
-      value = target2.checked ? "true" : "false";
-    } else if (target2.type === "radio") {
-      value = target2.value;
-    }
-    contents.value = value;
-  }
-  if (event.target instanceof HTMLTextAreaElement) {
-    contents.value = event.target.value;
-  }
-  if (event.target instanceof HTMLSelectElement) {
-    contents.value = retriveSelectValue(event.target).join(",");
-  }
-  if (contents.value === undefined) {
-    contents.value = "";
-  }
-  return contents;
-};
-var serializeWheelEvent = function(event) {
-  return {
-    delta_x: event.deltaX,
-    delta_y: event.deltaY,
-    delta_z: event.deltaZ,
-    delta_mode: event.deltaMode
-  };
-};
-var serializeTouchEvent = function(event) {
-  return {
-    alt_key: event.altKey,
-    ctrl_key: event.ctrlKey,
-    meta_key: event.metaKey,
-    shift_key: event.shiftKey,
-    changed_touches: event.changedTouches,
-    target_touches: event.targetTouches,
-    touches: event.touches
-  };
-};
-var serializePointerEvent = function(event) {
-  return {
-    alt_key: event.altKey,
-    button: event.button,
-    buttons: event.buttons,
-    client_x: event.clientX,
-    client_y: event.clientY,
-    ctrl_key: event.ctrlKey,
-    meta_key: event.metaKey,
-    page_x: event.pageX,
-    page_y: event.pageY,
-    screen_x: event.screenX,
-    screen_y: event.screenY,
-    shift_key: event.shiftKey,
-    pointer_id: event.pointerId,
-    width: event.width,
-    height: event.height,
-    pressure: event.pressure,
-    tangential_pressure: event.tangentialPressure,
-    tilt_x: event.tiltX,
-    tilt_y: event.tiltY,
-    twist: event.twist,
-    pointer_type: event.pointerType,
-    is_primary: event.isPrimary
-  };
-};
-var serializeMouseEvent = function(event) {
-  return {
-    alt_key: event.altKey,
-    button: event.button,
-    buttons: event.buttons,
-    client_x: event.clientX,
-    client_y: event.clientY,
-    ctrl_key: event.ctrlKey,
-    meta_key: event.metaKey,
-    offset_x: event.offsetX,
-    offset_y: event.offsetY,
-    page_x: event.pageX,
-    page_y: event.pageY,
-    screen_x: event.screenX,
-    screen_y: event.screenY,
-    shift_key: event.shiftKey
-  };
-};
-var serializeKeyboardEvent = function(event) {
-  return {
-    char_code: event.charCode,
-    is_composing: event.isComposing,
-    key: event.key,
-    alt_key: event.altKey,
-    ctrl_key: event.ctrlKey,
-    meta_key: event.metaKey,
-    key_code: event.keyCode,
-    shift_key: event.shiftKey,
-    location: event.location,
-    repeat: event.repeat,
-    which: event.which,
-    code: event.code
-  };
-};
-var serializeAnimationEvent = function(event) {
-  return {
-    animation_name: event.animationName,
-    elapsed_time: event.elapsedTime,
-    pseudo_element: event.pseudoElement
-  };
-};
-var serializeDragEvent = function(event) {
-  return {
-    mouse: {
-      alt_key: event.altKey,
-      ctrl_key: event.ctrlKey,
-      meta_key: event.metaKey,
-      shift_key: event.shiftKey,
-      ...serializeMouseEvent(event)
-    },
-    files: {
-      files: {
-        a: [1, 2, 3]
-      }
-    }
-  };
-};
-
-// src/ts/native.ts
-var getTargetId = function(target) {
-  if (!(target instanceof Node)) {
-    return null;
-  }
-  let ourTarget = target;
-  let realId = null;
-  while (realId == null) {
-    if (ourTarget === null) {
-      return null;
-    }
-    if (ourTarget instanceof Element) {
-      realId = ourTarget.getAttribute(`data-dioxus-id`);
-    }
-    ourTarget = ourTarget.parentNode;
-  }
-  return parseInt(realId);
-};
-var JSChannel_;
-if (RawInterpreter) {
-  JSChannel_ = RawInterpreter;
-}
-
-class NativeInterpreter extends JSChannel_ {
-  intercept_link_redirects;
-  ipc;
-  editsPath;
-  liveview;
-  constructor(editsPath) {
-    super();
-    this.editsPath = editsPath;
-  }
-  initialize(root) {
-    this.intercept_link_redirects = true;
-    this.liveview = false;
-    const dragEventHandler = (e) => {
-    };
-    window.addEventListener("dragover", function(e) {
-      if (e.target instanceof Element && e.target.tagName != "INPUT") {
-        e.preventDefault();
-      }
-    }, false);
-    window.addEventListener("drop", function(e) {
-      let target = e.target;
-      if (!(target instanceof Element)) {
-        return;
-      }
-      e.preventDefault();
-    }, false);
-    window.addEventListener("click", (event) => {
-      const target = event.target;
-      if (target instanceof HTMLInputElement && target.getAttribute("type") === "file") {
-        let target_id = getTargetId(target);
-        if (target_id !== null) {
-          const message = this.serializeIpcMessage("file_dialog", {
-            event: "change&input",
-            accept: target.getAttribute("accept"),
-            directory: target.getAttribute("webkitdirectory") === "true",
-            multiple: target.hasAttribute("multiple"),
-            target: target_id,
-            bubbles: event.bubbles
-          });
-          this.ipc.postMessage(message);
-        }
-        event.preventDefault();
-      }
-    });
-    this.ipc = window.ipc;
-    const handler = (event) => this.handleEvent(event, event.type, true);
-    super.initialize(root, handler);
-  }
-  serializeIpcMessage(method, params = {}) {
-    return JSON.stringify({ method, params });
-  }
-  scrollTo(id, behavior) {
-    const node = this.nodes[id];
-    if (node instanceof HTMLElement) {
-      node.scrollIntoView({ behavior });
-    }
-  }
-  getClientRect(id) {
-    const node = this.nodes[id];
-    if (node instanceof HTMLElement) {
-      const rect = node.getBoundingClientRect();
-      return {
-        type: "GetClientRect",
-        origin: [rect.x, rect.y],
-        size: [rect.width, rect.height]
-      };
-    }
-  }
-  setFocus(id, focus) {
-    const node = this.nodes[id];
-    if (node instanceof HTMLElement) {
-      if (focus) {
-        node.focus();
-      } else {
-        node.blur();
-      }
-    }
-  }
-  loadChild(array) {
-    let node = this.stack[this.stack.length - 1];
-    for (let i = 0;i < array.length; i++) {
-      let end = array[i];
-      for (node = node.firstChild;end > 0; end--) {
-        node = node.nextSibling;
-      }
-    }
-    return node;
-  }
-  appendChildren(id, many) {
-    const root = this.nodes[id];
-    const els = this.stack.splice(this.stack.length - many);
-    for (let k = 0;k < many; k++) {
-      root.appendChild(els[k]);
-    }
-  }
-  handleEvent(event, name, bubbles) {
-    const target = event.target;
-    const realId = getTargetId(target);
-    const contents = serializeEvent(event, target);
-    let body = {
-      name,
-      data: contents,
-      element: realId,
-      bubbles
-    };
-    this.preventDefaults(event, target);
-    if (this.liveview) {
-      if (target instanceof HTMLInputElement && (event.type === "change" || event.type === "input")) {
-        if (target.getAttribute("type") === "file") {
-          this.readFiles(target, contents, bubbles, realId, name);
-        }
-      }
-    } else {
-      const message = this.serializeIpcMessage("user_event", body);
-      this.ipc.postMessage(message);
-    }
-  }
-  preventDefaults(event, target) {
-    let preventDefaultRequests = null;
-    if (target instanceof Element) {
-      preventDefaultRequests = target.getAttribute(`dioxus-prevent-default`);
-    }
-    if (preventDefaultRequests && preventDefaultRequests.includes(`on${event.type}`)) {
-      event.preventDefault();
-    }
-    if (event.type === "submit") {
-      event.preventDefault();
-    }
-    if (target instanceof Element && event.type === "click") {
-      this.handleClickNavigate(event, target, preventDefaultRequests);
-    }
-  }
-  handleClickNavigate(event, target, preventDefaultRequests) {
-    if (!this.intercept_link_redirects) {
-      return;
-    }
-    if (target.tagName === "BUTTON" && event.type == "submit") {
-      event.preventDefault();
-    }
-    let a_element = target.closest("a");
-    if (a_element == null) {
-      return;
-    }
-    event.preventDefault();
-    let elementShouldPreventDefault = preventDefaultRequests && preventDefaultRequests.includes(`onclick`);
-    let aElementShouldPreventDefault = a_element.getAttribute(`dioxus-prevent-default`);
-    let linkShouldPreventDefault = aElementShouldPreventDefault && aElementShouldPreventDefault.includes(`onclick`);
-    if (!elementShouldPreventDefault && !linkShouldPreventDefault) {
-      const href = a_element.getAttribute("href");
-      if (href !== "" && href !== null && href !== undefined) {
-        this.ipc.postMessage(this.serializeIpcMessage("browser_open", { href }));
-      }
-    }
-  }
-  waitForRequest(headless) {
-    fetch(new Request(this.editsPath)).then((response) => response.arrayBuffer()).then((bytes) => {
-      if (headless) {
-        this.run_from_bytes(bytes);
-      } else {
-        requestAnimationFrame(() => this.run_from_bytes(bytes));
-      }
-      this.waitForRequest(headless);
-    });
-  }
-  async readFiles(target, contents, bubbles, realId, name) {
-    let files = target.files;
-    let file_contents = {};
-    for (let i = 0;i < files.length; i++) {
-      const file = files[i];
-      file_contents[file.name] = Array.from(new Uint8Array(await file.arrayBuffer()));
-    }
-    contents.files = { files: file_contents };
-    const message = this.serializeIpcMessage("user_event", {
-      name,
-      element: realId,
-      data: contents,
-      bubbles
-    });
-    this.ipc.postMessage(message);
-  }
-}
-export {
-  NativeInterpreter
-};
+function retriveValues(event,target){let contents={values:{}},form=target.closest("form");if(form){if(event.type==="input"||event.type==="change"||event.type==="submit"||event.type==="reset"||event.type==="click")contents=retrieveFormValues(form)}return contents}function retrieveFormValues(form){const formData=new FormData(form),contents={};return formData.forEach((value,key)=>{if(contents[key])contents[key]+=","+value;else contents[key]=value}),{valid:form.checkValidity(),values:contents}}function retriveSelectValue(target){let options=target.selectedOptions,values=[];for(let i=0;i<options.length;i++)values.push(options[i].value);return values}function serializeEvent(event,target){let contents={},extend=(obj)=>contents={...contents,...obj};if(event instanceof WheelEvent)extend(serializeWheelEvent(event));if(event instanceof MouseEvent)extend(serializeMouseEvent(event));if(event instanceof KeyboardEvent)extend(serializeKeyboardEvent(event));if(event instanceof InputEvent)extend(serializeInputEvent(event,target));if(event instanceof PointerEvent)extend(serializePointerEvent(event));if(event instanceof AnimationEvent)extend(serializeAnimationEvent(event));if(event instanceof TransitionEvent)extend({property_name:event.propertyName,elapsed_time:event.elapsedTime,pseudo_element:event.pseudoElement});if(event instanceof CompositionEvent)extend({data:event.data});if(event instanceof DragEvent)extend(serializeDragEvent(event));if(event instanceof FocusEvent)extend({});if(event instanceof ClipboardEvent)extend({});if(typeof TouchEvent!=="undefined"&&event instanceof TouchEvent)extend(serializeTouchEvent(event));if(event.type==="submit"||event.type==="reset"||event.type==="click"||event.type==="change"||event.type==="input")extend(serializeInputEvent(event,target));if(event instanceof DragEvent);return contents}var serializeInputEvent=function(event,target){let contents={};if(target instanceof HTMLElement){let values=retriveValues(event,target);contents.values=values.values,contents.valid=values.valid}if(event.target instanceof HTMLInputElement){let target2=event.target,value=target2.value??target2.textContent??"";if(target2.type==="checkbox")value=target2.checked?"true":"false";else if(target2.type==="radio")value=target2.value;contents.value=value}if(event.target instanceof HTMLTextAreaElement)contents.value=event.target.value;if(event.target instanceof HTMLSelectElement)contents.value=retriveSelectValue(event.target).join(",");if(contents.value===void 0)contents.value="";return contents},serializeWheelEvent=function(event){return{delta_x:event.deltaX,delta_y:event.deltaY,delta_z:event.deltaZ,delta_mode:event.deltaMode}},serializeTouchEvent=function(event){return{alt_key:event.altKey,ctrl_key:event.ctrlKey,meta_key:event.metaKey,shift_key:event.shiftKey,changed_touches:event.changedTouches,target_touches:event.targetTouches,touches:event.touches}},serializePointerEvent=function(event){return{alt_key:event.altKey,button:event.button,buttons:event.buttons,client_x:event.clientX,client_y:event.clientY,ctrl_key:event.ctrlKey,meta_key:event.metaKey,page_x:event.pageX,page_y:event.pageY,screen_x:event.screenX,screen_y:event.screenY,shift_key:event.shiftKey,pointer_id:event.pointerId,width:event.width,height:event.height,pressure:event.pressure,tangential_pressure:event.tangentialPressure,tilt_x:event.tiltX,tilt_y:event.tiltY,twist:event.twist,pointer_type:event.pointerType,is_primary:event.isPrimary}},serializeMouseEvent=function(event){return{alt_key:event.altKey,button:event.button,buttons:event.buttons,client_x:event.clientX,client_y:event.clientY,ctrl_key:event.ctrlKey,meta_key:event.metaKey,offset_x:event.offsetX,offset_y:event.offsetY,page_x:event.pageX,page_y:event.pageY,screen_x:event.screenX,screen_y:event.screenY,shift_key:event.shiftKey}},serializeKeyboardEvent=function(event){return{char_code:event.charCode,is_composing:event.isComposing,key:event.key,alt_key:event.altKey,ctrl_key:event.ctrlKey,meta_key:event.metaKey,key_code:event.keyCode,shift_key:event.shiftKey,location:event.location,repeat:event.repeat,which:event.which,code:event.code}},serializeAnimationEvent=function(event){return{animation_name:event.animationName,elapsed_time:event.elapsedTime,pseudo_element:event.pseudoElement}},serializeDragEvent=function(event){return{mouse:{alt_key:event.altKey,ctrl_key:event.ctrlKey,meta_key:event.metaKey,shift_key:event.shiftKey,...serializeMouseEvent(event)},files:{files:{a:[1,2,3]}}}};var getTargetId=function(target){if(!(target instanceof Node))return null;let ourTarget=target,realId=null;while(realId==null){if(ourTarget===null)return null;if(ourTarget instanceof Element)realId=ourTarget.getAttribute("data-dioxus-id");ourTarget=ourTarget.parentNode}return parseInt(realId)},JSChannel_;if(RawInterpreter)JSChannel_=RawInterpreter;class NativeInterpreter extends JSChannel_{intercept_link_redirects;ipc;editsPath;liveview;constructor(editsPath){super();this.editsPath=editsPath}initialize(root){this.intercept_link_redirects=!0,this.liveview=!1,window.addEventListener("dragover",function(e){if(e.target instanceof Element&&e.target.tagName!="INPUT")e.preventDefault()},!1),window.addEventListener("drop",function(e){if(!(e.target instanceof Element))return;e.preventDefault()},!1),window.addEventListener("click",(event)=>{const target=event.target;if(target instanceof HTMLInputElement&&target.getAttribute("type")==="file"){let target_id=getTargetId(target);if(target_id!==null){const message=this.serializeIpcMessage("file_dialog",{event:"change&input",accept:target.getAttribute("accept"),directory:target.getAttribute("webkitdirectory")==="true",multiple:target.hasAttribute("multiple"),target:target_id,bubbles:event.bubbles});this.ipc.postMessage(message)}event.preventDefault()}}),this.ipc=window.ipc;const handler=(event)=>this.handleEvent(event,event.type,!0);super.initialize(root,handler)}serializeIpcMessage(method,params={}){return JSON.stringify({method,params})}scrollTo(id,behavior){const node=this.nodes[id];if(node instanceof HTMLElement)node.scrollIntoView({behavior})}getClientRect(id){const node=this.nodes[id];if(node instanceof HTMLElement){const rect=node.getBoundingClientRect();return{type:"GetClientRect",origin:[rect.x,rect.y],size:[rect.width,rect.height]}}}setFocus(id,focus){const node=this.nodes[id];if(node instanceof HTMLElement)if(focus)node.focus();else node.blur()}loadChild(array){let node=this.stack[this.stack.length-1];for(let i=0;i<array.length;i++){let end=array[i];for(node=node.firstChild;end>0;end--)node=node.nextSibling}return node}appendChildren(id,many){const root=this.nodes[id],els=this.stack.splice(this.stack.length-many);for(let k=0;k<many;k++)root.appendChild(els[k])}handleEvent(event,name,bubbles){const target=event.target,realId=getTargetId(target),contents=serializeEvent(event,target);let body={name,data:contents,element:realId,bubbles};if(this.preventDefaults(event,target),this.liveview){if(target instanceof HTMLInputElement&&(event.type==="change"||event.type==="input")){if(target.getAttribute("type")==="file")this.readFiles(target,contents,bubbles,realId,name)}}else{const message=this.serializeIpcMessage("user_event",body);this.ipc.postMessage(message)}}preventDefaults(event,target){let preventDefaultRequests=null;if(target instanceof Element)preventDefaultRequests=target.getAttribute("dioxus-prevent-default");if(preventDefaultRequests&&preventDefaultRequests.includes(`on${event.type}`))event.preventDefault();if(event.type==="submit")event.preventDefault();if(target instanceof Element&&event.type==="click")this.handleClickNavigate(event,target,preventDefaultRequests)}handleClickNavigate(event,target,preventDefaultRequests){if(!this.intercept_link_redirects)return;if(target.tagName==="BUTTON"&&event.type=="submit")event.preventDefault();let a_element=target.closest("a");if(a_element==null)return;event.preventDefault();let elementShouldPreventDefault=preventDefaultRequests&&preventDefaultRequests.includes("onclick"),aElementShouldPreventDefault=a_element.getAttribute("dioxus-prevent-default"),linkShouldPreventDefault=aElementShouldPreventDefault&&aElementShouldPreventDefault.includes("onclick");if(!elementShouldPreventDefault&&!linkShouldPreventDefault){const href=a_element.getAttribute("href");if(href!==""&&href!==null&&href!==void 0)this.ipc.postMessage(this.serializeIpcMessage("browser_open",{href}))}}waitForRequest(headless){fetch(new Request(this.editsPath)).then((response)=>response.arrayBuffer()).then((bytes)=>{if(headless)this.run_from_bytes(bytes);else requestAnimationFrame(()=>this.run_from_bytes(bytes));this.waitForRequest(headless)})}async readFiles(target,contents,bubbles,realId,name){let files=target.files,file_contents={};for(let i=0;i<files.length;i++){const file=files[i];file_contents[file.name]=Array.from(new Uint8Array(await file.arrayBuffer()))}contents.files={files:file_contents};const message=this.serializeIpcMessage("user_event",{name,element:realId,data:contents,bubbles});this.ipc.postMessage(message)}}export{NativeInterpreter};

+ 0 - 41
packages/interpreter/src/ts/native.ts

@@ -32,47 +32,6 @@ export class NativeInterpreter extends JSChannel_ {
     this.intercept_link_redirects = true;
     this.liveview = false;
 
-
-    const dragEventHandler = (e: DragEvent) => {
-      // e.preventDefault();
-      // e.dataTransfer.effectAllowed = 'none';
-      // e.dataTransfer.dropEffect = 'none';
-
-      //
-
-      // we need to signal to the host to provide a native file path,
-      // not the one coming from here
-
-      // We can't get native
-      // if (e.type === "drop") {
-      //   let target = e.target;
-
-      //   if (target instanceof Element) {
-      //     let target_id = getTargetId(target);
-      //     if (target_id !== null) {
-      //       const message = this.serializeIpcMessage("file_drop", {
-      //         event: "drop",
-      //         target: target_id,
-      //         data: Array.from(e.dataTransfer.files).map(file => {
-      //           return {
-      //             name: file.name,
-      //             type: file.type,
-      //             size: file.size,
-      //           };
-      //         }),
-      //       });
-
-      //       this.ipc.postMessage(message);
-      //     }
-      //   }
-      // }
-    };
-
-
-    // ["dragenter", "dragover", "drop"].forEach((event) => {
-    //   window.addEventListener(event, dragEventHandler, false)
-    // });
-
     // attach an event listener on the body that prevents file drops from navigating
     // this is because the browser will try to navigate to the file if it's dropped on the window
     window.addEventListener("dragover", function (e) {

+ 1 - 1
packages/interpreter/src/unified_bindings.rs

@@ -28,7 +28,7 @@ impl Interpreter {
     /// Convert the interpreter to its baseclass, giving
     pub fn base(&self) -> &BaseInterpreter {
         use wasm_bindgen::prelude::JsCast;
-        &self.js_channel().unchecked_ref()
+        self.js_channel().unchecked_ref()
     }
 }
 

+ 4 - 6
packages/web/src/lib.rs

@@ -54,11 +54,9 @@ mod rehydrate;
 ///
 /// # Example
 ///
-/// ```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);
-/// }
+/// ```ignore, rust
+/// let app_fut = dioxus_web::run_with_props(App, RootProps { name: String::from("foo") });
+/// wasm_bindgen_futures::spawn_local(app_fut);
 /// ```
 pub async fn run(virtual_dom: VirtualDom, web_config: Config) {
     tracing::info!("Starting up");
@@ -66,7 +64,7 @@ pub async fn run(virtual_dom: VirtualDom, web_config: Config) {
     let mut dom = virtual_dom;
 
     #[cfg(feature = "eval")]
-    dom.in_runtime(|| eval::init_eval());
+    dom.in_runtime(eval::init_eval);
 
     #[cfg(feature = "panic_hook")]
     if web_config.default_panic_hook {