dioxus_router/components/
history_buttons.rs

1use dioxus_core::{Element, VNode};
2use dioxus_core_macro::{rsx, Props};
3use dioxus_html as dioxus_elements;
4
5use tracing::error;
6
7use crate::utils::use_router_internal::use_router_internal;
8
9/// The properties for a [`GoBackButton`] or a [`GoForwardButton`].
10#[derive(Debug, Props, Clone, PartialEq)]
11pub struct HistoryButtonProps {
12    /// The children to render within the generated HTML button tag.
13    pub children: Element,
14}
15
16/// A button to go back through the navigation history. Similar to a browsers back button.
17///
18/// Only works as descendant of a [`super::Link`] component, otherwise it will be inactive.
19///
20/// The button will disable itself if it is known that no prior history is available.
21///
22/// # Panic
23/// - When the [`GoBackButton`] is not nested within a [`super::Link`] component
24///   hook, but only in debug builds.
25///
26/// # Example
27/// ```rust
28/// # use dioxus::prelude::*;
29/// #[derive(Clone, Routable)]
30/// enum Route {
31///     #[route("/")]
32///     Index {},
33/// }
34///
35/// #[component]
36/// fn App() -> Element {
37///     rsx! {
38///         Router::<Route> {}
39///     }
40/// }
41///
42/// #[component]
43/// fn Index() -> Element {
44///     rsx! {
45///         GoBackButton {
46///             "go back"
47///         }
48///     }
49/// }
50/// #
51/// # let mut vdom = VirtualDom::new(App);
52/// # vdom.rebuild_in_place();
53/// # assert_eq!(
54/// #     dioxus_ssr::render(&vdom),
55/// #     r#"<button disabled="true">go back</button>"#
56/// # );
57/// ```
58pub fn GoBackButton(props: HistoryButtonProps) -> Element {
59    let HistoryButtonProps { children } = props;
60
61    // hook up to router
62    let router = match use_router_internal() {
63        Some(r) => r,
64        #[allow(unreachable_code)]
65        None => {
66            let msg = "`GoBackButton` must have access to a parent router";
67            error!("{msg}, will be inactive");
68            #[cfg(debug_assertions)]
69            panic!("{}", msg);
70            return VNode::empty();
71        }
72    };
73
74    let disabled = !router.can_go_back();
75
76    rsx! {
77        button {
78            disabled: "{disabled}",
79            onclick: move |evt| {
80                evt.prevent_default();
81                router.go_back()
82            },
83            {children}
84        }
85    }
86}
87
88/// A button to go forward through the navigation history. Similar to a browsers forward button.
89///
90/// Only works as descendant of a [`super::Link`] component, otherwise it will be inactive.
91///
92/// The button will disable itself if it is known that no later history is available.
93///
94/// # Panic
95/// - When the [`GoForwardButton`] is not nested within a [`super::Link`] component
96///   hook, but only in debug builds.
97///
98/// # Example
99/// ```rust
100/// # use dioxus::prelude::*;
101/// #[derive(Clone, Routable)]
102/// enum Route {
103///     #[route("/")]
104///     Index {},
105/// }
106///
107/// #[component]
108/// fn App() -> Element {
109///     rsx! {
110///         Router::<Route> {}
111///     }
112/// }
113///
114/// #[component]
115/// fn Index() -> Element {
116///     rsx! {
117///         GoForwardButton {
118///             "go forward"
119///         }
120///     }
121/// }
122/// #
123/// # let mut vdom = VirtualDom::new(App);
124/// # vdom.rebuild_in_place();
125/// # assert_eq!(
126/// #     dioxus_ssr::render(&vdom),
127/// #     r#"<button disabled="true">go forward</button>"#
128/// # );
129/// ```
130pub fn GoForwardButton(props: HistoryButtonProps) -> Element {
131    let HistoryButtonProps { children } = props;
132
133    // hook up to router
134    let router = match use_router_internal() {
135        Some(r) => r,
136        #[allow(unreachable_code)]
137        None => {
138            let msg = "`GoForwardButton` must have access to a parent router";
139            error!("{msg}, will be inactive");
140            #[cfg(debug_assertions)]
141            panic!("{}", msg);
142            return VNode::empty();
143        }
144    };
145
146    let disabled = !router.can_go_forward();
147
148    rsx! {
149        button {
150            disabled: "{disabled}",
151            onclick: move |evt| {
152                evt.prevent_default();
153                router.go_forward()
154            },
155            {children}
156        }
157    }
158}