diff --git a/.vscode/settings.json b/.vscode/settings.json index 44bcb08e3..819ffec5d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,4 @@ { - "rust-analyzer.cargo.allFeatures": true, - "rust-analyzer.cargo.features": [ - "desktop", - "router" - ], "editor.formatOnSave": true, "[toml]": { "editor.formatOnSave": false diff --git a/docs/guide/examples/component_props_options.rs b/docs/guide/examples/component_props_options.rs index a32e65a33..8963f6374 100644 --- a/docs/guide/examples/component_props_options.rs +++ b/docs/guide/examples/component_props_options.rs @@ -60,10 +60,10 @@ struct OptionalProps<'a> { } fn Title<'a>(cx: Scope<'a, OptionalProps>) -> Element<'a> { - return cx.render(rsx!(h1{ + cx.render(rsx!(h1{ "{cx.props.title}: ", - [cx.props.subtitle.unwrap_or("No subtitle provided")], - })); + cx.props.subtitle.unwrap_or("No subtitle provided"), + })) } // ANCHOR_END: OptionalProps @@ -76,10 +76,10 @@ struct ExplicitOptionProps<'a> { } fn ExplicitOption<'a>(cx: Scope<'a, ExplicitOptionProps>) -> Element<'a> { - return cx.render(rsx!(h1{ + cx.render(rsx!(h1 { "{cx.props.title}: ", - [cx.props.subtitle.unwrap_or("No subtitle provided")], - })); + cx.props.subtitle.unwrap_or("No subtitle provided"), + })) } // ANCHOR_END: ExplicitOption @@ -92,9 +92,7 @@ struct DefaultProps { } fn DefaultComponent(cx: Scope) -> Element { - return cx.render(rsx!(h1{ - "{cx.props.number}", - })); + cx.render(rsx!(h1 { "{cx.props.number}" })) } // ANCHOR_END: DefaultComponent @@ -106,8 +104,6 @@ struct IntoProps { } fn IntoComponent(cx: Scope) -> Element { - return cx.render(rsx!(h1{ - "{cx.props.string}", - })); + cx.render(rsx!(h1 { "{cx.props.string}" })) } // ANCHOR_END: IntoComponent diff --git a/docs/guide/examples/hooks_bad.rs b/docs/guide/examples/hooks_bad.rs index 1503f11bd..4fb389bb7 100644 --- a/docs/guide/examples/hooks_bad.rs +++ b/docs/guide/examples/hooks_bad.rs @@ -55,7 +55,7 @@ fn App(cx: Scope) -> Element { } // ✅ Instead, use a hashmap with use_ref - let selection_map = use_ref(&cx, || HashMap::<&str, bool>::new()); + let selection_map = use_ref(&cx, HashMap::<&str, bool>::new); for name in &names { let is_selected = selection_map.read()[name]; diff --git a/docs/guide/examples/hooks_composed.rs b/docs/guide/examples/hooks_composed.rs index 3e90bb2bb..f14c1a323 100644 --- a/docs/guide/examples/hooks_composed.rs +++ b/docs/guide/examples/hooks_composed.rs @@ -8,6 +8,6 @@ struct AppSettings {} // ANCHOR: wrap_context fn use_settings(cx: &ScopeState) -> UseSharedState { - use_context::(&cx).expect("App settings not provided") + use_context::(cx).expect("App settings not provided") } // ANCHOR_END: wrap_context diff --git a/docs/guide/examples/hooks_use_ref.rs b/docs/guide/examples/hooks_use_ref.rs index 8c06247ac..862937aab 100644 --- a/docs/guide/examples/hooks_use_ref.rs +++ b/docs/guide/examples/hooks_use_ref.rs @@ -7,7 +7,7 @@ fn main() { // ANCHOR: component fn App(cx: Scope) -> Element { - let list = use_ref(&cx, || Vec::new()); + let list = use_ref(&cx, Vec::new); let list_formatted = format!("{:?}", *list.read()); cx.render(rsx!( diff --git a/docs/guide/examples/meme_editor_dark_mode.rs b/docs/guide/examples/meme_editor_dark_mode.rs index 6c58a540b..85fed5664 100644 --- a/docs/guide/examples/meme_editor_dark_mode.rs +++ b/docs/guide/examples/meme_editor_dark_mode.rs @@ -37,7 +37,7 @@ pub fn App(cx: Scope) -> Element { pub fn use_is_dark_mode(cx: &ScopeState) -> bool { // ANCHOR: use_context - let dark_mode_context = use_context::(&cx); + let dark_mode_context = use_context::(cx); // ANCHOR_END: use_context dark_mode_context diff --git a/docs/guide/examples/rendering_lists.rs b/docs/guide/examples/rendering_lists.rs index 9e873979d..deb32f1fc 100644 --- a/docs/guide/examples/rendering_lists.rs +++ b/docs/guide/examples/rendering_lists.rs @@ -14,9 +14,9 @@ struct Comment { pub fn App(cx: Scope) -> Element { // ANCHOR: render_list - let comment_field = use_state(&cx, || String::new()); + let comment_field = use_state(&cx, String::new); let mut next_id = use_state(&cx, || 0); - let comments = use_ref(&cx, || Vec::::new()); + let comments = use_ref(&cx, Vec::::new); let comments_lock = comments.read(); let comments_rendered = comments_lock.iter().map(|comment| { diff --git a/examples/calculator.rs b/examples/calculator.rs index 37ab0c794..4f5d7dedd 100644 --- a/examples/calculator.rs +++ b/examples/calculator.rs @@ -6,16 +6,16 @@ This calculator version uses React-style state management. All state is held as use dioxus::events::*; use dioxus::html::input_data::keyboard_types::Key; use dioxus::prelude::*; +use dioxus_desktop::{Config, WindowBuilder}; fn main() { - use dioxus_desktop::tao::dpi::LogicalSize; - dioxus_desktop::launch_cfg(app, |cfg| { - cfg.with_window(|w| { - w.with_title("Calculator Demo") - .with_resizable(false) - .with_inner_size(LogicalSize::new(320.0, 530.0)) - }) - }); + let config = Config::new().with_window( + WindowBuilder::default() + .with_title("Calculator") + .with_inner_size(dioxus_desktop::LogicalSize::new(300.0, 500.0)), + ); + + dioxus_desktop::launch_cfg(app, config); } fn app(cx: Scope) -> Element { diff --git a/examples/custom_html.rs b/examples/custom_html.rs index 9c42b7e8f..a73394de1 100644 --- a/examples/custom_html.rs +++ b/examples/custom_html.rs @@ -2,14 +2,17 @@ //! to add things like stylesheets, scripts, and third-party JS libraries. use dioxus::prelude::*; +use dioxus_desktop::Config; fn main() { - dioxus_desktop::launch_cfg(app, |c| { - c.with_custom_head("".into()) - }); + dioxus_desktop::launch_cfg( + app, + Config::new().with_custom_head("".into()), + ); - dioxus_desktop::launch_cfg(app, |c| { - c.with_custom_index( + dioxus_desktop::launch_cfg( + app, + Config::new().with_custom_index( r#" @@ -24,8 +27,8 @@ fn main() { "# .into(), - ) - }); + ), + ); } fn app(cx: Scope) -> Element { diff --git a/examples/file_explorer.rs b/examples/file_explorer.rs index 24ac60c90..c1bbeeaaf 100644 --- a/examples/file_explorer.rs +++ b/examples/file_explorer.rs @@ -9,9 +9,13 @@ //! we dont need to clutter our code with `read` commands. use dioxus::prelude::*; +use dioxus_desktop::{Config, WindowBuilder}; fn main() { - dioxus_desktop::launch_cfg(app, |c| c.with_window(|w| w.with_resizable(true))); + dioxus_desktop::launch_cfg( + app, + Config::new().with_window(WindowBuilder::new().with_resizable(true)), + ); } fn app(cx: Scope) -> Element { diff --git a/examples/filedragdrop.rs b/examples/filedragdrop.rs index caa86a529..79d784f1b 100644 --- a/examples/filedragdrop.rs +++ b/examples/filedragdrop.rs @@ -1,12 +1,13 @@ use dioxus::prelude::*; +use dioxus_desktop::Config; fn main() { - dioxus_desktop::launch_with_props(app, (), |c| { - c.with_file_drop_handler(|_w, e| { - println!("{:?}", e); - true - }) + let cfg = Config::new().with_file_drop_handler(|_w, e| { + println!("{:?}", e); + true }); + + dioxus_desktop::launch_with_props(app, (), cfg); } fn app(cx: Scope) -> Element { diff --git a/examples/flat_router.rs b/examples/flat_router.rs index fe1a7b112..752b58760 100644 --- a/examples/flat_router.rs +++ b/examples/flat_router.rs @@ -1,17 +1,18 @@ use dioxus::prelude::*; -use dioxus_desktop::tao::dpi::LogicalSize; +use dioxus_desktop::{tao::dpi::LogicalSize, Config, WindowBuilder}; use dioxus_router::{Link, Route, Router}; fn main() { env_logger::init(); - dioxus_desktop::launch_cfg(app, |c| { - c.with_window(|c| { - c.with_title("Spinsense Client") - .with_inner_size(LogicalSize::new(600, 1000)) - .with_resizable(false) - }) - }) + let cfg = Config::new().with_window( + WindowBuilder::new() + .with_title("Spinsense Client") + .with_inner_size(LogicalSize::new(600, 1000)) + .with_resizable(false), + ); + + dioxus_desktop::launch_cfg(app, cfg) } fn app(cx: Scope) -> Element { diff --git a/examples/hydration.rs b/examples/hydration.rs index c126d7dae..692944f6b 100644 --- a/examples/hydration.rs +++ b/examples/hydration.rs @@ -10,12 +10,13 @@ //! proof-of-concept for the hydration feature, but you'll probably only want to use hydration for the web. use dioxus::prelude::*; +use dioxus_desktop::Config; fn main() { let vdom = VirtualDom::new(app); let content = dioxus_ssr::render_vdom_cfg(&vdom, |f| f.pre_render(true)); - dioxus_desktop::launch_cfg(app, |c| c.with_prerendered(content)); + dioxus_desktop::launch_cfg(app, Config::new().with_prerendered(content)); } fn app(cx: Scope) -> Element { diff --git a/examples/pattern_model.rs b/examples/pattern_model.rs index f379277e5..7feff27b6 100644 --- a/examples/pattern_model.rs +++ b/examples/pattern_model.rs @@ -21,15 +21,17 @@ use dioxus::events::*; use dioxus::html::input_data::keyboard_types::Key; use dioxus::prelude::*; use dioxus_desktop::wry::application::dpi::LogicalSize; +use dioxus_desktop::{Config, WindowBuilder}; fn main() { - dioxus_desktop::launch_cfg(app, |cfg| { - cfg.with_window(|w| { - w.with_title("Calculator Demo") - .with_resizable(false) - .with_inner_size(LogicalSize::new(320.0, 530.0)) - }) - }); + let cfg = Config::new().with_window( + WindowBuilder::new() + .with_title("Calculator Demo") + .with_resizable(false) + .with_inner_size(LogicalSize::new(320.0, 530.0)), + ); + + dioxus_desktop::launch_cfg(app, cfg); } fn app(cx: Scope) -> Element { diff --git a/examples/suspense.rs b/examples/suspense.rs index 0c2d4959e..c1a0e4c03 100644 --- a/examples/suspense.rs +++ b/examples/suspense.rs @@ -14,15 +14,16 @@ //! primitives in our own custom components. use dioxus::prelude::*; +use dioxus_desktop::{Config, LogicalSize, WindowBuilder}; fn main() { - use dioxus_desktop::tao::dpi::LogicalSize; - dioxus_desktop::launch_cfg(app, |cfg| { - cfg.with_window(|w| { - w.with_title("Doggo Fetcher") - .with_inner_size(LogicalSize::new(600.0, 800.0)) - }) - }); + let cfg = Config::new().with_window( + WindowBuilder::new() + .with_title("Doggo Fetcher") + .with_inner_size(LogicalSize::new(600.0, 800.0)), + ); + + dioxus_desktop::launch_cfg(app, cfg); } #[derive(serde::Deserialize)] diff --git a/examples/tailwind.rs b/examples/tailwind.rs index 77918b735..af6bc4c4f 100644 --- a/examples/tailwind.rs +++ b/examples/tailwind.rs @@ -9,11 +9,14 @@ //! https://dev.to/arctic_hen7/how-to-set-up-tailwind-css-with-yew-and-trunk-il9 use dioxus::prelude::*; +use dioxus_desktop::Config; fn main() { - dioxus_desktop::launch_cfg(app, |c| { - c.with_custom_head("".to_string()) - }); + dioxus_desktop::launch_cfg( + app, + Config::new() + .with_custom_head("".to_string()), + ); } pub fn app(cx: Scope) -> Element { diff --git a/examples/todomvc.rs b/examples/todomvc.rs index 073cbaee8..71ceee8e1 100644 --- a/examples/todomvc.rs +++ b/examples/todomvc.rs @@ -7,14 +7,14 @@ fn main() { dioxus_desktop::launch(app); } -#[derive(Eq, PartialEq)] +#[derive(PartialEq, Eq)] pub enum FilterState { All, Active, Completed, } -#[derive(Debug, Eq, PartialEq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct TodoItem { pub id: u32, pub checked: bool, diff --git a/examples/window_event.rs b/examples/window_event.rs index 7384b5be9..8805bcfdd 100644 --- a/examples/window_event.rs +++ b/examples/window_event.rs @@ -1,9 +1,14 @@ use dioxus::prelude::*; +use dioxus_desktop::{Config, WindowBuilder}; fn main() { - dioxus_desktop::launch_cfg(app, |cfg| { - cfg.with_window(|w| w.with_title("BorderLess Demo").with_decorations(false)) - }); + let cfg = Config::new().with_window( + WindowBuilder::new() + .with_title("Borderless Window") + .with_decorations(false), + ); + + dioxus_desktop::launch_cfg(app, cfg); } fn app(cx: Scope) -> Element { diff --git a/packages/desktop/src/cfg.rs b/packages/desktop/src/cfg.rs index af758175b..85be2727f 100644 --- a/packages/desktop/src/cfg.rs +++ b/packages/desktop/src/cfg.rs @@ -11,9 +11,9 @@ use wry::{ // pub(crate) type DynEventHandlerFn = dyn Fn(&mut EventLoop<()>, &mut WebView); /// The configuration for the desktop application. -pub struct DesktopConfig { +pub struct Config { pub(crate) window: WindowBuilder, - pub(crate) file_drop_handler: Option bool>>, + pub(crate) file_drop_handler: Option, pub(crate) protocols: Vec, pub(crate) pre_rendered: Option, // pub(crate) event_handler: Option>, @@ -23,12 +23,14 @@ pub struct DesktopConfig { pub(crate) custom_index: Option, } +type DropHandler = Box bool>; + pub(crate) type WryProtocol = ( String, Box WryResult + 'static>, ); -impl DesktopConfig { +impl Config { /// Initializes a new `WindowBuilder` with default values. #[inline] pub fn new() -> Self { @@ -48,57 +50,51 @@ impl DesktopConfig { } /// set the directory from which assets will be searched in release mode - pub fn with_resource_directory(&mut self, path: impl Into) -> &mut Self { + pub fn with_resource_directory(mut self, path: impl Into) -> Self { self.resource_dir = Some(path.into()); self } /// Set whether or not the right-click context menu should be disabled. - pub fn with_disable_context_menu(&mut self, disable: bool) -> &mut Self { + pub fn with_disable_context_menu(mut self, disable: bool) -> Self { self.disable_context_menu = disable; self } /// Set the pre-rendered HTML content - pub fn with_prerendered(&mut self, content: String) -> &mut Self { + pub fn with_prerendered(mut self, content: String) -> Self { self.pre_rendered = Some(content); self } /// Set the configuration for the window. - pub fn with_window( - &mut self, - configure: impl FnOnce(WindowBuilder) -> WindowBuilder, - ) -> &mut Self { + pub fn with_window(mut self, window: WindowBuilder) -> Self { // gots to do a swap because the window builder only takes itself as muy self // I wish more people knew about returning &mut Self - let mut builder = WindowBuilder::default().with_title("Dioxus App"); - std::mem::swap(&mut self.window, &mut builder); - builder = configure(builder); - std::mem::swap(&mut self.window, &mut builder); + self.window = window; self } // /// Set a custom event handler // pub fn with_event_handler( - // &mut self, + // mut self, // handler: impl Fn(&mut EventLoop<()>, &mut WebView) + 'static, - // ) -> &mut Self { + // ) -> Self { // self.event_handler = Some(Box::new(handler)); // self // } /// Set a file drop handler pub fn with_file_drop_handler( - &mut self, + mut self, handler: impl Fn(&Window, FileDropEvent) -> bool + 'static, - ) -> &mut Self { + ) -> Self { self.file_drop_handler = Some(Box::new(handler)); self } /// Set a custom protocol - pub fn with_custom_protocol(&mut self, name: String, handler: F) -> &mut Self + pub fn with_custom_protocol(mut self, name: String, handler: F) -> Self where F: Fn(&HttpRequest) -> WryResult + 'static, { @@ -107,7 +103,7 @@ impl DesktopConfig { } /// Set a custom icon for this application - pub fn with_icon(&mut self, icon: Icon) -> &mut Self { + pub fn with_icon(mut self, icon: Icon) -> Self { self.window.window.window_icon = Some(icon); self } @@ -115,7 +111,7 @@ impl DesktopConfig { /// Inject additional content into the document's HEAD. /// /// This is useful for loading CSS libraries, JS libraries, etc. - pub fn with_custom_head(&mut self, head: String) -> &mut Self { + pub fn with_custom_head(mut self, head: String) -> Self { self.custom_head = Some(head); self } @@ -126,22 +122,13 @@ impl DesktopConfig { /// /// Dioxus injects some loader code into the closing body tag. Your document /// must include a body element! - pub fn with_custom_index(&mut self, index: String) -> &mut Self { + pub fn with_custom_index(mut self, index: String) -> Self { self.custom_index = Some(index); self } } -impl DesktopConfig { - pub(crate) fn with_default_icon(mut self) -> Self { - let bin: &[u8] = include_bytes!("./assets/default_icon.bin"); - let rgba = Icon::from_rgba(bin.to_owned(), 460, 460).expect("image parse failed"); - self.window.window.window_icon = Some(rgba); - self - } -} - -impl Default for DesktopConfig { +impl Default for Config { fn default() -> Self { Self::new() } diff --git a/packages/desktop/src/lib.rs b/packages/desktop/src/lib.rs index e2de6f1d7..20086a48d 100644 --- a/packages/desktop/src/lib.rs +++ b/packages/desktop/src/lib.rs @@ -18,10 +18,11 @@ pub use wry; pub use wry::application as tao; use crate::events::trigger_from_serialized; -pub use cfg::DesktopConfig; +pub use cfg::Config; use controller::DesktopController; use dioxus_core::*; use events::parse_ipc_message; +pub use tao::dpi::{LogicalSize, PhysicalSize}; pub use tao::window::WindowBuilder; use tao::{ event::{Event, StartCause, WindowEvent}, @@ -48,7 +49,7 @@ use wry::webview::WebViewBuilder; /// } /// ``` pub fn launch(root: Component) { - launch_with_props(root, (), |c| c) + launch_with_props(root, (), Config::default()) } /// Launch the WebView and run the event loop, with configuration. @@ -70,10 +71,7 @@ pub fn launch(root: Component) { /// }) /// } /// ``` -pub fn launch_cfg( - root: Component, - config_builder: impl FnOnce(&mut DesktopConfig) -> &mut DesktopConfig, -) { +pub fn launch_cfg(root: Component, config_builder: Config) { launch_with_props(root, (), config_builder) } @@ -100,19 +98,24 @@ pub fn launch_cfg( /// }) /// } /// ``` -pub fn launch_with_props( - root: Component

, - props: P, - builder: impl FnOnce(&mut DesktopConfig) -> &mut DesktopConfig, -) { - let mut cfg = DesktopConfig::default().with_default_icon(); - builder(&mut cfg); - +pub fn launch_with_props(root: Component

, props: P, mut cfg: Config) { let event_loop = EventLoop::with_user_event(); let mut desktop = DesktopController::new_on_tokio(root, props, event_loop.create_proxy()); let proxy = event_loop.create_proxy(); + // We assume that if the icon is None, then the user just didnt set it + if cfg.window.window.window_icon.is_none() { + cfg.window.window.window_icon = Some( + tao::window::Icon::from_rgba( + include_bytes!("./assets/default_icon.bin").to_vec(), + 460, + 460, + ) + .expect("image parse failed"), + ); + } + event_loop.run(move |window_event, event_loop, control_flow| { *control_flow = ControlFlow::Wait; diff --git a/packages/router/src/service.rs b/packages/router/src/service.rs index 0f028383e..039d0033d 100644 --- a/packages/router/src/service.rs +++ b/packages/router/src/service.rs @@ -87,11 +87,11 @@ impl RouterCore { let route = match &cfg.initial_url { Some(url) => Arc::new(ParsedRoute { - url: Url::from_str(&url).expect( - format!( + url: Url::from_str(url).unwrap_or_else(|_| + panic!( "RouterCfg expects a valid initial_url, but got '{}'. Example: '{{scheme}}://{{?authority}}/{{?path}}'", &url - ).as_str() + ) ), title: None, serialized_state: None, diff --git a/packages/tui/src/style_attributes.rs b/packages/tui/src/style_attributes.rs index d5fb2fb63..05b478865 100644 --- a/packages/tui/src/style_attributes.rs +++ b/packages/tui/src/style_attributes.rs @@ -143,7 +143,7 @@ impl Default for BorderEdge { } } -#[derive(Clone, Copy, PartialEq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum BorderStyle { Dotted, Dashed, diff --git a/packages/web/examples/hydrate.rs b/packages/web/examples/hydrate.rs index 2790379c9..30c1ee5b2 100644 --- a/packages/web/examples/hydrate.rs +++ b/packages/web/examples/hydrate.rs @@ -1,4 +1,5 @@ use dioxus::prelude::*; +use dioxus_web::Config; use web_sys::window; fn app(cx: Scope) -> Element { @@ -59,5 +60,5 @@ fn main() { .set_inner_html(&pre); // now rehydtrate - dioxus_web::launch_with_props(app, (), |c| c.hydrate(true)); + dioxus_web::launch_with_props(app, (), Config::new().hydrate(true)); } diff --git a/packages/web/src/cfg.rs b/packages/web/src/cfg.rs index d9c448f92..1e84b1d92 100644 --- a/packages/web/src/cfg.rs +++ b/packages/web/src/cfg.rs @@ -5,32 +5,41 @@ /// # Example /// /// ```rust, ignore -/// dioxus_web::launch(App, |cfg| cfg.hydrate(true).root_name("myroot")) +/// dioxus_web::launch(App, Config::new().hydrate(true).root_name("myroot")) /// ``` -pub struct WebConfig { +pub struct Config { pub(crate) hydrate: bool, pub(crate) rootname: String, pub(crate) cached_strings: Vec, + pub(crate) default_panic_hook: bool, } -impl Default for WebConfig { +impl Default for Config { fn default() -> Self { Self { hydrate: false, rootname: "main".to_string(), cached_strings: Vec::new(), + default_panic_hook: true, } } } -impl WebConfig { +impl Config { + /// Create a new Default instance of the Config. + /// + /// This is no different than calling `Config::default()` + pub fn new() -> Self { + Self::default() + } + /// Enable SSR hydration /// /// This enables Dioxus to pick up work from a pre-renderd HTML file. Hydration will completely skip over any async /// work and suspended nodes. /// /// Dioxus will load up all the elements with the `dio_el` data attribute into memory when the page is loaded. - pub fn hydrate(&mut self, f: bool) -> &mut Self { + pub fn hydrate(mut self, f: bool) -> Self { self.hydrate = f; self } @@ -38,7 +47,7 @@ impl WebConfig { /// Set the name of the element that Dioxus will use as the root. /// /// This is akint to calling React.render() on the element with the specified name. - pub fn rootname(&mut self, name: impl Into) -> &mut Self { + pub fn rootname(mut self, name: impl Into) -> Self { self.rootname = name.into(); self } @@ -46,8 +55,16 @@ impl WebConfig { /// Set the name of the element that Dioxus will use as the root. /// /// This is akint to calling React.render() on the element with the specified name. - pub fn with_string_cache(&mut self, cache: Vec) -> &mut Self { + pub fn with_string_cache(mut self, cache: Vec) -> Self { self.cached_strings = cache; self } + + /// Set whether or not Dioxus should use the built-in panic hook or defer to your own. + /// + /// The panic hook is set to true normally so even the simplest apps have helpful error messages. + pub fn with_default_panic_hook(mut self, f: bool) -> Self { + self.default_panic_hook = f; + self + } } diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index 0e434c1a0..65da8136d 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -15,7 +15,7 @@ use std::{any::Any, rc::Rc, sync::Arc}; use wasm_bindgen::{closure::Closure, JsCast}; use web_sys::{Document, Element, Event, HtmlElement}; -use crate::WebConfig; +use crate::Config; pub struct WebsysDom { pub interpreter: Interpreter, @@ -26,7 +26,7 @@ pub struct WebsysDom { } impl WebsysDom { - pub fn new(cfg: WebConfig, sender_callback: Rc) -> Self { + pub fn new(cfg: Config, sender_callback: Rc) -> Self { // eventually, we just want to let the interpreter do all the work of decoding events into our event type let callback: Box = Box::new(move |event: &web_sys::Event| { let mut target = event diff --git a/packages/web/src/lib.rs b/packages/web/src/lib.rs index afed73c11..81e76afbc 100644 --- a/packages/web/src/lib.rs +++ b/packages/web/src/lib.rs @@ -56,7 +56,7 @@ use std::rc::Rc; -pub use crate::cfg::WebConfig; +pub use crate::cfg::Config; pub use crate::util::use_eval; use dioxus_core::prelude::Component; use dioxus_core::SchedulerMsg; @@ -93,7 +93,7 @@ mod util; /// } /// ``` pub fn launch(root_component: Component) { - launch_with_props(root_component, (), |c| c); + launch_with_props(root_component, (), Config::default()); } /// Launch your app and run the event loop, with configuration. @@ -106,7 +106,7 @@ pub fn launch(root_component: Component) { /// use dioxus::prelude::*; /// /// fn main() { -/// dioxus_web::launch_with_props(App, |config| config.pre_render(true)); +/// dioxus_web::launch_with_props(App, Config::new().pre_render(true)); /// } /// /// fn app(cx: Scope) -> Element { @@ -115,8 +115,8 @@ pub fn launch(root_component: Component) { /// }) /// } /// ``` -pub fn launch_cfg(root: Component, config_builder: impl FnOnce(&mut WebConfig) -> &mut WebConfig) { - launch_with_props(root, (), config_builder) +pub fn launch_cfg(root: Component, config: Config) { + launch_with_props(root, (), config) } /// Launches the VirtualDOM from the specified component function and props. @@ -130,7 +130,7 @@ pub fn launch_cfg(root: Component, config_builder: impl FnOnce(&mut WebConfig) - /// dioxus_web::launch_with_props( /// App, /// RootProps { name: String::from("joe") }, -/// |config| config +/// Config::new() /// ); /// } /// @@ -143,19 +143,10 @@ pub fn launch_cfg(root: Component, config_builder: impl FnOnce(&mut WebConfig) - /// rsx!(cx, div {"hello {cx.props.name}"}) /// } /// ``` -pub fn launch_with_props( - root_component: Component, - root_properties: T, - configuration_builder: impl FnOnce(&mut WebConfig) -> &mut WebConfig, -) where +pub fn launch_with_props(root_component: Component, root_properties: T, config: Config) +where T: Send + 'static, { - if cfg!(feature = "panic_hook") { - console_error_panic_hook::set_once(); - } - - let mut config = WebConfig::default(); - configuration_builder(&mut config); wasm_bindgen_futures::spawn_local(run_with_props(root_component, root_properties, config)); } @@ -171,9 +162,13 @@ pub fn launch_with_props( /// wasm_bindgen_futures::spawn_local(app_fut); /// } /// ``` -pub async fn run_with_props(root: Component, root_props: T, cfg: WebConfig) { +pub async fn run_with_props(root: Component, root_props: T, cfg: Config) { let mut dom = VirtualDom::new_with_props(root, root_props); + if cfg!(feature = "panic_hook") && cfg.default_panic_hook { + console_error_panic_hook::set_once(); + } + #[cfg(feature = "hot-reload")] hot_reload::init(&dom); diff --git a/packages/web/src/olddom.rs b/packages/web/src/olddom.rs index d6035d5ab..5e5032773 100644 --- a/packages/web/src/olddom.rs +++ b/packages/web/src/olddom.rs @@ -16,7 +16,7 @@ use web_sys::{ HtmlOptionElement, HtmlTextAreaElement, Node, }; -use crate::{nodeslab::NodeSlab, WebConfig}; +use crate::{nodeslab::NodeSlab, Config}; pub struct WebsysDom { stack: Stack, @@ -39,7 +39,7 @@ pub struct WebsysDom { type ListenerEntry = (usize, Closure); impl WebsysDom { - pub fn new(cfg: WebConfig, sender_callback: Rc) -> Self { + pub fn new(cfg: Config, sender_callback: Rc) -> Self { let document = load_document(); let nodes = NodeSlab::new(2000); diff --git a/packages/web/tests/hydrate.rs b/packages/web/tests/hydrate.rs index a7236b94f..af6e49cc2 100644 --- a/packages/web/tests/hydrate.rs +++ b/packages/web/tests/hydrate.rs @@ -1,4 +1,5 @@ use dioxus::prelude::*; +use dioxus_web::Config; use wasm_bindgen_test::wasm_bindgen_test; use web_sys::window; @@ -59,5 +60,5 @@ fn rehydrates() { .unwrap() .set_inner_html(&format!("

{}
", out)); - dioxus_web::launch_cfg(app, |c| c.hydrate(true)); + dioxus_web::launch_cfg(app, Config::new().hydrate(true)); }