mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-10 06:34:20 +00:00
Fix flakey windows tests (#2332)
This commit is contained in:
parent
c9ab09b348
commit
5ce91e1bfc
31 changed files with 217 additions and 136 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -2371,6 +2371,7 @@ dependencies = [
|
|||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"ciborium",
|
||||
"dioxus",
|
||||
"dioxus-cli-config",
|
||||
"dioxus-desktop",
|
||||
"dioxus-hot-reload",
|
||||
|
@ -2488,6 +2489,7 @@ dependencies = [
|
|||
name = "dioxus-lib"
|
||||
version = "0.5.2"
|
||||
dependencies = [
|
||||
"dioxus",
|
||||
"dioxus-config-macro",
|
||||
"dioxus-core 0.5.2",
|
||||
"dioxus-core-macro",
|
||||
|
@ -2603,6 +2605,7 @@ dependencies = [
|
|||
name = "dioxus-router-macro"
|
||||
version = "0.5.2"
|
||||
dependencies = [
|
||||
"dioxus",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"slab",
|
||||
|
|
|
@ -88,7 +88,7 @@ command = "cargo"
|
|||
args = ["build"]
|
||||
|
||||
[tasks.test-flow]
|
||||
dependencies = ["test"]
|
||||
dependencies = ["test", "docs"]
|
||||
private = true
|
||||
|
||||
[tasks.test]
|
||||
|
@ -101,8 +101,7 @@ args = [
|
|||
"--tests",
|
||||
"--examples",
|
||||
"--workspace",
|
||||
"--exclude",
|
||||
"dioxus-router",
|
||||
# These tests run on Ubuntu without a screen. Desktop tests that require a screen fail, so we skip them
|
||||
"--exclude",
|
||||
"dioxus-desktop",
|
||||
"--exclude",
|
||||
|
@ -110,6 +109,16 @@ args = [
|
|||
]
|
||||
private = true
|
||||
|
||||
[tasks.docs]
|
||||
dependencies = ["build"]
|
||||
command = "cargo"
|
||||
args = [
|
||||
"test",
|
||||
"--doc",
|
||||
"--workspace",
|
||||
]
|
||||
private = true
|
||||
|
||||
[tasks.test-with-browser]
|
||||
env = { CARGO_MAKE_WORKSPACE_INCLUDE_MEMBERS = [
|
||||
"**/packages/router",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//! The typical TodoMVC app, implemented in Dioxus.
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_elements::input_data::keyboard_types::Key;
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn main() {
|
||||
|
@ -74,7 +73,7 @@ fn app() -> Element {
|
|||
class: "toggle-all",
|
||||
r#type: "checkbox",
|
||||
onchange: toggle_all,
|
||||
checked: active_todo_count() == 0,
|
||||
checked: active_todo_count() == 0
|
||||
}
|
||||
label { r#for: "toggle-all" }
|
||||
}
|
||||
|
@ -98,8 +97,14 @@ fn app() -> Element {
|
|||
// A simple info footer
|
||||
footer { class: "info",
|
||||
p { "Double-click to edit a todo" }
|
||||
p { "Created by " a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" } }
|
||||
p { "Part of " a { href: "http://todomvc.com", "TodoMVC" } }
|
||||
p {
|
||||
"Created by "
|
||||
a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" }
|
||||
}
|
||||
p {
|
||||
"Part of "
|
||||
a { href: "http://todomvc.com", "TodoMVC" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +137,7 @@ fn TodoHeader(mut todos: Signal<HashMap<u32, TodoItem>>) -> Element {
|
|||
value: "{draft}",
|
||||
autofocus: "true",
|
||||
oninput: move |evt| draft.set(evt.value()),
|
||||
onkeydown,
|
||||
onkeydown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +170,7 @@ fn TodoEntry(mut todos: Signal<HashMap<u32, TodoItem>>, id: u32) -> Element {
|
|||
r#type: "checkbox",
|
||||
id: "cbg-{id}",
|
||||
checked: "{checked}",
|
||||
oninput: move |evt| todos.write().get_mut(&id).unwrap().checked = evt.checked(),
|
||||
oninput: move |evt| todos.write().get_mut(&id).unwrap().checked = evt.checked()
|
||||
}
|
||||
label {
|
||||
r#for: "cbg-{id}",
|
||||
|
@ -175,7 +180,9 @@ fn TodoEntry(mut todos: Signal<HashMap<u32, TodoItem>>, id: u32) -> Element {
|
|||
}
|
||||
button {
|
||||
class: "destroy",
|
||||
onclick: move |_| { todos.write().remove(&id); },
|
||||
onclick: move |_| {
|
||||
todos.write().remove(&id);
|
||||
},
|
||||
prevent_default: "onclick"
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +225,7 @@ fn ListFooter(
|
|||
match active_todo_count() {
|
||||
1 => "item",
|
||||
_ => "items",
|
||||
}
|
||||
},
|
||||
" left"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ pub fn remove_future(id: Task) {
|
|||
///
|
||||
/// pub fn use_custom_state() -> CustomState {
|
||||
/// use_hook(|| CustomState {
|
||||
/// inner: Signal::new(InnerCustomState)
|
||||
/// inner: Signal::new(InnerCustomState(0))
|
||||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
|
|
|
@ -310,7 +310,7 @@ impl Scope {
|
|||
///
|
||||
/// pub fn use_custom_state() -> CustomState {
|
||||
/// use_hook(|| CustomState {
|
||||
/// inner: Signal::new(InnerCustomState)
|
||||
/// inner: Signal::new(InnerCustomState(0))
|
||||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
|
|
|
@ -138,7 +138,7 @@ use tracing::instrument;
|
|||
///
|
||||
/// let dom = VirtualDom::new(app);
|
||||
///
|
||||
/// real_dom.apply(dom.rebuild());
|
||||
/// dom.rebuild(real_dom.apply());
|
||||
///
|
||||
/// loop {
|
||||
/// select! {
|
||||
|
@ -258,7 +258,7 @@ impl VirtualDom {
|
|||
///
|
||||
/// ```rust, ignore
|
||||
/// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" });
|
||||
/// let mutations = dom.rebuild();
|
||||
/// dom.rebuild_in_place();
|
||||
/// ```
|
||||
pub fn new_with_props<P: Clone + 'static, M: 'static>(
|
||||
root: impl ComponentFunction<P, M>,
|
||||
|
@ -302,7 +302,7 @@ impl VirtualDom {
|
|||
///
|
||||
/// ```rust, ignore
|
||||
/// let mut dom = VirtualDom::new_from_root(VComponent::new(Example, SomeProps { name: "jane" }, "Example"));
|
||||
/// let mutations = dom.rebuild();
|
||||
/// dom.rebuild(to_writer);
|
||||
/// ```
|
||||
#[instrument(skip(root), level = "trace", name = "VirtualDom::new")]
|
||||
pub(crate) fn new_with_component(root: impl AnyProps + 'static) -> Self {
|
||||
|
@ -611,9 +611,7 @@ impl VirtualDom {
|
|||
/// static app: Component = |cx| rsx!{ "hello world" };
|
||||
///
|
||||
/// let mut dom = VirtualDom::new();
|
||||
/// let edits = dom.rebuild();
|
||||
///
|
||||
/// apply_edits(edits);
|
||||
/// dom.rebuild(to_writer);
|
||||
/// ```
|
||||
#[instrument(skip(self, to), level = "trace", name = "VirtualDom::rebuild")]
|
||||
pub fn rebuild(&mut self, to: &mut impl WriteMutations) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::dioxus_elements::SerializedMouseData;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core::ElementId;
|
||||
use dioxus_elements::SerializedHtmlEventConverter;
|
||||
|
|
|
@ -66,7 +66,7 @@ async fn spawn_forever_persists() {
|
|||
#[component]
|
||||
fn Child() -> Element {
|
||||
spawn_forever(async move {
|
||||
loop {
|
||||
for _ in 0..10 {
|
||||
POLL_COUNT.fetch_add(1, Ordering::Relaxed);
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
}
|
||||
|
@ -82,7 +82,9 @@ async fn spawn_forever_persists() {
|
|||
|
||||
tokio::select! {
|
||||
_ = dom.wait_for_work() => {}
|
||||
_ = tokio::time::sleep(Duration::from_millis(500)) => {}
|
||||
// We intentionally wait a bit longer than 50ms*10 to make sure the test has time to finish
|
||||
// Without the extra time, the test can fail on windows
|
||||
_ = tokio::time::sleep(Duration::from_millis(1000)) => {}
|
||||
};
|
||||
|
||||
// By the time the tasks are finished, we should've accumulated ticks from two tasks
|
||||
|
|
|
@ -2,7 +2,6 @@ use std::collections::HashMap;
|
|||
|
||||
use dioxus::html::geometry::euclid::Vector3D;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core::prelude::consume_context;
|
||||
use dioxus_desktop::DesktopContext;
|
||||
|
||||
#[path = "./utils.rs"]
|
||||
|
@ -179,7 +178,10 @@ fn test_mouse_dblclick_div() -> Element {
|
|||
println!("{:?}", event.data);
|
||||
assert!(event.data.modifiers().is_empty());
|
||||
assert!(
|
||||
event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Primary),
|
||||
event
|
||||
.data
|
||||
.held_buttons()
|
||||
.contains(dioxus_html::input_data::MouseButton::Primary),
|
||||
);
|
||||
assert!(
|
||||
event
|
||||
|
@ -282,7 +284,8 @@ fn test_mouse_scroll_div() -> Element {
|
|||
onwheel: move |event| {
|
||||
println!("{:?}", event.data);
|
||||
let dioxus_html::geometry::WheelDelta::Pixels(delta) = event.data.delta() else {
|
||||
panic!("Expected delta to be in pixels") };
|
||||
panic!("Expected delta to be in pixels")
|
||||
};
|
||||
assert_eq!(delta, Vector3D::new(1.0, 2.0, 3.0));
|
||||
RECEIVED_EVENTS.with_mut(|x| *x += 1);
|
||||
}
|
||||
|
@ -476,11 +479,16 @@ fn test_form_input() -> Element {
|
|||
r#type: "text",
|
||||
name: "username",
|
||||
id: "form-username",
|
||||
oninput: set_username,
|
||||
oninput: set_username
|
||||
}
|
||||
input { r#type: "text", name: "full-name", value: "lorem" }
|
||||
input { r#type: "password", name: "password", value: "ipsum" }
|
||||
input { r#type: "radio", name: "color", value: "red", checked: true }
|
||||
input {
|
||||
r#type: "radio",
|
||||
name: "color",
|
||||
value: "red",
|
||||
checked: true
|
||||
}
|
||||
input { r#type: "radio", name: "color", value: "blue" }
|
||||
button { r#type: "submit", value: "Submit", "Submit the form" }
|
||||
}
|
||||
|
@ -511,13 +519,21 @@ fn test_form_submit() -> Element {
|
|||
rsx! {
|
||||
div {
|
||||
h1 { "Form" }
|
||||
form {
|
||||
id: "form-submitter",
|
||||
onsubmit: set_values,
|
||||
input { r#type: "text", name: "username", id: "username", value: "goodbye" }
|
||||
form { id: "form-submitter", onsubmit: set_values,
|
||||
input {
|
||||
r#type: "text",
|
||||
name: "username",
|
||||
id: "username",
|
||||
value: "goodbye"
|
||||
}
|
||||
input { r#type: "text", name: "full-name", value: "lorem" }
|
||||
input { r#type: "password", name: "password", value: "ipsum" }
|
||||
input { r#type: "radio", name: "color", value: "red", checked: true }
|
||||
input {
|
||||
r#type: "radio",
|
||||
name: "color",
|
||||
value: "red",
|
||||
checked: true
|
||||
}
|
||||
input { r#type: "radio", name: "color", value: "blue" }
|
||||
button { r#type: "submit", value: "Submit", "Submit the form" }
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use dioxus::prelude::*;
|
||||
use dioxus_core::Element;
|
||||
use dioxus_desktop::DesktopContext;
|
||||
|
||||
#[path = "./utils.rs"]
|
||||
|
@ -53,26 +52,17 @@ fn check_html_renders() -> Element {
|
|||
}
|
||||
|
||||
let dyn_value = 0;
|
||||
let dyn_element = rsx! {
|
||||
div {
|
||||
dangerous_inner_html: "<p>hello world</p>",
|
||||
}
|
||||
};
|
||||
let dyn_element = rsx! { div { dangerous_inner_html: "<p>hello world</p>" } };
|
||||
|
||||
rsx! {
|
||||
div {
|
||||
id: "main_div",
|
||||
div { id: "main_div",
|
||||
div {
|
||||
width: "100px",
|
||||
height: "100px",
|
||||
color: "rgb({dyn_value}, {dyn_value}, {dyn_value})",
|
||||
id: 5,
|
||||
input {
|
||||
"type": "checkbox",
|
||||
},
|
||||
h1 {
|
||||
"text"
|
||||
}
|
||||
input { "type": "checkbox" }
|
||||
h1 { "text" }
|
||||
{dyn_element}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ pub fn check_app_exits(app: fn() -> Element) {
|
|||
});
|
||||
|
||||
LaunchBuilder::desktop()
|
||||
.with_cfg(Config::new().with_window(WindowBuilder::new().with_visible(true)))
|
||||
.with_cfg(Config::new().with_window(WindowBuilder::new().with_visible(false)))
|
||||
.launch(app);
|
||||
|
||||
// Stop deadman's switch
|
||||
|
|
|
@ -19,6 +19,9 @@ dioxus-hooks = { workspace = true, optional = true }
|
|||
dioxus-rsx = { workspace = true, optional = true }
|
||||
dioxus-signals = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
dioxus = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = ["macro", "html", "signals", "hooks"]
|
||||
signals = ["dioxus-signals"]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div>
|
||||
<h1>🌗🚀 Dioxus</h1>
|
||||
<h1>🌗🚀 Dioxus (lib)</h1>
|
||||
<p>
|
||||
<strong>A concurrent, functional, virtual DOM for Rust</strong>
|
||||
</p>
|
||||
|
@ -38,9 +38,9 @@ Remember: Dioxus is a library for declaring interactive user interfaces—it is
|
|||
|
||||
All Dioxus apps are built by composing functions that return an `Element`.
|
||||
|
||||
To launch an app, we use the `launch` method and use features in ``Cargo.toml`` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`.
|
||||
To launch an app, we use the `launch` method and use features in `Cargo.toml` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`.
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -36,9 +36,9 @@ Remember: Dioxus is a library for declaring interactive user interfaces—it is
|
|||
|
||||
All Dioxus apps are built by composing functions that return an `Element`.
|
||||
|
||||
To launch an app, we use the `launch` method and use features in ``Cargo.toml`` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`.
|
||||
To launch an app, we use the `launch` method and use features in `Cargo.toml` to specify which renderer we want to use. In the launch function, we pass the app's root `Component`.
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -66,6 +66,9 @@ tokio = { workspace = true, features = ["rt", "sync"], optional = true }
|
|||
dioxus-hot-reload = { workspace = true }
|
||||
tokio = { workspace = true, features = ["rt", "sync", "rt-multi-thread"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
dioxus = { workspace = true, features = ["fullstack"] }
|
||||
|
||||
[features]
|
||||
default = ["hot-reload"]
|
||||
hot-reload = ["serde_json"]
|
||||
|
|
|
@ -32,7 +32,7 @@ Fullstack utilities for the [`Dioxus`](https://dioxuslabs.com) framework.
|
|||
|
||||
Full stack Dioxus in under 30 lines of code
|
||||
|
||||
```rust
|
||||
```rust, no_run
|
||||
#![allow(non_snake_case)]
|
||||
use dioxus::prelude::*;
|
||||
|
||||
|
@ -42,7 +42,7 @@ fn main() {
|
|||
|
||||
#[component]
|
||||
fn App() -> Element {
|
||||
let meaning = use_signal(|| None);
|
||||
let mut meaning = use_signal(|| None);
|
||||
|
||||
rsx! {
|
||||
h1 { "Meaning of life: {meaning:?}" }
|
||||
|
|
|
@ -12,9 +12,9 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||
/// use dioxus_fullstack::prelude::*;
|
||||
///
|
||||
/// fn app() -> Element {
|
||||
/// let state1 = server_cached(|| from_server(|| {
|
||||
/// let state1 = server_cached(|| {
|
||||
/// 1234
|
||||
/// }));
|
||||
/// });
|
||||
///
|
||||
/// None
|
||||
/// }
|
||||
|
|
|
@ -34,7 +34,7 @@ use crate::use_callback;
|
|||
/// #[component]
|
||||
/// fn Comp(count: u32) -> Element {
|
||||
/// // Because the memo subscribes to `count` by adding it as a dependency, the memo will rerun every time `count` changes.
|
||||
/// use_effect(use_reactive((&count, |(count,)| println!("Manually manipulate the dom") )));
|
||||
/// use_effect(use_reactive((&count,), |(count,)| println!("Manually manipulate the dom") ));
|
||||
///
|
||||
/// todo!()
|
||||
/// }
|
||||
|
|
|
@ -32,7 +32,7 @@ use dioxus_signals::{Memo, Signal};
|
|||
/// #[component]
|
||||
/// fn Comp(count: u32) -> Element {
|
||||
/// // Because the memo subscribes to `count` by adding it as a dependency, the memo will rerun every time `count` changes.
|
||||
/// let new_count = use_memo(use_reactive((&count, |(count,)| count + 1)));
|
||||
/// let new_count = use_memo(use_reactive((&count,), |(count,)| count + 1));
|
||||
///
|
||||
/// todo!()
|
||||
/// }
|
||||
|
|
|
@ -74,7 +74,7 @@ impl_dep!(A = a1 a2, B = b1 b2, C = c1 c2, D = d1 d2, E = e1 e2, F = f1 f2, G =
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// ```rust, no_run
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// let data = 5;
|
||||
|
@ -104,7 +104,7 @@ pub fn use_reactive<O, D: Dependency>(
|
|||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// ```rust, no_run
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// let data = 5;
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
use crate::{use_callback, use_signal, UseCallback};
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_core::{
|
||||
prelude::{spawn, use_hook},
|
||||
Task,
|
||||
};
|
||||
use dioxus_signals::*;
|
||||
use futures_util::{future, pin_mut, FutureExt, StreamExt};
|
||||
use std::ops::Deref;
|
||||
|
@ -66,7 +62,7 @@ use std::{cell::Cell, future::Future, rc::Rc};
|
|||
/// #[component]
|
||||
/// fn Comp(count: u32) -> Element {
|
||||
/// // Because the memo subscribes to `count` by adding it as a dependency, the memo will rerun every time `count` changes.
|
||||
/// let new_count = use_resource(use_reactive((&count, |(count,)| async move {count + 1} )));
|
||||
/// let new_count = use_resource(use_reactive((&count,), |(count,)| async move {count + 1} ));
|
||||
///
|
||||
/// todo!()
|
||||
/// }
|
||||
|
|
|
@ -25,7 +25,7 @@ The Dioxus `rsx!` and `html!` macros can accept any compile-time correct namespa
|
|||
|
||||
However, this abstraction enables you to add any namespace of elements, provided they're in scope when rsx! is called. For an example, a UI that is designed for Augmented Reality might use different primitives than HTML:
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
use ar_namespace::*;
|
||||
|
||||
rsx! {
|
||||
|
@ -46,7 +46,7 @@ This is currently a not-very-explored part of Dioxus. However, the namespacing s
|
|||
|
||||
Elements for dioxus must implement the (simple) DioxusElement trait to be used in the rsx! macro.
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
struct div;
|
||||
impl DioxusElement for div {
|
||||
const TAG_NAME: &'static str = "div";
|
||||
|
@ -60,7 +60,7 @@ Attributes would then be implemented as constants on these unit structs.
|
|||
|
||||
The HTML namespace is defined mostly with macros. However, the expanded form would look something like this:
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
struct base;
|
||||
impl DioxusElement for base {
|
||||
const TAG_NAME: &'static str = "base";
|
||||
|
@ -78,7 +78,7 @@ Because attributes are defined as methods on the unit struct, they guard the att
|
|||
|
||||
Whenever the rsx! macro is called, it relies on a module `dioxus_elements` to be in scope. When you enable the `html` feature in dioxus, this module gets imported in the prelude. However, you can extend this with your own set of custom elements by making your own `dioxus_elements` module and re-exporting the html namespace.
|
||||
|
||||
```rust
|
||||
```rust, ignore
|
||||
mod dioxus_elements {
|
||||
use dioxus::prelude::dioxus_elements::*;
|
||||
struct my_element;
|
||||
|
|
|
@ -106,7 +106,9 @@ fn handle_edits_code() -> String {
|
|||
/// If you enter a relative path, the web client automatically prefixes the host address in
|
||||
/// `window.location` when creating a web socket to LiveView.
|
||||
///
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use dioxus_liveview::interpreter_glue;
|
||||
///
|
||||
/// // Creates websocket connection to same host as current page
|
||||
/// interpreter_glue("/api/liveview");
|
||||
///
|
||||
|
|
|
@ -20,6 +20,9 @@ quote = { workspace = true }
|
|||
proc-macro2 = { workspace = true }
|
||||
slab = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
dioxus = { workspace = true, features = ["router"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
web = []
|
||||
|
|
|
@ -42,7 +42,9 @@ mod segment;
|
|||
/// 2. By the order they are defined in the enum
|
||||
///
|
||||
/// All features:
|
||||
/// ```rust, skip
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// #[rustfmt::skip]
|
||||
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||
/// enum Route {
|
||||
|
@ -75,9 +77,17 @@ mod segment;
|
|||
/// #[redirect("/:id/user", |id: usize| Route::Route3 { dynamic: id.to_string()})]
|
||||
/// #[route("/:dynamic")]
|
||||
/// Route3 { dynamic: String },
|
||||
/// #[child]
|
||||
/// NestedRoute(NestedRoute),
|
||||
/// }
|
||||
/// # #[component]
|
||||
/// # fn Route1(user_id: usize, dynamic: usize, query: String) -> Element { None }
|
||||
/// # #[component]
|
||||
/// # fn Route2(user_id: usize) -> Element { None }
|
||||
/// # #[component]
|
||||
/// # fn Route3(dynamic: String) -> Element { None }
|
||||
/// # #[component]
|
||||
/// # fn UserFrame(user_id: usize) -> Element { None }
|
||||
/// # #[component]
|
||||
/// # fn IndexComponent() -> Element { None }
|
||||
/// ```
|
||||
///
|
||||
/// # `#[route("path", component)]`
|
||||
|
@ -89,7 +99,9 @@ mod segment;
|
|||
/// Routes are the most basic attribute. They allow you to define a route and the component to render when the route is matched. The component must take all dynamic parameters of the route and all parent nests.
|
||||
/// The next variant will be tied to the component. If you link to that variant, the component will be rendered.
|
||||
///
|
||||
/// ```rust, skip
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||
/// enum Route {
|
||||
/// // Define routes that renders the IndexComponent
|
||||
|
@ -97,6 +109,8 @@ mod segment;
|
|||
/// #[route("/", Index)]
|
||||
/// Index {},
|
||||
/// }
|
||||
/// # #[component]
|
||||
/// # fn Index() -> Element { None }
|
||||
/// ```
|
||||
///
|
||||
/// # `#[redirect("path", function)]`
|
||||
|
@ -105,14 +119,18 @@ mod segment;
|
|||
/// - `path`: The path to the enum variant (relative to the parent nest)
|
||||
/// - `function`: A function that takes the parameters from the path and returns a new route
|
||||
///
|
||||
/// ```rust, skip
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||
/// enum Route {
|
||||
/// // Redirects the /:id route to the Index route
|
||||
/// #[redirect("/:id", |_: usize| Route::Index {})]
|
||||
/// #[redirect("/:id", |id: usize| Route::Index {})]
|
||||
/// #[route("/", Index)]
|
||||
/// Index {},
|
||||
/// }
|
||||
/// # #[component]
|
||||
/// # fn Index() -> Element { None }
|
||||
/// ```
|
||||
///
|
||||
/// Redirects allow you to redirect a route to another route. The function must take all dynamic parameters of the route and all parent nests.
|
||||
|
@ -124,29 +142,35 @@ mod segment;
|
|||
///
|
||||
/// Nests effect all nests, routes and redirects defined until the next `#[end_nest]` attribute. All children of nests are relative to the nest route and must include all dynamic parameters of the nest.
|
||||
///
|
||||
/// ```rust, skip
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||
/// enum Route {
|
||||
/// // Nests all child routes in the /blog route
|
||||
/// #[nest("/blog")]
|
||||
/// // This is at /blog/:id
|
||||
/// #[redirect("/:id", |_: usize| Route::Index {})]
|
||||
/// #[redirect("/:id", |id: usize| Route::Index {})]
|
||||
/// // This is at /blog
|
||||
/// #[route("/", Index)]
|
||||
/// Index {},
|
||||
/// }
|
||||
/// # #[component]
|
||||
/// # fn Index() -> Element { None }
|
||||
/// ```
|
||||
///
|
||||
/// # `#[end_nest]`
|
||||
///
|
||||
/// The `#[end_nest]` attribute is used to end a nest. It takes no parameters.
|
||||
///
|
||||
/// ```rust, skip
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||
/// enum Route {
|
||||
/// #[nest("/blog")]
|
||||
/// // This is at /blog/:id
|
||||
/// #[redirect("/:id", |_: usize| Route::Index {})]
|
||||
/// #[redirect("/:id", |id: usize| Route::Index {})]
|
||||
/// // This is at /blog
|
||||
/// #[route("/", Index)]
|
||||
/// Index {},
|
||||
|
@ -156,6 +180,10 @@ mod segment;
|
|||
/// #[route("/")]
|
||||
/// Home {},
|
||||
/// }
|
||||
/// # #[component]
|
||||
/// # fn Index() -> Element { None }
|
||||
/// # #[component]
|
||||
/// # fn Home() -> Element { None }
|
||||
/// ```
|
||||
///
|
||||
/// # `#[layout(component)]`
|
||||
|
@ -165,26 +193,34 @@ mod segment;
|
|||
///
|
||||
/// The layout component allows you to wrap all children of the layout in a component. The child routes are rendered in the Outlet of the layout component. The layout component must take all dynamic parameters of the nests it is nested in.
|
||||
///
|
||||
/// ```rust, skip
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||
/// enum Route {
|
||||
/// #[layout(BlogFrame)]
|
||||
/// #[redirect("/:id", |_: usize| Route::Index {})]
|
||||
/// #[redirect("/:id", |id: usize| Route::Index {})]
|
||||
/// // Index will be rendered in the Outlet of the BlogFrame component
|
||||
/// #[route("/", Index)]
|
||||
/// Index {},
|
||||
/// }
|
||||
/// # #[component]
|
||||
/// # fn Index() -> Element { None }
|
||||
/// # #[component]
|
||||
/// # fn BlogFrame() -> Element { None }
|
||||
/// ```
|
||||
///
|
||||
/// # `#[end_layout]`
|
||||
///
|
||||
/// The `#[end_layout]` attribute is used to end a layout. It takes no parameters.
|
||||
///
|
||||
/// ```rust, skip
|
||||
/// ```rust
|
||||
/// use dioxus::prelude::*;
|
||||
///
|
||||
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||
/// enum Route {
|
||||
/// #[layout(BlogFrame)]
|
||||
/// #[redirect("/:id", |_: usize| Route::Index {})]
|
||||
/// #[redirect("/:id", |id: usize| Route::Index {})]
|
||||
/// // Index will be rendered in the Outlet of the BlogFrame component
|
||||
/// #[route("/", Index)]
|
||||
/// Index {},
|
||||
|
@ -194,6 +230,12 @@ mod segment;
|
|||
/// #[route("/")]
|
||||
/// Home {},
|
||||
/// }
|
||||
/// # #[component]
|
||||
/// # fn Index() -> Element { None }
|
||||
/// # #[component]
|
||||
/// # fn BlogFrame() -> Element { None }
|
||||
/// # #[component]
|
||||
/// # fn Home() -> Element { None }
|
||||
/// ```
|
||||
#[proc_macro_derive(
|
||||
Routable,
|
||||
|
|
|
@ -73,7 +73,12 @@ pub fn GoBackButton(props: HistoryButtonProps) -> Element {
|
|||
let disabled = !router.can_go_back();
|
||||
|
||||
rsx! {
|
||||
button { disabled: "{disabled}", prevent_default: "onclick", onclick: move |_| router.go_back(), {children} }
|
||||
button {
|
||||
disabled: "{disabled}",
|
||||
prevent_default: "onclick",
|
||||
onclick: move |_| router.go_back(),
|
||||
{children}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +119,7 @@ pub fn GoBackButton(props: HistoryButtonProps) -> Element {
|
|||
/// }
|
||||
/// #
|
||||
/// # let mut vdom = VirtualDom::new(App);
|
||||
/// # let _ = vdom.rebuild();
|
||||
/// # vdom.rebuild_in_place();
|
||||
/// # assert_eq!(
|
||||
/// # dioxus_ssr::render(&vdom),
|
||||
/// # r#"<button disabled="true" dioxus-prevent-default="onclick">go forward</button>"#
|
||||
|
@ -139,6 +144,11 @@ pub fn GoForwardButton(props: HistoryButtonProps) -> Element {
|
|||
let disabled = !router.can_go_forward();
|
||||
|
||||
rsx! {
|
||||
button { disabled: "{disabled}", prevent_default: "onclick", onclick: move |_| router.go_forward(), {children} }
|
||||
button {
|
||||
disabled: "{disabled}",
|
||||
prevent_default: "onclick",
|
||||
onclick: move |_| router.go_forward(),
|
||||
{children}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,7 +178,6 @@ impl Debug for LinkProps {
|
|||
/// #[component]
|
||||
/// fn Index() -> Element {
|
||||
/// rsx! {
|
||||
/// rsx! {
|
||||
/// Link {
|
||||
/// active_class: "active",
|
||||
/// class: "link_class",
|
||||
|
@ -191,13 +190,12 @@ impl Debug for LinkProps {
|
|||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// #
|
||||
/// # let mut vdom = VirtualDom::new(App);
|
||||
/// # let _ = vdom.rebuild();
|
||||
/// # vdom.rebuild_in_place();
|
||||
/// # assert_eq!(
|
||||
/// # dioxus_ssr::render(&vdom),
|
||||
/// # r#"<a href="/" dioxus-prevent-default="" class="link_class active" id="link_id" rel="link_rel" target="_blank">A fully configured link</a>"#
|
||||
/// # r#"<a href="/" dioxus-prevent-default="" class="link_class active" rel="link_rel" target="_blank" id="link_id">A fully configured link</a>"#
|
||||
/// # );
|
||||
/// ```
|
||||
#[allow(non_snake_case)]
|
||||
|
|
|
@ -65,7 +65,7 @@ use dioxus_lib::prelude::*;
|
|||
/// # }
|
||||
/// #
|
||||
/// # let mut vdom = VirtualDom::new(App);
|
||||
/// # let _ = vdom.rebuild();
|
||||
/// # vdom.rebuild_in_place();
|
||||
/// # assert_eq!(dioxus_ssr::render(&vdom), "<h1>App</h1><p>Child</p>");
|
||||
/// ```
|
||||
pub fn Outlet<R: Routable + Clone>() -> Element {
|
||||
|
|
|
@ -46,7 +46,7 @@ use crate::prelude::{Navigator, RouterContext};
|
|||
/// }
|
||||
///
|
||||
/// # let mut vdom = VirtualDom::new(App);
|
||||
/// # let _ = vdom.rebuild();
|
||||
/// # vdom.rebuild_in_place();
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn use_navigator() -> Navigator {
|
||||
|
|
|
@ -37,7 +37,7 @@ use crate::utils::use_router_internal::use_router_internal;
|
|||
/// }
|
||||
/// #
|
||||
/// # let mut vdom = VirtualDom::new(App);
|
||||
/// # let _ = vdom.rebuild();
|
||||
/// # vdom.rebuild_in_place();
|
||||
/// # assert_eq!(dioxus_ssr::render(&vdom), "<h1>App</h1><h2>Current Path</h2><p>/</p>")
|
||||
/// ```
|
||||
#[must_use]
|
||||
|
|
|
@ -21,7 +21,7 @@ Dioxus SSR provides utilities to render Dioxus components to valid HTML. Once re
|
|||
let app: Component = |cx| rsx!(div {"hello world!"});
|
||||
|
||||
let mut vdom = VirtualDom::new(app);
|
||||
let _ = vdom.rebuild();
|
||||
vdom.rebuild_in_place();
|
||||
|
||||
let text = dioxus_ssr::render(&vdom);
|
||||
assert_eq!(text, "<div>hello world!</div>")
|
||||
|
@ -45,7 +45,7 @@ let content = dioxus_ssr::render_element(rsx!{
|
|||
|
||||
```rust, ignore
|
||||
let mut vdom = VirtualDom::new(app);
|
||||
let _ = vdom.rebuild();
|
||||
vdom.rebuild_in_place();
|
||||
|
||||
let content = dioxus_ssr::render(&vdom);
|
||||
```
|
||||
|
@ -63,7 +63,7 @@ To enable pre-rendering, simply set the pre-rendering flag to true.
|
|||
```rust, ignore
|
||||
let mut vdom = VirtualDom::new(App);
|
||||
|
||||
let _ = vdom.rebuild();
|
||||
vdom.rebuild_in_place();
|
||||
|
||||
let mut renderer = dioxus_ssr::Renderer::new();
|
||||
renderer.pre_render = true;
|
||||
|
|
Loading…
Reference in a new issue