mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 12:43:08 +00:00
Merge pull request #1916 from DogeDark/master
Add Prerelease Doc Generation
This commit is contained in:
commit
f4651cecb8
29 changed files with 191 additions and 425 deletions
60
.github/workflows/docs.yml
vendored
60
.github/workflows/docs.yml
vendored
|
@ -1,49 +1,37 @@
|
|||
name: github pages
|
||||
|
||||
name: Deploy Nightly Docs
|
||||
on:
|
||||
workflow_dispatch:
|
||||
# push:
|
||||
# paths:
|
||||
# - docs/**
|
||||
# - .github/workflows/docs.yml
|
||||
# branches:
|
||||
# - master
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build-deploy:
|
||||
deploy:
|
||||
name: Build & Deploy
|
||||
runs-on: ubuntu-latest
|
||||
environment: docs
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
|
||||
# NOTE: Comment out when https://github.com/rust-lang/mdBook/pull/1306 is merged and released
|
||||
# - name: Setup mdBook
|
||||
# uses: peaceiris/actions-mdbook@v1
|
||||
# with:
|
||||
# mdbook-version: "0.4.10"
|
||||
|
||||
# NOTE: Delete when the previous one is enabled
|
||||
- name: Setup mdBook
|
||||
run: |
|
||||
cargo install mdbook --git https://github.com/Demonthos/mdBook.git --branch master
|
||||
- uses: actions/checkout@v4
|
||||
- run: sudo apt-get update
|
||||
- run: sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
cache-all-crates: "true"
|
||||
save-if: ${{ github.ref == 'refs/heads/master' }}
|
||||
- uses: ilammy/setup-nasm@v1
|
||||
|
||||
- name: Build
|
||||
run: cd docs &&
|
||||
cd guide && mdbook build -d ../nightly/guide && cd .. &&
|
||||
cd router && mdbook build -d ../nightly/router && cd ..
|
||||
# cd reference && mdbook build -d ../nightly/reference && cd .. &&
|
||||
# cd fermi && mdbook build -d ../nightly/fermi && cd ..
|
||||
- name: cargo doc
|
||||
run: cargo doc --no-deps --workspace --all-features
|
||||
|
||||
- name: Deploy 🚀
|
||||
- name: Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@v4.5.0
|
||||
with:
|
||||
branch: gh-pages # The branch the action should deploy to.
|
||||
folder: docs/nightly # The folder the action should deploy.
|
||||
target-folder: docs/nightly
|
||||
branch: gh-pages
|
||||
folder: target/doc
|
||||
target-folder: api-docs/nightly
|
||||
repository-name: dioxuslabs/docsite
|
||||
clean: false
|
||||
token: ${{ secrets.DEPLOY_KEY }} # let's pretend I don't need it for now
|
||||
|
||||
|
|
|
@ -112,12 +112,6 @@ async fn setup_file_watcher<F: Fn() -> Result<BuildResult> + Send + 'static>(
|
|||
},
|
||||
web_info.clone(),
|
||||
);
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
let _ = PluginManager::on_serve_rebuild(
|
||||
chrono::Local::now().timestamp(),
|
||||
e.paths,
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
last_update_time = chrono::Local::now().timestamp();
|
||||
|
|
|
@ -140,12 +140,12 @@ impl ErrorBoundary {
|
|||
///
|
||||
/// ```rust, ignore
|
||||
/// #[component]
|
||||
/// fn app( count: String) -> Element {
|
||||
/// fn app(count: String) -> Element {
|
||||
/// let id: i32 = count.parse().throw()?;
|
||||
///
|
||||
/// rsx! {
|
||||
/// div { "Count {}" }
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait Throw<S = ()>: Sized {
|
||||
|
@ -170,7 +170,7 @@ pub trait Throw<S = ()>: Sized {
|
|||
///
|
||||
/// rsx! {
|
||||
/// div { "Count {}" }
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn throw(self) -> Option<Self::Out>;
|
||||
|
@ -193,7 +193,7 @@ pub trait Throw<S = ()>: Sized {
|
|||
///
|
||||
/// rsx! {
|
||||
/// div { "Count {}" }
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn throw_with<D: Debug + 'static>(self, e: impl FnOnce() -> D) -> Option<Self::Out> {
|
||||
|
|
|
@ -159,7 +159,7 @@ impl<T: std::fmt::Debug> std::fmt::Debug for Event<T> {
|
|||
/// button {
|
||||
/// onclick: move |evt| cx.onclick.call(evt),
|
||||
/// }
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// ```
|
||||
|
|
|
@ -42,7 +42,7 @@ pub(crate) mod innerlude {
|
|||
/// An Errored [`Element`] will propagate the error to the nearest error boundary.
|
||||
pub type Element = Option<VNode>;
|
||||
|
||||
/// A [`Component`] is a function that takes a [`Scope`] and returns an [`Element`].
|
||||
/// A [`Component`] is a function that takes [`Properties`] and returns an [`Element`].
|
||||
///
|
||||
/// Components can be used in other components with two syntax options:
|
||||
/// - lowercase as a function call with named arguments (rust style)
|
||||
|
@ -84,7 +84,7 @@ pub use crate::innerlude::{
|
|||
|
||||
/// The purpose of this module is to alleviate imports of many common types
|
||||
///
|
||||
/// This includes types like [`Scope`], [`Element`], and [`Component`].
|
||||
/// This includes types like [`Element`], and [`Component`].
|
||||
pub mod prelude {
|
||||
pub use crate::innerlude::{
|
||||
consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, flush_sync,
|
||||
|
|
|
@ -24,7 +24,7 @@ use std::{any::Any, collections::BTreeSet, rc::Rc};
|
|||
///
|
||||
/// ## Guide
|
||||
///
|
||||
/// Components are defined as simple functions that take [`Scope`] and return an [`Element`].
|
||||
/// Components are defined as simple functions that take [`crate::properties::Properties`] and return an [`Element`].
|
||||
///
|
||||
/// ```rust
|
||||
/// # use dioxus::prelude::*;
|
||||
|
@ -218,7 +218,7 @@ impl VirtualDom {
|
|||
/// # Example
|
||||
/// ```rust, ignore
|
||||
/// fn Example() -> Element {
|
||||
/// rsx!( div { "hello world" } ))
|
||||
/// rsx!( div { "hello world" } )
|
||||
/// }
|
||||
///
|
||||
/// let dom = VirtualDom::new(Example);
|
||||
|
@ -526,7 +526,7 @@ impl VirtualDom {
|
|||
///
|
||||
/// # Example
|
||||
/// ```rust, ignore
|
||||
/// static app: Component = |cx| rsx!{ "hello world" });
|
||||
/// static app: Component = |cx| rsx!{ "hello world" };
|
||||
///
|
||||
/// let mut dom = VirtualDom::new();
|
||||
/// let edits = dom.rebuild();
|
||||
|
|
|
@ -55,6 +55,9 @@ warp = ["dioxus-fullstack?/warp", "ssr", "dioxus-liveview?/warp"]
|
|||
rocket = ["dioxus-liveview?/rocket"]
|
||||
tui = ["dioxus-tui", "dioxus-config-macro/tui"]
|
||||
|
||||
# This feature enables some nightly flags that make it more clear what structs/methods are available in each feature
|
||||
nightly-doc = []
|
||||
|
||||
[dev-dependencies]
|
||||
futures-util = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
|
|
@ -50,7 +50,7 @@ fn main() {
|
|||
// It's not required, but highly recommended. For example, UpperCamelCase components will not generate a warning.
|
||||
#[component]
|
||||
fn App() -> Element {
|
||||
rsx!("hello world!"))
|
||||
rsx!("hello world!")
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -97,13 +97,12 @@ If we want to omit the boilerplate of `cx.render`, we can simply pass in
|
|||
render nodes in match statements.
|
||||
|
||||
```rust, ignore
|
||||
#[component[
|
||||
#[component]
|
||||
fn Example() -> Element {
|
||||
|
||||
// both of these are equivalent
|
||||
rsx!("hello world"))
|
||||
rsx!("hello world");
|
||||
|
||||
rsx!("hello world!")
|
||||
rsx!("hello world!");
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -127,7 +126,7 @@ fn App() -> Element {
|
|||
))
|
||||
|
||||
}
|
||||
))
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -147,7 +146,7 @@ fn App() -> Element {
|
|||
title: "My App",
|
||||
color: "red",
|
||||
}
|
||||
))
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -169,7 +168,7 @@ fn Header(cx: Scope<HeaderProps>) -> Element {
|
|||
background_color: "{cx.props.color}"
|
||||
h1 { "{cx.props.title}" }
|
||||
}
|
||||
))
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -184,7 +183,7 @@ fn Header(title: String, color: String) -> Element {
|
|||
background_color: "{color}"
|
||||
h1 { "{title}" }
|
||||
}
|
||||
))
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -201,13 +200,13 @@ struct HeaderProps<'a> {
|
|||
}
|
||||
|
||||
#[component]
|
||||
fn Header(props: HeaderProps -> Element {
|
||||
fn Header(props: HeaderProps) -> Element {
|
||||
rsx!(
|
||||
div {
|
||||
background_color: "{cx.props.color}"
|
||||
h1 { "{cx.props.title}" }
|
||||
}
|
||||
))
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -299,7 +298,7 @@ fn App() -> Element {
|
|||
div { "Count: {count}" }
|
||||
button { onclick: move |_| count.set(count + 1), "Increment" }
|
||||
button { onclick: move |_| count.set(count - 1), "Decrement" }
|
||||
))
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ impl LaunchBuilder {
|
|||
|
||||
/// Launch your web application.
|
||||
#[cfg(feature = "web")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))]
|
||||
pub fn web() -> LaunchBuilder<dioxus_web::Config, UnsendContext> {
|
||||
LaunchBuilder {
|
||||
launch_fn: dioxus_web::launch::launch,
|
||||
|
@ -48,6 +49,7 @@ impl LaunchBuilder {
|
|||
|
||||
/// Launch your desktop application.
|
||||
#[cfg(feature = "desktop")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))]
|
||||
pub fn desktop() -> LaunchBuilder<dioxus_desktop::Config, UnsendContext> {
|
||||
LaunchBuilder {
|
||||
launch_fn: dioxus_desktop::launch::launch,
|
||||
|
@ -58,6 +60,7 @@ impl LaunchBuilder {
|
|||
|
||||
/// Launch your fullstack application.
|
||||
#[cfg(feature = "fullstack")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))]
|
||||
pub fn fullstack() -> LaunchBuilder<dioxus_fullstack::Config, SendContext> {
|
||||
LaunchBuilder {
|
||||
launch_fn: dioxus_fullstack::launch::launch,
|
||||
|
@ -68,6 +71,7 @@ impl LaunchBuilder {
|
|||
|
||||
/// Launch your fullstack application.
|
||||
#[cfg(feature = "mobile")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "mobile")))]
|
||||
pub fn mobile() -> LaunchBuilder<dioxus_mobile::Config, UnsendContext> {
|
||||
LaunchBuilder {
|
||||
launch_fn: dioxus_mobile::launch::launch,
|
||||
|
@ -77,6 +81,7 @@ impl LaunchBuilder {
|
|||
}
|
||||
|
||||
#[cfg(feature = "tui")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))]
|
||||
/// Launch your tui application
|
||||
pub fn tui() -> LaunchBuilder<dioxus_tui::Config, UnsendContext> {
|
||||
LaunchBuilder {
|
||||
|
@ -209,24 +214,28 @@ pub fn launch(app: fn() -> Element) {
|
|||
}
|
||||
|
||||
#[cfg(feature = "web")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))]
|
||||
/// Launch your web application without any additional configuration. See [`LaunchBuilder`] for more options.
|
||||
pub fn launch_web(app: fn() -> Element) {
|
||||
LaunchBuilder::web().launch(app)
|
||||
}
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))]
|
||||
/// Launch your desktop application without any additional configuration. See [`LaunchBuilder`] for more options.
|
||||
pub fn launch_desktop(app: fn() -> Element) {
|
||||
LaunchBuilder::desktop().launch(app)
|
||||
}
|
||||
|
||||
#[cfg(feature = "fullstack")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))]
|
||||
/// Launch your fullstack application without any additional configuration. See [`LaunchBuilder`] for more options.
|
||||
pub fn launch_fullstack(app: fn() -> Element) {
|
||||
LaunchBuilder::fullstack().launch(app)
|
||||
}
|
||||
|
||||
#[cfg(feature = "tui")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))]
|
||||
/// Launch your tui application without any additional configuration. See [`LaunchBuilder`] for more options.
|
||||
pub fn launch_tui(app: fn() -> Element) {
|
||||
LaunchBuilder::tui().launch(app)
|
||||
|
|
|
@ -1,88 +1,114 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||
#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||
#![cfg_attr(any(docsrs, feature = "nightly-doc"), feature(doc_cfg))]
|
||||
|
||||
pub use dioxus_core;
|
||||
|
||||
#[cfg(feature = "launch")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "launch")))]
|
||||
mod launch;
|
||||
|
||||
#[cfg(feature = "hooks")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "hooks")))]
|
||||
pub use dioxus_hooks as hooks;
|
||||
|
||||
#[cfg(feature = "signals")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "signals")))]
|
||||
pub use dioxus_signals as signals;
|
||||
|
||||
pub mod events {
|
||||
#[cfg(feature = "html")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))]
|
||||
pub use dioxus_html::prelude::*;
|
||||
}
|
||||
|
||||
#[cfg(feature = "html")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))]
|
||||
pub use dioxus_html as html;
|
||||
|
||||
#[cfg(feature = "macro")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "macro")))]
|
||||
pub use dioxus_core_macro as core_macro;
|
||||
|
||||
pub mod prelude {
|
||||
#[cfg(feature = "launch")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "launch")))]
|
||||
pub use crate::launch::*;
|
||||
|
||||
#[cfg(feature = "hooks")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "hooks")))]
|
||||
pub use crate::hooks::*;
|
||||
|
||||
#[cfg(feature = "signals")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "signals")))]
|
||||
pub use dioxus_signals::*;
|
||||
|
||||
pub use dioxus_core::prelude::*;
|
||||
|
||||
#[cfg(feature = "macro")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "macro")))]
|
||||
#[allow(deprecated)]
|
||||
pub use dioxus_core_macro::{component, format_args_f, inline_props, render, rsx, Props};
|
||||
|
||||
#[cfg(feature = "launch")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "launch")))]
|
||||
pub use dioxus_config_macro::*;
|
||||
|
||||
#[cfg(feature = "html")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))]
|
||||
pub use dioxus_html as dioxus_elements;
|
||||
|
||||
#[cfg(feature = "html")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))]
|
||||
pub use dioxus_elements::{prelude::*, GlobalAttributes, SvgAttributes};
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "hot-reload"))]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "hot-reload")))]
|
||||
pub use dioxus_hot_reload::{self, hot_reload_init};
|
||||
|
||||
pub use dioxus_core;
|
||||
|
||||
#[cfg(feature = "fullstack")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))]
|
||||
pub use dioxus_fullstack::prelude::*;
|
||||
|
||||
#[cfg(feature = "router")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))]
|
||||
pub use dioxus_router;
|
||||
#[cfg(feature = "router")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))]
|
||||
pub use dioxus_router::prelude::*;
|
||||
}
|
||||
|
||||
#[cfg(feature = "web")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))]
|
||||
pub use dioxus_web as web;
|
||||
|
||||
#[cfg(feature = "router")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))]
|
||||
pub use dioxus_router as router;
|
||||
|
||||
#[cfg(feature = "fullstack")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))]
|
||||
pub use dioxus_fullstack as fullstack;
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))]
|
||||
pub use dioxus_desktop as desktop;
|
||||
|
||||
#[cfg(feature = "mobile")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "mobile")))]
|
||||
pub use dioxus_desktop as mobile;
|
||||
|
||||
#[cfg(feature = "liveview")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "liveview")))]
|
||||
pub use dioxus_liveview as liveview;
|
||||
|
||||
#[cfg(feature = "tui")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))]
|
||||
pub use dioxus_tui as tui;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "ssr")))]
|
||||
pub use dioxus_ssr as ssr;
|
||||
|
|
|
@ -81,3 +81,5 @@ salvo = ["dep:salvo", "server", "http-body-util"]
|
|||
server = ["server_fn/ssr", "dioxus_server_macro/server", "tokio", "tokio-util", "tokio-stream", "dioxus-ssr", "dioxus-ssr/incremental", "tower", "hyper", "http", "tower-layer", "anymap", "tracing-futures", "pin-project", "thiserror", "dioxus-cli-config"]
|
||||
default-tls = ["server_fn/default-tls"]
|
||||
rustls = ["server_fn/rustls"]
|
||||
# This feature enables some nightly flags that make it more clear what structs/methods are available in each feature
|
||||
nightly-doc = []
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
// ```
|
||||
|
||||
use axum_desktop::*;
|
||||
use dioxus_fullstack::prelude::server_fn::set_server_url;
|
||||
|
||||
fn main() {
|
||||
// Set the url of the server where server functions are hosted.
|
||||
set_server_url("http://127.0.0.1:8080");
|
||||
#[cfg(not(feature = "server"))]
|
||||
dioxus::fullstack::prelude::server_fn::set_server_url("http://127.0.0.1:8080");
|
||||
dioxus::desktop::launch(app)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// ```
|
||||
|
||||
use axum_desktop::*;
|
||||
use dioxus_fullstack::prelude::*;
|
||||
use dioxus::prelude::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
|
|
@ -27,7 +27,7 @@ async fn main() {
|
|||
}
|
||||
|
||||
// Hydrate the page
|
||||
#[cfg(feature = "web")]
|
||||
#[cfg(all(feature = "web", not(feature = "server")))]
|
||||
fn main() {
|
||||
dioxus_web::launch_with_props(
|
||||
dioxus_fullstack::router::RouteWithCfg::<Route>,
|
||||
|
|
|
@ -332,7 +332,7 @@ where
|
|||
}
|
||||
|
||||
fn connect_hot_reload(self) -> Self {
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))]
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload"))]
|
||||
{
|
||||
self.nest(
|
||||
"/_dioxus",
|
||||
|
@ -354,7 +354,7 @@ where
|
|||
.route("/hot_reload", get(hot_reload_handler)),
|
||||
)
|
||||
}
|
||||
#[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "server")))]
|
||||
#[cfg(not(all(debug_assertions, feature = "hot-reload")))]
|
||||
{
|
||||
self
|
||||
}
|
||||
|
@ -476,7 +476,7 @@ fn report_err<E: std::fmt::Display>(e: E) -> Response<BoxBody> {
|
|||
}
|
||||
|
||||
/// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change.
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))]
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload"))]
|
||||
pub async fn hot_reload_handler(ws: axum::extract::WebSocketUpgrade) -> impl IntoResponse {
|
||||
use axum::extract::ws::Message;
|
||||
use futures_util::StreamExt;
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
#[cfg(feature = "axum")]
|
||||
pub mod axum_adapter;
|
||||
#[cfg(feature = "salvo")]
|
||||
pub mod salvo_adapter;
|
||||
// #[cfg(feature = "salvo")]
|
||||
// pub mod salvo_adapter;
|
||||
#[cfg(feature = "warp")]
|
||||
pub mod warp_adapter;
|
||||
|
||||
|
|
|
@ -291,17 +291,20 @@ impl DioxusRouterExt for Router {
|
|||
) -> Self {
|
||||
let cfg = cfg.into();
|
||||
|
||||
self.serve_static_assets(cfg.assets_path)
|
||||
self.serve_static_assets(cfg.assets_path.clone())
|
||||
.connect_hot_reload()
|
||||
.register_server_fns(server_fn_path)
|
||||
.push(Router::with_path("/<**any_path>").get(SSRHandler { cfg }))
|
||||
.push(Router::with_path("/<**any_path>").get(SSRHandler {
|
||||
config: cfg,
|
||||
virtual_dom: virtual_dom_factory,
|
||||
}))
|
||||
}
|
||||
|
||||
fn connect_hot_reload(self) -> Self {
|
||||
let mut _dioxus_router = Router::with_path("_dioxus");
|
||||
_dioxus_router =
|
||||
_dioxus_router.push(Router::with_path("hot_reload").handle(HotReloadHandler));
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))]
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload"))]
|
||||
{
|
||||
_dioxus_router = _dioxus_router.push(Router::with_path("disconnect").handle(ignore_ws));
|
||||
}
|
||||
|
@ -485,11 +488,11 @@ fn handle_error(error: impl Error + Send + Sync, res: &mut Response) {
|
|||
}
|
||||
|
||||
/// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change.
|
||||
#[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "server")))]
|
||||
#[cfg(not(all(debug_assertions, feature = "hot-reload")))]
|
||||
#[derive(Default)]
|
||||
pub struct HotReloadHandler;
|
||||
|
||||
#[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "server")))]
|
||||
#[cfg(not(all(debug_assertions, feature = "hot-reload")))]
|
||||
#[handler]
|
||||
impl HotReloadHandler {
|
||||
async fn handle(
|
||||
|
@ -503,11 +506,11 @@ impl HotReloadHandler {
|
|||
}
|
||||
|
||||
/// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change.
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))]
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload"))]
|
||||
#[derive(Default)]
|
||||
pub struct HotReloadHandler;
|
||||
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))]
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload"))]
|
||||
#[handler]
|
||||
impl HotReloadHandler {
|
||||
async fn handle(
|
||||
|
@ -561,7 +564,7 @@ impl HotReloadHandler {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))]
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload"))]
|
||||
#[handler]
|
||||
async fn ignore_ws(req: &mut Request, res: &mut Response) -> Result<(), salvo::http::StatusError> {
|
||||
use salvo::websocket::WebSocketUpgrade;
|
||||
|
|
|
@ -187,7 +187,7 @@ pub fn serve_dioxus_application(
|
|||
) -> BoxedFilter<(impl Reply,)> {
|
||||
let cfg = cfg.into();
|
||||
// Serve the dist folder and the index.html file
|
||||
let serve_dir = warp::fs::dir(cfg.assets_path);
|
||||
let serve_dir = warp::fs::dir(cfg.assets_path.clone());
|
||||
|
||||
let virtual_dom_factory =
|
||||
Arc::new(virtual_dom_factory) as Arc<dyn Fn() -> VirtualDom + Send + Sync + 'static>;
|
||||
|
@ -332,13 +332,13 @@ impl warp::reject::Reject for RecieveFailed {}
|
|||
/// ```
|
||||
pub fn connect_hot_reload() -> impl Filter<Extract = (impl Reply,), Error = warp::Rejection> + Clone
|
||||
{
|
||||
#[cfg(not(all(debug_assertions, feature = "hot-reload", feature = "server")))]
|
||||
#[cfg(not(all(debug_assertions, feature = "hot-reload")))]
|
||||
{
|
||||
warp::path!("_dioxus" / "hot_reload")
|
||||
.map(warp::reply)
|
||||
.map(|reply| warp::reply::with_status(reply, warp::http::StatusCode::NOT_FOUND))
|
||||
}
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))]
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload"))]
|
||||
{
|
||||
use crate::hot_reload::HotReloadState;
|
||||
use futures_util::sink::SinkExt;
|
||||
|
@ -349,7 +349,7 @@ pub fn connect_hot_reload() -> impl Filter<Extract = (impl Reply,), Error = warp
|
|||
.and(warp::any().then(crate::hot_reload::spawn_hot_reload))
|
||||
.and(warp::ws())
|
||||
.map(move |state: &'static HotReloadState, ws: warp::ws::Ws| {
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))]
|
||||
// #[cfg(all(debug_assertions, feature = "hot-reload"))]
|
||||
ws.on_upgrade(move |mut websocket| {
|
||||
async move {
|
||||
println!("🔥 Hot Reload WebSocket connected");
|
||||
|
@ -393,7 +393,7 @@ pub fn connect_hot_reload() -> impl Filter<Extract = (impl Reply,), Error = warp
|
|||
.and(warp::ws())
|
||||
.map(move |ws: warp::ws::Ws| {
|
||||
println!("disconnect");
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))]
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload",))]
|
||||
ws.on_upgrade(move |mut websocket| async move {
|
||||
struct DisconnectOnDrop(Option<warp::ws::WebSocket>);
|
||||
impl Drop for DisconnectOnDrop {
|
||||
|
|
|
@ -53,6 +53,7 @@ impl Config {
|
|||
|
||||
/// Set the address to serve the app on.
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
pub fn addr(self, addr: impl Into<std::net::SocketAddr>) -> Self {
|
||||
let addr = addr.into();
|
||||
Self { addr, ..self }
|
||||
|
@ -60,6 +61,7 @@ impl Config {
|
|||
|
||||
/// Set the route to the server functions.
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
pub fn server_fn_route(self, server_fn_route: &'static str) -> Self {
|
||||
Self {
|
||||
server_fn_route,
|
||||
|
@ -69,6 +71,7 @@ impl Config {
|
|||
|
||||
/// Set the incremental renderer config.
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
pub fn incremental(self, cfg: IncrementalRendererConfig) -> Self {
|
||||
Self {
|
||||
server_cfg: self.server_cfg.incremental(cfg),
|
||||
|
@ -78,18 +81,21 @@ impl Config {
|
|||
|
||||
/// Set the server config.
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
pub fn server_cfg(self, server_cfg: ServeConfigBuilder) -> Self {
|
||||
Self { server_cfg, ..self }
|
||||
}
|
||||
|
||||
/// Set the web config.
|
||||
#[cfg(feature = "web")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))]
|
||||
pub fn web_cfg(self, web_cfg: dioxus_web::Config) -> Self {
|
||||
Self { web_cfg, ..self }
|
||||
}
|
||||
|
||||
/// Set the desktop config.
|
||||
#[cfg(feature = "desktop")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))]
|
||||
pub fn desktop_cfg(self, desktop_cfg: dioxus_desktop::Config) -> Self {
|
||||
Self {
|
||||
desktop_cfg,
|
||||
|
@ -99,11 +105,13 @@ impl Config {
|
|||
|
||||
/// Set the mobile config.
|
||||
#[cfg(feature = "mobile")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "mobile")))]
|
||||
pub fn mobile_cfg(self, mobile_cfg: dioxus_mobile::Config) -> Self {
|
||||
Self { mobile_cfg, ..self }
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
/// Launch a server application
|
||||
pub async fn launch_server(
|
||||
self,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||
#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(any(docsrs, feature = "nightly-doc"), feature(doc_cfg))]
|
||||
|
||||
pub use once_cell;
|
||||
|
||||
|
@ -9,8 +10,20 @@ mod html_storage;
|
|||
|
||||
#[cfg(feature = "server")]
|
||||
mod adapters;
|
||||
// Splitting up the glob export lets us document features required for each adapter
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "axum")))]
|
||||
#[cfg(feature = "axum")]
|
||||
pub use adapters::axum_adapter;
|
||||
// TODO: Compilation seems to be broken with the salvo feature enabled. Fix and add more features to checks in CI
|
||||
// #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "salvo")))]
|
||||
// #[cfg(feature = "salvo")]
|
||||
// pub use adapters::salvo_adapter;
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "warp")))]
|
||||
#[cfg(feature = "warp")]
|
||||
pub use adapters::warp_adapter;
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
#[cfg(feature = "server")]
|
||||
pub use adapters::*;
|
||||
pub use adapters::{server_fn_service, ServerFnHandler};
|
||||
mod config;
|
||||
mod hooks;
|
||||
#[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))]
|
||||
|
@ -30,35 +43,57 @@ mod server_fn;
|
|||
/// A prelude of commonly used items in dioxus-fullstack.
|
||||
pub mod prelude {
|
||||
#[cfg(feature = "axum")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "axum")))]
|
||||
pub use crate::adapters::axum_adapter::*;
|
||||
#[cfg(feature = "salvo")]
|
||||
pub use crate::adapters::salvo_adapter::*;
|
||||
// #[cfg(feature = "salvo")]
|
||||
// #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "salvo")))]
|
||||
// pub use crate::adapters::salvo_adapter::*;
|
||||
#[cfg(feature = "warp")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "warp")))]
|
||||
pub use crate::adapters::warp_adapter::*;
|
||||
use crate::hooks;
|
||||
#[cfg(not(feature = "server"))]
|
||||
#[cfg_attr(
|
||||
any(docsrs, feature = "nightly-doc"),
|
||||
doc(cfg(not(feature = "server")))
|
||||
)]
|
||||
pub use crate::html_storage::deserialize::get_root_props_from_document;
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
pub use crate::layer::{Layer, Service};
|
||||
#[cfg(all(feature = "server", feature = "router"))]
|
||||
#[cfg_attr(
|
||||
any(docsrs, feature = "nightly-doc"),
|
||||
doc(cfg(all(feature = "server", feature = "router")))
|
||||
)]
|
||||
pub use crate::render::pre_cache_static_routes_with_props;
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
pub use crate::render::SSRState;
|
||||
#[cfg(feature = "router")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))]
|
||||
pub use crate::router::FullstackRouterConfig;
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
pub use crate::serve_config::{ServeConfig, ServeConfigBuilder};
|
||||
#[cfg(all(feature = "server", feature = "axum"))]
|
||||
#[cfg_attr(
|
||||
any(docsrs, feature = "nightly-doc"),
|
||||
doc(cfg(all(feature = "server", feature = "axum")))
|
||||
)]
|
||||
pub use crate::server_context::Axum;
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
pub use crate::server_context::{
|
||||
extract, server_context, DioxusServerContext, FromServerContext, ProvideServerContext,
|
||||
};
|
||||
pub use crate::server_fn::DioxusServerFn;
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
pub use crate::server_fn::{ServerFnMiddleware, ServerFnTraitObj, ServerFunction};
|
||||
pub use dioxus_server_macro::*;
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
pub use dioxus_ssr::incremental::IncrementalRendererConfig;
|
||||
pub use server_fn::{self, ServerFn as _, ServerFnError};
|
||||
|
||||
|
@ -66,11 +101,26 @@ pub mod prelude {
|
|||
}
|
||||
|
||||
// Warn users about overlapping features
|
||||
#[cfg(all(feature = "server", feature = "web", not(doc)))]
|
||||
#[cfg(all(
|
||||
feature = "server",
|
||||
feature = "web",
|
||||
not(doc),
|
||||
not(feature = "nightly-doc")
|
||||
))]
|
||||
compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `web` feature are overlapping. Please choose one or the other.");
|
||||
|
||||
#[cfg(all(feature = "server", feature = "desktop", not(doc)))]
|
||||
#[cfg(all(
|
||||
feature = "server",
|
||||
feature = "desktop",
|
||||
not(doc),
|
||||
not(feature = "nightly-doc")
|
||||
))]
|
||||
compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `desktop` feature are overlapping. Please choose one or the other.");
|
||||
|
||||
#[cfg(all(feature = "server", feature = "mobile", not(doc)))]
|
||||
#[cfg(all(
|
||||
feature = "server",
|
||||
feature = "mobile",
|
||||
not(doc),
|
||||
not(feature = "nightly-doc")
|
||||
))]
|
||||
compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `mobile` feature are overlapping. Please choose one or the other.");
|
||||
|
|
|
@ -228,6 +228,7 @@ impl<T: Send + Sync + Clone + 'static> FromServerContext for FromContext<T> {
|
|||
}
|
||||
|
||||
#[cfg(feature = "axum")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "axum")))]
|
||||
/// An adapter for axum extractors for the server context
|
||||
pub struct Axum;
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#[cfg(any(feature = "server", doc))]
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
#[derive(Clone)]
|
||||
/// A trait object for a function that be called on serializable arguments and returns a serializable result.
|
||||
pub struct ServerFnTraitObj(server_fn::ServerFnTraitObj<()>);
|
||||
|
||||
#[cfg(any(feature = "server", doc))]
|
||||
#[cfg(feature = "server")]
|
||||
impl std::ops::Deref for ServerFnTraitObj {
|
||||
type Target = server_fn::ServerFnTraitObj<()>;
|
||||
|
||||
|
@ -12,14 +13,14 @@ impl std::ops::Deref for ServerFnTraitObj {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "server", doc))]
|
||||
#[cfg(feature = "server")]
|
||||
impl std::ops::DerefMut for ServerFnTraitObj {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "server", doc))]
|
||||
#[cfg(feature = "server")]
|
||||
impl ServerFnTraitObj {
|
||||
fn new(
|
||||
prefix: &'static str,
|
||||
|
@ -40,6 +41,7 @@ impl ServerFnTraitObj {
|
|||
server_fn::inventory::collect!(ServerFnTraitObj);
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
/// Middleware for a server function
|
||||
pub struct ServerFnMiddleware {
|
||||
/// The prefix of the server function.
|
||||
|
@ -72,7 +74,8 @@ pub(crate) static MIDDLEWARE: once_cell::sync::Lazy<
|
|||
#[cfg(feature = "server")]
|
||||
server_fn::inventory::collect!(ServerFnMiddleware);
|
||||
|
||||
#[cfg(any(feature = "server", doc))]
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
/// A server function that can be called on serializable arguments and returns a serializable result.
|
||||
pub type ServerFunction = server_fn::SerializedFnTraitObj<()>;
|
||||
|
||||
|
@ -88,7 +91,8 @@ static REGISTERED_SERVER_FUNCTIONS: once_cell::sync::Lazy<
|
|||
std::sync::Arc::new(std::sync::RwLock::new(map))
|
||||
});
|
||||
|
||||
#[cfg(any(feature = "server", doc))]
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
/// The registry of all Dioxus server functions.
|
||||
pub struct DioxusServerFnRegistry;
|
||||
|
||||
|
@ -155,7 +159,8 @@ impl server_fn::ServerFunctionRegistry<()> for DioxusServerFnRegistry {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "server", doc))]
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
/// Errors that can occur when registering a server function.
|
||||
#[derive(thiserror::Error, Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum ServerRegistrationFnError {
|
||||
|
@ -178,7 +183,8 @@ pub enum ServerRegistrationFnError {
|
|||
/// Technically, the trait is implemented on a type that describes the server function's arguments, not the function itself.
|
||||
pub trait DioxusServerFn: server_fn::ServerFn<()> {
|
||||
/// Registers the server function, allowing the client to query it by URL.
|
||||
#[cfg(any(feature = "server", doc))]
|
||||
#[cfg(feature = "server")]
|
||||
#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))]
|
||||
fn register_explicit() -> Result<(), server_fn::ServerFnError> {
|
||||
Self::register_in_explicit::<DioxusServerFnRegistry>()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||
#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||
#![cfg_attr(feature = "nightly-features", feature(debug_refcell))]
|
||||
|
||||
#[macro_export]
|
||||
/// A helper macro for using hooks and properties in async environments.
|
||||
|
|
|
@ -3,9 +3,9 @@ use std::any::Any;
|
|||
|
||||
#[cfg(feature = "axum")]
|
||||
pub type Config = crate::Config<axum::Router>;
|
||||
#[cfg(feature = "salvo")]
|
||||
#[cfg(all(feature = "salvo", not(feature = "axum")))]
|
||||
pub type Config = crate::Config<salvo::Router>;
|
||||
#[cfg(feature = "rocket")]
|
||||
#[cfg(all(feature = "rocket", not(any(feature = "axum", feature = "salvo"))))]
|
||||
pub type Config = crate::Config<rocket::Rocket<rocket::Build>>;
|
||||
|
||||
/// Launches the WebView and runs the event loop, with configuration and root props.
|
||||
|
|
|
@ -35,7 +35,6 @@ default = []
|
|||
ssr = ["dioxus-ssr/incremental", "tokio", "dioxus-fullstack?/server"]
|
||||
liveview = ["dioxus-liveview", "tokio", "dep:serde", "serde_json"]
|
||||
wasm_test = []
|
||||
serde = ["dep:serde", "gloo-utils?/serde"]
|
||||
web = ["gloo", "web-sys", "wasm-bindgen", "gloo-utils", "js-sys"]
|
||||
fullstack = ["dioxus-fullstack"]
|
||||
|
||||
|
|
|
@ -11,18 +11,6 @@ pub struct RouterConfigFactory<R: Routable> {
|
|||
config: Rc<RefCell<Option<Box<dyn FnOnce() -> RouterConfig<R>>>>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable> Default for RouterConfigFactory<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::from(RouterConfig::default)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable> Default for RouterConfigFactory<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
|
@ -40,19 +28,6 @@ impl<R: Routable, F: FnOnce() -> RouterConfig<R> + 'static> From<F> for RouterCo
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
/// The props for [`Router`].
|
||||
#[derive(Props)]
|
||||
pub struct RouterProps<R: Routable>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
#[props(default, into)]
|
||||
config: RouterConfigFactory<R>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
/// The props for [`Router`].
|
||||
#[derive(Props)]
|
||||
pub struct RouterProps<R: Routable>
|
||||
|
@ -74,7 +49,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable> Default for RouterProps<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
|
@ -86,20 +60,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable> Default for RouterProps<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
config: RouterConfigFactory::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable> PartialEq for RouterProps<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
|
@ -110,19 +70,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable> PartialEq for RouterProps<R>
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn eq(&self, _: &Self) -> bool {
|
||||
// prevent the router from re-rendering when the initial url or config changes
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
/// A component that renders the current route.
|
||||
pub fn Router<R: Routable + Clone>(props: RouterProps<R>) -> Element
|
||||
where
|
||||
|
@ -148,28 +95,3 @@ where
|
|||
|
||||
rsx! { Outlet::<R> {} }
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
/// A component that renders the current route.
|
||||
pub fn Router<R: Routable + Clone>(cx: ScopeState<RouterProps<R>>) -> Element
|
||||
where
|
||||
<R as FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
use_context_provider(|| {
|
||||
RouterContext::new(
|
||||
(cx.props
|
||||
.config
|
||||
.config
|
||||
.take()
|
||||
.expect("use_context_provider ran twice"))(),
|
||||
cx.schedule_update_any(),
|
||||
)
|
||||
});
|
||||
use_context_provider(|| OutletContext::<R> {
|
||||
current_level: 0,
|
||||
_marker: std::marker::PhantomData,
|
||||
});
|
||||
|
||||
rsx! { Outlet::<R> {} }
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ fn base_path() -> Option<&'static str> {
|
|||
base_path
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
#[allow(clippy::extra_unused_type_parameters)]
|
||||
fn update_scroll<R>(window: &Window, history: &History) {
|
||||
let scroll = ScrollPosition::of_window(window);
|
||||
|
@ -32,27 +31,6 @@ fn update_scroll<R>(window: &Window, history: &History) {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
fn update_scroll<R: serde::Serialize + serde::de::DeserializeOwned + Routable>(
|
||||
window: &Window,
|
||||
history: &History,
|
||||
) {
|
||||
if let Some(WebHistoryState { state, .. }) = get_current::<WebHistoryState<R>>(history) {
|
||||
let scroll = ScrollPosition::of_window(window);
|
||||
let state = WebHistoryState { state, scroll };
|
||||
if let Err(err) = replace_state_with_url(history, &state, None) {
|
||||
error!(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
#[derive(serde::Deserialize, serde::Serialize)]
|
||||
struct WebHistoryState<R> {
|
||||
state: R,
|
||||
scroll: ScrollPosition,
|
||||
}
|
||||
|
||||
/// A [`HistoryProvider`] that integrates with a browser via the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API).
|
||||
///
|
||||
/// # Prefix
|
||||
|
@ -75,7 +53,6 @@ pub struct WebHistory<R: Routable> {
|
|||
phantom: std::marker::PhantomData<R>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable> Default for WebHistory<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
|
@ -85,19 +62,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable> Default for WebHistory<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new(None, true)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Routable> WebHistory<R> {
|
||||
#[cfg(not(feature = "serde"))]
|
||||
/// Create a new [`WebHistory`].
|
||||
///
|
||||
/// If `do_scroll_restoration` is [`true`], [`WebHistory`] will take control of the history
|
||||
|
@ -116,47 +81,6 @@ impl<R: Routable> WebHistory<R> {
|
|||
myself
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
/// Create a new [`WebHistory`].
|
||||
///
|
||||
/// If `do_scroll_restoration` is [`true`], [`WebHistory`] will take control of the history
|
||||
/// state. It'll also set the browsers scroll restoration to `manual`.
|
||||
pub fn new(prefix: Option<String>, do_scroll_restoration: bool) -> Self
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
let w = window().expect("access to `window`");
|
||||
let h = w.history().expect("`window` has access to `history`");
|
||||
let document = w.document().expect("`window` has access to `document`");
|
||||
|
||||
let myself = Self::new_inner(
|
||||
prefix,
|
||||
do_scroll_restoration,
|
||||
EventListener::new(&document, "scroll", {
|
||||
let mut last_updated = 0.0;
|
||||
move |evt| {
|
||||
// the time stamp in milliseconds
|
||||
let time_stamp = evt.time_stamp();
|
||||
// throttle the scroll event to 100ms
|
||||
if (time_stamp - last_updated) < 100.0 {
|
||||
return;
|
||||
}
|
||||
update_scroll::<R>(&w, &h);
|
||||
last_updated = time_stamp;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
let current_route = myself.current_route();
|
||||
tracing::trace!("initial route: {:?}", current_route);
|
||||
let current_url = current_route.to_string();
|
||||
let state = myself.create_state(current_route);
|
||||
let _ = replace_state_with_url(&myself.history, &state, Some(¤t_url));
|
||||
|
||||
myself
|
||||
}
|
||||
|
||||
fn new_inner(prefix: Option<String>, do_scroll_restoration: bool) -> Self
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
|
@ -191,17 +115,10 @@ impl<R: Routable> WebHistory<R> {
|
|||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
fn create_state(&self, _state: R) -> [f64; 2] {
|
||||
let scroll = self.scroll_pos();
|
||||
[scroll.x, scroll.y]
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
fn create_state(&self, state: R) -> WebHistoryState<R> {
|
||||
let scroll = self.scroll_pos();
|
||||
WebHistoryState { state, scroll }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Routable> WebHistory<R>
|
||||
|
@ -254,91 +171,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: serde::Serialize + serde::de::DeserializeOwned + Routable> HistoryProvider<R>
|
||||
for WebHistory<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
{
|
||||
fn current_route(&self) -> R {
|
||||
match get_current::<WebHistoryState<_>>(&self.history) {
|
||||
// Try to get the route from the history state
|
||||
Some(route) => route.state,
|
||||
// If that fails, get the route from the current URL
|
||||
None => self.route_from_location(),
|
||||
}
|
||||
}
|
||||
|
||||
fn current_prefix(&self) -> Option<String> {
|
||||
self.prefix.clone()
|
||||
}
|
||||
|
||||
fn go_back(&mut self) {
|
||||
if let Err(e) = self.history.back() {
|
||||
error!("failed to go back: ", e)
|
||||
}
|
||||
}
|
||||
|
||||
fn go_forward(&mut self) {
|
||||
if let Err(e) = self.history.forward() {
|
||||
error!("failed to go forward: ", e)
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, state: R) {
|
||||
use gloo_utils::format::JsValueSerdeExt;
|
||||
if JsValue::from_serde(&state) != JsValue::from_serde(&self.current_route()) {
|
||||
// don't push the same state twice
|
||||
return;
|
||||
}
|
||||
|
||||
let w = window().expect("access to `window`");
|
||||
let h = w.history().expect("`window` has access to `history`");
|
||||
|
||||
// update the scroll position before pushing the new state
|
||||
update_scroll::<R>(&w, &h);
|
||||
|
||||
let path = self.full_path(&state);
|
||||
|
||||
let state = self.create_state(state);
|
||||
|
||||
self.handle_nav(push_state_and_url(&self.history, &state, path));
|
||||
}
|
||||
|
||||
fn replace(&mut self, state: R) {
|
||||
let path = match &self.prefix {
|
||||
None => format!("{state}"),
|
||||
Some(prefix) => format!("{prefix}{state}"),
|
||||
};
|
||||
|
||||
let state = self.create_state(state);
|
||||
|
||||
self.handle_nav(replace_state_with_url(&self.history, &state, Some(&path)));
|
||||
}
|
||||
|
||||
fn external(&mut self, url: String) -> bool {
|
||||
self.navigate_external(url)
|
||||
}
|
||||
|
||||
fn updater(&mut self, callback: std::sync::Arc<dyn Fn() + Send + Sync>) {
|
||||
let w = self.window.clone();
|
||||
let h = self.history.clone();
|
||||
let s = self.listener_animation_frame.clone();
|
||||
let d = self.do_scroll_restoration;
|
||||
|
||||
self.listener_navigation = Some(EventListener::new(&self.window, "popstate", move |_| {
|
||||
(*callback)();
|
||||
if d {
|
||||
let mut s = s.lock().expect("unpoisoned scroll mutex");
|
||||
if let Some(current_state) = get_current::<WebHistoryState<R>>(&h) {
|
||||
*s = Some(current_state.scroll.scroll_to(w.clone()));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable> HistoryProvider<R> for WebHistory<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
use gloo::console::error;
|
||||
#[cfg(feature = "serde")]
|
||||
use gloo_utils::format::JsValueSerdeExt;
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::History;
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
pub(crate) fn replace_state_with_url(
|
||||
history: &History,
|
||||
value: &[f64; 2],
|
||||
|
@ -17,18 +14,6 @@ pub(crate) fn replace_state_with_url(
|
|||
history.replace_state_with_url(&position, "", url)
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub(crate) fn replace_state_with_url<V: serde::Serialize>(
|
||||
history: &History,
|
||||
value: &V,
|
||||
url: Option<&str>,
|
||||
) -> Result<(), JsValue> {
|
||||
let position = JsValue::from_serde(value).unwrap();
|
||||
|
||||
history.replace_state_with_url(&position, "", url)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
pub(crate) fn push_state_and_url(
|
||||
history: &History,
|
||||
value: &[f64; 2],
|
||||
|
@ -41,33 +26,6 @@ pub(crate) fn push_state_and_url(
|
|||
history.push_state_with_url(&position, "", Some(&url))
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub(crate) fn push_state_and_url<V: serde::Serialize>(
|
||||
history: &History,
|
||||
value: &V,
|
||||
url: String,
|
||||
) -> Result<(), JsValue> {
|
||||
let position = JsValue::from_serde(value).unwrap();
|
||||
|
||||
history.push_state_with_url(&position, "", Some(&url))
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub(crate) fn get_current<V: serde::de::DeserializeOwned>(history: &History) -> Option<V> {
|
||||
let state = history.state();
|
||||
if let Err(err) = &state {
|
||||
error!(err);
|
||||
}
|
||||
state.ok().and_then(|state| {
|
||||
let deserialized = state.into_serde();
|
||||
if let Err(err) = &deserialized {
|
||||
error!(format!("{}", err));
|
||||
}
|
||||
deserialized.ok()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
pub(crate) fn get_current(history: &History) -> Option<[f64; 2]> {
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
|
|
|
@ -31,21 +31,6 @@ pub struct RouterConfig<R: Routable> {
|
|||
pub(crate) initial_route: Option<R>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable + Clone> Default for RouterConfig<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
failure_external_navigation: FailureExternalNavigation::<R>,
|
||||
history: None,
|
||||
on_update: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! default_history {
|
||||
($initial_route:ident) => {
|
||||
{
|
||||
|
@ -83,24 +68,6 @@ macro_rules! default_history {
|
|||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<R: Routable + Clone> RouterConfig<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
R: serde::Serialize + serde::de::DeserializeOwned,
|
||||
{
|
||||
pub(crate) fn get_history(self) -> Box<dyn HistoryProvider<R>> {
|
||||
#[allow(unused)]
|
||||
let initial_route = self.initial_route.clone().unwrap_or("/".parse().unwrap_or_else(|err|
|
||||
panic!("index route does not exist:\n{}\n use MemoryHistory::with_initial_path or RouterConfig::initial_route to set a custom path", err)
|
||||
));
|
||||
self.history
|
||||
.take()
|
||||
.unwrap_or_else(|| default_history!(initial_route))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "serde"))]
|
||||
impl<R: Routable + Clone> Default for RouterConfig<R>
|
||||
where
|
||||
<R as std::str::FromStr>::Err: std::fmt::Display,
|
||||
|
|
Loading…
Reference in a new issue