Pārlūkot izejas kodu

wip: start moving events to rc<event>

Jonathan Kelley 4 gadi atpakaļ
vecāks
revīzija
b9ff95fa12

+ 29 - 32
Cargo.toml

@@ -23,41 +23,38 @@ router = []
 web = []
 desktop = []
 
+
+[profile.dev]
+split-debuginfo = "unpacked"
+
+
+[dev-dependencies]
+# For the tide ssr examples
+async-std = { version="1.9.0", features=["attributes"] }
+tide = { version="0.16.0" }
+
+# For the livewview example
+tide-websockets = "0.4.0"
+serde_millis = "0.1"
+serde_json = "1"
+serde = { version="1", features=['derive'] }
+
+# For the doc generator
+pulldown-cmark = { version="0.8.0", default-features=false }
+
+dioxus-webview = { path="./packages/webview", version="0.0.0" }
+dioxus-hooks = { path="./packages/hooks", version="0.0.0" }
+rand = "0.8.4"
+
+
 [workspace]
-# members = ["packages/core-macro"]
 members = [
     "packages/core-macro",
     "packages/core",
     "packages/web",
-    "packages/ssr",
-    "packages/docsite",
-    "packages/atoms",
-    "packages/router",
+    # "packages/ssr",
+    # "packages/docsite",
+    # "packages/atoms",
+    # "packages/router",
+    # "packages/inputs",
 ]
-# "packages/webview",
-
-# "packages/cli",
-# "packages/webview",
-# "packages/hooks",
-# "packages/ios",
-
-[profile.dev]
-split-debuginfo = "unpacked"
-
-# "packages/liveview",
-# "packages/3d",
-
-# Built-in
-# "packages/webview/client",
-# "packages/router",
-# "packages/webview",
-# "packages/livehost",
-# "packages/vscode-ext",
-# "packages/recoil",
-# "packages/redux",
-# "packages/macro",
-# TODO @Jon, share the validation code
-# "packages/web",
-# "packages/cli",
-# "examples",
-# "packages/html-macro",

+ 0 - 82
examples/Cargo.toml

@@ -1,82 +0,0 @@
-[package]
-name = "dioxus-examples"
-version = "0.0.0"
-authors = ["Jonathan Kelley <jkelleyrtp@gmail.com>"]
-edition = "2018"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-fern = { version = "0.6.0", features = ["colored"] }
-log = "0.4.1"
-dioxus = { path = "../packages/dioxus" }
-dioxus-ssr = { path = "../packages/ssr" }
-rand = "0.8.2"
-anyhow = "*"
-
-
-[dev-dependencies]
-# For the tide ssr examples
-async-std = { version = "1.9.0", features = ["attributes"] }
-tide = { version = "0.15.0" }
-
-# For the livewview example
-tide-websockets = "0.1.0"
-serde_millis = "0.1"
-serde_json = "1"
-serde = { version = "1", features = ['derive'] }
-
-# For the doc generator
-pulldown-cmark = { version = "0.8.0", default-features = false }
-
-dioxus-webview = { path = "../packages/webview", version = "0.0.0" }
-dioxus-hooks = { path = "../packages/hooks", version = "0.0.0" }
-
-
-# Shared functionality is done as a lib
-[lib]
-path = "common.rs"
-
-# ================================
-# Examples are manually keyed in
-# ================================
-
-[[example]]
-path = "example_app.rs"
-name = "example_app"
-
-[[example]]
-path = "website.rs"
-name = "website"
-
-# [[example]]
-# path = "hello_web.rs"
-# name = "hello_web"
-
-# [[example]]
-# path = "tide_ssr.rs"
-# name = "tide_ssr"
-
-# [[example]]
-# path = "doc_generator.rs"
-# name = "doc_generator"
-
-# [[example]]
-# path = "router.rs"
-# name = "router"
-
-# [[example]]
-# path = "fc_macro.rs"
-# name = "fc_macro"
-
-# [[example]]
-# path = "webview.rs"
-# name = "webview"
-
-# [[example]]
-# path = "blah.rs"
-# name = "blah"
-
-# [[example]]
-# path = "live.rs"
-# name = "live"

+ 3 - 1
examples/README.md

@@ -1,3 +1,5 @@
 # Examples
 
-Most of these examples are run through webview so you don't need the dioxus cli installed to preview the functionality. Anything labeled `_web` will need to be compiled with Dioxus CLI.
+Most of these examples are run through webview so you don't need the dioxus cli installed to preview the functionality. Anything labeled `_web` will need to be built with the Dioxus CLI to preview features that only a native bundle can handle.
+
+List of examples:

+ 0 - 9
examples/blah.rs

@@ -1,9 +0,0 @@
-use dioxus::prelude::*;
-
-fn main() {
-    let g = html! {
-        <div>
-            <style> </style>
-        </div>
-    };
-}

+ 0 - 50
examples/common.rs

@@ -1,50 +0,0 @@
-//! Common utilities for integration examples
-
-pub mod logger {
-
-    use fern::colors::{Color, ColoredLevelConfig};
-    use log::debug;
-
-    pub fn set_up_logging(bin_name: &'static str) {
-        // configure colors for the whole line
-        let colors_line = ColoredLevelConfig::new()
-            .error(Color::Red)
-            .warn(Color::Yellow)
-            // we actually don't need to specify the color for debug and info, they are white by default
-            .info(Color::White)
-            .debug(Color::White)
-            // depending on the terminals color scheme, this is the same as the background color
-            .trace(Color::BrightBlack);
-
-        // configure colors for the name of the level.
-        // since almost all of them are the same as the color for the whole line, we
-        // just clone `colors_line` and overwrite our changes
-        let colors_level = colors_line.clone().info(Color::Green);
-        // here we set up our fern Dispatch
-        fern::Dispatch::new()
-            .format(move |out, message, record| {
-                out.finish(format_args!(
-                    "{color_line}[{level}{color_line}] {message}\x1B[0m",
-                    color_line = format_args!(
-                        "\x1B[{}m",
-                        colors_line.get_color(&record.level()).to_fg_str()
-                    ),
-                    level = colors_level.color(record.level()),
-                    message = message,
-                ));
-            })
-            // set the default log level. to filter out verbose log messages from dependencies, set
-            // this to Warn and overwrite the log level for your crate.
-            .level(log::LevelFilter::Warn)
-            // change log levels for individual modules. Note: This looks for the record's target
-            // field which defaults to the module path but can be overwritten with the `target`
-            // parameter:
-            // `info!(target="special_target", "This log message is about special_target");`
-            .level_for(bin_name, log::LevelFilter::Info)
-            // .level_for("pretty_colored", log::LevelFilter::Trace)
-            // output to stdout
-            .chain(std::io::stdout())
-            .apply()
-            .unwrap();
-    }
-}

+ 0 - 56
examples/doc_generator.rs

@@ -1,56 +0,0 @@
-//! The docs generator takes in the `docs` folder and creates a neat, statically-renderer webpage.
-//! These docs are used to generate the public-facing doc content, showcasing Dioxus' abiltity to
-//! be used in custom static rendering pipelines.
-//!
-//! We use pulldown_cmark as the markdown parser, but instead of outputting html directly, we output
-//! VNodes to be used in conjuction with our custom templates.
-
-use dioxus::core::prelude::*;
-use pulldown_cmark::{Options, Parser};
-
-fn main() {
-    let gen_dir = "../docs/";
-
-    let site: FC<()> = |_| {
-        html! {
-            <html>
-
-            <head>
-            </head>
-            <body>
-            </body>
-
-            </html>
-        }
-    };
-}
-
-static Homepage: FC<()> = |_| {
-    html! {<div> </div>}
-};
-
-static DocPage: FC<()> = |_| {
-    html! {<div> </div>}
-};
-
-// struct StaticSiteCfg {
-//     gen_dir: &'static str,
-//     homepage_template: fn() -> VNode,
-//     page_template: fn(page: &'static str) -> VNode,
-// }
-
-// impl StaticSiteCfg {
-//     fn render(self) -> anyhow::Result<VNode> {
-//         let StaticSiteCfg { .. } = self;
-
-//         // Set up options and parser. Strikethroughs are not part of the CommonMark standard
-//         // and we therefore must enable it explicitly.
-//         let mut options = Options::empty();
-//         options.insert(Options::ENABLE_STRIKETHROUGH);
-//         let parser = Parser::new_ext(markdown_input, options);
-
-//         //
-
-//         Ok(html! {<div> </div>})
-//     }
-// }

+ 3 - 2
examples/external_updates.rs

@@ -1,5 +1,6 @@
 //! Example: External Updates
 //! -------------------------
+//!
 //! Cause updates to the VirtualDOM state from outside the component lifecycle.
 //! The root props could be changed or the use_receiver hook could be used.
 //!
@@ -30,8 +31,8 @@ fn App(ctx: Context, props: &RootProps) -> VNode {
 
     ctx.render(rsx! {
         div {
-            a { href="/dogs/"}
-            a { href="/cats/"}
+            a { href: "/dogs/"}
+            a { href: "/cats/"}
             {content}
         }
     })

+ 0 - 75
examples/fc_macro.rs

@@ -1,75 +0,0 @@
-use dioxus::prelude::*;
-use dioxus_ssr::TextRenderer;
-
-// todo @Jon, support components in the html! macro
-// let renderer = TextRenderer::new(|_| html! {<Example name="world"/>});
-fn main() {
-    let renderer = TextRenderer::<()>::new(|_| html! {<div> "Hello world" </div>});
-    let output = renderer.render();
-}
-
-/// An example component that demonstrates how to use the functional_component macro
-/// This macro makes writing functional components elegant, similar to how Rocket parses URIs.
-///
-/// You don't actually *need* this macro to be productive, but it makes life easier, and components cleaner.
-/// This approach also integrates well with tools like Rust-Analyzer.
-///
-/// Notice that Context is normally generic over props, but RA doesn't care when in proc-macro mode.
-/// Also notice that ctx.props still works like you would expect, so migrating to the macro is easy.
-#[fc]
-fn example(ctx: &Context, name: String) -> VNode {
-    html! { <div> "Hello, {name}!" </div> }
-}
-
-/*
-TODO
-
-/// The macro can also be applied to statics in order to make components less verbose
-/// The FC type automatically adds the inference, and property fields are automatically added as function arguments
-#[fc]
-static Example: FC = |ctx, name: String| {
-    html! { <div> "Hello, {name}!" </div> }
-};
-*/
-
-// This trait is not exposed to users directly, though they could manually implement this for struct-style components
-trait Comp {
-    type Props: Properties;
-    fn render(&self, ctx: &mut Context<Self::Props>) -> VNode;
-    fn builder(&self) -> Self::Props;
-}
-trait Properties {
-    fn new() -> Self;
-}
-
-impl<T: Properties> Comp for FC<T> {
-    type Props = T;
-
-    fn render(&self, ctx: &mut Context<T>) -> VNode {
-        let g = self(ctx);
-        g
-    }
-
-    fn builder(&self) -> T {
-        T::new()
-    }
-}
-
-#[allow(unused, non_upper_case_globals)]
-static MyComp: FC<()> = |ctx| {
-    html! {
-        <div>
-            <p> "hello world" </p>
-        </div>
-    }
-};
-
-fn my_comp(ctx: &Context<()>) -> VNode {
-    todo!()
-}
-
-fn test() {
-    let mut ctx = Context { props: &() };
-    let f = MyComp.render(&mut ctx);
-    let props = MyComp.builder();
-}

+ 0 - 6
examples/hello_web.rs

@@ -1,6 +0,0 @@
-//! Example: Hello-web
-//! -----------------
-//!
-//! This example showcases Dioxus-websys to build interactive single-page-applications, much like React.
-
-fn main() {}

+ 2 - 2
examples/router.rs

@@ -34,8 +34,8 @@ fn App(ctx: Context<()>) -> VNode {
 
     ctx.render(rsx! {
         div {
-            a { href="/dogs/"}
-            a { href="/cats/"}
+            a { href: "/dogs/"}
+            a { href: "/cats/"}
             {router.render()}
         }
     })

+ 0 - 104
examples/tide_ssr.rs

@@ -1,104 +0,0 @@
-//! Example: Tide Server-Side-Rendering
-//! -----------------------------------
-//!
-//! This demo shows how to use the to_string utility on VNodes to convert them into valid HTML.
-//! You can use the html! macro to craft webpages generated by the server on-the-fly.
-//!
-//! Server-side-renderered webpages are a great use of Rust's async story, where servers can handle
-//! thousands of simultaneous clients on minimal hardware.
-
-use dioxus::prelude::*;
-use dioxus_ssr::TextRenderer;
-use rand::Rng;
-use tide::{Request, Response};
-
-#[async_std::main]
-async fn main() -> Result<(), std::io::Error> {
-    dioxus_examples::logger::set_up_logging("tide_ssr");
-
-    // Build the API
-    let mut app = tide::new();
-    app.at("/fib/:n").get(fibsum);
-
-    // Launch the server
-    let addr = "127.0.0.1:8080";
-    log::info!("App is ready at {}", addr);
-    log::info!("Navigate to a fibonacci number: http://{}/fib/21", addr);
-    app.listen(addr).await?;
-
-    Ok(())
-}
-
-fn fib(n: usize) -> usize {
-    if n == 0 || n == 1 {
-        n
-    } else {
-        fib(n - 1) + fib(n - 2)
-    }
-}
-
-/// Calculate the fibonacci number for a given request input
-async fn fibsum(req: Request<()>) -> tide::Result<tide::Response> {
-    let n: usize = req.param("n")?.parse().unwrap_or(0);
-
-    // Start a stopwatch
-    // Compute the nth number in the fibonacci sequence
-    // Stop the stopwatch
-    let start = std::time::Instant::now();
-    let fib_n = fib(n);
-    let duration = start.elapsed().as_nanos();
-
-    // Generate another random number to try
-    let other_fib_to_try = rand::thread_rng().gen_range(1..42);
-
-    let text = TextRenderer::<()>::to_text(html! {
-        <html>
-
-        // Header
-        <head>
-            <meta content="text/html;charset=utf-8" />
-            <meta charset="UTF-8" />
-            <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" />
-        </head>
-
-        // Body
-        <body>
-            <div class="flex items-center justify-center flex-col">
-                <div class="flex items-center justify-center">
-                    <div class="flex flex-col bg-white rounded p-4 w-full max-w-xs">
-                        // Title
-                        <div class="font-bold text-xl">
-                            {format!("Fibonacci Calculator: n = {}",n)}
-                        </div>
-
-                        // Subtext / description
-                        <div class="text-sm text-gray-500">
-                            {format!("Calculated in {} nanoseconds",duration)}
-                        </div>
-
-                        <div class="flex flex-row items-center justify-center mt-6">
-                            // Main number
-                            <div class="font-medium text-6xl">
-                                {format!("{}",fib_n)}
-                            </div>
-                        </div>
-
-                        // Try another
-                        <div class="flex flex-row justify-between mt-6">
-                            <a href=format!("http://localhost:8080/fib/{}", other_fib_to_try) class="underline">
-                                {"Click to try another number"}
-                            </a>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </body>
-
-        </html>
-    });
-
-    Ok(Response::builder(203)
-        .body(text)
-        .content_type(tide::http::mime::HTML)
-        .build())
-}

+ 0 - 78
packages/core/examples/rsx_usage.rs

@@ -45,81 +45,3 @@ impl Render for Button {
         })
     }
 }
-
-// #[fc]
-// fn Button(ctx: Context, onhover: Option<&dyn Fn()>) -> VNode {}
-
-// h1 {
-//     tag: "type", abc: 123, class: "big small wide short",
-//     "title1"
-//     "title1"
-//     "title1"
-//     "title"
-// }
-
-//     h1 ("title") {
-//          tag: "type",
-//          abc: 123,
-//          class: "big small wide short",
-//     }
-
-//     // <button
-//     //     class="inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
-//     //     onclick={move |_| set_name("jill")}
-//     //     onclick={move |_| set_name("jill")}
-//     // >
-//     //     "Jill!"
-//     // </button>
-
-//     button { "Jill!",
-//         class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
-//         onclick: move |_| set_name("jill"),
-//         onclick: move |_| set_name("jill"),
-//     }
-
-//     button {
-//         class: "inline-block py-4 px-8 mr-6 leading-none text-white bg-indigo-600 hover:bg-indigo-900 font-semibold rounded shadow"
-//         onclick: move |_| set_name("jill"),
-//         onclick: move |_| set_name("jill"),
-//         // this is valid
-//         "Jill!",
-//         // this is also valid
-//         {"Jill!"}
-//     }
-
-//     h1 { "Text", class: "inline-block py-4 px-8 mr-6 leading-none" }
-
-//     // <h1 class="inline-block py-4 px-8 mr-6 leading-none">
-//     //     "Text"
-//     // </h1>
-
-//     h1 {
-//         div {
-//             h1 {}
-//             h2 {}
-//             Brick {}
-
-//             p {}
-//             p {
-//                 tag: "type",
-//                 abc: 123,
-//                 enabled: true,
-//                 class: "big small wide short",
-
-//                 a { "abcder" },
-//                 h2 { "whatsup", class: "abc-123" },
-//                 CustomComponent { a: 123, b: 456, key: "1" },
-//             }
-
-//             div { class: "big small wide short",
-//                 div {},
-//                 div {},
-//                 div {},
-//                 div {},
-//             }
-//         }
-//     }
-
-//     h2 {}
-//     h3 {}
-//     "abcd123"

+ 46 - 97
packages/core/src/events.rs

@@ -1,9 +1,8 @@
-//! Virtual Events
-//! This module provides a wrapping of platform-specific events with a list of events easier to work with.
-//! 3rd party renderers are responsible for forming this virtual events from events.
-//! The goal here is to provide a consistent event interface across all renderer types.
+//! This module provides a set of common events for all Dioxus apps to target, regardless of host platform.
+//! -------------------------------------------------------------------------------------------------------
 //!
-//! also... websys integerates poorly with rust analyzer, so we handle that for you automatically.
+//! 3rd party renderers are responsible for converting their native events into these virtual event types. Events might
+//! be heavy or need to interact through FFI, so the events themselves are designed to be lazy.
 
 use crate::innerlude::ScopeIdx;
 
@@ -46,15 +45,13 @@ pub enum VirtualEvent {
     MouseEvent(on::MouseEvent),
     PointerEvent(on::PointerEvent),
 
-    // todo
-
     // ImageEvent(event_data::ImageEvent),
     OtherEvent,
 }
 
 pub mod on {
     #![allow(unused)]
-    use std::ops::Deref;
+    use std::{ops::Deref, rc::Rc};
 
     use crate::{
         builder::ElementBuilder,
@@ -64,15 +61,10 @@ pub mod on {
 
     use super::VirtualEvent;
 
-    macro_rules! event_builder {
-            (
-                $eventdata:ident;
+    macro_rules! event_directory {
+        ( $( $eventdata:ident: [ $( $name:ident )* ]; )* ) => {
             $(
-                $(#[$attr:meta])*
-                $name:ident
-            )* ) => {
                 $(
-                    $(#[$attr])*
                     pub fn $name<'a>(
                         c: &'_ NodeCtx<'a>,
                         callback: impl Fn($eventdata) + 'a,
@@ -84,41 +76,61 @@ pub mod on {
                             scope: c.scope_ref.arena_idx,
                             callback: bump.alloc(move |evt: VirtualEvent| match evt {
                                 VirtualEvent::$eventdata(event) => callback(event),
-                                _ => {
-                                    unreachable!("Downcasted VirtualEvent to wrong event type - this is a bug!")
-                                }
+                                _ => unreachable!("Downcasted VirtualEvent to wrong event type - this is an internal bug!")
                             }),
                         }
                     }
                 )*
-            };
-        }
+            )*
+        };
+    }
+
+    event_directory! {
+        ClipboardEvent: [copy cut paste];
+        CompositionEvent: [compositionend compositionstart compositionupdate];
+        KeyboardEvent: [keydown keypress keyup];
+        FocusEvent: [focus blur];
+        FormEvent: [change input invalid reset submit];
+        GenericEvent: [];
+        MouseEvent: [
+            click contextmenu doubleclick drag dragend dragenter dragexit
+            dragleave dragover dragstart drop mousedown mouseenter mouseleave
+            mousemove mouseout mouseover mouseup
+        ];
+        PointerEvent: [
+            pointerdown pointermove pointerup pointercancel gotpointercapture
+            lostpointercapture pointerenter pointerleave pointerover pointerout
+        ];
+        SelectionEvent: [select];
+        TouchEvent: [touchcancel touchend touchmove touchstart];
+        UIEvent: [scroll];
+        WheelEvent: [wheel];
+        MediaEvent: [
+            abort canplay canplaythrough durationchange emptied encrypted
+            ended error loadeddata loadedmetadata loadstart pause play
+            playing progress ratechange seeked seeking stalled suspend
+            timeupdate volumechange waiting
+        ];
+        AnimationEvent: [animationstart animationend animationiteration];
+        TransitionEvent: [transitionend];
+        ToggleEvent: [toggle];
+    }
 
     pub struct GetModifierKey(pub Box<dyn Fn(usize) -> bool>);
     impl std::fmt::Debug for GetModifierKey {
         fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-            // just skip for now
-            Ok(())
+            Ok(()) // just skip for now
         }
     }
 
     // DOMDataTransfer clipboardData
     #[derive(Debug)]
     pub struct ClipboardEvent {}
-    event_builder! {
-        ClipboardEvent;
-        copy cut paste
-    }
 
-    // string data
     #[derive(Debug)]
     pub struct CompositionEvent {
         data: String,
     }
-    event_builder! {
-        CompositionEvent;
-        compositionend compositionstart compositionupdate
-    }
 
     #[derive(Debug)]
     pub struct KeyboardEvent {
@@ -134,12 +146,11 @@ pub mod on {
         which: usize,
         get_modifier_state: GetModifierKey,
     }
-    pub struct KeyboardEvent2(pub Box<dyn KeyboardEventT>);
+    pub struct KeyboardEvent2(pub Rc<dyn KeyboardEventT>);
     impl std::ops::Deref for KeyboardEvent2 {
-        type Target = Box<dyn KeyboardEventT>;
-
+        type Target = dyn KeyboardEventT;
         fn deref(&self) -> &Self::Target {
-            &self.0
+            self.0.as_ref()
         }
     }
 
@@ -157,32 +168,16 @@ pub mod on {
         fn get_modifier_state(&self) -> GetModifierKey;
     }
 
-    event_builder! {
-        KeyboardEvent;
-        keydown keypress keyup
-    }
-
     #[derive(Debug)]
     pub struct FocusEvent {/* DOMEventTarget relatedTarget */}
-    event_builder! {
-        FocusEvent;
-        focus blur
-    }
 
     #[derive(Debug)]
     pub struct FormEvent {
         pub value: String,
     }
-    event_builder! {
-        FormEvent;
-        change input invalid reset submit
-    }
 
     #[derive(Debug)]
     pub struct GenericEvent {/* Error Load */}
-    event_builder! {
-        GenericEvent;
-    }
 
     #[derive(Debug)]
     pub struct MouseEvent(pub Box<RawMouseEvent>);
@@ -210,12 +205,6 @@ pub mod on {
             self.0.as_ref()
         }
     }
-    event_builder! {
-        MouseEvent;
-        click contextmenu doubleclick drag dragend dragenter dragexit
-        dragleave dragover dragstart drop mousedown mouseenter mouseleave
-        mousemove mouseout mouseover mouseup
-    }
 
     #[derive(Debug)]
     pub struct PointerEvent(Box<RawPointerEvent>);
@@ -255,18 +244,9 @@ pub mod on {
         pointer_type: String,
         is_primary: bool,
     }
-    event_builder! {
-        PointerEvent;
-        pointerdown pointermove pointerup pointercancel gotpointercapture
-        lostpointercapture pointerenter pointerleave pointerover pointerout
-    }
 
     #[derive(Debug)]
     pub struct SelectionEvent {}
-    event_builder! {
-        SelectionEvent;
-        select
-    }
 
     #[derive(Debug)]
     pub struct TouchEvent {
@@ -282,20 +262,12 @@ pub mod on {
         // touches: DOMTouchList,
         //  getModifierState(key): boolean
     }
-    event_builder! {
-        TouchEvent;
-        touchcancel touchend touchmove touchstart
-    }
 
     #[derive(Debug)]
     pub struct UIEvent {
         // DOMAbstractView view
         detail: i32,
     }
-    event_builder! {
-        UIEvent;
-        scroll
-    }
 
     #[derive(Debug)]
     pub struct WheelEvent {
@@ -304,20 +276,9 @@ pub mod on {
         delta_y: i32,
         delta_z: i32,
     }
-    event_builder! {
-        WheelEvent;
-        wheel
-    }
 
     #[derive(Debug)]
     pub struct MediaEvent {}
-    event_builder! {
-        MediaEvent;
-        abort canplay canplaythrough durationchange emptied encrypted
-        ended error loadeddata loadedmetadata loadstart pause play
-        playing progress ratechange seeked seeking stalled suspend
-        timeupdate volumechange waiting
-    }
 
     // todo!
     // imageevent clashes with media event
@@ -336,10 +297,6 @@ pub mod on {
         pseudo_element: String,
         elapsed_time: f32,
     }
-    event_builder! {
-        AnimationEvent;
-        animationstart animationend animationiteration
-    }
 
     #[derive(Debug)]
     pub struct TransitionEvent {
@@ -347,15 +304,7 @@ pub mod on {
         pseudo_element: String,
         elapsed_time: f32,
     }
-    event_builder! {
-        TransitionEvent;
-        transitionend
-    }
 
     #[derive(Debug)]
     pub struct ToggleEvent {}
-    event_builder! {
-        ToggleEvent;
-        toggle
-    }
 }

+ 2 - 1
packages/core/src/virtual_dom.rs

@@ -274,7 +274,7 @@ impl VirtualDom {
         // Now, there are events in the queue
         let mut updates = self.event_queue.0.as_ref().borrow_mut();
 
-        // Order the nodes by their height, we want the biggest nodes on the top
+        // Order the nodes by their height, we want the nodes with the smallest depth on top
         // This prevents us from running the same component multiple times
         updates.sort_unstable();
 
@@ -300,6 +300,7 @@ impl VirtualDom {
             // let cur_component = inner.get_mut(update.idx).unwrap();
 
             cur_component.run_scope()?;
+            // diff_machine.change_list.load_known_root(1);
 
             diff_machine.diff_node(cur_component.old_frame(), cur_component.next_frame());
 

+ 8 - 0
packages/inputs/Cargo.toml

@@ -0,0 +1,8 @@
+[package]
+name = "dioxus-inputs"
+version = "0.0.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]

+ 28 - 0
packages/inputs/README.md

@@ -0,0 +1,28 @@
+# Cross-platform controlled inputs
+
+Dioxus does not include controlled inputs in Dioxus-Core. This would require core integration with HTML that is inherently not cross platform. Instead, this crate exists to provide a bunch of cross-platform input types that abstract over renderer quirks.
+
+Included is:
+
+- Button
+- Checkbox
+- Color
+- Date
+- Datetime-local
+- Email
+- File
+- Hidden
+- Image
+- Month
+- Number
+- Password
+- Radio
+- Range
+- Reset
+- Search
+- Submit
+- Tel
+- Text
+- Time
+- Url
+- Week

+ 7 - 0
packages/inputs/src/lib.rs

@@ -0,0 +1,7 @@
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn it_works() {
+        assert_eq!(2 + 2, 4);
+    }
+}

+ 4 - 0
packages/web/Cargo.toml

@@ -36,9 +36,12 @@ version = "0.3.50"
 features = [
     "Comment",
     "Document",
+    # "DataTransfer",
     "Element",
     "HtmlElement",
     "HtmlInputElement",
+    "HtmlSelectElement",
+    "HtmlTextAreaElement",
     "EventTarget",
     "HtmlCollection",
     "Node",
@@ -60,6 +63,7 @@ features = [
     "DocumentType",
     "CharacterData",
     "HtmlOptionElement",
+
 ]
 
 [profile.release]

+ 72 - 0
packages/web/examples/input.rs

@@ -0,0 +1,72 @@
+use dioxus_core as dioxus;
+use dioxus_core::prelude::*;
+use dioxus_web::WebsysRenderer;
+
+fn main() {
+    // wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
+    console_error_panic_hook::set_once();
+
+    log::info!("hello world");
+    wasm_bindgen_futures::spawn_local(WebsysRenderer::start(App));
+}
+
+static App: FC<()> = |ctx| {
+    let (val, set_val) = use_state(&ctx, || "asd".to_string());
+
+    ctx.render(rsx! {
+        div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
+            div { class: "container py-5 max-w-md mx-auto"
+                h1 { class: "text-gray-200 text-center font-extrabold -mt-3 text-3xl", 
+                    "Text Input Example"
+                } 
+                div { class: "mb-4"
+                    input {
+                        placeholder: "Username"
+                        class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
+                        id: "username" 
+                        type: "text"
+                        value: "{val}"
+                        oninput: move |evet| {
+                            log::debug!("Value is {:#?}", evet);
+                            set_val(evet.value);
+                        }
+                    }
+                    p { "Val is: {val}" }
+                }            
+            }
+        }
+    })    
+};
+
+static Example: FC<()> = |ctx| {
+    ctx.render(rsx! {
+        div { class: "max-w-lg max-w-xs bg-blue-800 shadow-2xl rounded-lg mx-auto text-center py-12 mt-4 rounded-xl"
+            div { class: "container py-5 max-w-md mx-auto"
+                h1 { class: "text-gray-200 text-center font-extrabold -mt-3 text-3xl", 
+                    "Text Input Example"
+                } 
+                UserInput {}
+            }
+        }
+    })
+};
+
+static UserInput: FC<()> = |ctx| {
+    let (val, set_val) = use_state(&ctx, || "asd".to_string());
+
+    rsx!{ in ctx,
+        div { class: "mb-4"
+            input { class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
+                placeholder: "Username"
+                id: "username" 
+                type: "text"
+                oninput: move |evet| {
+                    log::debug!("Value is {:#?}", evet);
+                    set_val(evet.value);
+                }
+            }
+            p { "Val is: {val}" }
+        }
+    }
+    
+};

+ 33 - 4
packages/web/src/interpreter.rs

@@ -7,7 +7,9 @@ use dioxus_core::{
 };
 use fxhash::FxHashMap;
 use wasm_bindgen::{closure::Closure, JsCast};
-use web_sys::{window, Document, Element, Event, HtmlInputElement, HtmlOptionElement, Node};
+use web_sys::{
+    window, Document, Element, Event, HtmlElement, HtmlInputElement, HtmlOptionElement, Node,
+};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
 pub struct CacheId(u32);
@@ -564,11 +566,38 @@ fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
             todo!()
         }
 
-        "change" | "input" | "invalid" | "reset" | "submit" => {
+        "change" => {
+            let evt: web_sys::Event = event.clone().dyn_into().expect("wrong error typ");
+            todo!()
+            // VirtualEvent::FormEvent(FormEvent {value:})
+        }
+
+        "input" | "invalid" | "reset" | "submit" => {
             // is a special react events
             let evt: web_sys::InputEvent = event.clone().dyn_into().expect("wrong event type");
-            let value: Option<String> = (&evt).data();
-            let value = value.unwrap_or_default();
+            let this: web_sys::EventTarget = evt.target().unwrap();
+
+            let value = (&this)
+                .dyn_ref()
+                .map(|input: &web_sys::HtmlInputElement| input.value())
+                .or_else(|| {
+                    (&this)
+                        .dyn_ref()
+                        .map(|input: &web_sys::HtmlTextAreaElement| input.value())
+                })
+                .or_else(|| {
+                    (&this)
+                        .dyn_ref::<web_sys::HtmlElement>()
+                        .unwrap()
+                        .text_content()
+                })
+                .expect("only an InputElement or TextAreaElement or an element with contenteditable=true can have an oninput event listener");
+
+            // let p2 = evt.data_transfer();
+
+            // let value: Option<String> = (&evt).data();
+            // let value = val;
+            // let value = value.unwrap_or_default();
             // let value = (&evt).data().expect("No data to unwrap");
 
             // todo - this needs to be a "controlled" event

+ 11 - 5
src/lib.rs

@@ -177,6 +177,11 @@
 //! };
 //! ```
 
+pub mod prelude {
+    //! A glob import that includes helper types like FC, rsx!, html!, and required traits
+    pub use dioxus_core::prelude::*;
+    pub use dioxus_core_macro::fc;
+}
 // Just a heads-up, the core functionality of dioxus rests in Dioxus-Core. This crate just wraps a bunch of utilities
 // together and exports their namespaces to something predicatble.
 #[cfg(feature = "core")]
@@ -186,12 +191,12 @@ pub mod core {
     // Re-export core completely
     pub use dioxus_core::*;
 }
-pub mod prelude {
-    //! A glob import that includes helper types like FC, rsx!, html!, and required traits
-    pub use dioxus_core::prelude::*;
-    pub use dioxus_core_macro::fc;
-}
 
+// Input elements work differently on different platforms.
+// This module helps abstract over Selects, TextInputs, TextAreas, Radios, etc for a cross-platform input experience
+pub mod inputs {
+    //! Cross-platform abstractions over user inputs
+}
 #[cfg(feature = "web")]
 pub mod web {
     //! A web-sys based renderer for building fast and interactive web applications
@@ -214,6 +219,7 @@ pub mod testing {
 }
 #[cfg(feature = "atoms")]
 pub mod atoms {}
+
 #[cfg(feature = "desktop")]
 pub mod desktop {
     //! A webview based renderer for building desktop applications with Dioxus