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",
|
"base64 0.21.7",
|
||||||
"bytes",
|
"bytes",
|
||||||
"ciborium",
|
"ciborium",
|
||||||
|
"dioxus",
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"dioxus-desktop",
|
"dioxus-desktop",
|
||||||
"dioxus-hot-reload",
|
"dioxus-hot-reload",
|
||||||
|
@ -2488,6 +2489,7 @@ dependencies = [
|
||||||
name = "dioxus-lib"
|
name = "dioxus-lib"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"dioxus",
|
||||||
"dioxus-config-macro",
|
"dioxus-config-macro",
|
||||||
"dioxus-core 0.5.2",
|
"dioxus-core 0.5.2",
|
||||||
"dioxus-core-macro",
|
"dioxus-core-macro",
|
||||||
|
@ -2603,6 +2605,7 @@ dependencies = [
|
||||||
name = "dioxus-router-macro"
|
name = "dioxus-router-macro"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"dioxus",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"slab",
|
"slab",
|
||||||
|
|
|
@ -88,7 +88,7 @@ command = "cargo"
|
||||||
args = ["build"]
|
args = ["build"]
|
||||||
|
|
||||||
[tasks.test-flow]
|
[tasks.test-flow]
|
||||||
dependencies = ["test"]
|
dependencies = ["test", "docs"]
|
||||||
private = true
|
private = true
|
||||||
|
|
||||||
[tasks.test]
|
[tasks.test]
|
||||||
|
@ -101,8 +101,7 @@ args = [
|
||||||
"--tests",
|
"--tests",
|
||||||
"--examples",
|
"--examples",
|
||||||
"--workspace",
|
"--workspace",
|
||||||
"--exclude",
|
# These tests run on Ubuntu without a screen. Desktop tests that require a screen fail, so we skip them
|
||||||
"dioxus-router",
|
|
||||||
"--exclude",
|
"--exclude",
|
||||||
"dioxus-desktop",
|
"dioxus-desktop",
|
||||||
"--exclude",
|
"--exclude",
|
||||||
|
@ -110,6 +109,16 @@ args = [
|
||||||
]
|
]
|
||||||
private = true
|
private = true
|
||||||
|
|
||||||
|
[tasks.docs]
|
||||||
|
dependencies = ["build"]
|
||||||
|
command = "cargo"
|
||||||
|
args = [
|
||||||
|
"test",
|
||||||
|
"--doc",
|
||||||
|
"--workspace",
|
||||||
|
]
|
||||||
|
private = true
|
||||||
|
|
||||||
[tasks.test-with-browser]
|
[tasks.test-with-browser]
|
||||||
env = { CARGO_MAKE_WORKSPACE_INCLUDE_MEMBERS = [
|
env = { CARGO_MAKE_WORKSPACE_INCLUDE_MEMBERS = [
|
||||||
"**/packages/router",
|
"**/packages/router",
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! The typical TodoMVC app, implemented in Dioxus.
|
//! The typical TodoMVC app, implemented in Dioxus.
|
||||||
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_elements::input_data::keyboard_types::Key;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -74,7 +73,7 @@ fn app() -> Element {
|
||||||
class: "toggle-all",
|
class: "toggle-all",
|
||||||
r#type: "checkbox",
|
r#type: "checkbox",
|
||||||
onchange: toggle_all,
|
onchange: toggle_all,
|
||||||
checked: active_todo_count() == 0,
|
checked: active_todo_count() == 0
|
||||||
}
|
}
|
||||||
label { r#for: "toggle-all" }
|
label { r#for: "toggle-all" }
|
||||||
}
|
}
|
||||||
|
@ -98,8 +97,14 @@ fn app() -> Element {
|
||||||
// A simple info footer
|
// A simple info footer
|
||||||
footer { class: "info",
|
footer { class: "info",
|
||||||
p { "Double-click to edit a todo" }
|
p { "Double-click to edit a todo" }
|
||||||
p { "Created by " a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" } }
|
p {
|
||||||
p { "Part of " a { href: "http://todomvc.com", "TodoMVC" } }
|
"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}",
|
value: "{draft}",
|
||||||
autofocus: "true",
|
autofocus: "true",
|
||||||
oninput: move |evt| draft.set(evt.value()),
|
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",
|
r#type: "checkbox",
|
||||||
id: "cbg-{id}",
|
id: "cbg-{id}",
|
||||||
checked: "{checked}",
|
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 {
|
label {
|
||||||
r#for: "cbg-{id}",
|
r#for: "cbg-{id}",
|
||||||
|
@ -175,7 +180,9 @@ fn TodoEntry(mut todos: Signal<HashMap<u32, TodoItem>>, id: u32) -> Element {
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
class: "destroy",
|
class: "destroy",
|
||||||
onclick: move |_| { todos.write().remove(&id); },
|
onclick: move |_| {
|
||||||
|
todos.write().remove(&id);
|
||||||
|
},
|
||||||
prevent_default: "onclick"
|
prevent_default: "onclick"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,41 +218,41 @@ fn ListFooter(
|
||||||
let show_clear_completed = use_memo(move || todos.read().values().any(|todo| todo.checked));
|
let show_clear_completed = use_memo(move || todos.read().values().any(|todo| todo.checked));
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
footer { class: "footer",
|
footer { class: "footer",
|
||||||
span { class: "todo-count",
|
span { class: "todo-count",
|
||||||
strong { "{active_todo_count} " }
|
strong { "{active_todo_count} " }
|
||||||
span {
|
span {
|
||||||
match active_todo_count() {
|
match active_todo_count() {
|
||||||
1 => "item",
|
1 => "item",
|
||||||
_ => "items",
|
_ => "items",
|
||||||
|
},
|
||||||
|
" left"
|
||||||
}
|
}
|
||||||
" left"
|
|
||||||
}
|
}
|
||||||
}
|
ul { class: "filters",
|
||||||
ul { class: "filters",
|
for (state , state_text , url) in [
|
||||||
for (state , state_text , url) in [
|
(FilterState::All, "All", "#/"),
|
||||||
(FilterState::All, "All", "#/"),
|
(FilterState::Active, "Active", "#/active"),
|
||||||
(FilterState::Active, "Active", "#/active"),
|
(FilterState::Completed, "Completed", "#/completed"),
|
||||||
(FilterState::Completed, "Completed", "#/completed"),
|
] {
|
||||||
] {
|
li {
|
||||||
li {
|
a {
|
||||||
a {
|
href: url,
|
||||||
href: url,
|
class: if filter() == state { "selected" },
|
||||||
class: if filter() == state { "selected" },
|
onclick: move |_| filter.set(state),
|
||||||
onclick: move |_| filter.set(state),
|
prevent_default: "onclick",
|
||||||
prevent_default: "onclick",
|
{state_text}
|
||||||
{state_text}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if show_clear_completed() {
|
||||||
if show_clear_completed() {
|
button {
|
||||||
button {
|
class: "clear-completed",
|
||||||
class: "clear-completed",
|
onclick: move |_| todos.write().retain(|_, todo| !todo.checked),
|
||||||
onclick: move |_| todos.write().retain(|_, todo| !todo.checked),
|
"Clear completed"
|
||||||
"Clear completed"
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ pub fn remove_future(id: Task) {
|
||||||
///
|
///
|
||||||
/// pub fn use_custom_state() -> CustomState {
|
/// pub fn use_custom_state() -> CustomState {
|
||||||
/// use_hook(|| 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 {
|
/// pub fn use_custom_state() -> CustomState {
|
||||||
/// use_hook(|| 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);
|
/// let dom = VirtualDom::new(app);
|
||||||
///
|
///
|
||||||
/// real_dom.apply(dom.rebuild());
|
/// dom.rebuild(real_dom.apply());
|
||||||
///
|
///
|
||||||
/// loop {
|
/// loop {
|
||||||
/// select! {
|
/// select! {
|
||||||
|
@ -258,7 +258,7 @@ impl VirtualDom {
|
||||||
///
|
///
|
||||||
/// ```rust, ignore
|
/// ```rust, ignore
|
||||||
/// let mut dom = VirtualDom::new_with_props(Example, SomeProps { name: "jane" });
|
/// 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>(
|
pub fn new_with_props<P: Clone + 'static, M: 'static>(
|
||||||
root: impl ComponentFunction<P, M>,
|
root: impl ComponentFunction<P, M>,
|
||||||
|
@ -302,7 +302,7 @@ impl VirtualDom {
|
||||||
///
|
///
|
||||||
/// ```rust, ignore
|
/// ```rust, ignore
|
||||||
/// let mut dom = VirtualDom::new_from_root(VComponent::new(Example, SomeProps { name: "jane" }, "Example"));
|
/// 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")]
|
#[instrument(skip(root), level = "trace", name = "VirtualDom::new")]
|
||||||
pub(crate) fn new_with_component(root: impl AnyProps + 'static) -> Self {
|
pub(crate) fn new_with_component(root: impl AnyProps + 'static) -> Self {
|
||||||
|
@ -611,9 +611,7 @@ impl VirtualDom {
|
||||||
/// static app: Component = |cx| rsx!{ "hello world" };
|
/// static app: Component = |cx| rsx!{ "hello world" };
|
||||||
///
|
///
|
||||||
/// let mut dom = VirtualDom::new();
|
/// let mut dom = VirtualDom::new();
|
||||||
/// let edits = dom.rebuild();
|
/// dom.rebuild(to_writer);
|
||||||
///
|
|
||||||
/// apply_edits(edits);
|
|
||||||
/// ```
|
/// ```
|
||||||
#[instrument(skip(self, to), level = "trace", name = "VirtualDom::rebuild")]
|
#[instrument(skip(self, to), level = "trace", name = "VirtualDom::rebuild")]
|
||||||
pub fn rebuild(&mut self, to: &mut impl WriteMutations) {
|
pub fn rebuild(&mut self, to: &mut impl WriteMutations) {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::dioxus_elements::SerializedMouseData;
|
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_core::ElementId;
|
use dioxus_core::ElementId;
|
||||||
use dioxus_elements::SerializedHtmlEventConverter;
|
use dioxus_elements::SerializedHtmlEventConverter;
|
||||||
|
|
|
@ -66,7 +66,7 @@ async fn spawn_forever_persists() {
|
||||||
#[component]
|
#[component]
|
||||||
fn Child() -> Element {
|
fn Child() -> Element {
|
||||||
spawn_forever(async move {
|
spawn_forever(async move {
|
||||||
loop {
|
for _ in 0..10 {
|
||||||
POLL_COUNT.fetch_add(1, Ordering::Relaxed);
|
POLL_COUNT.fetch_add(1, Ordering::Relaxed);
|
||||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,9 @@ async fn spawn_forever_persists() {
|
||||||
|
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = dom.wait_for_work() => {}
|
_ = 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
|
// 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::html::geometry::euclid::Vector3D;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_core::prelude::consume_context;
|
|
||||||
use dioxus_desktop::DesktopContext;
|
use dioxus_desktop::DesktopContext;
|
||||||
|
|
||||||
#[path = "./utils.rs"]
|
#[path = "./utils.rs"]
|
||||||
|
@ -179,7 +178,10 @@ fn test_mouse_dblclick_div() -> Element {
|
||||||
println!("{:?}", event.data);
|
println!("{:?}", event.data);
|
||||||
assert!(event.data.modifiers().is_empty());
|
assert!(event.data.modifiers().is_empty());
|
||||||
assert!(
|
assert!(
|
||||||
event.data.held_buttons().contains(dioxus_html::input_data::MouseButton::Primary),
|
event
|
||||||
|
.data
|
||||||
|
.held_buttons()
|
||||||
|
.contains(dioxus_html::input_data::MouseButton::Primary),
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
event
|
event
|
||||||
|
@ -282,7 +284,8 @@ fn test_mouse_scroll_div() -> Element {
|
||||||
onwheel: move |event| {
|
onwheel: move |event| {
|
||||||
println!("{:?}", event.data);
|
println!("{:?}", event.data);
|
||||||
let dioxus_html::geometry::WheelDelta::Pixels(delta) = event.data.delta() else {
|
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));
|
assert_eq!(delta, Vector3D::new(1.0, 2.0, 3.0));
|
||||||
RECEIVED_EVENTS.with_mut(|x| *x += 1);
|
RECEIVED_EVENTS.with_mut(|x| *x += 1);
|
||||||
}
|
}
|
||||||
|
@ -476,11 +479,16 @@ fn test_form_input() -> Element {
|
||||||
r#type: "text",
|
r#type: "text",
|
||||||
name: "username",
|
name: "username",
|
||||||
id: "form-username",
|
id: "form-username",
|
||||||
oninput: set_username,
|
oninput: set_username
|
||||||
}
|
}
|
||||||
input { r#type: "text", name: "full-name", value: "lorem" }
|
input { r#type: "text", name: "full-name", value: "lorem" }
|
||||||
input { r#type: "password", name: "password", value: "ipsum" }
|
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" }
|
input { r#type: "radio", name: "color", value: "blue" }
|
||||||
button { r#type: "submit", value: "Submit", "Submit the form" }
|
button { r#type: "submit", value: "Submit", "Submit the form" }
|
||||||
}
|
}
|
||||||
|
@ -511,13 +519,21 @@ fn test_form_submit() -> Element {
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
h1 { "Form" }
|
h1 { "Form" }
|
||||||
form {
|
form { id: "form-submitter", onsubmit: set_values,
|
||||||
id: "form-submitter",
|
input {
|
||||||
onsubmit: set_values,
|
r#type: "text",
|
||||||
input { r#type: "text", name: "username", id: "username", value: "goodbye" }
|
name: "username",
|
||||||
|
id: "username",
|
||||||
|
value: "goodbye"
|
||||||
|
}
|
||||||
input { r#type: "text", name: "full-name", value: "lorem" }
|
input { r#type: "text", name: "full-name", value: "lorem" }
|
||||||
input { r#type: "password", name: "password", value: "ipsum" }
|
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" }
|
input { r#type: "radio", name: "color", value: "blue" }
|
||||||
button { r#type: "submit", value: "Submit", "Submit the form" }
|
button { r#type: "submit", value: "Submit", "Submit the form" }
|
||||||
}
|
}
|
||||||
|
@ -547,9 +563,9 @@ fn test_select_multiple_options() -> Element {
|
||||||
assert_eq!(values, vec!["usa", "canada"]);
|
assert_eq!(values, vec!["usa", "canada"]);
|
||||||
RECEIVED_EVENTS.with_mut(|x| *x += 1);
|
RECEIVED_EVENTS.with_mut(|x| *x += 1);
|
||||||
},
|
},
|
||||||
option { id: "usa", value: "usa", "USA" }
|
option { id: "usa", value: "usa", "USA" }
|
||||||
option { id: "canada", value: "canada", "Canada" }
|
option { id: "canada", value: "canada", "Canada" }
|
||||||
option { id: "mexico", value: "mexico", selected: true, "Mexico" }
|
option { id: "mexico", value: "mexico", selected: true, "Mexico" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use dioxus_core::Element;
|
|
||||||
use dioxus_desktop::DesktopContext;
|
use dioxus_desktop::DesktopContext;
|
||||||
|
|
||||||
#[path = "./utils.rs"]
|
#[path = "./utils.rs"]
|
||||||
|
@ -53,26 +52,17 @@ fn check_html_renders() -> Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
let dyn_value = 0;
|
let dyn_value = 0;
|
||||||
let dyn_element = rsx! {
|
let dyn_element = rsx! { div { dangerous_inner_html: "<p>hello world</p>" } };
|
||||||
div {
|
|
||||||
dangerous_inner_html: "<p>hello world</p>",
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div { id: "main_div",
|
||||||
id: "main_div",
|
|
||||||
div {
|
div {
|
||||||
width: "100px",
|
width: "100px",
|
||||||
height: "100px",
|
height: "100px",
|
||||||
color: "rgb({dyn_value}, {dyn_value}, {dyn_value})",
|
color: "rgb({dyn_value}, {dyn_value}, {dyn_value})",
|
||||||
id: 5,
|
id: 5,
|
||||||
input {
|
input { "type": "checkbox" }
|
||||||
"type": "checkbox",
|
h1 { "text" }
|
||||||
},
|
|
||||||
h1 {
|
|
||||||
"text"
|
|
||||||
}
|
|
||||||
{dyn_element}
|
{dyn_element}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub fn check_app_exits(app: fn() -> Element) {
|
||||||
});
|
});
|
||||||
|
|
||||||
LaunchBuilder::desktop()
|
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);
|
.launch(app);
|
||||||
|
|
||||||
// Stop deadman's switch
|
// Stop deadman's switch
|
||||||
|
|
|
@ -19,6 +19,9 @@ dioxus-hooks = { workspace = true, optional = true }
|
||||||
dioxus-rsx = { workspace = true, optional = true }
|
dioxus-rsx = { workspace = true, optional = true }
|
||||||
dioxus-signals = { workspace = true, optional = true }
|
dioxus-signals = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
dioxus = { workspace = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["macro", "html", "signals", "hooks"]
|
default = ["macro", "html", "signals", "hooks"]
|
||||||
signals = ["dioxus-signals"]
|
signals = ["dioxus-signals"]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div>
|
<div>
|
||||||
<h1>🌗🚀 Dioxus</h1>
|
<h1>🌗🚀 Dioxus (lib)</h1>
|
||||||
<p>
|
<p>
|
||||||
<strong>A concurrent, functional, virtual DOM for Rust</strong>
|
<strong>A concurrent, functional, virtual DOM for Rust</strong>
|
||||||
</p>
|
</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`.
|
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::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
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`.
|
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::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -66,6 +66,9 @@ tokio = { workspace = true, features = ["rt", "sync"], optional = true }
|
||||||
dioxus-hot-reload = { workspace = true }
|
dioxus-hot-reload = { workspace = true }
|
||||||
tokio = { workspace = true, features = ["rt", "sync", "rt-multi-thread"], optional = true }
|
tokio = { workspace = true, features = ["rt", "sync", "rt-multi-thread"], optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
dioxus = { workspace = true, features = ["fullstack"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["hot-reload"]
|
default = ["hot-reload"]
|
||||||
hot-reload = ["serde_json"]
|
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
|
Full stack Dioxus in under 30 lines of code
|
||||||
|
|
||||||
```rust
|
```rust, no_run
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ fn main() {
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
fn App() -> Element {
|
fn App() -> Element {
|
||||||
let meaning = use_signal(|| None);
|
let mut meaning = use_signal(|| None);
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
h1 { "Meaning of life: {meaning:?}" }
|
h1 { "Meaning of life: {meaning:?}" }
|
||||||
|
|
|
@ -12,9 +12,9 @@ use serde::{de::DeserializeOwned, Serialize};
|
||||||
/// use dioxus_fullstack::prelude::*;
|
/// use dioxus_fullstack::prelude::*;
|
||||||
///
|
///
|
||||||
/// fn app() -> Element {
|
/// fn app() -> Element {
|
||||||
/// let state1 = server_cached(|| from_server(|| {
|
/// let state1 = server_cached(|| {
|
||||||
/// 1234
|
/// 1234
|
||||||
/// }));
|
/// });
|
||||||
///
|
///
|
||||||
/// None
|
/// None
|
||||||
/// }
|
/// }
|
||||||
|
|
|
@ -34,7 +34,7 @@ use crate::use_callback;
|
||||||
/// #[component]
|
/// #[component]
|
||||||
/// fn Comp(count: u32) -> Element {
|
/// 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.
|
/// // 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!()
|
/// todo!()
|
||||||
/// }
|
/// }
|
||||||
|
|
|
@ -32,7 +32,7 @@ use dioxus_signals::{Memo, Signal};
|
||||||
/// #[component]
|
/// #[component]
|
||||||
/// fn Comp(count: u32) -> Element {
|
/// 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.
|
/// // 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!()
|
/// 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
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust, no_run
|
||||||
/// use dioxus::prelude::*;
|
/// use dioxus::prelude::*;
|
||||||
///
|
///
|
||||||
/// let data = 5;
|
/// let data = 5;
|
||||||
|
@ -104,7 +104,7 @@ pub fn use_reactive<O, D: Dependency>(
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust, no_run
|
||||||
/// use dioxus::prelude::*;
|
/// use dioxus::prelude::*;
|
||||||
///
|
///
|
||||||
/// let data = 5;
|
/// let data = 5;
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
|
|
||||||
use crate::{use_callback, use_signal, UseCallback};
|
use crate::{use_callback, use_signal, UseCallback};
|
||||||
use dioxus_core::prelude::*;
|
use dioxus_core::prelude::*;
|
||||||
use dioxus_core::{
|
|
||||||
prelude::{spawn, use_hook},
|
|
||||||
Task,
|
|
||||||
};
|
|
||||||
use dioxus_signals::*;
|
use dioxus_signals::*;
|
||||||
use futures_util::{future, pin_mut, FutureExt, StreamExt};
|
use futures_util::{future, pin_mut, FutureExt, StreamExt};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -66,7 +62,7 @@ use std::{cell::Cell, future::Future, rc::Rc};
|
||||||
/// #[component]
|
/// #[component]
|
||||||
/// fn Comp(count: u32) -> Element {
|
/// 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.
|
/// // 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!()
|
/// 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:
|
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::*;
|
use ar_namespace::*;
|
||||||
|
|
||||||
rsx! {
|
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.
|
Elements for dioxus must implement the (simple) DioxusElement trait to be used in the rsx! macro.
|
||||||
|
|
||||||
```rust
|
```rust, ignore
|
||||||
struct div;
|
struct div;
|
||||||
impl DioxusElement for div {
|
impl DioxusElement for div {
|
||||||
const TAG_NAME: &'static str = "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:
|
The HTML namespace is defined mostly with macros. However, the expanded form would look something like this:
|
||||||
|
|
||||||
```rust
|
```rust, ignore
|
||||||
struct base;
|
struct base;
|
||||||
impl DioxusElement for base {
|
impl DioxusElement for base {
|
||||||
const TAG_NAME: &'static str = "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.
|
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 {
|
mod dioxus_elements {
|
||||||
use dioxus::prelude::dioxus_elements::*;
|
use dioxus::prelude::dioxus_elements::*;
|
||||||
struct my_element;
|
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
|
/// If you enter a relative path, the web client automatically prefixes the host address in
|
||||||
/// `window.location` when creating a web socket to LiveView.
|
/// `window.location` when creating a web socket to LiveView.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```rust
|
||||||
|
/// use dioxus_liveview::interpreter_glue;
|
||||||
|
///
|
||||||
/// // Creates websocket connection to same host as current page
|
/// // Creates websocket connection to same host as current page
|
||||||
/// interpreter_glue("/api/liveview");
|
/// interpreter_glue("/api/liveview");
|
||||||
///
|
///
|
||||||
|
|
|
@ -20,6 +20,9 @@ quote = { workspace = true }
|
||||||
proc-macro2 = { workspace = true }
|
proc-macro2 = { workspace = true }
|
||||||
slab = { workspace = true }
|
slab = { workspace = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
dioxus = { workspace = true, features = ["router"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
web = []
|
web = []
|
||||||
|
|
|
@ -42,7 +42,9 @@ mod segment;
|
||||||
/// 2. By the order they are defined in the enum
|
/// 2. By the order they are defined in the enum
|
||||||
///
|
///
|
||||||
/// All features:
|
/// All features:
|
||||||
/// ```rust, skip
|
/// ```rust
|
||||||
|
/// use dioxus::prelude::*;
|
||||||
|
///
|
||||||
/// #[rustfmt::skip]
|
/// #[rustfmt::skip]
|
||||||
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||||
/// enum Route {
|
/// enum Route {
|
||||||
|
@ -75,9 +77,17 @@ mod segment;
|
||||||
/// #[redirect("/:id/user", |id: usize| Route::Route3 { dynamic: id.to_string()})]
|
/// #[redirect("/:id/user", |id: usize| Route::Route3 { dynamic: id.to_string()})]
|
||||||
/// #[route("/:dynamic")]
|
/// #[route("/:dynamic")]
|
||||||
/// Route3 { dynamic: String },
|
/// 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)]`
|
/// # `#[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.
|
/// 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.
|
/// 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)]
|
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||||
/// enum Route {
|
/// enum Route {
|
||||||
/// // Define routes that renders the IndexComponent
|
/// // Define routes that renders the IndexComponent
|
||||||
|
@ -97,6 +109,8 @@ mod segment;
|
||||||
/// #[route("/", Index)]
|
/// #[route("/", Index)]
|
||||||
/// Index {},
|
/// Index {},
|
||||||
/// }
|
/// }
|
||||||
|
/// # #[component]
|
||||||
|
/// # fn Index() -> Element { None }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # `#[redirect("path", function)]`
|
/// # `#[redirect("path", function)]`
|
||||||
|
@ -105,14 +119,18 @@ mod segment;
|
||||||
/// - `path`: The path to the enum variant (relative to the parent nest)
|
/// - `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
|
/// - `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)]
|
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||||
/// enum Route {
|
/// enum Route {
|
||||||
/// // Redirects the /:id route to the Index route
|
/// // Redirects the /:id route to the Index route
|
||||||
/// #[redirect("/:id", |_: usize| Route::Index {})]
|
/// #[redirect("/:id", |id: usize| Route::Index {})]
|
||||||
/// #[route("/", Index)]
|
/// #[route("/", Index)]
|
||||||
/// 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.
|
/// 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.
|
/// 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)]
|
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||||
/// enum Route {
|
/// enum Route {
|
||||||
/// // Nests all child routes in the /blog route
|
/// // Nests all child routes in the /blog route
|
||||||
/// #[nest("/blog")]
|
/// #[nest("/blog")]
|
||||||
/// // This is at /blog/:id
|
/// // This is at /blog/:id
|
||||||
/// #[redirect("/:id", |_: usize| Route::Index {})]
|
/// #[redirect("/:id", |id: usize| Route::Index {})]
|
||||||
/// // This is at /blog
|
/// // This is at /blog
|
||||||
/// #[route("/", Index)]
|
/// #[route("/", Index)]
|
||||||
/// Index {},
|
/// Index {},
|
||||||
/// }
|
/// }
|
||||||
|
/// # #[component]
|
||||||
|
/// # fn Index() -> Element { None }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # `#[end_nest]`
|
/// # `#[end_nest]`
|
||||||
///
|
///
|
||||||
/// The `#[end_nest]` attribute is used to end a nest. It takes no parameters.
|
/// 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)]
|
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||||
/// enum Route {
|
/// enum Route {
|
||||||
/// #[nest("/blog")]
|
/// #[nest("/blog")]
|
||||||
/// // This is at /blog/:id
|
/// // This is at /blog/:id
|
||||||
/// #[redirect("/:id", |_: usize| Route::Index {})]
|
/// #[redirect("/:id", |id: usize| Route::Index {})]
|
||||||
/// // This is at /blog
|
/// // This is at /blog
|
||||||
/// #[route("/", Index)]
|
/// #[route("/", Index)]
|
||||||
/// Index {},
|
/// Index {},
|
||||||
|
@ -156,6 +180,10 @@ mod segment;
|
||||||
/// #[route("/")]
|
/// #[route("/")]
|
||||||
/// Home {},
|
/// Home {},
|
||||||
/// }
|
/// }
|
||||||
|
/// # #[component]
|
||||||
|
/// # fn Index() -> Element { None }
|
||||||
|
/// # #[component]
|
||||||
|
/// # fn Home() -> Element { None }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # `#[layout(component)]`
|
/// # `#[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.
|
/// 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)]
|
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||||
/// enum Route {
|
/// enum Route {
|
||||||
/// #[layout(BlogFrame)]
|
/// #[layout(BlogFrame)]
|
||||||
/// #[redirect("/:id", |_: usize| Route::Index {})]
|
/// #[redirect("/:id", |id: usize| Route::Index {})]
|
||||||
/// // Index will be rendered in the Outlet of the BlogFrame component
|
/// // Index will be rendered in the Outlet of the BlogFrame component
|
||||||
/// #[route("/", Index)]
|
/// #[route("/", Index)]
|
||||||
/// Index {},
|
/// Index {},
|
||||||
/// }
|
/// }
|
||||||
|
/// # #[component]
|
||||||
|
/// # fn Index() -> Element { None }
|
||||||
|
/// # #[component]
|
||||||
|
/// # fn BlogFrame() -> Element { None }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # `#[end_layout]`
|
/// # `#[end_layout]`
|
||||||
///
|
///
|
||||||
/// The `#[end_layout]` attribute is used to end a layout. It takes no parameters.
|
/// 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)]
|
/// #[derive(Clone, Debug, PartialEq, Routable)]
|
||||||
/// enum Route {
|
/// enum Route {
|
||||||
/// #[layout(BlogFrame)]
|
/// #[layout(BlogFrame)]
|
||||||
/// #[redirect("/:id", |_: usize| Route::Index {})]
|
/// #[redirect("/:id", |id: usize| Route::Index {})]
|
||||||
/// // Index will be rendered in the Outlet of the BlogFrame component
|
/// // Index will be rendered in the Outlet of the BlogFrame component
|
||||||
/// #[route("/", Index)]
|
/// #[route("/", Index)]
|
||||||
/// Index {},
|
/// Index {},
|
||||||
|
@ -194,6 +230,12 @@ mod segment;
|
||||||
/// #[route("/")]
|
/// #[route("/")]
|
||||||
/// Home {},
|
/// Home {},
|
||||||
/// }
|
/// }
|
||||||
|
/// # #[component]
|
||||||
|
/// # fn Index() -> Element { None }
|
||||||
|
/// # #[component]
|
||||||
|
/// # fn BlogFrame() -> Element { None }
|
||||||
|
/// # #[component]
|
||||||
|
/// # fn Home() -> Element { None }
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_derive(
|
#[proc_macro_derive(
|
||||||
Routable,
|
Routable,
|
||||||
|
|
|
@ -73,7 +73,12 @@ pub fn GoBackButton(props: HistoryButtonProps) -> Element {
|
||||||
let disabled = !router.can_go_back();
|
let disabled = !router.can_go_back();
|
||||||
|
|
||||||
rsx! {
|
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 mut vdom = VirtualDom::new(App);
|
||||||
/// # let _ = vdom.rebuild();
|
/// # vdom.rebuild_in_place();
|
||||||
/// # assert_eq!(
|
/// # assert_eq!(
|
||||||
/// # dioxus_ssr::render(&vdom),
|
/// # dioxus_ssr::render(&vdom),
|
||||||
/// # r#"<button disabled="true" dioxus-prevent-default="onclick">go forward</button>"#
|
/// # 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();
|
let disabled = !router.can_go_forward();
|
||||||
|
|
||||||
rsx! {
|
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,26 +178,24 @@ impl Debug for LinkProps {
|
||||||
/// #[component]
|
/// #[component]
|
||||||
/// fn Index() -> Element {
|
/// fn Index() -> Element {
|
||||||
/// rsx! {
|
/// rsx! {
|
||||||
/// rsx! {
|
/// Link {
|
||||||
/// Link {
|
/// active_class: "active",
|
||||||
/// active_class: "active",
|
/// class: "link_class",
|
||||||
/// class: "link_class",
|
/// id: "link_id",
|
||||||
/// id: "link_id",
|
/// new_tab: true,
|
||||||
/// new_tab: true,
|
/// rel: "link_rel",
|
||||||
/// rel: "link_rel",
|
/// to: Route::Index {},
|
||||||
/// to: Route::Index {},
|
|
||||||
///
|
///
|
||||||
/// "A fully configured link"
|
/// "A fully configured link"
|
||||||
/// }
|
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// #
|
/// #
|
||||||
/// # let mut vdom = VirtualDom::new(App);
|
/// # let mut vdom = VirtualDom::new(App);
|
||||||
/// # let _ = vdom.rebuild();
|
/// # vdom.rebuild_in_place();
|
||||||
/// # assert_eq!(
|
/// # assert_eq!(
|
||||||
/// # dioxus_ssr::render(&vdom),
|
/// # 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)]
|
#[allow(non_snake_case)]
|
||||||
|
|
|
@ -65,7 +65,7 @@ use dioxus_lib::prelude::*;
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # let mut vdom = VirtualDom::new(App);
|
/// # 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>");
|
/// # assert_eq!(dioxus_ssr::render(&vdom), "<h1>App</h1><p>Child</p>");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn Outlet<R: Routable + Clone>() -> Element {
|
pub fn Outlet<R: Routable + Clone>() -> Element {
|
||||||
|
|
|
@ -46,7 +46,7 @@ use crate::prelude::{Navigator, RouterContext};
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # let mut vdom = VirtualDom::new(App);
|
/// # let mut vdom = VirtualDom::new(App);
|
||||||
/// # let _ = vdom.rebuild();
|
/// # vdom.rebuild_in_place();
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn use_navigator() -> Navigator {
|
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 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>")
|
/// # assert_eq!(dioxus_ssr::render(&vdom), "<h1>App</h1><h2>Current Path</h2><p>/</p>")
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
#[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 app: Component = |cx| rsx!(div {"hello world!"});
|
||||||
|
|
||||||
let mut vdom = VirtualDom::new(app);
|
let mut vdom = VirtualDom::new(app);
|
||||||
let _ = vdom.rebuild();
|
vdom.rebuild_in_place();
|
||||||
|
|
||||||
let text = dioxus_ssr::render(&vdom);
|
let text = dioxus_ssr::render(&vdom);
|
||||||
assert_eq!(text, "<div>hello world!</div>")
|
assert_eq!(text, "<div>hello world!</div>")
|
||||||
|
@ -45,7 +45,7 @@ let content = dioxus_ssr::render_element(rsx!{
|
||||||
|
|
||||||
```rust, ignore
|
```rust, ignore
|
||||||
let mut vdom = VirtualDom::new(app);
|
let mut vdom = VirtualDom::new(app);
|
||||||
let _ = vdom.rebuild();
|
vdom.rebuild_in_place();
|
||||||
|
|
||||||
let content = dioxus_ssr::render(&vdom);
|
let content = dioxus_ssr::render(&vdom);
|
||||||
```
|
```
|
||||||
|
@ -63,7 +63,7 @@ To enable pre-rendering, simply set the pre-rendering flag to true.
|
||||||
```rust, ignore
|
```rust, ignore
|
||||||
let mut vdom = VirtualDom::new(App);
|
let mut vdom = VirtualDom::new(App);
|
||||||
|
|
||||||
let _ = vdom.rebuild();
|
vdom.rebuild_in_place();
|
||||||
|
|
||||||
let mut renderer = dioxus_ssr::Renderer::new();
|
let mut renderer = dioxus_ssr::Renderer::new();
|
||||||
renderer.pre_render = true;
|
renderer.pre_render = true;
|
||||||
|
|
Loading…
Reference in a new issue