diff --git a/Cargo.lock b/Cargo.lock index e2075b835f7..4fb288549fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -867,6 +867,18 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "form_file" +version = "0.1.0" +dependencies = [ + "base64 0.21.5", + "gloo 0.10.0", + "gloo-console 0.3.0", + "js-sys", + "web-sys", + "yew", +] + [[package]] name = "form_urlencoded" version = "1.2.0" @@ -2112,16 +2124,6 @@ dependencies = [ "yew", ] -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -2207,12 +2209,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "papergrid" version = "0.10.0" @@ -2787,15 +2783,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -2812,14 +2799,14 @@ dependencies = [ "bytes", "clap", "futures 0.3.29", + "log", "reqwest", "serde", - "time", "tokio", - "tracing-subscriber", - "tracing-web", "uuid", "warp", + "wasm-bindgen-futures", + "wasm-logger", "yew", ] @@ -3058,16 +3045,6 @@ dependencies = [ "syn 2.0.38", ] -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - [[package]] name = "time" version = "0.3.30" @@ -3075,7 +3052,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", - "js-sys", "powerfmt", "serde", "time-core", @@ -3310,45 +3286,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "tracing-web" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e6a141feebd51f8d91ebfd785af50fca223c570b86852166caa3b141defe7c" -dependencies = [ - "js-sys", - "tracing-core", - "tracing-subscriber", - "wasm-bindgen", - "web-sys", ] [[package]] @@ -3485,12 +3422,6 @@ dependencies = [ "serde", ] -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - [[package]] name = "vcpkg" version = "0.2.15" diff --git a/examples/form_file/Cargo.toml b/examples/form_file/Cargo.toml new file mode 100644 index 00000000000..2b26ff288b0 --- /dev/null +++ b/examples/form_file/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "form_file" +version = "0.1.0" +authors = ["Kenzi Connor "] +edition = "2021" +license = "MIT OR Apache-2.0" + +[dependencies] +base64 = "0.21.5" +gloo = "0.10" +gloo-console = "0.3.0" +js-sys = "0.3" +web-sys = { version = "0.3", features = ["FormData", "HtmlFormElement"] } +yew = { path = "../../packages/yew", features = ["csr"] } diff --git a/examples/form_file/README.md b/examples/form_file/README.md new file mode 100644 index 00000000000..45a99e0b22d --- /dev/null +++ b/examples/form_file/README.md @@ -0,0 +1,24 @@ +# Form /w File Upload Example + +[![Demo](https://img.shields.io/website?label=demo&url=https%3A%2F%2Fexamples.yew.rs%2Fform_file)](https://examples.yew.rs/form_file) + +This example shows some more comlicated interactions between file uploads, forms, and node_refs. + +The file selector change disables the form button untill the file is done being processed, at which point it's stashed in App state untill the form is submitted and it's stored in the FileDetails. + +## Concepts + +Demonstrates reading from files in Yew with the help of [`gloo::file`](https://docs.rs/gloo-file/latest/gloo_file/). +Check the file_upload example for the simpler case of just uploading a file. + +## Todo + + - [] disabled form entirely by checking if there are readers left before allowing submit to proceed + +## Running + +Run this application with the trunk development server: + +```bash +trunk serve --open +``` \ No newline at end of file diff --git a/examples/form_file/index.html b/examples/form_file/index.html new file mode 100644 index 00000000000..745fd8c94cd --- /dev/null +++ b/examples/form_file/index.html @@ -0,0 +1,11 @@ + + + + + Yew • Form w/ File Upload + + + + + + diff --git a/examples/form_file/src/main.rs b/examples/form_file/src/main.rs new file mode 100644 index 00000000000..48b028a8e44 --- /dev/null +++ b/examples/form_file/src/main.rs @@ -0,0 +1,135 @@ +use std::collections::HashMap; + +use base64::{engine::general_purpose::STANDARD, Engine}; +use gloo::file::{callbacks::FileReader, File, FileList}; +use gloo_console::debug; +use web_sys::{File as RawFile, FormData, HtmlFormElement, HtmlInputElement}; +use yew::prelude::*; + +pub struct FileDetails { + name: String, + file_type: String, + data: Vec, + alt_text: String, +} + +pub enum Msg { + Loaded(String, Vec), + Submit(SubmitEvent), + File(FileList), +} + +pub struct App { + readers: HashMap, + files: Vec, + button: NodeRef, + file_data: Vec, +} + +impl Component for App { + type Message = Msg; + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self { + readers: HashMap::default(), + files: Vec::default(), + button: NodeRef::default(), + file_data: Vec::default(), + } + } + + fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { + match msg { + Msg::Loaded(name, data) => { + let submit = self.button.cast::().expect("button"); + self.file_data = data; + submit.set_disabled(false); + self.readers.remove(&name); + } + Msg::File(files) => { + let submit = self.button.cast::().expect("button"); + submit.set_disabled(true); + + let file = files[0].clone(); + let link = ctx.link().clone(); + let name = file.name().clone(); + let task = { + gloo::file::callbacks::read_as_bytes(&file, move |res| { + link.send_message(Msg::Loaded(name, res.expect("failed to read file"))); + }) + }; + self.readers.insert(file.name(), task); + } + Msg::Submit(event) => { + debug!(event.clone()); + event.prevent_default(); + let form: HtmlFormElement = event.target_unchecked_into(); + let form_data = FormData::new_with_form(&form).expect("form data"); + let image_file = File::from(RawFile::from(form_data.get("file"))); + + let alt_text = form_data.get("alt-text").as_string().unwrap(); + let name = image_file.name(); + let data = self.file_data.clone(); + + let file_type = image_file.raw_mime_type(); + self.files.push(FileDetails { + alt_text, + name, + data, + file_type, + }); + self.file_data = Vec::default(); + } + } + true + } + + fn view(&self, ctx: &Context) -> Html { + html! { +
+
+ {"Alt Text"} + + + +
+
+ { for self.files.iter().map(Self::view_file) } +
+
+ } + } +} + +impl App { + fn view_file(file: &FileDetails) -> Html { + let src = format!( + "data:{};base64,{}", + file.file_type, + STANDARD.encode(&file.data) + ); + html! { +
+

{ format!("{}", file.name) }

+
+ {file.alt_text.clone()}/ +
+
+ } + } +} + +fn main() { + yew::Renderer::::new().render(); +}