From 3f3db39c2827106070161e34b2fd579ae2371f0f Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 15 Jan 2023 15:18:12 -0600 Subject: [PATCH 01/41] update doc links --- README.md | 2 +- docs/posts/release.md | 4 ++-- docs/reference/src/README_pt-br.md | 2 +- docs/reference/src/platforms/desktop.md | 2 +- notes/README/ZH_CN.md | 2 +- packages/autofmt/README.md | 2 +- packages/core-macro/README.md | 2 +- packages/desktop/README.md | 4 ++-- packages/desktop/src/readme.md | 2 +- packages/dioxus/README.md | 4 ++-- packages/hooks/README.md | 2 +- packages/html/README.md | 2 +- packages/interpreter/README.md | 2 +- packages/liveview/README.md | 2 +- packages/mobile/README.md | 4 ++-- packages/native-core-macro/README.md | 2 +- packages/native-core/README.md | 2 +- packages/router/README.md | 2 +- packages/rsx-rosetta/README.md | 2 +- packages/rsx/README.md | 2 +- packages/web/README.md | 2 +- translations/pt-br/README.md | 6 +++--- 22 files changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 4ef6acfee..5b680a1ba 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ | Examples | - Guide + Guide | 中文 | diff --git a/docs/posts/release.md b/docs/posts/release.md index b40b451cc..171664dd3 100644 --- a/docs/posts/release.md +++ b/docs/posts/release.md @@ -63,7 +63,7 @@ This very site is built with Dioxus, and the source code is available [here](htt To get started with Dioxus, check out any of the "Getting Started" guides for your platform of choice, or check out the GitHub Repository for more details. -- [Getting Started with Dioxus](https://dioxuslabs.com/guide) +- [Getting Started with Dioxus](https://dioxuslabs.com/guide/en) - [Getting Started with Web](https://dioxuslabs.com/reference/web) - [Getting Started with Desktop](https://dioxuslabs.com/reference/desktop) - [Getting Started with Mobile](https://dioxuslabs.com/reference/mobile) @@ -163,7 +163,7 @@ Today, to publish a Dioxus app, you don't need NPM/WebPack/Parcel/etc. Dioxus si ## Show me more -Here, we'll dive into some features of Dioxus and why it's so fun to use. The [guide](https://dioxuslabs.com/guide/) serves as a deeper and more comprehensive look at what Dioxus can do. +Here, we'll dive into some features of Dioxus and why it's so fun to use. The [guide](https://dioxuslabs.com/guide/en/) serves as a deeper and more comprehensive look at what Dioxus can do. ## Building a new project is simple diff --git a/docs/reference/src/README_pt-br.md b/docs/reference/src/README_pt-br.md index c345da6bd..e76f43516 100644 --- a/docs/reference/src/README_pt-br.md +++ b/docs/reference/src/README_pt-br.md @@ -4,7 +4,7 @@ **Dioxus** é um framework e ecossistema para desenvolver interfaces rápidas, escaláveis e robustas com a linguagem de Programação Rust. Este guia irá ajudar você a começar com o Dioxus para Web, Desktop, Móvel e mais. -> Este livro é a Referência e Guias Avançados para o framework Dioxus. Para um tutorial em como de fato _usar_ o Dioxus, procure o [guia oficial](https://dioxuslabs.com/guide/). +> Este livro é a Referência e Guias Avançados para o framework Dioxus. Para um tutorial em como de fato _usar_ o Dioxus, procure o [guia oficial](https://dioxuslabs.com/guide/en/). ## Guias e Referência diff --git a/docs/reference/src/platforms/desktop.md b/docs/reference/src/platforms/desktop.md index d444b90e4..a6c85c21e 100644 --- a/docs/reference/src/platforms/desktop.md +++ b/docs/reference/src/platforms/desktop.md @@ -42,4 +42,4 @@ To configure the webview, menubar, and other important desktop-specific features ## Future Steps -Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't! +Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide/en) if you already haven't! diff --git a/notes/README/ZH_CN.md b/notes/README/ZH_CN.md index 8b1e6185b..ca37f7be1 100644 --- a/notes/README/ZH_CN.md +++ b/notes/README/ZH_CN.md @@ -40,7 +40,7 @@ | 代码示例 | - 开发指南 + 开发指南 | English | diff --git a/packages/autofmt/README.md b/packages/autofmt/README.md index b0a418ee6..8cbd33d61 100644 --- a/packages/autofmt/README.md +++ b/packages/autofmt/README.md @@ -19,7 +19,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-autofmt/latest/dioxus_autofmt) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/core-macro/README.md b/packages/core-macro/README.md index 60654396e..076a0d9a1 100644 --- a/packages/core-macro/README.md +++ b/packages/core-macro/README.md @@ -19,7 +19,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-core-macro/latest/dioxus_core_macro) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/desktop/README.md b/packages/desktop/README.md index 9b1e7ad58..e122caf21 100644 --- a/packages/desktop/README.md +++ b/packages/desktop/README.md @@ -19,7 +19,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-desktop/latest/dioxus_desktop) | [Chat](https://discord.gg/XgGxMSkvUM) @@ -30,7 +30,7 @@ This requires that webview is installed on the target system. WebView is installed by default on macOS and iOS devices, but might not come preinstalled on Windows or Linux devices. To fix these issues, follow the [instructions in the guide](guide-url). -[guide-url]: https://dioxuslabs.com/guide/setup.html#platform-specific-dependencies +[guide-url]: https://dioxuslabs.com/guide/en/setup.html#platform-specific-dependencies diff --git a/packages/desktop/src/readme.md b/packages/desktop/src/readme.md index 567b05fcf..ddc49507b 100644 --- a/packages/desktop/src/readme.md +++ b/packages/desktop/src/readme.md @@ -49,4 +49,4 @@ To configure the webview, menubar, and other important desktop-specific features ## Future Steps -Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't! +Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide/en) if you already haven't! diff --git a/packages/dioxus/README.md b/packages/dioxus/README.md index 4dc007096..eaefa4fc7 100644 --- a/packages/dioxus/README.md +++ b/packages/dioxus/README.md @@ -9,8 +9,8 @@ This overview provides a brief introduction to Dioxus. For a more in-depth guide, make sure to check out: -- [Getting Started](https://dioxuslabs.com/guide/setup.html) -- [Book](https://dioxuslabs.com/guide/) +- [Getting Started](https://dioxuslabs.com/guide/en/setup.html) +- [Book](https://dioxuslabs.com/guide/en/) - [Reference](https://dioxuslabs.com/reference) - [Examples](https://github.com/DioxusLabs/example-projects) diff --git a/packages/hooks/README.md b/packages/hooks/README.md index 6d6f56d50..1e065475e 100644 --- a/packages/hooks/README.md +++ b/packages/hooks/README.md @@ -19,7 +19,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-hooks/latest/dioxus_hooks) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/html/README.md b/packages/html/README.md index 7bae7e197..8dd81c545 100644 --- a/packages/html/README.md +++ b/packages/html/README.md @@ -19,7 +19,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-html/latest/dioxus_html) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/interpreter/README.md b/packages/interpreter/README.md index cb01f2cc7..48fe641b1 100644 --- a/packages/interpreter/README.md +++ b/packages/interpreter/README.md @@ -19,7 +19,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-interpreter-js/latest/dioxus_interpreter_js) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/liveview/README.md b/packages/liveview/README.md index 6ab109f8e..c7a7f2393 100644 --- a/packages/liveview/README.md +++ b/packages/liveview/README.md @@ -19,7 +19,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-liveview/latest/dioxus_liveview) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/mobile/README.md b/packages/mobile/README.md index 7af09e970..d26408b36 100644 --- a/packages/mobile/README.md +++ b/packages/mobile/README.md @@ -18,7 +18,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-mobile/latest/dioxus_mobile) | [Chat](https://discord.gg/XgGxMSkvUM) @@ -98,7 +98,7 @@ To configure the web view, menubar, and other important desktop-specific feature ## Future Steps -Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide) if you already haven't! +Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide/en) if you already haven't! diff --git a/packages/native-core-macro/README.md b/packages/native-core-macro/README.md index 90d7123b1..ea3966774 100644 --- a/packages/native-core-macro/README.md +++ b/packages/native-core-macro/README.md @@ -18,7 +18,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-native-core-macro/latest/dioxus_native_core_macro) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/native-core/README.md b/packages/native-core/README.md index c467d37de..802e178fa 100644 --- a/packages/native-core/README.md +++ b/packages/native-core/README.md @@ -18,7 +18,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-native-core/latest/dioxus_native_core) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/router/README.md b/packages/router/README.md index 43bc2df2b..5daa43365 100644 --- a/packages/router/README.md +++ b/packages/router/README.md @@ -18,7 +18,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-router/latest/dioxus_router) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/rsx-rosetta/README.md b/packages/rsx-rosetta/README.md index bf811a5fe..6cf6c3b72 100644 --- a/packages/rsx-rosetta/README.md +++ b/packages/rsx-rosetta/README.md @@ -20,7 +20,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/rsx-rosetta/latest/rsx-rosetta) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/rsx/README.md b/packages/rsx/README.md index 707416b98..a189a2cf4 100644 --- a/packages/rsx/README.md +++ b/packages/rsx/README.md @@ -18,7 +18,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-rsx/latest/dioxus_rsx) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/packages/web/README.md b/packages/web/README.md index d3f4c1aeb..9a71e0c28 100644 --- a/packages/web/README.md +++ b/packages/web/README.md @@ -18,7 +18,7 @@ [discord-url]: https://discord.gg/XgGxMSkvUM [Website](https://dioxuslabs.com) | -[Guides](https://dioxuslabs.com/guide/) | +[Guides](https://dioxuslabs.com/guide/en/) | [API Docs](https://docs.rs/dioxus-web/latest/dioxus_web) | [Chat](https://discord.gg/XgGxMSkvUM) diff --git a/translations/pt-br/README.md b/translations/pt-br/README.md index ef14a1af9..a50727662 100644 --- a/translations/pt-br/README.md +++ b/translations/pt-br/README.md @@ -40,7 +40,7 @@ | Exemplos | - Guia + Guia | 中文 @@ -83,7 +83,7 @@ Se você conhece React, então você já conhece o Dioxus. - + @@ -159,7 +159,7 @@ Dioxus é único no ecossistema do Rust por suportar: - SSR com `hydration` feito pelo Cliente - Suporte à aplicação Desktop -Para mais informações sobre quais funções estão atualmente disponíveis e para o progresso futuro, veja [O Guia](https://dioxuslabs.com/guide/). +Para mais informações sobre quais funções estão atualmente disponíveis e para o progresso futuro, veja [O Guia](https://dioxuslabs.com/guide/pt-br/). ## Projeto dentro do ecossistema Dioxus From 362aadb021435f2c6dc038731b193b7ea1f20daa Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Feb 2023 09:03:35 -0600 Subject: [PATCH 02/41] sum nodes pushed instead of counting them --- packages/core/src/diff.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 37e9a0428..fdc1a03f1 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -717,7 +717,7 @@ impl<'b> VirtualDom { Fragment(nodes) => nodes .iter() .map(|node| self.push_all_real_nodes(node)) - .count(), + .sum(), Component(comp) => { let scope = comp.scope.get().unwrap(); @@ -729,7 +729,7 @@ impl<'b> VirtualDom { } } }) - .count() + .sum() } fn create_children(&mut self, nodes: impl IntoIterator>) -> usize { From 6bea6f63858813aaeade63cbde52c26b91368a1b Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Feb 2023 09:14:07 -0600 Subject: [PATCH 03/41] fix text dynamic node not assigning id --- packages/interpreter/src/interpreter.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/interpreter/src/interpreter.js b/packages/interpreter/src/interpreter.js index 06774e474..233c70590 100644 --- a/packages/interpreter/src/interpreter.js +++ b/packages/interpreter/src/interpreter.js @@ -116,9 +116,6 @@ class Interpreter { node.remove(); } } - CreateRawText(text) { - this.stack.push(document.createTextNode(text)); - } CreateTextNode(text, root) { const node = document.createTextNode(text); this.nodes[root] = node; @@ -306,7 +303,7 @@ class Interpreter { this.CreatePlaceholder(edit.id); break; case "CreateTextNode": - this.CreateTextNode(edit.value); + this.CreateTextNode(edit.value, edit.id); break; case "HydrateText": this.HydrateText(edit.path, edit.value, edit.id); From 32dc68c53950c147ef5ac8af6d17c0f2e558e762 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 9 Feb 2023 16:37:12 -0600 Subject: [PATCH 04/41] hot reloading: filter intial read of files by excluded dirs --- packages/hot-reload/src/lib.rs | 34 +++++++++++++------ .../src/hot_reload/hot_reloading_file_map.rs | 12 +++++-- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/packages/hot-reload/src/lib.rs b/packages/hot-reload/src/lib.rs index 1ddd32bb1..20cc70a9a 100644 --- a/packages/hot-reload/src/lib.rs +++ b/packages/hot-reload/src/lib.rs @@ -129,9 +129,30 @@ pub fn init(cfg: Config) { } = cfg; if let Ok(crate_dir) = PathBuf::from_str(root_path) { + // try to find the gitingore file + let gitignore_file_path = crate_dir.join(".gitignore"); + let (gitignore, _) = ignore::gitignore::Gitignore::new(gitignore_file_path); + + // convert the excluded paths to absolute paths + let excluded_paths = excluded_paths + .iter() + .map(|path| crate_dir.join(PathBuf::from(path))) + .collect::>(); + let temp_file = std::env::temp_dir().join("@dioxusin"); let channels = Arc::new(Mutex::new(Vec::new())); - let file_map = Arc::new(Mutex::new(FileMap::::new(crate_dir.clone()))); + let file_map = Arc::new(Mutex::new(FileMap::::new_with_filter( + crate_dir.clone(), + |path| { + // skip excluded paths + excluded_paths.iter().any(|p| path.starts_with(p)) || + // respect .gitignore + gitignore + .matched_path_or_any_parents(path, path.is_dir()) + .is_ignore() + }, + ))); + if let Ok(local_socket_stream) = LocalSocketListener::bind(temp_file.as_path()) { let aborted = Arc::new(Mutex::new(false)); @@ -177,10 +198,6 @@ pub fn init(cfg: Config) { // watch for changes std::thread::spawn(move || { - // try to find the gitingore file - let gitignore_file_path = crate_dir.join(".gitignore"); - let (gitignore, _) = ignore::gitignore::Gitignore::new(gitignore_file_path); - let mut last_update_time = chrono::Local::now().timestamp(); let (tx, rx) = std::sync::mpsc::channel(); @@ -198,11 +215,6 @@ pub fn init(cfg: Config) { } } - let excluded_paths = excluded_paths - .iter() - .map(|path| crate_dir.join(PathBuf::from(path))) - .collect::>(); - let mut rebuild = { let aborted = aborted.clone(); let channels = channels.clone(); @@ -242,7 +254,7 @@ pub fn init(cfg: Config) { matches!( path.extension().and_then(|p| p.to_str()), Some("rs" | "toml" | "css" | "html" | "js") - )&& + ) && // skip excluded paths !excluded_paths.iter().any(|p| path.starts_with(p)) && // respect .gitignore diff --git a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs index be4f5d828..156d64ce4 100644 --- a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs +++ b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs @@ -25,14 +25,22 @@ pub struct FileMap { impl FileMap { /// Create a new FileMap from a crate directory pub fn new(path: PathBuf) -> Self { + Self::new_with_filter(path, |_| false) + } + + /// Create a new FileMap from a crate directory + pub fn new_with_filter(path: PathBuf, mut filter: impl FnMut(&Path) -> bool) -> Self { fn find_rs_files( root: PathBuf, + filter: &mut impl FnMut(&Path) -> bool, ) -> io::Result>)>> { let mut files = HashMap::new(); if root.is_dir() { for entry in (fs::read_dir(root)?).flatten() { let path = entry.path(); - files.extend(find_rs_files(path)?); + if !filter(&path) { + files.extend(find_rs_files(path, filter)?); + } } } else if root.extension().and_then(|s| s.to_str()) == Some("rs") { if let Ok(mut file) = File::open(root.clone()) { @@ -45,7 +53,7 @@ impl FileMap { } let result = Self { - map: find_rs_files(path).unwrap(), + map: find_rs_files(path, &mut filter).unwrap(), phantom: std::marker::PhantomData, }; result From abd6132c038ea69b2fbc1e52f6fe5616df7a5ee6 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 12 Feb 2023 17:11:32 -0600 Subject: [PATCH 05/41] fix bfs ordering --- packages/core/src/create.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/create.rs b/packages/core/src/create.rs index 12c11d1e9..401c9784c 100644 --- a/packages/core/src/create.rs +++ b/packages/core/src/create.rs @@ -25,8 +25,8 @@ fn sort_bfs(paths: &[&'static [u8]]) -> Vec<(usize, &'static [u8])> { } } // The shorter path goes first - (Some(_), None) => return std::cmp::Ordering::Less, - (None, Some(_)) => return std::cmp::Ordering::Greater, + (None, Some(_)) => return std::cmp::Ordering::Less, + (Some(_), None) => return std::cmp::Ordering::Greater, (None, None) => return std::cmp::Ordering::Equal, } } From f652ac5e134ba4f6ce43bb8fd6d42c400f809d4e Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 12 Feb 2023 17:36:00 -0600 Subject: [PATCH 06/41] improve sorting test --- packages/core/src/create.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/core/src/create.rs b/packages/core/src/create.rs index 401c9784c..113fa7ae1 100644 --- a/packages/core/src/create.rs +++ b/packages/core/src/create.rs @@ -40,14 +40,25 @@ fn sorting() { (0, &[0, 1]), (1, &[0, 2]), (2, &[1, 0]), - (4, &[1, 1]), - (3, &[1, 2]), + (3, &[1, 0, 1]), + (4, &[1, 2]), ]; assert_eq!( - sort_bfs(&[&[0, 1,], &[0, 2,], &[1, 0,], &[1, 2,], &[1, 1,],]), + sort_bfs(&[&[0, 1,], &[0, 2,], &[1, 0,], &[1, 0, 1,], &[1, 2,],]), + r + ); + let r: [(usize, &[u8]); 6] = [ + (0, &[0]), + (1, &[0, 1]), + (2, &[0, 1, 2]), + (3, &[1]), + (4, &[1, 2]), + (5, &[2]), + ]; + assert_eq!( + sort_bfs(&[&[0], &[0, 1], &[0, 1, 2], &[1], &[1, 2], &[2],]), r ); - assert!(matches!(&[0], &[_, ..])) } impl<'b> VirtualDom { From c9f9b8b0fa71a8fabc6a216a8a7771a1f686d936 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 14 Feb 2023 08:44:01 -0600 Subject: [PATCH 07/41] escape text in ssr --- packages/ssr/Cargo.toml | 1 + packages/ssr/src/cache.rs | 8 +++++++- packages/ssr/src/renderer.rs | 7 +++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/ssr/Cargo.toml b/packages/ssr/Cargo.toml index 0ce901b5a..02900ca0e 100644 --- a/packages/ssr/Cargo.toml +++ b/packages/ssr/Cargo.toml @@ -14,6 +14,7 @@ keywords = ["dom", "ui", "gui", "react", "ssr"] [dependencies] dioxus-core = { path = "../core", version = "^0.3.0", features = ["serialize"] } +askama_escape = "0.10.3" [dev-dependencies] dioxus = { path = "../dioxus", version = "0.3.0" } diff --git a/packages/ssr/src/cache.rs b/packages/ssr/src/cache.rs index 39bfb8671..8556682f1 100644 --- a/packages/ssr/src/cache.rs +++ b/packages/ssr/src/cache.rs @@ -82,7 +82,13 @@ impl StringCache { } cur_path.pop(); } - TemplateNode::Text { text } => write!(chain, "{text}")?, + TemplateNode::Text { text } => { + write!( + chain, + "{}", + askama_escape::escape(text, askama_escape::Html) + )?; + } TemplateNode::Dynamic { id: idx } | TemplateNode::DynamicText { id: idx } => { chain.segments.push(Segment::Node(*idx)) } diff --git a/packages/ssr/src/renderer.rs b/packages/ssr/src/renderer.rs index 8c828f01c..d47a97c22 100644 --- a/packages/ssr/src/renderer.rs +++ b/packages/ssr/src/renderer.rs @@ -104,8 +104,11 @@ impl Renderer { write!(buf, "")?; } - // todo: escape the text - write!(buf, "{}", text.value)?; + write!( + buf, + "{}", + askama_escape::escape(text.value, askama_escape::Html) + )?; if self.pre_render { write!(buf, "")?; From c84003de98db33934e1e1486921577299a678f12 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 14 Feb 2023 09:06:59 -0600 Subject: [PATCH 08/41] update tests to escape text --- packages/ssr/src/renderer.rs | 8 ++++---- packages/ssr/tests/simple.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ssr/src/renderer.rs b/packages/ssr/src/renderer.rs index d47a97c22..5496148c4 100644 --- a/packages/ssr/src/renderer.rs +++ b/packages/ssr/src/renderer.rs @@ -141,7 +141,7 @@ fn to_string_works() { fn app(cx: Scope) -> Element { let dynamic = 123; - let dyn2 = ""; // todo: escape this + let dyn2 = ""; // this should be escaped render! { div { class: "asdasdasd", class: "asdasdasd", id: "id-{dynamic}", @@ -168,10 +168,10 @@ fn to_string_works() { vec![ PreRendered("
Hello world 1 -->".into(),), + PreRendered(">Hello world 1 -->".into(),), Node(0,), PreRendered( - "<-- Hello world 2
nest 1
nest 2
".into(), + "<-- Hello world 2
nest 1
nest 2
".into(), ), Node(1,), Node(2,), @@ -183,5 +183,5 @@ fn to_string_works() { use Segment::*; - assert_eq!(out, "
Hello world 1 -->123<-- Hello world 2
nest 1
nest 2
finalize 0
finalize 1
finalize 2
finalize 3
finalize 4
"); + assert_eq!(out, "
Hello world 1 -->123<-- Hello world 2
nest 1
nest 2
</diiiiiiiiv>
finalize 0
finalize 1
finalize 2
finalize 3
finalize 4
"); } diff --git a/packages/ssr/tests/simple.rs b/packages/ssr/tests/simple.rs index 63137aeae..395f801e1 100644 --- a/packages/ssr/tests/simple.rs +++ b/packages/ssr/tests/simple.rs @@ -38,7 +38,7 @@ fn dynamic() { dioxus_ssr::render_lazy(rsx! { div { "Hello world 1 -->" "{dynamic}" "<-- Hello world 2" } }), - "
Hello world 1 -->123<-- Hello world 2
" + "
Hello world 1 -->123<-- Hello world 2
" ); } From 4bf655851b38991a74c322d6c5805a892e8ef435 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 14 Feb 2023 09:56:39 -0600 Subject: [PATCH 09/41] fix pre tag typo --- packages/ssr/src/renderer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ssr/src/renderer.rs b/packages/ssr/src/renderer.rs index 8c828f01c..0f9b0a070 100644 --- a/packages/ssr/src/renderer.rs +++ b/packages/ssr/src/renderer.rs @@ -119,7 +119,7 @@ impl Renderer { DynamicNode::Placeholder(_el) => { if self.pre_render { - write!(buf, "
")?;
+                            write!(buf, "
")?;
                         }
                     }
                 },

From 33397b290dd1d5bb84eecf3874c34486fa1368b2 Mon Sep 17 00:00:00 2001
From: Jonathan Kelley 
Date: Thu, 16 Feb 2023 12:13:27 -0800
Subject: [PATCH 10/41] bump core

---
 packages/core/Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml
index 9f855e18e..b86466692 100644
--- a/packages/core/Cargo.toml
+++ b/packages/core/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-core"
-version = "0.3.1"
+version = "0.3.2"
 authors = ["Jonathan Kelley"]
 edition = "2018"
 description = "Core functionality for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences"

From f420c6f333908ed7e3f7c795438bdb201a2ef7c3 Mon Sep 17 00:00:00 2001
From: Jonathan Kelley 
Date: Thu, 16 Feb 2023 13:42:49 -0800
Subject: [PATCH 11/41] bump web and interpreter

---
 packages/interpreter/Cargo.toml | 2 +-
 packages/web/Cargo.toml         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/interpreter/Cargo.toml b/packages/interpreter/Cargo.toml
index a10377f34..7c7d79607 100644
--- a/packages/interpreter/Cargo.toml
+++ b/packages/interpreter/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-interpreter-js"
-version = "0.3.0"
+version = "0.3.1"
 edition = "2018"
 authors = ["Jonathan Kelley"]
 description = "JS Intepreter for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences"
diff --git a/packages/web/Cargo.toml b/packages/web/Cargo.toml
index 805cacddd..7adfbf13a 100644
--- a/packages/web/Cargo.toml
+++ b/packages/web/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-web"
-version = "0.3.0"
+version = "0.3.1"
 authors = ["Jonathan Kelley"]
 edition = "2018"
 description = "Dioxus VirtualDOM renderer for the web browser using websys"

From 2075ff3039feb1efb576d8f2ed5a2c4d0c554731 Mon Sep 17 00:00:00 2001
From: Jonathan Kelley 
Date: Thu, 16 Feb 2023 14:57:32 -0800
Subject: [PATCH 12/41] add more builds to docs

---
 .github/workflows/docs stable.yml | 4 +++-
 .github/workflows/docs.yml        | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/docs stable.yml b/.github/workflows/docs stable.yml
index 895e7e8d0..ad907f2c1 100644
--- a/.github/workflows/docs stable.yml	
+++ b/.github/workflows/docs stable.yml	
@@ -24,7 +24,9 @@ jobs:
       - name: Build
         run: cd docs &&
           cd guide && mdbook build -d ../nightly/guide && cd .. &&
-          cd router && mdbook build -d ../nightly/router  && cd ..
+          cd router && mdbook build -d ../nightly/router && cd .. &&
+          cd reference && mdbook build -d ../nightly/reference && cd ..
+          cd fermi && mdbook build -d ../nightly/fermi && cd ..
 
       - name: Deploy 🚀
         uses: JamesIves/github-pages-deploy-action@v4.4.1
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index f69053742..ef4a6574f 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -29,7 +29,9 @@ jobs:
       - name: Build
         run: cd docs &&
           cd guide && mdbook build -d ../nightly/guide && cd .. &&
-          cd router && mdbook build -d ../nightly/router  && cd ..
+          cd router && mdbook build -d ../nightly/router && cd .. &&
+          cd reference && mdbook build -d ../nightly/reference && cd ..
+          cd fermi && mdbook build -d ../nightly/fermi && cd ..
 
       - name: Deploy 🚀
         uses: JamesIves/github-pages-deploy-action@v4.4.1

From 6090dc063a46f04f3ae991fd0cf93af1e3afdd25 Mon Sep 17 00:00:00 2001
From: Jonathan Kelley 
Date: Thu, 16 Feb 2023 15:03:52 -0800
Subject: [PATCH 13/41] fix path

---
 .github/workflows/docs stable.yml | 2 +-
 .github/workflows/docs.yml        | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/docs stable.yml b/.github/workflows/docs stable.yml
index ad907f2c1..2cb17b5b0 100644
--- a/.github/workflows/docs stable.yml	
+++ b/.github/workflows/docs stable.yml	
@@ -25,7 +25,7 @@ jobs:
         run: cd docs &&
           cd guide && mdbook build -d ../nightly/guide && cd .. &&
           cd router && mdbook build -d ../nightly/router && cd .. &&
-          cd reference && mdbook build -d ../nightly/reference && cd ..
+          cd reference && mdbook build -d ../nightly/reference && cd .. &&
           cd fermi && mdbook build -d ../nightly/fermi && cd ..
 
       - name: Deploy 🚀
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index ef4a6574f..8e47813b9 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -30,7 +30,7 @@ jobs:
         run: cd docs &&
           cd guide && mdbook build -d ../nightly/guide && cd .. &&
           cd router && mdbook build -d ../nightly/router && cd .. &&
-          cd reference && mdbook build -d ../nightly/reference && cd ..
+          cd reference && mdbook build -d ../nightly/reference && cd .. &&
           cd fermi && mdbook build -d ../nightly/fermi && cd ..
 
       - name: Deploy 🚀

From 084aff8f3185cd486235dfc89d58396a8de715fc Mon Sep 17 00:00:00 2001
From: Jonathan Kelley 
Date: Thu, 16 Feb 2023 15:20:18 -0800
Subject: [PATCH 14/41] dont build reference

---
 .github/workflows/docs stable.yml | 6 +++---
 .github/workflows/docs.yml        | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.github/workflows/docs stable.yml b/.github/workflows/docs stable.yml
index 2cb17b5b0..2790b1d51 100644
--- a/.github/workflows/docs stable.yml	
+++ b/.github/workflows/docs stable.yml	
@@ -24,9 +24,9 @@ jobs:
       - name: Build
         run: cd docs &&
           cd guide && mdbook build -d ../nightly/guide && cd .. &&
-          cd router && mdbook build -d ../nightly/router && cd .. &&
-          cd reference && mdbook build -d ../nightly/reference && cd .. &&
-          cd fermi && mdbook build -d ../nightly/fermi && cd ..
+          cd router && mdbook build -d ../nightly/router && cd ..
+          # cd reference && mdbook build -d ../nightly/reference && cd .. &&
+          # cd fermi && mdbook build -d ../nightly/fermi && cd ..
 
       - name: Deploy 🚀
         uses: JamesIves/github-pages-deploy-action@v4.4.1
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 8e47813b9..07a8b462b 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -29,9 +29,9 @@ jobs:
       - name: Build
         run: cd docs &&
           cd guide && mdbook build -d ../nightly/guide && cd .. &&
-          cd router && mdbook build -d ../nightly/router && cd .. &&
-          cd reference && mdbook build -d ../nightly/reference && cd .. &&
-          cd fermi && mdbook build -d ../nightly/fermi && cd ..
+          cd router && mdbook build -d ../nightly/router && cd ..
+          # cd reference && mdbook build -d ../nightly/reference && cd .. &&
+          # cd fermi && mdbook build -d ../nightly/fermi && cd ..
 
       - name: Deploy 🚀
         uses: JamesIves/github-pages-deploy-action@v4.4.1

From a51f67c2ecf55583d45695e4c65efbd254830791 Mon Sep 17 00:00:00 2001
From: Evan Almloff 
Date: Sat, 18 Feb 2023 18:38:30 -0600
Subject: [PATCH 15/41] add version to docs links in readmes

---
 packages/autofmt/README.md           | 2 +-
 packages/core-macro/README.md        | 2 +-
 packages/desktop/README.md           | 4 ++--
 packages/desktop/src/readme.md       | 2 +-
 packages/dioxus/README.md            | 5 ++---
 packages/hooks/README.md             | 2 +-
 packages/hot-reload/README.md        | 2 +-
 packages/html/README.md              | 2 +-
 packages/interpreter/README.md       | 2 +-
 packages/liveview/README.md          | 2 +-
 packages/mobile/README.md            | 4 ++--
 packages/native-core-macro/README.md | 2 +-
 packages/native-core/README.md       | 2 +-
 packages/router/README.md            | 2 +-
 packages/rsx-rosetta/README.md       | 2 +-
 packages/rsx/README.md               | 2 +-
 packages/ssr/README.md               | 7 +++----
 packages/web/README.md               | 2 +-
 18 files changed, 23 insertions(+), 25 deletions(-)

diff --git a/packages/autofmt/README.md b/packages/autofmt/README.md
index 8cbd33d61..bd934f2c7 100644
--- a/packages/autofmt/README.md
+++ b/packages/autofmt/README.md
@@ -19,7 +19,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-autofmt/latest/dioxus_autofmt) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/core-macro/README.md b/packages/core-macro/README.md
index 076a0d9a1..bcf1572cf 100644
--- a/packages/core-macro/README.md
+++ b/packages/core-macro/README.md
@@ -19,7 +19,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-core-macro/latest/dioxus_core_macro) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/desktop/README.md b/packages/desktop/README.md
index e122caf21..964f90495 100644
--- a/packages/desktop/README.md
+++ b/packages/desktop/README.md
@@ -19,7 +19,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-desktop/latest/dioxus_desktop) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
@@ -30,7 +30,7 @@
 
 This requires that webview is installed on the target system. WebView is installed by default on macOS and iOS devices, but might not come preinstalled on Windows or Linux devices. To fix these issues, follow the [instructions in the guide](guide-url).
 
-[guide-url]: https://dioxuslabs.com/guide/en/setup.html#platform-specific-dependencies
+[guide-url]: https://dioxuslabs.com/docs/0.3/guide/en/getting_started/desktop.html
 
 
 
diff --git a/packages/desktop/src/readme.md b/packages/desktop/src/readme.md
index ddc49507b..5c22f015b 100644
--- a/packages/desktop/src/readme.md
+++ b/packages/desktop/src/readme.md
@@ -49,4 +49,4 @@ To configure the webview, menubar, and other important desktop-specific features
 
 ## Future Steps
 
-Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide/en) if you already haven't!
+Make sure to read the [Dioxus Guide](https://dioxuslabs.com/docs/0.3/guide/en) if you already haven't!
diff --git a/packages/dioxus/README.md b/packages/dioxus/README.md
index eaefa4fc7..31fff88fa 100644
--- a/packages/dioxus/README.md
+++ b/packages/dioxus/README.md
@@ -9,9 +9,8 @@
 
 This overview provides a brief introduction to Dioxus. For a more in-depth guide, make sure to check out:
 
-- [Getting Started](https://dioxuslabs.com/guide/en/setup.html)
-- [Book](https://dioxuslabs.com/guide/en/)
-- [Reference](https://dioxuslabs.com/reference)
+- [Getting Started](https://dioxuslabs.com/docs/0.3/guide/en/getting_started/index.html)
+- [Book](https://dioxuslabs.com/docs/0.3/guide/en/)
 - [Examples](https://github.com/DioxusLabs/example-projects)
 
 # Overview and Goals
diff --git a/packages/hooks/README.md b/packages/hooks/README.md
index 1e065475e..6c77867de 100644
--- a/packages/hooks/README.md
+++ b/packages/hooks/README.md
@@ -19,7 +19,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-hooks/latest/dioxus_hooks) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/hot-reload/README.md b/packages/hot-reload/README.md
index 126c42103..60b7b9c87 100644
--- a/packages/hot-reload/README.md
+++ b/packages/hot-reload/README.md
@@ -19,7 +19,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en) |
 [API Docs](https://docs.rs/dioxus-hot-reload/latest/dioxus_hot_reload) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/html/README.md b/packages/html/README.md
index 8dd81c545..59ec2f9ff 100644
--- a/packages/html/README.md
+++ b/packages/html/README.md
@@ -19,7 +19,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-html/latest/dioxus_html) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/interpreter/README.md b/packages/interpreter/README.md
index 48fe641b1..90e390f56 100644
--- a/packages/interpreter/README.md
+++ b/packages/interpreter/README.md
@@ -19,7 +19,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-interpreter-js/latest/dioxus_interpreter_js) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/liveview/README.md b/packages/liveview/README.md
index c7a7f2393..0a0e7de3a 100644
--- a/packages/liveview/README.md
+++ b/packages/liveview/README.md
@@ -19,7 +19,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-liveview/latest/dioxus_liveview) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/mobile/README.md b/packages/mobile/README.md
index d26408b36..46da9061a 100644
--- a/packages/mobile/README.md
+++ b/packages/mobile/README.md
@@ -18,7 +18,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-mobile/latest/dioxus_mobile) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
@@ -98,7 +98,7 @@ To configure the web view, menubar, and other important desktop-specific feature
 
 ## Future Steps
 
-Make sure to read the [Dioxus Guide](https://dioxuslabs.com/guide/en) if you already haven't!
+Make sure to read the [Dioxus Guide](https://dioxuslabs.com/docs/0.3/guide/en) if you already haven't!
 
 
 
diff --git a/packages/native-core-macro/README.md b/packages/native-core-macro/README.md
index ea3966774..6b8c13590 100644
--- a/packages/native-core-macro/README.md
+++ b/packages/native-core-macro/README.md
@@ -18,7 +18,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-native-core-macro/latest/dioxus_native_core_macro) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/native-core/README.md b/packages/native-core/README.md
index 802e178fa..d412ca7cd 100644
--- a/packages/native-core/README.md
+++ b/packages/native-core/README.md
@@ -18,7 +18,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-native-core/latest/dioxus_native_core) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/router/README.md b/packages/router/README.md
index 5daa43365..0e38512e8 100644
--- a/packages/router/README.md
+++ b/packages/router/README.md
@@ -18,7 +18,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-router/latest/dioxus_router) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/rsx-rosetta/README.md b/packages/rsx-rosetta/README.md
index 6cf6c3b72..da3049d3c 100644
--- a/packages/rsx-rosetta/README.md
+++ b/packages/rsx-rosetta/README.md
@@ -20,7 +20,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/rsx-rosetta/latest/rsx-rosetta) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/rsx/README.md b/packages/rsx/README.md
index a189a2cf4..c20737167 100644
--- a/packages/rsx/README.md
+++ b/packages/rsx/README.md
@@ -18,7 +18,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-rsx/latest/dioxus_rsx) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 
diff --git a/packages/ssr/README.md b/packages/ssr/README.md
index ef5931874..c5b91b7b8 100644
--- a/packages/ssr/README.md
+++ b/packages/ssr/README.md
@@ -8,10 +8,9 @@
 ## Resources
 This crate is a part of the broader Dioxus ecosystem. For more resources about Dioxus, check out:
 
-- [Getting Started](https://dioxuslabs.com/getting-started)
-- [Book](https://dioxuslabs.com/book)
-- [Reference](https://dioxuslabs.com/reference)
-- [Community Examples](https://github.com/DioxusLabs/community-examples)
+- [Getting Started](https://dioxuslabs.com/docs/0.3/guide/en/getting_started/index.html)
+- [Book](https://dioxuslabs.com/docs/0.3/guide/en/)
+- [Examples](https://github.com/DioxusLabs/example-projects)
 
 ## Overview
 
diff --git a/packages/web/README.md b/packages/web/README.md
index 9a71e0c28..87265c926 100644
--- a/packages/web/README.md
+++ b/packages/web/README.md
@@ -18,7 +18,7 @@
 [discord-url]: https://discord.gg/XgGxMSkvUM
 
 [Website](https://dioxuslabs.com) |
-[Guides](https://dioxuslabs.com/guide/en/) |
+[Guides](https://dioxuslabs.com/docs/0.3/guide/en/) |
 [API Docs](https://docs.rs/dioxus-web/latest/dioxus_web) |
 [Chat](https://discord.gg/XgGxMSkvUM)
 

From c012855659554e24e0f4cd47572acedbaa6cdb2f Mon Sep 17 00:00:00 2001
From: Evan Almloff 
Date: Wed, 22 Feb 2023 09:18:12 -0600
Subject: [PATCH 16/41] collect non-fatal errors in hot reloading

---
 packages/hot-reload/src/lib.rs                | 34 +++++++---
 .../src/hot_reload/hot_reloading_file_map.rs  | 64 ++++++++++++++-----
 2 files changed, 71 insertions(+), 27 deletions(-)

diff --git a/packages/hot-reload/src/lib.rs b/packages/hot-reload/src/lib.rs
index 20cc70a9a..5c79f9731 100644
--- a/packages/hot-reload/src/lib.rs
+++ b/packages/hot-reload/src/lib.rs
@@ -7,7 +7,7 @@ use std::{
 
 use dioxus_core::Template;
 use dioxus_rsx::{
-    hot_reload::{FileMap, UpdateResult},
+    hot_reload::{FileMap, FileMapBuildResult, UpdateResult},
     HotReloadingContext,
 };
 use interprocess::local_socket::{LocalSocketListener, LocalSocketStream};
@@ -141,17 +141,24 @@ pub fn init(cfg: Config) {
 
         let temp_file = std::env::temp_dir().join("@dioxusin");
         let channels = Arc::new(Mutex::new(Vec::new()));
-        let file_map = Arc::new(Mutex::new(FileMap::::new_with_filter(
-            crate_dir.clone(),
-            |path| {
-                // skip excluded paths
-                excluded_paths.iter().any(|p| path.starts_with(p)) ||
+        let FileMapBuildResult {
+            map: file_map,
+            errors,
+        } = FileMap::::create_with_filter(crate_dir.clone(), |path| {
+            // skip excluded paths
+            excluded_paths.iter().any(|p| path.starts_with(p)) ||
                 // respect .gitignore
                 gitignore
                     .matched_path_or_any_parents(path, path.is_dir())
                     .is_ignore()
-            },
-        )));
+        })
+        .unwrap();
+        for err in errors {
+            if log {
+                println!("hot reloading failed to initialize:\n{err:?}");
+            }
+        }
+        let file_map = Arc::new(Mutex::new(file_map));
 
         if let Ok(local_socket_stream) = LocalSocketListener::bind(temp_file.as_path()) {
             let aborted = Arc::new(Mutex::new(false));
@@ -283,7 +290,7 @@ pub fn init(cfg: Config) {
                                     .unwrap()
                                     .update_rsx(path, crate_dir.as_path())
                                 {
-                                    UpdateResult::UpdatedRsx(msgs) => {
+                                    Ok(UpdateResult::UpdatedRsx(msgs)) => {
                                         for msg in msgs {
                                             let mut i = 0;
                                             while i < channels.len() {
@@ -299,13 +306,20 @@ pub fn init(cfg: Config) {
                                             }
                                         }
                                     }
-                                    UpdateResult::NeedsRebuild => {
+                                    Ok(UpdateResult::NeedsRebuild) => {
                                         drop(channels);
                                         if rebuild() {
                                             return;
                                         }
                                         break;
                                     }
+                                    Err(err) => {
+                                        if log {
+                                            println!(
+                                                "hot reloading failed to update rsx:\n{err:?}"
+                                            );
+                                        }
+                                    }
                                 }
                             }
                         }
diff --git a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs
index 156d64ce4..38c1d9105 100644
--- a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs
+++ b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs
@@ -17,6 +17,14 @@ pub enum UpdateResult {
     NeedsRebuild,
 }
 
+/// The result of building a FileMap
+pub struct FileMapBuildResult {
+    /// The FileMap that was built
+    pub map: FileMap,
+    /// Any errors that occurred while building the FileMap that were not fatal
+    pub errors: Vec,
+}
+
 pub struct FileMap {
     pub map: HashMap>)>,
     phantom: std::marker::PhantomData,
@@ -24,46 +32,63 @@ pub struct FileMap {
 
 impl FileMap {
     /// Create a new FileMap from a crate directory
-    pub fn new(path: PathBuf) -> Self {
-        Self::new_with_filter(path, |_| false)
+    pub fn create(path: PathBuf) -> io::Result> {
+        Self::create_with_filter(path, |_| false)
     }
 
     /// Create a new FileMap from a crate directory
-    pub fn new_with_filter(path: PathBuf, mut filter: impl FnMut(&Path) -> bool) -> Self {
+    pub fn create_with_filter(
+        path: PathBuf,
+        mut filter: impl FnMut(&Path) -> bool,
+    ) -> io::Result> {
+        struct FileMapSearchResult {
+            map: HashMap>)>,
+            errors: Vec,
+        }
         fn find_rs_files(
             root: PathBuf,
             filter: &mut impl FnMut(&Path) -> bool,
-        ) -> io::Result>)>> {
+        ) -> io::Result {
             let mut files = HashMap::new();
+            let mut errors = Vec::new();
             if root.is_dir() {
                 for entry in (fs::read_dir(root)?).flatten() {
                     let path = entry.path();
                     if !filter(&path) {
-                        files.extend(find_rs_files(path, filter)?);
+                        let FileMapSearchResult {
+                            map,
+                            errors: child_errors,
+                        } = find_rs_files(path, filter)?;
+                        errors.extend(child_errors);
+                        files.extend(map);
                     }
                 }
             } else if root.extension().and_then(|s| s.to_str()) == Some("rs") {
                 if let Ok(mut file) = File::open(root.clone()) {
                     let mut src = String::new();
-                    file.read_to_string(&mut src).expect("Unable to read file");
+                    file.read_to_string(&mut src)?;
                     files.insert(root, (src, None));
                 }
             }
-            Ok(files)
+            Ok(FileMapSearchResult { map: files, errors })
         }
 
+        let FileMapSearchResult { map, errors } = find_rs_files(path, &mut filter)?;
         let result = Self {
-            map: find_rs_files(path, &mut filter).unwrap(),
+            map,
             phantom: std::marker::PhantomData,
         };
-        result
+        Ok(FileMapBuildResult {
+            map: result,
+            errors,
+        })
     }
 
     /// Try to update the rsx in a file
-    pub fn update_rsx(&mut self, file_path: &Path, crate_dir: &Path) -> UpdateResult {
-        let mut file = File::open(file_path).unwrap();
+    pub fn update_rsx(&mut self, file_path: &Path, crate_dir: &Path) -> io::Result {
+        let mut file = File::open(file_path)?;
         let mut src = String::new();
-        file.read_to_string(&mut src).expect("Unable to read file");
+        file.read_to_string(&mut src)?;
         if let Ok(syntax) = syn::parse_file(&src) {
             if let Some((old_src, template_slot)) = self.map.get_mut(file_path) {
                 if let Ok(old) = syn::parse_file(old_src) {
@@ -99,7 +124,7 @@ impl FileMap {
                                         {
                                             // dioxus cannot handle empty templates
                                             if template.roots.is_empty() {
-                                                return UpdateResult::NeedsRebuild;
+                                                return Ok(UpdateResult::NeedsRebuild);
                                             } else {
                                                 // if the template is the same, don't send it
                                                 if let Some(old_template) = template_slot {
@@ -111,20 +136,25 @@ impl FileMap {
                                                 messages.push(template);
                                             }
                                         } else {
-                                            return UpdateResult::NeedsRebuild;
+                                            return Ok(UpdateResult::NeedsRebuild);
                                         }
                                     }
                                 }
                             }
-                            return UpdateResult::UpdatedRsx(messages);
+                            return Ok(UpdateResult::UpdatedRsx(messages));
                         }
                     }
                 }
             } else {
                 // if this is a new file, rebuild the project
-                *self = FileMap::new(crate_dir.to_path_buf());
+                let FileMapBuildResult { map, mut errors } =
+                    FileMap::create(crate_dir.to_path_buf())?;
+                if let Some(err) = errors.pop() {
+                    return Err(err);
+                }
+                *self = map;
             }
         }
-        UpdateResult::NeedsRebuild
+        Ok(UpdateResult::NeedsRebuild)
     }
 }

From 9ac82101963e1aab9920495013ccee3ab62d2128 Mon Sep 17 00:00:00 2001
From: Jan-Mirko Otter 
Date: Wed, 22 Feb 2023 20:26:21 +0100
Subject: [PATCH 17/41] PartialEq for UseState/UseCoroutine

---
 packages/hooks/src/usecoroutine.rs | 6 ++++++
 packages/hooks/src/usestate.rs     | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/packages/hooks/src/usecoroutine.rs b/packages/hooks/src/usecoroutine.rs
index 2f2442f87..bc97735b9 100644
--- a/packages/hooks/src/usecoroutine.rs
+++ b/packages/hooks/src/usecoroutine.rs
@@ -108,6 +108,12 @@ impl Coroutine {
     }
 }
 
+impl PartialEq for Coroutine {
+    fn eq(&self, other: &Self) -> bool {
+        self.task == other.task
+    }
+}
+
 #[cfg(test)]
 mod tests {
     #![allow(unused)]
diff --git a/packages/hooks/src/usestate.rs b/packages/hooks/src/usestate.rs
index 2e1aa7295..d2b6db6fc 100644
--- a/packages/hooks/src/usestate.rs
+++ b/packages/hooks/src/usestate.rs
@@ -329,7 +329,7 @@ impl PartialEq for &UseState {
     }
 }
 
-impl PartialEq> for UseState {
+impl PartialEq> for UseState {
     fn eq(&self, other: &UseState) -> bool {
         Rc::ptr_eq(&self.current_val, &other.current_val)
     }

From ad70b46776df800c64e585e1f74fe1bee728e007 Mon Sep 17 00:00:00 2001
From: Jonathan Kelley 
Date: Wed, 22 Feb 2023 12:16:35 -0800
Subject: [PATCH 18/41] bump native core macro

---
 packages/hot-reload/Cargo.toml        | 2 +-
 packages/native-core-macro/Cargo.toml | 8 ++++----
 packages/native-core/Cargo.toml       | 2 +-
 packages/tui/Cargo.toml               | 2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/packages/hot-reload/Cargo.toml b/packages/hot-reload/Cargo.toml
index 99d5cb00d..c09284189 100644
--- a/packages/hot-reload/Cargo.toml
+++ b/packages/hot-reload/Cargo.toml
@@ -23,4 +23,4 @@ serde_json = "1.0.91"
 serde = { version = "1", features = ["derive"] }
 execute = "0.2.11"
 once_cell = "1.17.0"
-ignore = "0.4.19"
\ No newline at end of file
+ignore = "0.4.19"
diff --git a/packages/native-core-macro/Cargo.toml b/packages/native-core-macro/Cargo.toml
index 6a37f75b2..e98b994cb 100644
--- a/packages/native-core-macro/Cargo.toml
+++ b/packages/native-core-macro/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-native-core-macro"
-version = "0.2.0"
+version = "0.3.0"
 edition = "2021"
 description = "Build natively rendered apps with Dioxus"
 license = "MIT/Apache-2.0"
@@ -15,12 +15,12 @@ proc-macro = true
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 [dependencies]
-syn = { version = "1.0.11", features = ["extra-traits"] }
+syn = { version = "1.0.11", features = ["extra-traits", "full"] }
 quote = "1.0"
-dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
-dioxus = { path = "../dioxus" }
 
 [dev-dependencies]
 smallvec = "1.6"
 rustc-hash = "1.1.0"
 anymap = "0.12.1"
+dioxus = { path = "../dioxus" }
+dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml
index dd3ca1027..5689b49b3 100644
--- a/packages/native-core/Cargo.toml
+++ b/packages/native-core/Cargo.toml
@@ -30,5 +30,5 @@ lightningcss = "1.0.0-alpha.39"
 [dev-dependencies]
 rand = "0.8.5"
 dioxus = { path = "../dioxus", version = "^0.3.0" }
-dioxus-native-core-macro = { path = "../native-core-macro" }
+dioxus-native-core-macro = { path = "../native-core-macro" , version = "^0.3.0" }
 tokio = { version = "*", features = ["full"] }
diff --git a/packages/tui/Cargo.toml b/packages/tui/Cargo.toml
index bbf939d1a..a17b9fd94 100644
--- a/packages/tui/Cargo.toml
+++ b/packages/tui/Cargo.toml
@@ -17,7 +17,7 @@ dioxus = { path = "../dioxus", version = "^0.3.0" }
 dioxus-core = { path = "../core", version = "^0.3.0", features = ["serialize"] }
 dioxus-html = { path = "../html", version = "^0.3.0" }
 dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
-dioxus-native-core-macro = { path = "../native-core-macro", version = "^0.2.0" }
+dioxus-native-core-macro = { path = "../native-core-macro", version = "^0.3.0" }
 dioxus-hot-reload = { path = "../hot-reload", optional = true }
 
 tui = "0.17.0"

From 67fd94299aca4f236e4fa2deb6588c51ead87a79 Mon Sep 17 00:00:00 2001
From: Jonathan Kelley 
Date: Wed, 22 Feb 2023 12:21:28 -0800
Subject: [PATCH 19/41] bump native core

---
 packages/native-core-macro/Cargo.toml | 2 +-
 packages/native-core/Cargo.toml       | 6 +++---
 packages/tui/Cargo.toml               | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/packages/native-core-macro/Cargo.toml b/packages/native-core-macro/Cargo.toml
index e98b994cb..ed8648f93 100644
--- a/packages/native-core-macro/Cargo.toml
+++ b/packages/native-core-macro/Cargo.toml
@@ -23,4 +23,4 @@ smallvec = "1.6"
 rustc-hash = "1.1.0"
 anymap = "0.12.1"
 dioxus = { path = "../dioxus" }
-dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
+dioxus-native-core = { path = "../native-core" }
diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml
index 5689b49b3..59e5878c2 100644
--- a/packages/native-core/Cargo.toml
+++ b/packages/native-core/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-native-core"
-version = "0.2.0"
+version = "0.3.0"
 edition = "2021"
 license = "MIT/Apache-2.0"
 repository = "https://github.com/DioxusLabs/dioxus/"
@@ -30,5 +30,5 @@ lightningcss = "1.0.0-alpha.39"
 [dev-dependencies]
 rand = "0.8.5"
 dioxus = { path = "../dioxus", version = "^0.3.0" }
-dioxus-native-core-macro = { path = "../native-core-macro" , version = "^0.3.0" }
-tokio = { version = "*", features = ["full"] }
+dioxus-native-core-macro = { path = "../native-core-macro" }
+tokio = { version = "1.0", features = ["full"] }
diff --git a/packages/tui/Cargo.toml b/packages/tui/Cargo.toml
index a17b9fd94..9bc14303c 100644
--- a/packages/tui/Cargo.toml
+++ b/packages/tui/Cargo.toml
@@ -16,7 +16,7 @@ license = "MIT/Apache-2.0"
 dioxus = { path = "../dioxus", version = "^0.3.0" }
 dioxus-core = { path = "../core", version = "^0.3.0", features = ["serialize"] }
 dioxus-html = { path = "../html", version = "^0.3.0" }
-dioxus-native-core = { path = "../native-core", version = "^0.2.0" }
+dioxus-native-core = { path = "../native-core", version = "^0.3.0" }
 dioxus-native-core-macro = { path = "../native-core-macro", version = "^0.3.0" }
 dioxus-hot-reload = { path = "../hot-reload", optional = true }
 

From ab0023129dabba977165dc20319d7b397ca26d0c Mon Sep 17 00:00:00 2001
From: Jonathan Kelley 
Date: Wed, 22 Feb 2023 12:22:45 -0800
Subject: [PATCH 20/41] bump rsx

---
 packages/autofmt/Cargo.toml     | 2 +-
 packages/core-macro/Cargo.toml  | 2 +-
 packages/dioxus/Cargo.toml      | 2 +-
 packages/hot-reload/Cargo.toml  | 2 +-
 packages/html/Cargo.toml        | 2 +-
 packages/rsx-rosetta/Cargo.toml | 2 +-
 packages/rsx/Cargo.toml         | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/packages/autofmt/Cargo.toml b/packages/autofmt/Cargo.toml
index a1a4592d8..e409cfb2f 100644
--- a/packages/autofmt/Cargo.toml
+++ b/packages/autofmt/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-dioxus-rsx = { path = "../rsx", version = "0.0.2" }
+dioxus-rsx = { path = "../rsx", version = "^0.0.3" }
 proc-macro2 = { version = "1.0.6", features = ["span-locations"] }
 quote = "1.0"
 syn = { version = "1.0.11", features = ["full", "extra-traits"] }
diff --git a/packages/core-macro/Cargo.toml b/packages/core-macro/Cargo.toml
index 5338a7acc..843470646 100644
--- a/packages/core-macro/Cargo.toml
+++ b/packages/core-macro/Cargo.toml
@@ -18,7 +18,7 @@ proc-macro = true
 proc-macro2 = { version = "1.0" }
 quote = "1.0"
 syn = { version = "1.0", features = ["full", "extra-traits"] }
-dioxus-rsx = {  path = "../rsx", version = "0.0.2" }
+dioxus-rsx = {  path = "../rsx", version = "^0.0.3" }
 
 # testing
 [dev-dependencies]
diff --git a/packages/dioxus/Cargo.toml b/packages/dioxus/Cargo.toml
index afe0ea0c3..889a08f2f 100644
--- a/packages/dioxus/Cargo.toml
+++ b/packages/dioxus/Cargo.toml
@@ -16,7 +16,7 @@ dioxus-core = { path = "../core", version = "^0.3.0" }
 dioxus-html = { path = "../html", version = "^0.3.0", optional = true }
 dioxus-core-macro = { path = "../core-macro", version = "^0.3.0", optional = true }
 dioxus-hooks = { path = "../hooks", version = "^0.3.0", optional = true }
-dioxus-rsx = { path = "../rsx", version = "0.0.2", optional = true }
+dioxus-rsx = { path = "../rsx", version = "^0.0.3", optional = true }
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 dioxus-hot-reload = { path = "../hot-reload", version = "0.1.0", optional = true }
diff --git a/packages/hot-reload/Cargo.toml b/packages/hot-reload/Cargo.toml
index c09284189..7fae9bed4 100644
--- a/packages/hot-reload/Cargo.toml
+++ b/packages/hot-reload/Cargo.toml
@@ -12,7 +12,7 @@ keywords = ["dom", "ui", "gui", "react", "hot-reloading", "watch"]
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-dioxus-rsx = { path = "../rsx" }
+dioxus-rsx = { path = "../rsx" , version = "^0.0.3" }
 dioxus-core = { path = "../core", features = ["serialize"] }
 dioxus-html = { path = "../html", features = ["hot-reload-context"] }
 
diff --git a/packages/html/Cargo.toml b/packages/html/Cargo.toml
index 2159acb7b..5fe379057 100644
--- a/packages/html/Cargo.toml
+++ b/packages/html/Cargo.toml
@@ -12,7 +12,7 @@ keywords = ["dom", "ui", "gui", "react"]
 
 [dependencies]
 dioxus-core = { path = "../core", version = "^0.3.0" }
-dioxus-rsx = { path = "../rsx", version = "0.0.2", optional = true }
+dioxus-rsx = { path = "../rsx", version = "^0.0.3", optional = true }
 serde = { version = "1", features = ["derive"], optional = true }
 serde_repr = { version = "0.1", optional = true }
 wasm-bindgen = { version = "0.2.79", optional = true }
diff --git a/packages/rsx-rosetta/Cargo.toml b/packages/rsx-rosetta/Cargo.toml
index 2def4e7c8..a0a9763e1 100644
--- a/packages/rsx-rosetta/Cargo.toml
+++ b/packages/rsx-rosetta/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2018"
 
 [dependencies]
 dioxus-autofmt = { path = "../autofmt" }
-dioxus-rsx = { path = "../rsx" }
+dioxus-rsx = { path = "../rsx" , version = "^0.0.3" }
 html_parser = "0.6.3"
 proc-macro2 = "1.0.49"
 quote = "1.0.23"
diff --git a/packages/rsx/Cargo.toml b/packages/rsx/Cargo.toml
index 6f98b5f47..3096bbc2f 100644
--- a/packages/rsx/Cargo.toml
+++ b/packages/rsx/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-rsx"
-version = "0.0.2"
+version = "0.0.3"
 edition = "2018"
 license = "MIT/Apache-2.0"
 description = "Core functionality for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences"

From b27db17f76e59aad3b2d3c8299092b69dbc05052 Mon Sep 17 00:00:00 2001
From: Jonathan Kelley 
Date: Wed, 22 Feb 2023 12:55:54 -0800
Subject: [PATCH 21/41] bump hot-reload

---
 packages/hot-reload/Cargo.toml | 6 +++---
 packages/rsx/Cargo.toml        | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/packages/hot-reload/Cargo.toml b/packages/hot-reload/Cargo.toml
index 7fae9bed4..84dd8f474 100644
--- a/packages/hot-reload/Cargo.toml
+++ b/packages/hot-reload/Cargo.toml
@@ -7,14 +7,14 @@ repository = "https://github.com/DioxusLabs/dioxus/"
 homepage = "https://dioxuslabs.com"
 description = "Hot reloading utilites for Dioxus"
 documentation = "https://dioxuslabs.com"
-keywords = ["dom", "ui", "gui", "react", "hot-reloading", "watch"]
+keywords = ["dom", "ui", "gui", "react", "hot-reloading"]
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
 dioxus-rsx = { path = "../rsx" , version = "^0.0.3" }
-dioxus-core = { path = "../core", features = ["serialize"] }
-dioxus-html = { path = "../html", features = ["hot-reload-context"] }
+dioxus-core = { path = "../core", features = ["serialize"], version = "^0.3.2"}
+dioxus-html = { path = "../html", features = ["hot-reload-context"], version = "^0.3.0" }
 
 interprocess = { version = "1.2.1" }
 notify = "5.0.0"
diff --git a/packages/rsx/Cargo.toml b/packages/rsx/Cargo.toml
index 3096bbc2f..5aea4d03e 100644
--- a/packages/rsx/Cargo.toml
+++ b/packages/rsx/Cargo.toml
@@ -13,7 +13,7 @@ keywords = ["dom", "ui", "gui", "react"]
 
 [dependencies]
 proc-macro2 = { version = "1.0", features = ["span-locations"] }
-dioxus-core = { path = "../core", version = "0.3.0"}
+dioxus-core = { path = "../core", version = "^0.3.0"}
 syn = { version = "1.0", features = ["full", "extra-traits"] }
 quote = { version = "1.0" }
 serde = { version = "1.0", features = ["derive"] }

From 018a6e75785add8a8e4b524b1b5280bb540633ab Mon Sep 17 00:00:00 2001
From: Jonathan Kelley 
Date: Wed, 22 Feb 2023 13:06:33 -0800
Subject: [PATCH 22/41] bump dioxus, html, and hot-reload

---
 packages/dioxus/Cargo.toml     | 2 +-
 packages/hot-reload/Cargo.toml | 2 +-
 packages/html/Cargo.toml       | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/dioxus/Cargo.toml b/packages/dioxus/Cargo.toml
index 889a08f2f..bc2098285 100644
--- a/packages/dioxus/Cargo.toml
+++ b/packages/dioxus/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dioxus"
-version = "0.3.1"
+version = "0.3.2"
 authors = ["Jonathan Kelley", "Dioxus Labs", "ealmloff"]
 edition = "2021"
 description = "Core functionality for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences"
diff --git a/packages/hot-reload/Cargo.toml b/packages/hot-reload/Cargo.toml
index 84dd8f474..2d88bf029 100644
--- a/packages/hot-reload/Cargo.toml
+++ b/packages/hot-reload/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-hot-reload"
-version = "0.1.0"
+version = "0.1.1"
 edition = "2021"
 license = "MIT/Apache-2.0"
 repository = "https://github.com/DioxusLabs/dioxus/"
diff --git a/packages/html/Cargo.toml b/packages/html/Cargo.toml
index 5fe379057..e60fcd8e5 100644
--- a/packages/html/Cargo.toml
+++ b/packages/html/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "dioxus-html"
-version = "0.3.0"
+version = "0.3.1"
 authors = ["Jonathan Kelley"]
 edition = "2018"
 description = "HTML Element pack for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences"

From 62d30bc25450a037ea2da300b66c41f5ddcf2a98 Mon Sep 17 00:00:00 2001
From: Yin Jifeng 
Date: Thu, 23 Feb 2023 16:36:31 +0800
Subject: [PATCH 23/41] chore: reimplement usefuture::state

---
 packages/hooks/src/usefuture.rs | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/packages/hooks/src/usefuture.rs b/packages/hooks/src/usefuture.rs
index df34a6433..f540e0a6e 100644
--- a/packages/hooks/src/usefuture.rs
+++ b/packages/hooks/src/usefuture.rs
@@ -143,22 +143,21 @@ impl UseFuture {
         self.task.get()
     }
 
-    /// Get the current stateof the future.
+    /// Get the current state of the future.
     pub fn state(&self) -> UseFutureState {
-        todo!()
-        // match (&self.task.get(), &self.value) {
-        //     // If we have a task and an existing value, we're reloading
-        //     (Some(_), Some(val)) => UseFutureState::Reloading(val),
+        match (&self.task.get(), &self.value()) {
+            // If we have a task and an existing value, we're reloading
+            (Some(_), Some(val)) => UseFutureState::Reloading(val),
 
-        //     // no task, but value - we're done
-        //     (None, Some(val)) => UseFutureState::Complete(val),
+            // no task, but value - we're done
+            (None, Some(val)) => UseFutureState::Complete(val),
 
-        //     // no task, no value - something's wrong? return pending
-        //     (None, None) => UseFutureState::Pending,
+            // no task, no value - something's wrong? return pending
+            (None, None) => UseFutureState::Pending,
 
-        //     // Task, no value - we're still pending
-        //     (Some(_), None) => UseFutureState::Pending,
-        // }
+            // Task, no value - we're still pending
+            (Some(_), None) => UseFutureState::Pending,
+        }
     }
 }
 

From fdd71c11fef3bd1447dc749e0bae6952d40981af Mon Sep 17 00:00:00 2001
From: Yin Jifeng 
Date: Thu, 23 Feb 2023 16:36:45 +0800
Subject: [PATCH 24/41] chore: export AtomId

---
 packages/fermi/src/root.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/fermi/src/root.rs b/packages/fermi/src/root.rs
index 68a5d5d33..99e97bfbb 100644
--- a/packages/fermi/src/root.rs
+++ b/packages/fermi/src/root.rs
@@ -13,8 +13,8 @@ use crate::Readable;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct AtomId {
-    pub(crate) ptr: *const (),
-    pub(crate) type_id: TypeId,
+    pub ptr: *const (),
+    pub type_id: TypeId,
 }
 
 pub struct AtomRoot {

From 2c629f6d13257d4d841691f2caf0bb03d22287c2 Mon Sep 17 00:00:00 2001
From: Evan Almloff 
Date: Thu, 23 Feb 2023 12:05:17 -0600
Subject: [PATCH 25/41] use namespaced path instead of local path

---
 packages/hot-reload/src/lib.rs | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/packages/hot-reload/src/lib.rs b/packages/hot-reload/src/lib.rs
index 5c79f9731..d144fccfc 100644
--- a/packages/hot-reload/src/lib.rs
+++ b/packages/hot-reload/src/lib.rs
@@ -139,7 +139,6 @@ pub fn init(cfg: Config) {
             .map(|path| crate_dir.join(PathBuf::from(path)))
             .collect::>();
 
-        let temp_file = std::env::temp_dir().join("@dioxusin");
         let channels = Arc::new(Mutex::new(Vec::new()));
         let FileMapBuildResult {
             map: file_map,
@@ -160,7 +159,7 @@ pub fn init(cfg: Config) {
         }
         let file_map = Arc::new(Mutex::new(file_map));
 
-        if let Ok(local_socket_stream) = LocalSocketListener::bind(temp_file.as_path()) {
+        if let Ok(local_socket_stream) = LocalSocketListener::bind("@dioxusin") {
             let aborted = Arc::new(Mutex::new(false));
 
             // listen for connections
@@ -348,8 +347,7 @@ fn send_msg(msg: HotReloadMsg, channel: &mut impl Write) -> bool {
 /// Connect to the hot reloading listener. The callback provided will be called every time a template change is detected
 pub fn connect(mut f: impl FnMut(HotReloadMsg) + Send + 'static) {
     std::thread::spawn(move || {
-        let temp_file = std::env::temp_dir().join("@dioxusin");
-        if let Ok(socket) = LocalSocketStream::connect(temp_file.as_path()) {
+        if let Ok(socket) = LocalSocketStream::connect("@dioxusin") {
             let mut buf_reader = BufReader::new(socket);
             loop {
                 let mut buf = String::new();

From bf3f7ec4909a70f90e4950a59660d229c1767ea4 Mon Sep 17 00:00:00 2001
From: David Pedersen 
Date: Fri, 24 Feb 2023 22:41:16 +0100
Subject: [PATCH 26/41] Fix typos in examples

---
 packages/liveview/examples/axum.rs  | 2 +-
 packages/liveview/examples/salvo.rs | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/liveview/examples/axum.rs b/packages/liveview/examples/axum.rs
index df24de4aa..2e7f10ee7 100644
--- a/packages/liveview/examples/axum.rs
+++ b/packages/liveview/examples/axum.rs
@@ -28,7 +28,7 @@ async fn main() {
                     r#"
             
             
-                 Dioxus LiveView with Warp  
+                 Dioxus LiveView with axum  
                  
{glue} diff --git a/packages/liveview/examples/salvo.rs b/packages/liveview/examples/salvo.rs index 8cd2c0ca4..015892702 100644 --- a/packages/liveview/examples/salvo.rs +++ b/packages/liveview/examples/salvo.rs @@ -41,7 +41,7 @@ fn index(_depot: &mut Depot, res: &mut Response) { r#" - Dioxus LiveView with Warp + Dioxus LiveView with Salvo
{glue} From 55787c2e7d9a3ebe393ee4ca22e14e6561311abd Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 26 Feb 2023 18:42:14 -0600 Subject: [PATCH 27/41] fix hot reloading in a workspace --- packages/rsx/Cargo.toml | 1 + .../src/hot_reload/hot_reloading_file_map.rs | 36 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/rsx/Cargo.toml b/packages/rsx/Cargo.toml index 5aea4d03e..055a97132 100644 --- a/packages/rsx/Cargo.toml +++ b/packages/rsx/Cargo.toml @@ -18,3 +18,4 @@ syn = { version = "1.0", features = ["full", "extra-traits"] } quote = { version = "1.0" } serde = { version = "1.0", features = ["derive"] } internment = "0.7.0" +krates = "0.12.6" \ No newline at end of file diff --git a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs index 38c1d9105..2f0cc5246 100644 --- a/packages/rsx/src/hot_reload/hot_reloading_file_map.rs +++ b/packages/rsx/src/hot_reload/hot_reloading_file_map.rs @@ -1,5 +1,7 @@ use crate::{CallBody, HotReloadingContext}; use dioxus_core::Template; +use krates::cm::MetadataCommand; +use krates::Cmd; pub use proc_macro2::TokenStream; pub use std::collections::HashMap; use std::path::PathBuf; @@ -27,6 +29,7 @@ pub struct FileMapBuildResult { pub struct FileMap { pub map: HashMap>)>, + in_workspace: HashMap, phantom: std::marker::PhantomData, } @@ -76,6 +79,7 @@ impl FileMap { let FileMapSearchResult { map, errors } = find_rs_files(path, &mut filter)?; let result = Self { map, + in_workspace: HashMap::new(), phantom: std::marker::PhantomData, }; Ok(FileMapBuildResult { @@ -90,6 +94,7 @@ impl FileMap { let mut src = String::new(); file.read_to_string(&mut src)?; if let Ok(syntax) = syn::parse_file(&src) { + let in_workspace = self.child_in_workspace(crate_dir)?; if let Some((old_src, template_slot)) = self.map.get_mut(file_path) { if let Ok(old) = syn::parse_file(old_src) { match find_rsx(&syntax, &old) { @@ -105,7 +110,17 @@ impl FileMap { syn::parse2::(old.tokens), syn::parse2::(new), ) { - if let Ok(file) = file_path.strip_prefix(crate_dir) { + // if the file!() macro is invoked in a workspace, the path is relative to the workspace root, otherwise it's relative to the crate root + // we need to check if the file is in a workspace or not and strip the prefix accordingly + let prefix = if in_workspace { + crate_dir.parent().ok_or(io::Error::new( + io::ErrorKind::Other, + "Could not load workspace", + ))? + } else { + crate_dir + }; + if let Ok(file) = file_path.strip_prefix(prefix) { let line = old_start.line; let column = old_start.column + 1; let location = file.display().to_string() @@ -157,4 +172,23 @@ impl FileMap { } Ok(UpdateResult::NeedsRebuild) } + + fn child_in_workspace(&mut self, crate_dir: &Path) -> io::Result { + if let Some(in_workspace) = self.in_workspace.get(crate_dir) { + Ok(*in_workspace) + } else { + let mut cmd = Cmd::new(); + let manafest_path = crate_dir.join("Cargo.toml"); + cmd.manifest_path(&manafest_path); + let cmd: MetadataCommand = cmd.into(); + let metadata = cmd + .exec() + .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; + + let in_workspace = metadata.workspace_root != crate_dir; + self.in_workspace + .insert(crate_dir.to_path_buf(), in_workspace); + Ok(in_workspace) + } + } } From 2c0eb303f607f4f43ca4b0cc99be4004f8c2581b Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 27 Feb 2023 15:05:49 -0600 Subject: [PATCH 28/41] fix the provide context docs --- packages/core/src/scopes.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/core/src/scopes.rs b/packages/core/src/scopes.rs index fceaefec6..5601d57fe 100644 --- a/packages/core/src/scopes.rs +++ b/packages/core/src/scopes.rs @@ -373,17 +373,12 @@ impl<'src> ScopeState { None } - /// Expose state to children further down the [`crate::VirtualDom`] Tree. Does not require `clone` on the context, - /// though we do recommend it. + /// Expose state to children further down the [`crate::VirtualDom`] Tree. Requires `Clone` on the context to allow getting values down the tree. /// /// This is a "fundamental" operation and should only be called during initialization of a hook. /// /// For a hook that provides the same functionality, use `use_provide_context` and `use_context` instead. /// - /// If a state is provided that already exists, the new value will not be inserted. Instead, this method will - /// return the existing value. This behavior is chosen so shared values do not need to be `Clone`. This particular - /// behavior might change in the future. - /// /// # Example /// /// ```rust, ignore From abcb3f57f06c7966a0d616390036c37f07233d31 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 1 Mar 2023 13:15:58 -0600 Subject: [PATCH 29/41] create global shortcut handler for dioxus desktop --- examples/shortcut.rs | 17 ++ packages/desktop/src/desktop_context.rs | 28 +++ packages/desktop/src/lib.rs | 9 + packages/desktop/src/shortcut.rs | 279 ++++++++++++++++++++++++ 4 files changed, 333 insertions(+) create mode 100644 examples/shortcut.rs create mode 100644 packages/desktop/src/shortcut.rs diff --git a/examples/shortcut.rs b/examples/shortcut.rs new file mode 100644 index 000000000..d98a69ad6 --- /dev/null +++ b/examples/shortcut.rs @@ -0,0 +1,17 @@ +use dioxus::prelude::*; +use dioxus_desktop::tao::keyboard::ModifiersState; +use dioxus_desktop::use_global_shortcut; + +fn main() { + dioxus_desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + let toggled = use_state(cx, || false); + use_global_shortcut(cx, KeyCode::S, ModifiersState::CONTROL, { + to_owned![toggled]; + move || toggled.modify(|t| !*t) + }); + + cx.render(rsx!("toggle: {toggled.get()}")) +} diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index edddd7887..6549fad15 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -5,6 +5,10 @@ use std::rc::Weak; use crate::create_new_window; use crate::eval::EvalResult; use crate::events::IpcMessage; +use crate::shortcut::IntoKeyCode; +use crate::shortcut::ShortcutId; +use crate::shortcut::ShortcutRegistry; +use crate::shortcut::ShortcutRegistryError; use crate::Config; use crate::WebviewHandler; use dioxus_core::ScopeState; @@ -16,6 +20,7 @@ use slab::Slab; use wry::application::event::Event; use wry::application::event_loop::EventLoopProxy; use wry::application::event_loop::EventLoopWindowTarget; +use wry::application::keyboard::ModifiersState; #[cfg(target_os = "ios")] use wry::application::platform::ios::WindowExtIOS; use wry::application::window::Fullscreen as WryFullscreen; @@ -63,6 +68,8 @@ pub struct DesktopContext { pub(crate) event_handlers: WindowEventHandlers, + pub(crate) shortcut_manager: ShortcutRegistry, + #[cfg(target_os = "ios")] pub(crate) views: Rc>>, } @@ -83,6 +90,7 @@ impl DesktopContext { event_loop: EventLoopWindowTarget, webviews: WebviewQueue, event_handlers: WindowEventHandlers, + shortcut_manager: ShortcutRegistry, ) -> Self { Self { webview, @@ -91,6 +99,7 @@ impl DesktopContext { eval: tokio::sync::broadcast::channel(8).0, pending_windows: webviews, event_handlers, + shortcut_manager, #[cfg(target_os = "ios")] views: Default::default(), } @@ -111,6 +120,7 @@ impl DesktopContext { dom, &self.pending_windows, &self.event_handlers, + self.shortcut_manager.clone(), ); let id = window.webview.window().id(); @@ -240,6 +250,24 @@ impl DesktopContext { self.event_handlers.remove(id) } + /// Create a global shortcut + /// + /// Linux: Only works on x11. See [this issue](https://github.com/tauri-apps/tao/issues/331) for more information. + pub fn create_shortcut( + &self, + key: impl IntoKeyCode, + modifiers: impl Into>, + callback: impl FnMut() + 'static, + ) -> Result { + self.shortcut_manager + .add_shortcut(modifiers, key.into_key_code(), Box::new(callback)) + } + + /// Remove a global shortcut + pub fn remove_shortcut(&self, id: ShortcutId) { + self.shortcut_manager.remove_shortcut(id) + } + /// Push an objc view to the window #[cfg(target_os = "ios")] pub fn push_view(&self, view: objc_id::ShareId) { diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 16f562464..75c67dd22 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -9,6 +9,7 @@ mod escape; mod eval; mod events; mod protocol; +mod shortcut; mod waker; mod webview; @@ -21,6 +22,8 @@ use dioxus_core::*; use dioxus_html::HtmlEvent; pub use eval::{use_eval, EvalResult}; use futures_util::{pin_mut, FutureExt}; +use shortcut::ShortcutRegistry; +pub use shortcut::{use_global_shortcut, ShortcutHandle, ShortcutId, ShortcutRegistryError}; use std::collections::HashMap; use std::rc::Rc; use std::task::Waker; @@ -139,6 +142,8 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) let queue = WebviewQueue::default(); + let shortcut_manager = ShortcutRegistry::new(&event_loop); + // By default, we'll create a new window when the app starts queue.borrow_mut().push(create_new_window( cfg, @@ -147,6 +152,7 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) VirtualDom::new_with_props(root, props), &queue, &event_handlers, + shortcut_manager.clone(), )); event_loop.run(move |window_event, event_loop, control_flow| { @@ -260,6 +266,7 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) _ => {} }, + Event::GlobalShortcutEvent(id) => shortcut_manager.call_handlers(id), _ => {} } }) @@ -272,6 +279,7 @@ fn create_new_window( dom: VirtualDom, queue: &WebviewQueue, event_handlers: &WindowEventHandlers, + shortcut_manager: ShortcutRegistry, ) -> WebviewHandler { let webview = webview::build(&mut cfg, event_loop, proxy.clone()); @@ -281,6 +289,7 @@ fn create_new_window( event_loop.clone(), queue.clone(), event_handlers.clone(), + shortcut_manager, )); let id = webview.window().id(); diff --git a/packages/desktop/src/shortcut.rs b/packages/desktop/src/shortcut.rs new file mode 100644 index 000000000..141d9af46 --- /dev/null +++ b/packages/desktop/src/shortcut.rs @@ -0,0 +1,279 @@ +use std::{cell::RefCell, collections::HashMap, rc::Rc}; + +use dioxus_core::ScopeState; +use slab::Slab; +use wry::application::{ + accelerator::{Accelerator, AcceleratorId}, + event_loop::EventLoopWindowTarget, + global_shortcut::{GlobalShortcut, ShortcutManager, ShortcutManagerError}, + keyboard::{KeyCode, ModifiersState}, +}; + +use crate::{use_window, DesktopContext}; + +#[derive(Clone)] +pub(crate) struct ShortcutRegistry { + manager: Rc>, + shortcuts: ShortcutMap, +} + +type ShortcutMap = Rc>>; + +struct Shortcut { + shortcut: GlobalShortcut, + callbacks: Slab>, +} + +impl Shortcut { + fn insert(&mut self, callback: Box) -> usize { + self.callbacks.insert(callback) + } + + fn remove(&mut self, id: usize) { + let _ = self.callbacks.remove(id); + } + + fn is_empty(&self) -> bool { + self.callbacks.is_empty() + } +} + +impl ShortcutRegistry { + pub fn new(target: &EventLoopWindowTarget) -> Self { + Self { + manager: Rc::new(RefCell::new(ShortcutManager::new(target))), + shortcuts: Rc::new(RefCell::new(HashMap::new())), + } + } + + pub(crate) fn call_handlers(&self, id: AcceleratorId) { + if let Some(Shortcut { callbacks, .. }) = self.shortcuts.borrow_mut().get_mut(&id) { + for (_, callback) in callbacks.iter_mut() { + (callback)(); + } + } + } + + pub(crate) fn add_shortcut( + &self, + modifiers: impl Into>, + key: KeyCode, + callback: Box, + ) -> Result { + let accelerator = Accelerator::new(modifiers, key); + let accelerator_id = accelerator.clone().id(); + let mut shortcuts = self.shortcuts.borrow_mut(); + Ok( + if let Some(callbacks) = shortcuts.get_mut(&accelerator_id) { + let id = callbacks.insert(callback); + ShortcutId { + id: accelerator_id, + number: id, + } + } else { + match self.manager.borrow_mut().register(accelerator) { + Ok(global_shortcut) => { + let mut slab = Slab::new(); + let id = slab.insert(callback); + let shortcut = Shortcut { + shortcut: global_shortcut, + callbacks: slab, + }; + shortcuts.insert(accelerator_id, shortcut); + ShortcutId { + id: accelerator_id, + number: id, + } + } + Err(ShortcutManagerError::InvalidAccelerator(shortcut)) => { + return Err(ShortcutRegistryError::InvalidShortcut(shortcut)) + } + Err(err) => return Err(ShortcutRegistryError::Other(Box::new(err))), + } + }, + ) + } + + pub(crate) fn remove_shortcut(&self, id: ShortcutId) { + let mut shortcuts = self.shortcuts.borrow_mut(); + if let Some(callbacks) = shortcuts.get_mut(&id.id) { + callbacks.remove(id.number); + if callbacks.is_empty() { + if let Some(shortcut) = shortcuts.remove(&id.id) { + let _ = self.manager.borrow_mut().unregister(shortcut.shortcut); + } + } + } + } +} + +#[non_exhaustive] +#[derive(Debug)] +/// An error that can occur when registering a shortcut. +pub enum ShortcutRegistryError { + /// The shortcut is invalid. + InvalidShortcut(String), + /// An unknown error occurred. + Other(Box), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +/// An global id for a shortcut. +pub struct ShortcutId { + id: AcceleratorId, + number: usize, +} + +/// A global shortcut. This will be automatically removed when it is dropped. +pub struct ShortcutHandle { + desktop: DesktopContext, + /// The id of the shortcut + pub shortcut_id: ShortcutId, +} + +/// Get a closure that executes any JavaScript in the WebView context. +pub fn use_global_shortcut( + cx: &ScopeState, + key: impl IntoKeyCode, + modifiers: impl Into>, + handler: impl FnMut() + 'static, +) -> &Result { + let desktop = use_window(cx); + cx.use_hook(move || { + let desktop = desktop.clone(); + + let id = desktop.create_shortcut(key.into_key_code(), modifiers, handler); + + Ok(ShortcutHandle { + desktop, + shortcut_id: id?, + }) + }) +} + +impl ShortcutHandle { + /// Remove the shortcut. + pub fn remove(&self) { + self.desktop.remove_shortcut(self.shortcut_id); + } +} + +impl Drop for ShortcutHandle { + fn drop(&mut self) { + self.remove() + } +} + +pub trait IntoKeyCode { + fn into_key_code(self) -> KeyCode; +} + +impl IntoKeyCode for KeyCode { + fn into_key_code(self) -> KeyCode { + self + } +} + +impl IntoKeyCode for dioxus_html::KeyCode { + fn into_key_code(self) -> KeyCode { + match self { + dioxus_html::KeyCode::Backspace => KeyCode::Backspace, + dioxus_html::KeyCode::Tab => KeyCode::Tab, + dioxus_html::KeyCode::Clear => KeyCode::NumpadClear, + dioxus_html::KeyCode::Enter => KeyCode::Enter, + dioxus_html::KeyCode::Shift => KeyCode::ShiftLeft, + dioxus_html::KeyCode::Ctrl => KeyCode::ControlLeft, + dioxus_html::KeyCode::Alt => KeyCode::AltLeft, + dioxus_html::KeyCode::Pause => KeyCode::Pause, + dioxus_html::KeyCode::CapsLock => KeyCode::CapsLock, + dioxus_html::KeyCode::Escape => KeyCode::Escape, + dioxus_html::KeyCode::Space => KeyCode::Space, + dioxus_html::KeyCode::PageUp => KeyCode::PageUp, + dioxus_html::KeyCode::PageDown => KeyCode::PageDown, + dioxus_html::KeyCode::End => KeyCode::End, + dioxus_html::KeyCode::Home => KeyCode::Home, + dioxus_html::KeyCode::LeftArrow => KeyCode::ArrowLeft, + dioxus_html::KeyCode::UpArrow => KeyCode::ArrowUp, + dioxus_html::KeyCode::RightArrow => KeyCode::ArrowRight, + dioxus_html::KeyCode::DownArrow => KeyCode::ArrowDown, + dioxus_html::KeyCode::Insert => KeyCode::Insert, + dioxus_html::KeyCode::Delete => KeyCode::Delete, + dioxus_html::KeyCode::Num0 => KeyCode::Numpad0, + dioxus_html::KeyCode::Num1 => KeyCode::Numpad1, + dioxus_html::KeyCode::Num2 => KeyCode::Numpad2, + dioxus_html::KeyCode::Num3 => KeyCode::Numpad3, + dioxus_html::KeyCode::Num4 => KeyCode::Numpad4, + dioxus_html::KeyCode::Num5 => KeyCode::Numpad5, + dioxus_html::KeyCode::Num6 => KeyCode::Numpad6, + dioxus_html::KeyCode::Num7 => KeyCode::Numpad7, + dioxus_html::KeyCode::Num8 => KeyCode::Numpad8, + dioxus_html::KeyCode::Num9 => KeyCode::Numpad9, + dioxus_html::KeyCode::A => KeyCode::KeyA, + dioxus_html::KeyCode::B => KeyCode::KeyB, + dioxus_html::KeyCode::C => KeyCode::KeyC, + dioxus_html::KeyCode::D => KeyCode::KeyD, + dioxus_html::KeyCode::E => KeyCode::KeyE, + dioxus_html::KeyCode::F => KeyCode::KeyF, + dioxus_html::KeyCode::G => KeyCode::KeyG, + dioxus_html::KeyCode::H => KeyCode::KeyH, + dioxus_html::KeyCode::I => KeyCode::KeyI, + dioxus_html::KeyCode::J => KeyCode::KeyJ, + dioxus_html::KeyCode::K => KeyCode::KeyK, + dioxus_html::KeyCode::L => KeyCode::KeyL, + dioxus_html::KeyCode::M => KeyCode::KeyM, + dioxus_html::KeyCode::N => KeyCode::KeyN, + dioxus_html::KeyCode::O => KeyCode::KeyO, + dioxus_html::KeyCode::P => KeyCode::KeyP, + dioxus_html::KeyCode::Q => KeyCode::KeyQ, + dioxus_html::KeyCode::R => KeyCode::KeyR, + dioxus_html::KeyCode::S => KeyCode::KeyS, + dioxus_html::KeyCode::T => KeyCode::KeyT, + dioxus_html::KeyCode::U => KeyCode::KeyU, + dioxus_html::KeyCode::V => KeyCode::KeyV, + dioxus_html::KeyCode::W => KeyCode::KeyW, + dioxus_html::KeyCode::X => KeyCode::KeyX, + dioxus_html::KeyCode::Y => KeyCode::KeyY, + dioxus_html::KeyCode::Z => KeyCode::KeyZ, + dioxus_html::KeyCode::Numpad0 => KeyCode::Numpad0, + dioxus_html::KeyCode::Numpad1 => KeyCode::Numpad1, + dioxus_html::KeyCode::Numpad2 => KeyCode::Numpad2, + dioxus_html::KeyCode::Numpad3 => KeyCode::Numpad3, + dioxus_html::KeyCode::Numpad4 => KeyCode::Numpad4, + dioxus_html::KeyCode::Numpad5 => KeyCode::Numpad5, + dioxus_html::KeyCode::Numpad6 => KeyCode::Numpad6, + dioxus_html::KeyCode::Numpad7 => KeyCode::Numpad7, + dioxus_html::KeyCode::Numpad8 => KeyCode::Numpad8, + dioxus_html::KeyCode::Numpad9 => KeyCode::Numpad9, + dioxus_html::KeyCode::Multiply => KeyCode::NumpadMultiply, + dioxus_html::KeyCode::Add => KeyCode::NumpadAdd, + dioxus_html::KeyCode::Subtract => KeyCode::NumpadSubtract, + dioxus_html::KeyCode::DecimalPoint => KeyCode::NumpadDecimal, + dioxus_html::KeyCode::Divide => KeyCode::NumpadDivide, + dioxus_html::KeyCode::F1 => KeyCode::F1, + dioxus_html::KeyCode::F2 => KeyCode::F2, + dioxus_html::KeyCode::F3 => KeyCode::F3, + dioxus_html::KeyCode::F4 => KeyCode::F4, + dioxus_html::KeyCode::F5 => KeyCode::F5, + dioxus_html::KeyCode::F6 => KeyCode::F6, + dioxus_html::KeyCode::F7 => KeyCode::F7, + dioxus_html::KeyCode::F8 => KeyCode::F8, + dioxus_html::KeyCode::F9 => KeyCode::F9, + dioxus_html::KeyCode::F10 => KeyCode::F10, + dioxus_html::KeyCode::F11 => KeyCode::F11, + dioxus_html::KeyCode::F12 => KeyCode::F12, + dioxus_html::KeyCode::NumLock => KeyCode::NumLock, + dioxus_html::KeyCode::ScrollLock => KeyCode::ScrollLock, + dioxus_html::KeyCode::Semicolon => KeyCode::Semicolon, + dioxus_html::KeyCode::EqualSign => KeyCode::Equal, + dioxus_html::KeyCode::Comma => KeyCode::Comma, + dioxus_html::KeyCode::Period => KeyCode::Period, + dioxus_html::KeyCode::ForwardSlash => KeyCode::Slash, + dioxus_html::KeyCode::GraveAccent => KeyCode::Backquote, + dioxus_html::KeyCode::OpenBracket => KeyCode::BracketLeft, + dioxus_html::KeyCode::BackSlash => KeyCode::Backslash, + dioxus_html::KeyCode::CloseBraket => KeyCode::BracketRight, + dioxus_html::KeyCode::SingleQuote => KeyCode::Quote, + key => panic!("Failed to convert {:?} to tao::keyboard::KeyCode, try using tao::keyboard::KeyCode directly", key), + } + } +} From cf2a79c173e352430a5b67a5bc2b1ef625592a66 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 1 Mar 2023 13:23:15 -0600 Subject: [PATCH 30/41] create global shortcut handler for dioxus desktop --- examples/shortcut.rs | 17 ++ packages/desktop/src/desktop_context.rs | 31 +++ packages/desktop/src/lib.rs | 9 + packages/desktop/src/shortcut.rs | 313 ++++++++++++++++++++++++ 4 files changed, 370 insertions(+) create mode 100644 examples/shortcut.rs create mode 100644 packages/desktop/src/shortcut.rs diff --git a/examples/shortcut.rs b/examples/shortcut.rs new file mode 100644 index 000000000..d98a69ad6 --- /dev/null +++ b/examples/shortcut.rs @@ -0,0 +1,17 @@ +use dioxus::prelude::*; +use dioxus_desktop::tao::keyboard::ModifiersState; +use dioxus_desktop::use_global_shortcut; + +fn main() { + dioxus_desktop::launch(app); +} + +fn app(cx: Scope) -> Element { + let toggled = use_state(cx, || false); + use_global_shortcut(cx, KeyCode::S, ModifiersState::CONTROL, { + to_owned![toggled]; + move || toggled.modify(|t| !*t) + }); + + cx.render(rsx!("toggle: {toggled.get()}")) +} diff --git a/packages/desktop/src/desktop_context.rs b/packages/desktop/src/desktop_context.rs index edddd7887..7db554517 100644 --- a/packages/desktop/src/desktop_context.rs +++ b/packages/desktop/src/desktop_context.rs @@ -5,6 +5,11 @@ use std::rc::Weak; use crate::create_new_window; use crate::eval::EvalResult; use crate::events::IpcMessage; +use crate::shortcut::IntoKeyCode; +use crate::shortcut::IntoModifersState; +use crate::shortcut::ShortcutId; +use crate::shortcut::ShortcutRegistry; +use crate::shortcut::ShortcutRegistryError; use crate::Config; use crate::WebviewHandler; use dioxus_core::ScopeState; @@ -63,6 +68,8 @@ pub struct DesktopContext { pub(crate) event_handlers: WindowEventHandlers, + pub(crate) shortcut_manager: ShortcutRegistry, + #[cfg(target_os = "ios")] pub(crate) views: Rc>>, } @@ -83,6 +90,7 @@ impl DesktopContext { event_loop: EventLoopWindowTarget, webviews: WebviewQueue, event_handlers: WindowEventHandlers, + shortcut_manager: ShortcutRegistry, ) -> Self { Self { webview, @@ -91,6 +99,7 @@ impl DesktopContext { eval: tokio::sync::broadcast::channel(8).0, pending_windows: webviews, event_handlers, + shortcut_manager, #[cfg(target_os = "ios")] views: Default::default(), } @@ -111,6 +120,7 @@ impl DesktopContext { dom, &self.pending_windows, &self.event_handlers, + self.shortcut_manager.clone(), ); let id = window.webview.window().id(); @@ -240,6 +250,27 @@ impl DesktopContext { self.event_handlers.remove(id) } + /// Create a global shortcut + /// + /// Linux: Only works on x11. See [this issue](https://github.com/tauri-apps/tao/issues/331) for more information. + pub fn create_shortcut( + &self, + key: impl IntoKeyCode, + modifiers: impl IntoModifersState, + callback: impl FnMut() + 'static, + ) -> Result { + self.shortcut_manager.add_shortcut( + modifiers.into_modifiers_state(), + key.into_key_code(), + Box::new(callback), + ) + } + + /// Remove a global shortcut + pub fn remove_shortcut(&self, id: ShortcutId) { + self.shortcut_manager.remove_shortcut(id) + } + /// Push an objc view to the window #[cfg(target_os = "ios")] pub fn push_view(&self, view: objc_id::ShareId) { diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index 16f562464..75c67dd22 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -9,6 +9,7 @@ mod escape; mod eval; mod events; mod protocol; +mod shortcut; mod waker; mod webview; @@ -21,6 +22,8 @@ use dioxus_core::*; use dioxus_html::HtmlEvent; pub use eval::{use_eval, EvalResult}; use futures_util::{pin_mut, FutureExt}; +use shortcut::ShortcutRegistry; +pub use shortcut::{use_global_shortcut, ShortcutHandle, ShortcutId, ShortcutRegistryError}; use std::collections::HashMap; use std::rc::Rc; use std::task::Waker; @@ -139,6 +142,8 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) let queue = WebviewQueue::default(); + let shortcut_manager = ShortcutRegistry::new(&event_loop); + // By default, we'll create a new window when the app starts queue.borrow_mut().push(create_new_window( cfg, @@ -147,6 +152,7 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) VirtualDom::new_with_props(root, props), &queue, &event_handlers, + shortcut_manager.clone(), )); event_loop.run(move |window_event, event_loop, control_flow| { @@ -260,6 +266,7 @@ pub fn launch_with_props(root: Component

, props: P, cfg: Config) _ => {} }, + Event::GlobalShortcutEvent(id) => shortcut_manager.call_handlers(id), _ => {} } }) @@ -272,6 +279,7 @@ fn create_new_window( dom: VirtualDom, queue: &WebviewQueue, event_handlers: &WindowEventHandlers, + shortcut_manager: ShortcutRegistry, ) -> WebviewHandler { let webview = webview::build(&mut cfg, event_loop, proxy.clone()); @@ -281,6 +289,7 @@ fn create_new_window( event_loop.clone(), queue.clone(), event_handlers.clone(), + shortcut_manager, )); let id = webview.window().id(); diff --git a/packages/desktop/src/shortcut.rs b/packages/desktop/src/shortcut.rs new file mode 100644 index 000000000..9b36a5638 --- /dev/null +++ b/packages/desktop/src/shortcut.rs @@ -0,0 +1,313 @@ +use std::{cell::RefCell, collections::HashMap, rc::Rc}; + +use dioxus_core::ScopeState; +use dioxus_html::input_data::keyboard_types::Modifiers; +use slab::Slab; +use wry::application::{ + accelerator::{Accelerator, AcceleratorId}, + event_loop::EventLoopWindowTarget, + global_shortcut::{GlobalShortcut, ShortcutManager, ShortcutManagerError}, + keyboard::{KeyCode, ModifiersState}, +}; + +use crate::{use_window, DesktopContext}; + +#[derive(Clone)] +pub(crate) struct ShortcutRegistry { + manager: Rc>, + shortcuts: ShortcutMap, +} + +type ShortcutMap = Rc>>; + +struct Shortcut { + shortcut: GlobalShortcut, + callbacks: Slab>, +} + +impl Shortcut { + fn insert(&mut self, callback: Box) -> usize { + self.callbacks.insert(callback) + } + + fn remove(&mut self, id: usize) { + let _ = self.callbacks.remove(id); + } + + fn is_empty(&self) -> bool { + self.callbacks.is_empty() + } +} + +impl ShortcutRegistry { + pub fn new(target: &EventLoopWindowTarget) -> Self { + Self { + manager: Rc::new(RefCell::new(ShortcutManager::new(target))), + shortcuts: Rc::new(RefCell::new(HashMap::new())), + } + } + + pub(crate) fn call_handlers(&self, id: AcceleratorId) { + if let Some(Shortcut { callbacks, .. }) = self.shortcuts.borrow_mut().get_mut(&id) { + for (_, callback) in callbacks.iter_mut() { + (callback)(); + } + } + } + + pub(crate) fn add_shortcut( + &self, + modifiers: impl Into>, + key: KeyCode, + callback: Box, + ) -> Result { + let accelerator = Accelerator::new(modifiers, key); + let accelerator_id = accelerator.clone().id(); + let mut shortcuts = self.shortcuts.borrow_mut(); + Ok( + if let Some(callbacks) = shortcuts.get_mut(&accelerator_id) { + let id = callbacks.insert(callback); + ShortcutId { + id: accelerator_id, + number: id, + } + } else { + match self.manager.borrow_mut().register(accelerator) { + Ok(global_shortcut) => { + let mut slab = Slab::new(); + let id = slab.insert(callback); + let shortcut = Shortcut { + shortcut: global_shortcut, + callbacks: slab, + }; + shortcuts.insert(accelerator_id, shortcut); + ShortcutId { + id: accelerator_id, + number: id, + } + } + Err(ShortcutManagerError::InvalidAccelerator(shortcut)) => { + return Err(ShortcutRegistryError::InvalidShortcut(shortcut)) + } + Err(err) => return Err(ShortcutRegistryError::Other(Box::new(err))), + } + }, + ) + } + + pub(crate) fn remove_shortcut(&self, id: ShortcutId) { + let mut shortcuts = self.shortcuts.borrow_mut(); + if let Some(callbacks) = shortcuts.get_mut(&id.id) { + callbacks.remove(id.number); + if callbacks.is_empty() { + if let Some(shortcut) = shortcuts.remove(&id.id) { + let _ = self.manager.borrow_mut().unregister(shortcut.shortcut); + } + } + } + } +} + +#[non_exhaustive] +#[derive(Debug)] +/// An error that can occur when registering a shortcut. +pub enum ShortcutRegistryError { + /// The shortcut is invalid. + InvalidShortcut(String), + /// An unknown error occurred. + Other(Box), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +/// An global id for a shortcut. +pub struct ShortcutId { + id: AcceleratorId, + number: usize, +} + +/// A global shortcut. This will be automatically removed when it is dropped. +pub struct ShortcutHandle { + desktop: DesktopContext, + /// The id of the shortcut + pub shortcut_id: ShortcutId, +} + +/// Get a closure that executes any JavaScript in the WebView context. +pub fn use_global_shortcut( + cx: &ScopeState, + key: impl IntoKeyCode, + modifiers: impl IntoModifersState, + handler: impl FnMut() + 'static, +) -> &Result { + let desktop = use_window(cx); + cx.use_hook(move || { + let desktop = desktop.clone(); + + let id = desktop.create_shortcut( + key.into_key_code(), + modifiers.into_modifiers_state(), + handler, + ); + + Ok(ShortcutHandle { + desktop, + shortcut_id: id?, + }) + }) +} + +impl ShortcutHandle { + /// Remove the shortcut. + pub fn remove(&self) { + self.desktop.remove_shortcut(self.shortcut_id); + } +} + +impl Drop for ShortcutHandle { + fn drop(&mut self) { + self.remove() + } +} + +pub trait IntoModifersState { + fn into_modifiers_state(self) -> ModifiersState; +} + +impl IntoModifersState for ModifiersState { + fn into_modifiers_state(self) -> ModifiersState { + self + } +} + +impl IntoModifersState for Modifiers { + fn into_modifiers_state(self) -> ModifiersState { + let mut state = ModifiersState::empty(); + if self.contains(Modifiers::SHIFT) { + state |= ModifiersState::SHIFT + } + if self.contains(Modifiers::CONTROL) { + state |= ModifiersState::CONTROL + } + if self.contains(Modifiers::ALT) { + state |= ModifiersState::ALT + } + if self.contains(Modifiers::META) || self.contains(Modifiers::SUPER) { + state |= ModifiersState::SUPER + } + state + } +} + +pub trait IntoKeyCode { + fn into_key_code(self) -> KeyCode; +} + +impl IntoKeyCode for KeyCode { + fn into_key_code(self) -> KeyCode { + self + } +} + +impl IntoKeyCode for dioxus_html::KeyCode { + fn into_key_code(self) -> KeyCode { + match self { + dioxus_html::KeyCode::Backspace => KeyCode::Backspace, + dioxus_html::KeyCode::Tab => KeyCode::Tab, + dioxus_html::KeyCode::Clear => KeyCode::NumpadClear, + dioxus_html::KeyCode::Enter => KeyCode::Enter, + dioxus_html::KeyCode::Shift => KeyCode::ShiftLeft, + dioxus_html::KeyCode::Ctrl => KeyCode::ControlLeft, + dioxus_html::KeyCode::Alt => KeyCode::AltLeft, + dioxus_html::KeyCode::Pause => KeyCode::Pause, + dioxus_html::KeyCode::CapsLock => KeyCode::CapsLock, + dioxus_html::KeyCode::Escape => KeyCode::Escape, + dioxus_html::KeyCode::Space => KeyCode::Space, + dioxus_html::KeyCode::PageUp => KeyCode::PageUp, + dioxus_html::KeyCode::PageDown => KeyCode::PageDown, + dioxus_html::KeyCode::End => KeyCode::End, + dioxus_html::KeyCode::Home => KeyCode::Home, + dioxus_html::KeyCode::LeftArrow => KeyCode::ArrowLeft, + dioxus_html::KeyCode::UpArrow => KeyCode::ArrowUp, + dioxus_html::KeyCode::RightArrow => KeyCode::ArrowRight, + dioxus_html::KeyCode::DownArrow => KeyCode::ArrowDown, + dioxus_html::KeyCode::Insert => KeyCode::Insert, + dioxus_html::KeyCode::Delete => KeyCode::Delete, + dioxus_html::KeyCode::Num0 => KeyCode::Numpad0, + dioxus_html::KeyCode::Num1 => KeyCode::Numpad1, + dioxus_html::KeyCode::Num2 => KeyCode::Numpad2, + dioxus_html::KeyCode::Num3 => KeyCode::Numpad3, + dioxus_html::KeyCode::Num4 => KeyCode::Numpad4, + dioxus_html::KeyCode::Num5 => KeyCode::Numpad5, + dioxus_html::KeyCode::Num6 => KeyCode::Numpad6, + dioxus_html::KeyCode::Num7 => KeyCode::Numpad7, + dioxus_html::KeyCode::Num8 => KeyCode::Numpad8, + dioxus_html::KeyCode::Num9 => KeyCode::Numpad9, + dioxus_html::KeyCode::A => KeyCode::KeyA, + dioxus_html::KeyCode::B => KeyCode::KeyB, + dioxus_html::KeyCode::C => KeyCode::KeyC, + dioxus_html::KeyCode::D => KeyCode::KeyD, + dioxus_html::KeyCode::E => KeyCode::KeyE, + dioxus_html::KeyCode::F => KeyCode::KeyF, + dioxus_html::KeyCode::G => KeyCode::KeyG, + dioxus_html::KeyCode::H => KeyCode::KeyH, + dioxus_html::KeyCode::I => KeyCode::KeyI, + dioxus_html::KeyCode::J => KeyCode::KeyJ, + dioxus_html::KeyCode::K => KeyCode::KeyK, + dioxus_html::KeyCode::L => KeyCode::KeyL, + dioxus_html::KeyCode::M => KeyCode::KeyM, + dioxus_html::KeyCode::N => KeyCode::KeyN, + dioxus_html::KeyCode::O => KeyCode::KeyO, + dioxus_html::KeyCode::P => KeyCode::KeyP, + dioxus_html::KeyCode::Q => KeyCode::KeyQ, + dioxus_html::KeyCode::R => KeyCode::KeyR, + dioxus_html::KeyCode::S => KeyCode::KeyS, + dioxus_html::KeyCode::T => KeyCode::KeyT, + dioxus_html::KeyCode::U => KeyCode::KeyU, + dioxus_html::KeyCode::V => KeyCode::KeyV, + dioxus_html::KeyCode::W => KeyCode::KeyW, + dioxus_html::KeyCode::X => KeyCode::KeyX, + dioxus_html::KeyCode::Y => KeyCode::KeyY, + dioxus_html::KeyCode::Z => KeyCode::KeyZ, + dioxus_html::KeyCode::Numpad0 => KeyCode::Numpad0, + dioxus_html::KeyCode::Numpad1 => KeyCode::Numpad1, + dioxus_html::KeyCode::Numpad2 => KeyCode::Numpad2, + dioxus_html::KeyCode::Numpad3 => KeyCode::Numpad3, + dioxus_html::KeyCode::Numpad4 => KeyCode::Numpad4, + dioxus_html::KeyCode::Numpad5 => KeyCode::Numpad5, + dioxus_html::KeyCode::Numpad6 => KeyCode::Numpad6, + dioxus_html::KeyCode::Numpad7 => KeyCode::Numpad7, + dioxus_html::KeyCode::Numpad8 => KeyCode::Numpad8, + dioxus_html::KeyCode::Numpad9 => KeyCode::Numpad9, + dioxus_html::KeyCode::Multiply => KeyCode::NumpadMultiply, + dioxus_html::KeyCode::Add => KeyCode::NumpadAdd, + dioxus_html::KeyCode::Subtract => KeyCode::NumpadSubtract, + dioxus_html::KeyCode::DecimalPoint => KeyCode::NumpadDecimal, + dioxus_html::KeyCode::Divide => KeyCode::NumpadDivide, + dioxus_html::KeyCode::F1 => KeyCode::F1, + dioxus_html::KeyCode::F2 => KeyCode::F2, + dioxus_html::KeyCode::F3 => KeyCode::F3, + dioxus_html::KeyCode::F4 => KeyCode::F4, + dioxus_html::KeyCode::F5 => KeyCode::F5, + dioxus_html::KeyCode::F6 => KeyCode::F6, + dioxus_html::KeyCode::F7 => KeyCode::F7, + dioxus_html::KeyCode::F8 => KeyCode::F8, + dioxus_html::KeyCode::F9 => KeyCode::F9, + dioxus_html::KeyCode::F10 => KeyCode::F10, + dioxus_html::KeyCode::F11 => KeyCode::F11, + dioxus_html::KeyCode::F12 => KeyCode::F12, + dioxus_html::KeyCode::NumLock => KeyCode::NumLock, + dioxus_html::KeyCode::ScrollLock => KeyCode::ScrollLock, + dioxus_html::KeyCode::Semicolon => KeyCode::Semicolon, + dioxus_html::KeyCode::EqualSign => KeyCode::Equal, + dioxus_html::KeyCode::Comma => KeyCode::Comma, + dioxus_html::KeyCode::Period => KeyCode::Period, + dioxus_html::KeyCode::ForwardSlash => KeyCode::Slash, + dioxus_html::KeyCode::GraveAccent => KeyCode::Backquote, + dioxus_html::KeyCode::OpenBracket => KeyCode::BracketLeft, + dioxus_html::KeyCode::BackSlash => KeyCode::Backslash, + dioxus_html::KeyCode::CloseBraket => KeyCode::BracketRight, + dioxus_html::KeyCode::SingleQuote => KeyCode::Quote, + key => panic!("Failed to convert {:?} to tao::keyboard::KeyCode, try using tao::keyboard::KeyCode directly", key), + } + } +} From 2d21f7ade1d90d3e157b6e63dffd1353dcbba339 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 1 Mar 2023 13:32:13 -0600 Subject: [PATCH 31/41] add a shortcut for ctrl-r to prevent it breaking the application --- packages/desktop/src/shortcut.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/desktop/src/shortcut.rs b/packages/desktop/src/shortcut.rs index 9b36a5638..cf70d307a 100644 --- a/packages/desktop/src/shortcut.rs +++ b/packages/desktop/src/shortcut.rs @@ -41,10 +41,17 @@ impl Shortcut { impl ShortcutRegistry { pub fn new(target: &EventLoopWindowTarget) -> Self { - Self { + let myself = Self { manager: Rc::new(RefCell::new(ShortcutManager::new(target))), shortcuts: Rc::new(RefCell::new(HashMap::new())), - } + }; + // prevent CTRL+R from reloading the page which breaks apps + let _ = myself.add_shortcut( + Some(ModifiersState::CONTROL), + KeyCode::KeyR, + Box::new(|| {}), + ); + myself } pub(crate) fn call_handlers(&self, id: AcceleratorId) { From bfdcad6edebfe9c7b3bb42a44a7d1352819fe2fb Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 1 Mar 2023 20:41:49 -0600 Subject: [PATCH 32/41] fix trait bounds on generics with inline_props --- packages/core-macro/src/inlineprops.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/core-macro/src/inlineprops.rs b/packages/core-macro/src/inlineprops.rs index 8eaadff32..814724b56 100644 --- a/packages/core-macro/src/inlineprops.rs +++ b/packages/core-macro/src/inlineprops.rs @@ -145,6 +145,25 @@ impl ToTokens for InlinePropsBody { (quote! { #lifetime, }, fn_generics, quote! { #generics }) }; + let generics_no_bounds = { + let mut generics = generics.clone(); + generics.params = generics + .params + .iter() + .map(|it| match it { + GenericParam::Type(tp) => { + let mut tp = tp.clone(); + tp.bounds.clear(); + + GenericParam::Type(tp) + } + _ => it.clone(), + }) + .collect(); + + generics + }; + out_tokens.append_all(quote! { #modifiers #[allow(non_camel_case_types)] @@ -155,7 +174,7 @@ impl ToTokens for InlinePropsBody { } #(#attrs)* - #maybe_async #vis fn #ident #fn_generics (#cx_token: Scope<#scope_lifetime #struct_name #generics>) #output + #maybe_async #vis fn #ident #fn_generics (#cx_token: Scope<#scope_lifetime #struct_name #generics_no_bounds>) #output #where_clause { let #struct_name { #(#field_names),* } = &#cx_token.props; From f5c058a2ebaa49bb8dfe902fcfbe799955d1b2c5 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 2 Mar 2023 11:42:02 -0600 Subject: [PATCH 33/41] make use_shared_state usable in static futures --- packages/hooks/Cargo.toml | 1 + packages/hooks/src/use_shared_state.rs | 187 ++++++++++++++++--------- 2 files changed, 120 insertions(+), 68 deletions(-) diff --git a/packages/hooks/Cargo.toml b/packages/hooks/Cargo.toml index c1b31ea65..c0e1ea783 100644 --- a/packages/hooks/Cargo.toml +++ b/packages/hooks/Cargo.toml @@ -20,3 +20,4 @@ log = "0.4" [dev-dependencies] futures-util = { version = "0.3", default-features = false } dioxus-core = { path = "../../packages/core", version = "^0.3.0" } +dioxus = { path = "../../packages/dioxus", version = "^0.3.0" } diff --git a/packages/hooks/src/use_shared_state.rs b/packages/hooks/src/use_shared_state.rs index a355ae42a..173bfbb71 100644 --- a/packages/hooks/src/use_shared_state.rs +++ b/packages/hooks/src/use_shared_state.rs @@ -1,6 +1,6 @@ use dioxus_core::{ScopeId, ScopeState}; use std::{ - cell::{Cell, Ref, RefCell, RefMut}, + cell::{Ref, RefCell, RefMut}, collections::HashSet, rc::Rc, sync::Arc, @@ -38,18 +38,57 @@ impl ProvidedStateInner { /// /// # Example /// -/// ## Provider +/// ```rust +/// # use dioxus::prelude::*; +/// # +/// # fn app(cx: Scope) -> Element { +/// # render! { +/// # Parent{} +/// # } +/// # } /// -/// ```rust, ignore +/// #[derive(Clone, Copy)] +/// enum Theme { +/// Light, +/// Dark, +/// } /// +/// // Provider +/// fn Parent<'a>(cx: Scope<'a>) -> Element<'a> { +/// use_shared_state_provider(cx, || Theme::Dark); +/// let theme = use_shared_state::(cx).unwrap(); /// -/// ``` -/// -/// ## Consumer -/// -/// ```rust, ignore +/// render! { +/// button{ +/// onclick: move |_| { +/// let current_theme = *theme.read(); +/// *theme.write() = match current_theme { +/// Theme::Dark => Theme::Light, +/// Theme::Light => Theme::Dark, +/// }; +/// }, +/// "Change theme" +/// } +/// Child{} +/// } +/// } /// +/// // Consumer +/// fn Child<'a>(cx: Scope<'a>) -> Element<'a> { +/// let theme = use_shared_state::(cx).unwrap(); +/// let current_theme = *theme.read(); /// +/// render! { +/// match &*theme.read() { +/// Theme::Dark => { +/// "Dark mode" +/// } +/// Theme::Light => { +/// "Light mode" +/// } +/// } +/// } +/// } /// ``` /// /// # How it works @@ -57,72 +96,46 @@ impl ProvidedStateInner { /// Any time a component calls `write`, every consumer of the state will be notified - excluding the provider. /// /// Right now, there is not a distinction between read-only and write-only, so every consumer will be notified. -/// -/// -/// -pub fn use_shared_state(cx: &ScopeState) -> Option> { - let state = cx.use_hook(|| { +pub fn use_shared_state(cx: &ScopeState) -> Option<&UseSharedState> { + let state: &Option> = &*cx.use_hook(move || { let scope_id = cx.scope_id(); - let root = cx.consume_context::>(); + let root = cx.consume_context::>()?; - if let Some(root) = root.as_ref() { - root.borrow_mut().consumers.insert(scope_id); - } + root.borrow_mut().consumers.insert(scope_id); - let value = root.as_ref().map(|f| f.borrow().value.clone()); - SharedStateInner { - root, - value, - scope_id, - needs_notification: Cell::new(false), - } + let value = root.borrow().value.clone(); + let state = UseSharedState { value, root }; + let owner = UseSharedStateOwner { state, scope_id }; + Some(owner) }); - - state.needs_notification.set(false); - match (&state.value, &state.root) { - (Some(value), Some(root)) => Some(UseSharedState { - cx, - value, - root, - needs_notification: &state.needs_notification, - }), - _ => None, - } + state.as_ref().map(|s| &s.state) } -struct SharedStateInner { - root: Option>, - value: Option>>, +struct UseSharedStateOwner { + state: UseSharedState, scope_id: ScopeId, - needs_notification: Cell, } -impl Drop for SharedStateInner { + +impl Drop for UseSharedStateOwner { fn drop(&mut self) { - // we need to unsubscribe when our component is unounted - if let Some(root) = &self.root { - let mut root = root.borrow_mut(); - root.consumers.remove(&self.scope_id); - } + // we need to unsubscribe when our component is unmounted + let mut root = self.state.root.borrow_mut(); + root.consumers.remove(&self.scope_id); } } -pub struct UseSharedState<'a, T: 'static> { - pub(crate) cx: &'a ScopeState, - pub(crate) value: &'a Rc>, - pub(crate) root: &'a Rc>>, - pub(crate) needs_notification: &'a Cell, +pub struct UseSharedState { + pub(crate) value: Rc>, + pub(crate) root: Rc>>, } -impl<'a, T: 'static> UseSharedState<'a, T> { +impl UseSharedState { pub fn read(&self) -> Ref<'_, T> { self.value.borrow() } - pub fn notify_consumers(self) { - if !self.needs_notification.get() { - self.root.borrow_mut().notify_consumers(); - self.needs_notification.set(true); - } + pub fn notify_consumers(&self) { + self.root.borrow_mut().notify_consumers(); } pub fn read_write(&self) -> (Ref<'_, T>, &Self) { @@ -134,7 +147,6 @@ impl<'a, T: 'static> UseSharedState<'a, T> { /// /// TODO: We prevent unncessary notifications only in the hook, but we should figure out some more global lock pub fn write(&self) -> RefMut<'_, T> { - self.cx.needs_update(); self.notify_consumers(); self.value.borrow_mut() } @@ -149,22 +161,61 @@ impl<'a, T: 'static> UseSharedState<'a, T> { } } -impl Copy for UseSharedState<'_, T> {} -impl<'a, T> Clone for UseSharedState<'a, T> -where - T: 'static, -{ +impl Clone for UseSharedState { fn clone(&self) -> Self { - UseSharedState { - cx: self.cx, - value: self.value, - root: self.root, - needs_notification: self.needs_notification, + Self { + value: self.value.clone(), + root: self.root.clone(), } } } -/// Provide some state for components down the hierarchy to consume without having to drill props. +impl PartialEq for UseSharedState { + fn eq(&self, other: &Self) -> bool { + self.value == other.value + } +} + +/// Provide some state for components down the hierarchy to consume without having to drill props. See [`use_shared_state`] to consume the state +/// +/// +/// # Example +/// +/// ```rust +/// # use dioxus::prelude::*; +/// # +/// # fn app(cx: Scope) -> Element { +/// # render! { +/// # Parent{} +/// # } +/// # } +/// +/// #[derive(Clone, Copy)] +/// enum Theme { +/// Light, +/// Dark, +/// } +/// +/// // Provider +/// fn Parent<'a>(cx: Scope<'a>) -> Element<'a> { +/// use_shared_state_provider(cx, || Theme::Dark); +/// let theme = use_shared_state::(cx).unwrap(); +/// +/// render! { +/// button{ +/// onclick: move |_| { +/// let current_theme = *theme.read(); +/// *theme.write() = match current_theme { +/// Theme::Dark => Theme::Light, +/// Theme::Light => Theme::Dark, +/// }; +/// }, +/// "Change theme" +/// } +/// // Children components that consume the state... +/// } +/// } +/// ``` pub fn use_shared_state_provider(cx: &ScopeState, f: impl FnOnce() -> T) { cx.use_hook(|| { let state: ProvidedState = Rc::new(RefCell::new(ProvidedStateInner { From d23848193686b8ca9fb6b1820ccac0e18b9c0fde Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 2 Mar 2023 11:54:21 -0600 Subject: [PATCH 34/41] reduce indirection and remove some unnecessary methods --- packages/hooks/src/use_shared_state.rs | 50 +++++++++----------------- 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/packages/hooks/src/use_shared_state.rs b/packages/hooks/src/use_shared_state.rs index 173bfbb71..8e0e813c8 100644 --- a/packages/hooks/src/use_shared_state.rs +++ b/packages/hooks/src/use_shared_state.rs @@ -9,8 +9,8 @@ use std::{ type ProvidedState = Rc>>; // Tracks all the subscribers to a shared State -pub struct ProvidedStateInner { - value: Rc>, +pub(crate) struct ProvidedStateInner { + value: T, notify_any: Arc, consumers: HashSet, } @@ -21,14 +21,6 @@ impl ProvidedStateInner { (self.notify_any)(*consumer); } } - - pub fn write(&self) -> RefMut { - self.value.borrow_mut() - } - - pub fn read(&self) -> Ref { - self.value.borrow() - } } /// This hook provides some relatively light ergonomics around shared state. @@ -103,8 +95,7 @@ pub fn use_shared_state(cx: &ScopeState) -> Option<&UseSharedState { impl Drop for UseSharedStateOwner { fn drop(&mut self) { // we need to unsubscribe when our component is unmounted - let mut root = self.state.root.borrow_mut(); + let mut root = self.state.inner.borrow_mut(); root.consumers.remove(&self.scope_id); } } pub struct UseSharedState { - pub(crate) value: Rc>, - pub(crate) root: Rc>>, + pub(crate) inner: Rc>>, } impl UseSharedState { - pub fn read(&self) -> Ref<'_, T> { - self.value.borrow() - } - pub fn notify_consumers(&self) { - self.root.borrow_mut().notify_consumers(); + self.inner.borrow_mut().notify_consumers(); } - pub fn read_write(&self) -> (Ref<'_, T>, &Self) { - (self.read(), self) + pub fn read(&self) -> Ref<'_, T> { + Ref::map(self.inner.borrow(), |inner| &inner.value) } /// Calling "write" will force the component to re-render @@ -147,32 +133,30 @@ impl UseSharedState { /// /// TODO: We prevent unncessary notifications only in the hook, but we should figure out some more global lock pub fn write(&self) -> RefMut<'_, T> { - self.notify_consumers(); - self.value.borrow_mut() + let mut value = self.inner.borrow_mut(); + value.notify_consumers(); + RefMut::map(value, |inner| &mut inner.value) } /// Allows the ability to write the value without forcing a re-render pub fn write_silent(&self) -> RefMut<'_, T> { - self.value.borrow_mut() - } - - pub fn inner(&self) -> Rc>> { - self.root.clone() + RefMut::map(self.inner.borrow_mut(), |inner| &mut inner.value) } } impl Clone for UseSharedState { fn clone(&self) -> Self { Self { - value: self.value.clone(), - root: self.root.clone(), + inner: self.inner.clone(), } } } impl PartialEq for UseSharedState { fn eq(&self, other: &Self) -> bool { - self.value == other.value + let first = self.inner.borrow(); + let second = other.inner.borrow(); + first.value == second.value } } @@ -219,7 +203,7 @@ impl PartialEq for UseSharedState { pub fn use_shared_state_provider(cx: &ScopeState, f: impl FnOnce() -> T) { cx.use_hook(|| { let state: ProvidedState = Rc::new(RefCell::new(ProvidedStateInner { - value: Rc::new(RefCell::new(f())), + value: f(), notify_any: cx.schedule_update_any(), consumers: HashSet::new(), })); From 90b4dd806e1491414971dc3138a42f12887298c9 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 2 Mar 2023 11:57:58 -0600 Subject: [PATCH 35/41] update docs example --- docs/guide/examples/hooks_composed.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/examples/hooks_composed.rs b/docs/guide/examples/hooks_composed.rs index 5b1f5ebfe..801474aa3 100644 --- a/docs/guide/examples/hooks_composed.rs +++ b/docs/guide/examples/hooks_composed.rs @@ -7,7 +7,7 @@ fn main() {} struct AppSettings {} // ANCHOR: wrap_context -fn use_settings(cx: &ScopeState) -> UseSharedState { +fn use_settings(cx: &ScopeState) -> &UseSharedState { use_shared_state::(cx).expect("App settings not provided") } // ANCHOR_END: wrap_context From 88198fc47cd7608bd3e1ec3c415d11f6a67505b3 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 2 Mar 2023 11:59:25 -0600 Subject: [PATCH 36/41] remove static bound on owner --- packages/hooks/src/use_shared_state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hooks/src/use_shared_state.rs b/packages/hooks/src/use_shared_state.rs index 8e0e813c8..a7afc619e 100644 --- a/packages/hooks/src/use_shared_state.rs +++ b/packages/hooks/src/use_shared_state.rs @@ -102,7 +102,7 @@ pub fn use_shared_state(cx: &ScopeState) -> Option<&UseSharedState { +struct UseSharedStateOwner { state: UseSharedState, scope_id: ScopeId, } From 2dd40ec202c0005a62fec2c6fedf032a682f6cee Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 2 Mar 2023 12:02:12 -0600 Subject: [PATCH 37/41] add docs to remaining items --- packages/hooks/src/use_shared_state.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/hooks/src/use_shared_state.rs b/packages/hooks/src/use_shared_state.rs index a7afc619e..eb836a211 100644 --- a/packages/hooks/src/use_shared_state.rs +++ b/packages/hooks/src/use_shared_state.rs @@ -102,6 +102,7 @@ pub fn use_shared_state(cx: &ScopeState) -> Option<&UseSharedState { state: UseSharedState, scope_id: ScopeId, @@ -115,15 +116,18 @@ impl Drop for UseSharedStateOwner { } } +/// State that is shared between components through the context system pub struct UseSharedState { pub(crate) inner: Rc>>, } impl UseSharedState { + /// Notify all consumers of the state that it has changed. (This is called automatically when you call "write") pub fn notify_consumers(&self) { self.inner.borrow_mut().notify_consumers(); } + /// Read the shared value pub fn read(&self) -> Ref<'_, T> { Ref::map(self.inner.borrow(), |inner| &inner.value) } @@ -131,7 +135,7 @@ impl UseSharedState { /// Calling "write" will force the component to re-render /// /// - /// TODO: We prevent unncessary notifications only in the hook, but we should figure out some more global lock + // TODO: We prevent unncessary notifications only in the hook, but we should figure out some more global lock pub fn write(&self) -> RefMut<'_, T> { let mut value = self.inner.borrow_mut(); value.notify_consumers(); From 7253eabe0ac689c1d4945a1c90b15bf16fd05dbe Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 6 Mar 2023 20:49:23 -0600 Subject: [PATCH 38/41] fix anchor link for block-level elements --- packages/interpreter/src/interpreter.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/interpreter/src/interpreter.js b/packages/interpreter/src/interpreter.js index 233c70590..b921c7c22 100644 --- a/packages/interpreter/src/interpreter.js +++ b/packages/interpreter/src/interpreter.js @@ -357,10 +357,11 @@ class Interpreter { if (event.type === "click") { // todo call prevent default if it's the right type of event - if (shouldPreventDefault !== `onclick`) { - if (target.tagName === "A") { - event.preventDefault(); - const href = target.getAttribute("href"); + let a_element = target.closest("a"); + if (a_element != null) { + event.preventDefault(); + if (shouldPreventDefault !== `onclick` && a_element.getAttribute(`dioxus-prevent-default`) !== `onclick`) { + const href = a_element.getAttribute("href"); if (href !== "" && href !== null && href !== undefined) { window.ipc.postMessage( serializeIpcMessage("browser_open", { href }) From f40ba5ec3c0e153c8cf1a1d7328336958a587918 Mon Sep 17 00:00:00 2001 From: Michael Clayton Date: Thu, 9 Mar 2023 12:36:49 -0500 Subject: [PATCH 39/41] fix Guide link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b680a1ba..40981401e 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ | Examples | - Guide + Guide | 中文 | From eee6cbabb20258c0d64621ce9bc156342b25d7ce Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Fri, 10 Mar 2023 08:07:53 -0500 Subject: [PATCH 40/41] Update Router book to reflect crate separation and need for `web` feature. (#873) --- docs/router/src/README.md | 11 ++++++----- packages/router/README.md | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/router/src/README.md b/docs/router/src/README.md index fcbd79aef..055c3009b 100644 --- a/docs/router/src/README.md +++ b/docs/router/src/README.md @@ -1,10 +1,11 @@ # Dioxus Router: Introduction + Whether or not you're building a website, desktop app, or mobile app, organizing your app's views into "pages" can be an effective method for organization and maintainability. -Dioxus comes with a router built-in. To start utilizing Dioxus Router, enable the ``router`` feature in your ``Cargo.toml`` file. -```toml -[dependencies] -dioxus = { version = "x.x.x", features = [.., "router"] } -``` +The `dioxus-router` crate contains the Router module. To add it to your project run: + + cargo add dioxus-router + +> **Be sure to include the `web` feature (`--feature web`) for deployment into a browser!** In this book you'll find a short [guide](./guide/index.md) to get up to speed with Dioxus Router, as well as the router's [reference](./reference/index.md). \ No newline at end of file diff --git a/packages/router/README.md b/packages/router/README.md index 0e38512e8..c7be4496d 100644 --- a/packages/router/README.md +++ b/packages/router/README.md @@ -1,4 +1,4 @@ -# Dioxus Native Core +# Dioxus Router [![Crates.io][crates-badge]][crates-url] [![MIT licensed][mit-badge]][mit-url] From fda125de5f620a8fdf6334fa9cb13d6e94a01bac Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Sun, 12 Mar 2023 15:13:34 -0500 Subject: [PATCH 41/41] fix clippy --- packages/tui/src/config.rs | 9 ++------- packages/tui/src/focus.rs | 9 ++------- packages/tui/src/node.rs | 9 ++------- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/packages/tui/src/config.rs b/packages/tui/src/config.rs index 8251b13b6..41e068542 100644 --- a/packages/tui/src/config.rs +++ b/packages/tui/src/config.rs @@ -46,18 +46,13 @@ impl Default for Config { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] pub enum RenderingMode { /// only 16 colors by accessed by name, no alpha support BaseColors, /// 8 bit colors, will be downsampled from rgb colors Ansi, /// 24 bit colors, most terminals support this + #[default] Rgb, } - -impl Default for RenderingMode { - fn default() -> Self { - RenderingMode::Rgb - } -} diff --git a/packages/tui/src/focus.rs b/packages/tui/src/focus.rs index 57f1c9e1f..89245d9b9 100644 --- a/packages/tui/src/focus.rs +++ b/packages/tui/src/focus.rs @@ -14,8 +14,9 @@ use dioxus_native_core::{ state::NodeDepState, }; -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] pub(crate) enum FocusLevel { + #[default] Unfocusable, Focusable, Ordered(std::num::NonZeroU16), @@ -53,12 +54,6 @@ impl Ord for FocusLevel { } } -impl Default for FocusLevel { - fn default() -> Self { - FocusLevel::Unfocusable - } -} - #[derive(Clone, PartialEq, Debug, Default)] pub(crate) struct Focus { pub level: FocusLevel, diff --git a/packages/tui/src/node.rs b/packages/tui/src/node.rs index 26ea4412e..7ef7d9c9a 100644 --- a/packages/tui/src/node.rs +++ b/packages/tui/src/node.rs @@ -20,7 +20,7 @@ pub(crate) struct NodeState { pub focused: bool, } -#[derive(PartialEq, Debug, Clone)] +#[derive(PartialEq, Debug, Clone, Default)] pub(crate) enum PreventDefault { Focus, KeyPress, @@ -32,6 +32,7 @@ pub(crate) enum PreventDefault { MouseEnter, MouseLeave, MouseOut, + #[default] Unknown, MouseOver, ContextMenu, @@ -39,12 +40,6 @@ pub(crate) enum PreventDefault { MouseUp, } -impl Default for PreventDefault { - fn default() -> Self { - PreventDefault::Unknown - } -} - impl NodeDepState for PreventDefault { type DepState = (); type Ctx = ();

TutorialTutorial Web Desktop SSR