Less clumsy configuration for desktop and mobile (#553)
* chore: dont use prebuilt builder pattern for configuring desktop * chore: use regular config pattern for web * Chore: update docs too * chore: clean up some warnings
This commit is contained in:
1 parent
41b450eedf
commit
540e785d8b
28 files changed
+172
-156
No files matched your search
Vendored
-5
@@ -1,9 +1,4 @@
|
||||
{
|
||||
"rust-analyzer.cargo.allFeatures": true,
|
||||
"rust-analyzer.cargo.features": [
|
||||
"desktop",
|
||||
"router"
|
||||
],
|
||||
"editor.formatOnSave": true,
|
||||
"[toml]": {
|
||||
"editor.formatOnSave": false
|
||||
|
||||
@@ -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<DefaultProps>) -> 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<IntoProps>) -> Element {
|
||||
return cx.render(rsx!(h1{
|
||||
"{cx.props.string}",
|
||||
}));
|
||||
cx.render(rsx!(h1 { "{cx.props.string}" }))
|
||||
}
|
||||
// ANCHOR_END: IntoComponent
|
||||
@@ -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];
|
||||
|
||||
@@ -8,6 +8,6 @@ struct AppSettings {}
|
||||
|
||||
// ANCHOR: wrap_context
|
||||
fn use_settings(cx: &ScopeState) -> UseSharedState<AppSettings> {
|
||||
use_context::<AppSettings>(&cx).expect("App settings not provided")
|
||||
use_context::<AppSettings>(cx).expect("App settings not provided")
|
||||
}
|
||||
// ANCHOR_END: wrap_context
|
||||
@@ -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!(
|
||||
|
||||
@@ -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::<DarkMode>(&cx);
|
||||
let dark_mode_context = use_context::<DarkMode>(cx);
|
||||
// ANCHOR_END: use_context
|
||||
|
||||
dark_mode_context
|
||||
|
||||
@@ -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::<Comment>::new());
|
||||
let comments = use_ref(&cx, Vec::<Comment>::new);
|
||||
|
||||
let comments_lock = comments.read();
|
||||
let comments_rendered = comments_lock.iter().map(|comment| {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+10
-7
@@ -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("<style>body { background-color: red; }</style>".into())
|
||||
});
|
||||
dioxus_desktop::launch_cfg(
|
||||
app,
|
||||
Config::new().with_custom_head("<style>body { background-color: red; }</style>".into()),
|
||||
);
|
||||
|
||||
dioxus_desktop::launch_cfg(app, |c| {
|
||||
c.with_custom_index(
|
||||
dioxus_desktop::launch_cfg(
|
||||
app,
|
||||
Config::new().with_custom_index(
|
||||
r#"
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@@ -24,8 +27,8 @@ fn main() {
|
||||
</html>
|
||||
"#
|
||||
.into(),
|
||||
)
|
||||
});
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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("<script src=\"https://cdn.tailwindcss.com\"></script>".to_string())
|
||||
});
|
||||
dioxus_desktop::launch_cfg(
|
||||
app,
|
||||
Config::new()
|
||||
.with_custom_head("<script src=\"https://cdn.tailwindcss.com\"></script>".to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn app(cx: Scope) -> Element {
|
||||
|
||||
+2
-2
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+19
-32
@@ -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<Box<dyn Fn(&Window, FileDropEvent) -> bool>>,
|
||||
pub(crate) file_drop_handler: Option<DropHandler>,
|
||||
pub(crate) protocols: Vec<WryProtocol>,
|
||||
pub(crate) pre_rendered: Option<String>,
|
||||
// pub(crate) event_handler: Option<Box<DynEventHandlerFn>>,
|
||||
@@ -23,12 +23,14 @@ pub struct DesktopConfig {
|
||||
pub(crate) custom_index: Option<String>,
|
||||
}
|
||||
|
||||
type DropHandler = Box<dyn Fn(&Window, FileDropEvent) -> bool>;
|
||||
|
||||
pub(crate) type WryProtocol = (
|
||||
String,
|
||||
Box<dyn Fn(&HttpRequest) -> WryResult<HttpResponse> + '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<PathBuf>) -> &mut Self {
|
||||
pub fn with_resource_directory(mut self, path: impl Into<PathBuf>) -> 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<F>(&mut self, name: String, handler: F) -> &mut Self
|
||||
pub fn with_custom_protocol<F>(mut self, name: String, handler: F) -> Self
|
||||
where
|
||||
F: Fn(&HttpRequest) -> WryResult<HttpResponse> + '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()
|
||||
}
|
||||
|
||||
+17
-14
@@ -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<P: 'static + Send>(
|
||||
root: Component<P>,
|
||||
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<P: 'static + Send>(root: Component<P>, 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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -143,7 +143,7 @@ impl Default for BorderEdge {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub enum BorderStyle {
|
||||
Dotted,
|
||||
Dashed,
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
+24
-7
@@ -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<String>,
|
||||
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<String>) -> &mut Self {
|
||||
pub fn rootname(mut self, name: impl Into<String>) -> 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<String>) -> &mut Self {
|
||||
pub fn with_string_cache(mut self, cache: Vec<String>) -> 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
|
||||
}
|
||||
}
|
||||
@@ -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<dyn Fn(SchedulerMsg)>) -> Self {
|
||||
pub fn new(cfg: Config, sender_callback: Rc<dyn Fn(SchedulerMsg)>) -> Self {
|
||||
// eventually, we just want to let the interpreter do all the work of decoding events into our event type
|
||||
let callback: Box<dyn FnMut(&Event)> = Box::new(move |event: &web_sys::Event| {
|
||||
let mut target = event
|
||||
|
||||
+13
-18
@@ -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<T>(
|
||||
root_component: Component<T>,
|
||||
root_properties: T,
|
||||
configuration_builder: impl FnOnce(&mut WebConfig) -> &mut WebConfig,
|
||||
) where
|
||||
pub fn launch_with_props<T>(root_component: Component<T>, 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<T>(
|
||||
/// wasm_bindgen_futures::spawn_local(app_fut);
|
||||
/// }
|
||||
/// ```
|
||||
pub async fn run_with_props<T: 'static + Send>(root: Component<T>, root_props: T, cfg: WebConfig) {
|
||||
pub async fn run_with_props<T: 'static + Send>(root: Component<T>, 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);
|
||||
|
||||
|
||||
@@ -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<dyn FnMut(&Event)>);
|
||||
|
||||
impl WebsysDom {
|
||||
pub fn new(cfg: WebConfig, sender_callback: Rc<dyn Fn(SchedulerMsg)>) -> Self {
|
||||
pub fn new(cfg: Config, sender_callback: Rc<dyn Fn(SchedulerMsg)>) -> Self {
|
||||
let document = load_document();
|
||||
|
||||
let nodes = NodeSlab::new(2000);
|
||||
|
||||
@@ -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!("<div id='main'>{}</div>", out));
|
||||
|
||||
dioxus_web::launch_cfg(app, |c| c.hydrate(true));
|
||||
dioxus_web::launch_cfg(app, Config::new().hydrate(true));
|
||||
}
|
||||
Reference in new issue
Block a user