mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-28 19:32:37 -05:00
Compare commits
4 Commits
server_fn_
...
docs-clean
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e5bfd0009 | ||
|
|
36132a5823 | ||
|
|
6f35f8d197 | ||
|
|
3973c4f420 |
@@ -6,7 +6,116 @@ Feature: Check aria-current being applied to make links bolded
|
||||
Given I see the app
|
||||
|
||||
Scenario: Should see the base case working
|
||||
Then I see the link Out-of-Order being bolded
|
||||
Then I see the following links being bolded
|
||||
Then I see the Out-of-Order link being bolded
|
||||
And I see the following links being bolded
|
||||
| Out-of-Order |
|
||||
| Nested |
|
||||
And I see the In-Order link not being bolded
|
||||
And I see the following links not being bolded
|
||||
| In-Order |
|
||||
| Single |
|
||||
|
||||
Scenario: Should see client-side render the correct bolded links
|
||||
When I select the link In-Order
|
||||
And I select the link Single
|
||||
Then I see the following links being bolded
|
||||
| In-Order |
|
||||
| Single |
|
||||
And I see the following links not being bolded
|
||||
| Out-of-Order |
|
||||
| Nested |
|
||||
|
||||
Scenario: Should see server-side render the correct bolded links
|
||||
When I select the link In-Order
|
||||
And I select the link Single
|
||||
And I reload the page
|
||||
Then I see the following links being bolded
|
||||
| In-Order |
|
||||
| Single |
|
||||
And I see the following links not being bolded
|
||||
| Out-of-Order |
|
||||
| Nested |
|
||||
|
||||
Scenario: Check that the base nested route links are working
|
||||
When I select the link Instrumented
|
||||
Then I see the Instrumented link being bolded
|
||||
And I see the Item Listing link not being bolded
|
||||
|
||||
Scenario: Should see going deep down into nested routes bold links
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| Target 421 |
|
||||
| field1 |
|
||||
|
||||
Scenario: Should see going deep down into nested routes in SSR bold links
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
And I reload the page
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| Target 421 |
|
||||
| field1 |
|
||||
|
||||
Scenario: Going deep down navigate around nested links bold correctly
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
And I select the link Inspect path2/field3
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| field3 |
|
||||
And I see the following links not being bolded
|
||||
| Target 421 |
|
||||
| field1 |
|
||||
|
||||
Scenario: Going deep down navigate around nested links bold correctly, SSR
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
And I select the link Inspect path2/field3
|
||||
And I reload the page
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| field3 |
|
||||
And I see the following links not being bolded
|
||||
| Target 421 |
|
||||
| field1 |
|
||||
|
||||
Scenario: Going deep down back out nested routes reset bolded states
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
And I select the link Counters
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Counters |
|
||||
And I see the following links not being bolded
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| Target 421 |
|
||||
|
||||
Scenario: Going deep down back out nested routes reset bolded states, SSR
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
And I select the link Counters
|
||||
And I reload the page
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Counters |
|
||||
And I see the following links not being bolded
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| Target 421 |
|
||||
|
||||
@@ -90,3 +90,11 @@ pub async fn link_text_is_aria_current(client: &Client, text: &str) -> Result<()
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn link_text_is_not_aria_current(client: &Client, text: &str) -> Result<()> {
|
||||
let link = find::link_with_text(client, text).await?;
|
||||
|
||||
link.attr("aria-current").await?
|
||||
.map(|_| anyhow::bail!("aria-current mistakenly set for {text}"))
|
||||
.unwrap_or(Ok(()))
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ async fn i_see_the_second_count_is(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(regex = r"^I see the link (.*) being bolded$")]
|
||||
#[then(regex = r"^I see the (.*) link being bolded$")]
|
||||
async fn i_see_the_link_being_bolded(
|
||||
world: &mut AppWorld,
|
||||
text: String,
|
||||
@@ -106,6 +106,32 @@ async fn i_see_the_following_links_being_bolded(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(regex = r"^I see the (.*) link not being bolded$")]
|
||||
async fn i_see_the_link_being_not_bolded(
|
||||
world: &mut AppWorld,
|
||||
text: String,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
check::link_text_is_not_aria_current(client, &text).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(expr = "I see the following links not being bolded")]
|
||||
async fn i_see_the_following_links_not_being_bolded(
|
||||
world: &mut AppWorld,
|
||||
step: &Step,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
if let Some(table) = step.table.as_ref() {
|
||||
for row in table.rows.iter() {
|
||||
check::link_text_is_not_aria_current(client, &row[0]).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(expr = "I see the following counters under section")]
|
||||
#[then(expr = "the following counters under section")]
|
||||
async fn i_see_the_following_counters_under_section(
|
||||
|
||||
@@ -83,15 +83,14 @@ pub trait SharedContext: Debug {
|
||||
|
||||
/// Reads the current value of some data from the shared context, if it has been
|
||||
/// sent from the server. This returns the serialized data as a `String` that should
|
||||
/// be deserialized using [`Serializable::de`].
|
||||
/// be deserialized.
|
||||
///
|
||||
/// On the server and in client-side rendered implementations, this should
|
||||
/// always return [`None`].
|
||||
fn read_data(&self, id: &SerializedDataId) -> Option<String>;
|
||||
|
||||
/// Returns a [`Future`] that resolves with a `String` that should
|
||||
/// be deserialized using [`Serializable::de`] once the given piece of server
|
||||
/// data has resolved.
|
||||
/// be deserialized once the given piece of server data has resolved.
|
||||
///
|
||||
/// On the server and in client-side rendered implementations, this should
|
||||
/// return a [`Future`] that is immediately ready with [`None`].
|
||||
@@ -148,8 +147,8 @@ pub trait SharedContext: Debug {
|
||||
|
||||
/// Adds a `Future` to the set of “blocking resources” that should prevent the server’s
|
||||
/// response stream from beginning until all are resolved. The `Future` returned by
|
||||
/// [`blocking_resources`](Self::blocking_resources) will not resolve until every `Future`
|
||||
/// added by this method has resolved.
|
||||
/// blocking resources will not resolve until every `Future` added by this method
|
||||
/// has resolved.
|
||||
///
|
||||
/// In browser implementations, this should be a no-op.
|
||||
fn defer_stream(&self, wait_for: PinnedFuture<()>);
|
||||
|
||||
@@ -82,7 +82,7 @@ impl ResponseParts {
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper for an Actix [`HttpRequest`](actix_web::HttpRequest) that allows it to be used in an
|
||||
/// A wrapper for an Actix [`HttpRequest`] that allows it to be used in an
|
||||
/// `Send`/`Sync` setting like Leptos's Context API.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Request(SendWrapper<HttpRequest>);
|
||||
@@ -419,12 +419,6 @@ pub fn handle_server_fns_with_context(
|
||||
/// will include fallback content for any `<Suspense/>` nodes, and be immediately interactive,
|
||||
/// but requires some client-side JavaScript.
|
||||
///
|
||||
/// The provides a [MetaContext] and a [RouterIntegrationContext] to app’s context before
|
||||
/// rendering it, and includes any meta tags injected using [leptos_meta].
|
||||
///
|
||||
/// The HTML stream is rendered using [render_to_stream](leptos::ssr::render_to_stream), and
|
||||
/// includes everything described in the documentation for that function.
|
||||
///
|
||||
/// This can then be set up at an appropriate route in your application:
|
||||
/// ```
|
||||
/// use actix_web::{App, HttpServer};
|
||||
@@ -465,7 +459,6 @@ pub fn handle_server_fns_with_context(
|
||||
/// - [ResponseOptions]
|
||||
/// - [Request]
|
||||
/// - [MetaContext](leptos_meta::MetaContext)
|
||||
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
@@ -485,13 +478,6 @@ where
|
||||
/// This stream will pause at each `<Suspense/>` node and wait for it to resolve before
|
||||
/// sending down its HTML. The app will become interactive once it has fully loaded.
|
||||
///
|
||||
/// The provides a [MetaContext] and a [RouterIntegrationContext] to app’s context before
|
||||
/// rendering it, and includes any meta tags injected using [leptos_meta].
|
||||
///
|
||||
/// The HTML stream is rendered using
|
||||
/// [render_to_stream_in_order](leptos::ssr::render_to_stream_in_order),
|
||||
/// and includes everything described in the documentation for that function.
|
||||
///
|
||||
/// This can then be set up at an appropriate route in your application:
|
||||
/// ```
|
||||
/// use actix_web::{App, HttpServer};
|
||||
@@ -534,7 +520,6 @@ where
|
||||
/// This function always provides context values including the following types:
|
||||
/// - [ResponseOptions]
|
||||
/// - [Request]
|
||||
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
@@ -551,13 +536,7 @@ where
|
||||
|
||||
/// Returns an Actix [struct@Route](actix_web::Route) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], asynchronously rendering an HTML page after all
|
||||
/// `async` [Resource](leptos::Resource)s have loaded.
|
||||
///
|
||||
/// The provides a [MetaContext] and a [RouterIntegrationContext] to the app’s context before
|
||||
/// rendering it, and includes any meta tags injected using [leptos_meta].
|
||||
///
|
||||
/// The HTML stream is rendered using [render_to_string_async](leptos::ssr::render_to_string_async), and
|
||||
/// includes everything described in the documentation for that function.
|
||||
/// `async` resources have loaded.
|
||||
///
|
||||
/// This can then be set up at an appropriate route in your application:
|
||||
/// ```
|
||||
@@ -690,7 +669,6 @@ where
|
||||
/// - [ResponseOptions]
|
||||
/// - [Request]
|
||||
/// - [MetaContext](leptos_meta::MetaContext)
|
||||
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
@@ -713,7 +691,7 @@ where
|
||||
|
||||
/// Returns an Actix [struct@Route](actix_web::Route) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], asynchronously serving the page once all `async`
|
||||
/// [Resource](leptos::Resource)s have loaded.
|
||||
/// resources have loaded.
|
||||
///
|
||||
/// This function allows you to provide additional information to Leptos for your route.
|
||||
/// It could be used to pass in Path Info, Connection Info, or anything your heart desires.
|
||||
|
||||
@@ -197,9 +197,9 @@ impl ExtendResponse for AxumResponse {
|
||||
/// 2. A server function that is called from WASM running in the client (e.g., a dispatched action
|
||||
/// or a spawned `Future`).
|
||||
/// 3. A `<form>` submitted to the server function endpoint using default browser APIs (often due
|
||||
/// to using [`ActionForm`](leptos::form::ActionForm) without JS/WASM present.)
|
||||
/// to using [`ActionForm`] without JS/WASM present.)
|
||||
///
|
||||
/// Using it with a non-blocking [`Resource`](leptos::server::Resource) will not work if you are using streaming rendering,
|
||||
/// Using it with a non-blocking [`Resource`] will not work if you are using streaming rendering,
|
||||
/// as the response's headers will already have been sent by the time the server function calls `redirect()`.
|
||||
///
|
||||
/// ### Implementation
|
||||
@@ -442,12 +442,6 @@ pub type PinnedHtmlStream =
|
||||
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], serving an HTML stream of your application.
|
||||
///
|
||||
/// The provides a [MetaContext] and a [RouterIntegrationContext] to app’s context before
|
||||
/// rendering it, and includes any meta tags injected using [leptos_meta].
|
||||
///
|
||||
/// The HTML stream is rendered using [render_to_stream](leptos::ssr::render_to_stream), and
|
||||
/// includes everything described in the documentation for that function.
|
||||
///
|
||||
/// This can then be set up at an appropriate route in your application:
|
||||
/// ```
|
||||
/// use axum::{handler::Handler, Router};
|
||||
@@ -485,8 +479,7 @@ pub type PinnedHtmlStream =
|
||||
/// This function always provides context values including the following types:
|
||||
/// - [`Parts`]
|
||||
/// - [`ResponseOptions`]
|
||||
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
|
||||
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
|
||||
/// - [`ServerMetaContext`]
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
@@ -537,12 +530,6 @@ where
|
||||
/// This stream will pause at each `<Suspense/>` node and wait for it to resolve before
|
||||
/// sending down its HTML. The app will become interactive once it has fully loaded.
|
||||
///
|
||||
/// The provides a [MetaContext] and a [RouterIntegrationContext] to app’s context before
|
||||
/// rendering it, and includes any meta tags injected using [leptos_meta].
|
||||
///
|
||||
/// The HTML stream is rendered using [render_to_stream_in_order], and includes everything described in
|
||||
/// the documentation for that function.
|
||||
///
|
||||
/// This can then be set up at an appropriate route in your application:
|
||||
/// ```
|
||||
/// use axum::{handler::Handler, Router};
|
||||
@@ -580,8 +567,7 @@ where
|
||||
/// This function always provides context values including the following types:
|
||||
/// - [`Parts`]
|
||||
/// - [`ResponseOptions`]
|
||||
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
|
||||
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
|
||||
/// - [`ServerMetaContext`]
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
@@ -634,8 +620,7 @@ where
|
||||
/// This function always provides context values including the following types:
|
||||
/// - [`Parts`]
|
||||
/// - [`ResponseOptions`]
|
||||
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
|
||||
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
|
||||
/// - [`ServerMetaContext`]
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
@@ -766,8 +751,7 @@ where
|
||||
/// This function always provides context values including the following types:
|
||||
/// - [`Parts`]
|
||||
/// - [`ResponseOptions`]
|
||||
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
|
||||
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
|
||||
/// - [`ServerMetaContext`]
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
@@ -834,8 +818,7 @@ where
|
||||
/// This function always provides context values including the following types:
|
||||
/// - [`Parts`]
|
||||
/// - [`ResponseOptions`]
|
||||
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
|
||||
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
|
||||
/// - [`ServerMetaContext`]
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
@@ -952,13 +935,7 @@ fn provide_contexts(
|
||||
|
||||
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], asynchronously rendering an HTML page after all
|
||||
/// `async` [Resource](leptos::Resource)s have loaded.
|
||||
///
|
||||
/// The provides a [MetaContext] and a [RouterIntegrationContext] to app’s context before
|
||||
/// rendering it, and includes any meta tags injected using [leptos_meta].
|
||||
///
|
||||
/// The HTML stream is rendered using [render_to_string_async], and includes everything described in
|
||||
/// the documentation for that function.
|
||||
/// `async` resources have loaded.
|
||||
///
|
||||
/// This can then be set up at an appropriate route in your application:
|
||||
/// ```
|
||||
@@ -998,8 +975,7 @@ fn provide_contexts(
|
||||
/// This function always provides context values including the following types:
|
||||
/// - [`Parts`]
|
||||
/// - [`ResponseOptions`]
|
||||
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
|
||||
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
|
||||
/// - [`ServerMetaContext`]
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
@@ -1020,7 +996,7 @@ where
|
||||
|
||||
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], asynchronously rendering an HTML page after all
|
||||
/// `async` [Resource](leptos::Resource)s have loaded.
|
||||
/// `async` resources have loaded.
|
||||
///
|
||||
/// This version allows us to pass Axum State/Extension/Extractor or other infro from Axum or network
|
||||
/// layers above Leptos itself. To use it, you'll need to write your own handler function that provides
|
||||
@@ -1053,8 +1029,7 @@ where
|
||||
/// This function always provides context values including the following types:
|
||||
/// - [`Parts`]
|
||||
/// - [`ResponseOptions`]
|
||||
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
|
||||
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
|
||||
/// - [`ServerMetaContext`]
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
@@ -1088,7 +1063,7 @@ where
|
||||
|
||||
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], asynchronously rendering an HTML page after all
|
||||
/// `async` [Resource](leptos::Resource)s have loaded.
|
||||
/// `async` resources have loaded.
|
||||
///
|
||||
/// This version allows us to pass Axum State/Extension/Extractor or other infro from Axum or network
|
||||
/// layers above Leptos itself. To use it, you'll need to write your own handler function that provides
|
||||
@@ -1121,8 +1096,7 @@ where
|
||||
/// This function always provides context values including the following types:
|
||||
/// - [`Parts`]
|
||||
/// - [`ResponseOptions`]
|
||||
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
|
||||
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
|
||||
/// - [`ServerMetaContext`]
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
tracing::instrument(level = "trace", fields(error), skip_all)
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
//! *Notes*:
|
||||
//! - The `render_number` prop can receive any type that implements `Fn(i32) -> String`.
|
||||
//! - Callbacks are most useful when you want optional generic props.
|
||||
//! - All callbacks implement the [`Callable`] trait, and can be invoked with `my_callback.run(input)`.
|
||||
//! - All callbacks implement the [`Callable`](leptos::callback::Callable) trait, and can be invoked with `my_callback.run(input)`.
|
||||
//! - The callback types implement [`Copy`], so they can easily be moved into and out of other closures, just like signals.
|
||||
//!
|
||||
//! # Types
|
||||
//! This modules implements 2 callback types:
|
||||
//! - [`Callback`]
|
||||
//! - [`UnsyncCallback`]
|
||||
//! - [`Callback`](leptos::callback::Callback)
|
||||
//! - [`UnsyncCallback`](leptos::callback::UnsyncCallback)
|
||||
//!
|
||||
//! Use `SyncCallback` if the function is not `Sync` and `Send`.
|
||||
|
||||
|
||||
@@ -246,7 +246,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A typed equivalent to [`ChildrenMut`], which takes a generic but preserves type information to
|
||||
/// A typed equivalent to [`ChildrenFnMut`], which takes a generic but preserves type information to
|
||||
/// allow the compiler to optimize the view more effectively.
|
||||
pub struct TypedChildrenMut<T>(Box<dyn FnMut() -> View<T> + Send>);
|
||||
|
||||
|
||||
@@ -72,9 +72,7 @@ use web_sys::{
|
||||
#[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
|
||||
#[component]
|
||||
pub fn ActionForm<ServFn>(
|
||||
/// The action from which to build the form. This should include a URL, which can be generated
|
||||
/// by default using [`create_server_action`](leptos_server::create_server_action) or added
|
||||
/// manually using [`using_server_fn`](leptos_server::Action::using_server_fn).
|
||||
/// The action from which to build the form.
|
||||
action: ServerAction<ServFn>,
|
||||
/// A [`NodeRef`] in which the `<form>` element should be stored.
|
||||
#[prop(optional)]
|
||||
@@ -149,9 +147,7 @@ where
|
||||
/// progressively enhanced to use client-side routing.
|
||||
#[component]
|
||||
pub fn MultiActionForm<ServFn>(
|
||||
/// The action from which to build the form. This should include a URL, which can be generated
|
||||
/// by default using [create_server_action](leptos_server::create_server_action) or added
|
||||
/// manually using [leptos_server::Action::using_server_fn].
|
||||
/// The action from which to build the form.
|
||||
action: ServerMultiAction<ServFn>,
|
||||
/// A [`NodeRef`] in which the `<form>` element should be stored.
|
||||
#[prop(optional)]
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
//! server actions, forms, and server-sent events (SSE).
|
||||
//! - **[`todomvc`]** shows the basics of building an isomorphic web app. Both the server and the client import the same app code.
|
||||
//! The server renders the app directly to an HTML string, and the client hydrates that HTML to make it interactive.
|
||||
//! You might also want to see how we use [`Effect::new`](leptos::prelude::Effect::new) to
|
||||
//! You might also want to see how we use [`Effect::new`](leptos::prelude::Effect) to
|
||||
//! [serialize JSON to `localStorage`](https://github.com/leptos-rs/leptos/blob/20af4928b2fffe017408d3f4e7330db22cf68277/examples/todomvc/src/lib.rs#L191-L209)
|
||||
//! and [reactively call DOM methods](https://github.com/leptos-rs/leptos/blob/16f084a71268ac325fbc4a5e50c260df185eadb6/examples/todomvc/src/lib.rs#L292-L296)
|
||||
//! on [references to elements](https://github.com/leptos-rs/leptos/blob/20af4928b2fffe017408d3f4e7330db22cf68277/examples/todomvc/src/lib.rs#L228).
|
||||
@@ -78,7 +78,7 @@
|
||||
//! + `async` interop: [`Resource`](leptos::prelude::Resource) for loading data using `async` functions
|
||||
//! and [`Action`](leptos::prelude::Action) to mutate data or imperatively call `async` functions.
|
||||
//! + reactions: [`Effect`](leptos::prelude::Effect) and [`RenderEffect`](leptos::prelude::RenderEffect).
|
||||
//! - **Templating/Views**: the [`view`] macro and [`IntoView`](leptos::IntoView) trait.
|
||||
//! - **Templating/Views**: the [`view`] macro and [`IntoView`] trait.
|
||||
//! - **Routing**: the [`leptos_router`](https://docs.rs/leptos_router/latest/leptos_router/) crate
|
||||
//! - **Server Functions**: the [`server`](macro@leptos::prelude::server) macro and [`ServerAction`](leptos::prelude::ServerAction).
|
||||
//!
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Macros for use with the [`leptos`] framework.
|
||||
//! Macros for use with the Leptos framework.
|
||||
|
||||
#![cfg_attr(feature = "nightly", feature(proc_macro_span))]
|
||||
#![forbid(unsafe_code)]
|
||||
@@ -272,8 +272,8 @@ pub fn view(tokens: TokenStream) -> TokenStream {
|
||||
view_macro_impl(tokens, false)
|
||||
}
|
||||
|
||||
/// The `template` macro behaves like [`view`], except that it wraps the entire tree in a
|
||||
/// [`ViewTemplate`](leptos::prelude::ViewTemplate). This optimizes creation speed by rendering
|
||||
/// The `template` macro behaves like [`view`](view!), except that it wraps the entire tree in a
|
||||
/// [`ViewTemplate`](https://docs.rs/leptos/0.7.0-gamma3/leptos/prelude/struct.ViewTemplate.html). This optimizes creation speed by rendering
|
||||
/// most of the view into a `<template>` tag with HTML rendered at compile time, then hydrating it.
|
||||
/// In exchange, there is a small binary size overhead.
|
||||
#[proc_macro_error2::proc_macro_error]
|
||||
@@ -366,7 +366,7 @@ fn normalized_call_site(site: proc_macro::Span) -> Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
/// This behaves like the [`view`] macro, but loads the view from an external file instead of
|
||||
/// This behaves like the [`view`](view!) macro, but loads the view from an external file instead of
|
||||
/// parsing it inline.
|
||||
///
|
||||
/// This is designed to allow editing views in a separate file, if this improves a user's workflow.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Utilities for communicating between the server and the client with [`leptos`].
|
||||
//! Utilities for communicating between the server and the client with Leptos.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
@@ -253,7 +253,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Future`] that is ready when an [`ArcAsyncDerived`] is finished loading or reloading,
|
||||
/// A [`Future`] that is ready when an
|
||||
/// [`ArcAsyncDerived`](reactive_graph::computed::ArcAsyncDerived) is finished loading or reloading,
|
||||
/// and contains its value. `.await`ing this clones the value `T`.
|
||||
pub struct OnceResourceFuture<T> {
|
||||
source: AnySource,
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
//! using the [`Leptos`](https://github.com/leptos-rs/leptos) web framework.
|
||||
//!
|
||||
//! Document metadata is updated automatically when running in the browser. For server-side
|
||||
//! rendering, after the component tree is rendered to HTML, [`MetaContext::dehydrate`] can generate
|
||||
//! HTML that should be injected into the `<head>` of the HTML document being rendered.
|
||||
//! rendering, after the component tree is rendered to HTML, [`ServerMetaContextOutput::inject_meta_context`] will inject meta tags into a stream of HTML inside the `<head>`.
|
||||
//!
|
||||
//! ```
|
||||
//! use leptos::prelude::*;
|
||||
|
||||
@@ -19,7 +19,7 @@ pub(crate) use inner::MemoInner;
|
||||
pub use memo::*;
|
||||
pub use selector::*;
|
||||
|
||||
/// Derives a reactive slice of an [`RwSignal`](crate::signal::RwSignal).
|
||||
/// Derives a reactive slice of an [`RwSignal`].
|
||||
///
|
||||
/// Slices have the same guarantees as [`Memo`s](crate::computed::Memo):
|
||||
/// they only emit their value when it has actually been changed.
|
||||
|
||||
@@ -124,7 +124,7 @@ pub fn log_warning(text: Arguments) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls [`Executor::spawn`], but ensures that the task also runs in the current arena, if
|
||||
/// Calls [`Executor::spawn`](any_spawner::Executor), but ensures that the task also runs in the current arena, if
|
||||
/// multithreaded arena sandboxing is enabled.
|
||||
pub fn spawn(task: impl Future<Output = ()> + Send + 'static) {
|
||||
#[cfg(feature = "sandboxed-arenas")]
|
||||
@@ -133,8 +133,9 @@ pub fn spawn(task: impl Future<Output = ()> + Send + 'static) {
|
||||
any_spawner::Executor::spawn(task);
|
||||
}
|
||||
|
||||
/// Calls [`Executor::spawn_local`], but ensures that the task runs under the current reactive [`Owner`]
|
||||
/// and [`Observed`]. Does not cancel the task if the owner is cleaned up.
|
||||
/// Calls [`Executor::spawn_local`](any_spawner::Executor), but ensures that the task runs under the current reactive [`Owner`](crate::owner::Owner) and observer.
|
||||
///
|
||||
/// Does not cancel the task if the owner is cleaned up.
|
||||
pub fn spawn_local_scoped(task: impl Future<Output = ()> + 'static) {
|
||||
let task = ScopedFuture::new(task);
|
||||
|
||||
@@ -144,8 +145,9 @@ pub fn spawn_local_scoped(task: impl Future<Output = ()> + 'static) {
|
||||
any_spawner::Executor::spawn_local(task);
|
||||
}
|
||||
|
||||
/// Calls [`Executor::spawn_local`], but ensures that the task runs under the current reactive [`Owner`]
|
||||
/// and [`Observed`]. Cancels the task if the owner is cleaned up.
|
||||
/// Calls [`Executor::spawn_local`](any_spawner::Executor), but ensures that the task runs under the current reactive [`Owner`](crate::owner::Owner) and observer.
|
||||
///
|
||||
/// Cancels the task if the owner is cleaned up.
|
||||
pub fn spawn_local_scoped_with_cancellation(
|
||||
task: impl Future<Output = ()> + 'static,
|
||||
) {
|
||||
|
||||
@@ -30,7 +30,7 @@ impl<T> StorageAccess<T> for SendWrapper<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A way of storing a [`ArenaItem`], either as itself or with a wrapper to make it threadsafe.
|
||||
/// A way of storing an [`ArenaItem`](super::arena_item::ArenaItem), either as itself or with a wrapper to make it threadsafe.
|
||||
///
|
||||
/// This exists because all items stored in the arena must be `Send + Sync`, but in single-threaded
|
||||
/// environments you might want or need to use thread-unsafe types.
|
||||
|
||||
@@ -220,7 +220,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait to implement flatten() on Option<&Option<T>>.
|
||||
/// Helper trait to implement flatten() on `Option<&Option<T>>`.
|
||||
pub trait FlattenOptionRefOption {
|
||||
/// The type of the value contained in the double option.
|
||||
type Value;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
//! | Trait | Mode | Description |
|
||||
//! |-------------------|-------|---------------------------------------------------------------------------------------|
|
||||
//! | [`Track`] | — | Tracks changes to this value, adding it as a source of the current reactive observer. |
|
||||
//! | [`Trigger`] | — | Notifies subscribers that this value has changed. |
|
||||
//! | [`Notify`] | — | Notifies subscribers that this value has changed. |
|
||||
//! | [`ReadUntracked`] | Guard | Gives immutable access to the value of this signal. |
|
||||
//! | [`Write`] | Guard | Gives mutable access to the value of this signal.
|
||||
//!
|
||||
@@ -34,7 +34,7 @@
|
||||
//! | Trait | Mode | Composition | Description
|
||||
//! |---------------------|---------------|-----------------------------------|------------
|
||||
//! | [`UpdateUntracked`] | `fn(&mut T)` | [`Write`] | Applies closure to the current value to update it, but doesn't notify subscribers.
|
||||
//! | [`Update`] | `fn(&mut T)` | [`UpdateUntracked`] + [`Trigger`] | Applies closure to the current value to update it, and notifies subscribers.
|
||||
//! | [`Update`] | `fn(&mut T)` | [`UpdateUntracked`] + [`Notify`] | Applies closure to the current value to update it, and notifies subscribers.
|
||||
//! | [`Set`] | `T` | [`Update`] | Sets the value to a new value, and notifies subscribers.
|
||||
//!
|
||||
//! ## Using the Traits
|
||||
|
||||
@@ -64,8 +64,8 @@ pub fn Router<Chil>(
|
||||
//#[prop(optional)]
|
||||
//trailing_slash: TrailingSlash,
|
||||
/// The `<Router/>` should usually wrap your whole page. It can contain
|
||||
/// any elements, and should include a [`Routes`](crate::Routes) component somewhere
|
||||
/// to define and display [`Route`](crate::Route)s.
|
||||
/// any elements, and should include a [`Routes`] component somewhere
|
||||
/// to define and display [`Route`]s.
|
||||
children: TypedChildren<Chil>,
|
||||
) -> impl IntoView
|
||||
where
|
||||
@@ -328,9 +328,10 @@ where
|
||||
/// and the element it should display.
|
||||
#[component(transparent)]
|
||||
pub fn Route<Segments, View>(
|
||||
/// The path fragment that this route should match. This can be created using the [`path`]
|
||||
/// macro, or path segments ([`StaticSegment`], [`ParamSegment`], [`WildcardSegment`], and
|
||||
/// [`OptionalParamSegment`]).
|
||||
/// The path fragment that this route should match. This can be created using the
|
||||
/// [`path`](crate::path) macro, or path segments ([`StaticSegment`](crate::StaticSegment),
|
||||
/// [`ParamSegment`](crate::ParamSegment), [`WildcardSegment`](crate::WildcardSegment), and
|
||||
/// [`OptionalParamSegment`](crate::OptionalParamSegment)).
|
||||
path: Segments,
|
||||
/// The view for this route.
|
||||
view: View,
|
||||
@@ -349,9 +350,10 @@ where
|
||||
/// and the element it should display.
|
||||
#[component(transparent)]
|
||||
pub fn ParentRoute<Segments, View, Children>(
|
||||
/// The path fragment that this route should match. This can be created using the [`path`]
|
||||
/// macro, or path segments ([`StaticSegment`], [`ParamSegment`], [`WildcardSegment`], and
|
||||
/// [`OptionalParamSegment`]).
|
||||
/// The path fragment that this route should match. This can be created using the
|
||||
/// [`path`](crate::path) macro, or path segments ([`StaticSegment`](crate::StaticSegment),
|
||||
/// [`ParamSegment`](crate::ParamSegment), [`WildcardSegment`](crate::WildcardSegment), and
|
||||
/// [`OptionalParamSegment`](crate::OptionalParamSegment)).
|
||||
path: Segments,
|
||||
/// The view for this route.
|
||||
view: View,
|
||||
@@ -374,9 +376,10 @@ where
|
||||
/// redirects to `redirect_path` instead of displaying its `view`.
|
||||
#[component(transparent)]
|
||||
pub fn ProtectedRoute<Segments, ViewFn, View, C, PathFn, P>(
|
||||
/// The path fragment that this route should match. This can be created using the [`path`]
|
||||
/// macro, or path segments ([`StaticSegment`], [`ParamSegment`], [`WildcardSegment`], and
|
||||
/// [`OptionalParamSegment`]).
|
||||
/// The path fragment that this route should match. This can be created using the
|
||||
/// [`path`](crate::path) macro, or path segments ([`StaticSegment`](crate::StaticSegment),
|
||||
/// [`ParamSegment`](crate::ParamSegment), [`WildcardSegment`](crate::WildcardSegment), and
|
||||
/// [`OptionalParamSegment`](crate::OptionalParamSegment)).
|
||||
path: Segments,
|
||||
/// The view for this route.
|
||||
view: ViewFn,
|
||||
@@ -427,9 +430,10 @@ where
|
||||
|
||||
#[component(transparent)]
|
||||
pub fn ProtectedParentRoute<Segments, ViewFn, View, C, PathFn, P, Children>(
|
||||
/// The path fragment that this route should match. This can be created using the [`path`]
|
||||
/// macro, or path segments ([`StaticSegment`], [`ParamSegment`], [`WildcardSegment`], and
|
||||
/// [`OptionalParamSegment`]).
|
||||
/// The path fragment that this route should match. This can be created using the
|
||||
/// [`path`](crate::path) macro, or path segments ([`StaticSegment`](crate::StaticSegment),
|
||||
/// [`ParamSegment`](crate::ParamSegment), [`WildcardSegment`](crate::WildcardSegment), and
|
||||
/// [`OptionalParamSegment`](crate::OptionalParamSegment)).
|
||||
path: Segments,
|
||||
/// The view for this route.
|
||||
view: ViewFn,
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
//! and are rendered by different components. This means you can navigate between siblings
|
||||
//! in this tree without re-rendering or triggering any change in the parent routes.
|
||||
//!
|
||||
//! 3. **Progressive enhancement.** The [`A`] and [`Form`] components resolve any relative
|
||||
//! 3. **Progressive enhancement.** The [`A`](crate::components::A) and
|
||||
//! [`Form`](crate::components::Form) components resolve any relative
|
||||
//! nested routes, render actual `<a>` and `<form>` elements, and (when possible)
|
||||
//! upgrading them to handle those navigations with client-side routing. If you’re using
|
||||
//! them with server-side rendering (with or without hydration), they just work,
|
||||
|
||||
@@ -9,8 +9,7 @@ pub use static_segment::*;
|
||||
/// or URL segment.
|
||||
///
|
||||
/// This is a "horizontal" matching: i.e., it treats a tuple of route segments
|
||||
/// as subsequent segments of the URL and tries to match them all. For a "vertical"
|
||||
/// matching that sees a tuple as alternatives to one another, see [`RouteChild`](super::RouteChild).
|
||||
/// as subsequent segments of the URL and tries to match them all.
|
||||
pub trait PossibleRouteMatch {
|
||||
const OPTIONAL: bool = false;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::location::State;
|
||||
|
||||
/// Options that can be used to configure a navigation. Used with [use_navigate](crate::use_navigate).
|
||||
/// Options that can be used to configure a navigation. Used with [use_navigate](crate::hooks::use_navigate).
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NavigateOptions {
|
||||
/// Whether the URL being navigated to should be resolved relative to the current route.
|
||||
|
||||
@@ -24,7 +24,7 @@ impl ParamsMap {
|
||||
/// Inserts a value into the map.
|
||||
///
|
||||
/// If a value with that key already exists, the new value will be added to it.
|
||||
/// To replace the value instead, see [`replace`].
|
||||
/// To replace the value instead, see [`replace`](Self::replace).
|
||||
pub fn insert(&mut self, key: impl Into<Cow<'static, str>>, value: String) {
|
||||
let value = Url::unescape(&value);
|
||||
|
||||
|
||||
@@ -5,11 +5,18 @@ use std::{
|
||||
str::FromStr,
|
||||
};
|
||||
use thiserror::Error;
|
||||
use throw_error::Error;
|
||||
use url::Url;
|
||||
|
||||
/// A custom header that can be used to indicate a server function returned an error.
|
||||
pub const SERVER_FN_ERROR_HEADER: &str = "serverfnerror";
|
||||
|
||||
impl From<ServerFnError> for Error {
|
||||
fn from(e: ServerFnError) -> Self {
|
||||
Error::from(ServerFnErrorErr::from(e))
|
||||
}
|
||||
}
|
||||
|
||||
/// An empty value indicating that there is no custom error type associated
|
||||
/// with this server function.
|
||||
#[derive(
|
||||
@@ -129,39 +136,30 @@ impl<E> ViaError<E> for WrapError<E> {
|
||||
/// Unlike [`ServerFnErrorErr`], this does not implement [`Error`](trait@std::error::Error).
|
||||
/// This means that other error types can easily be converted into it using the
|
||||
/// `?` operator.
|
||||
#[derive(Debug, Error, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[cfg_attr(
|
||||
feature = "rkyv",
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
pub enum ServerFnError<E = NoCustomError> {
|
||||
/// A user-defined custom error type, which defaults to [`NoCustomError`].
|
||||
#[error("internal error: {0}")]
|
||||
WrappedServerError(E),
|
||||
/// Error while trying to register the server function (only occurs in case of poisoned RwLock).
|
||||
#[error("error while trying to register the server function: {0}")]
|
||||
Registration(String),
|
||||
/// Occurs on the client if there is a network error while trying to run function on server.
|
||||
#[error("error reaching server to call server function: {0}")]
|
||||
Request(String),
|
||||
/// Occurs on the server if there is an error creating an HTTP response.
|
||||
Response(String),
|
||||
/// Occurs when there is an error while actually running the function on the server.
|
||||
#[error("error running server function: {0}")]
|
||||
ServerError(String),
|
||||
/// Occurs on the client if there is an error deserializing the server's response.
|
||||
#[error("error deserializing server function results: {0}")]
|
||||
Deserialization(String),
|
||||
/// Occurs on the client if there is an error serializing the server function arguments.
|
||||
#[error("error serializing server function arguments: {0}")]
|
||||
Serialization(String),
|
||||
/// Occurs on the server if there is an error deserializing one of the arguments that's been sent.
|
||||
#[error("error deserializing server function arguments: {0}")]
|
||||
Args(String),
|
||||
/// Occurs on the server if there's a missing argument.
|
||||
#[error("missing argument {0}")]
|
||||
MissingArg(String),
|
||||
/// Occurs on the server if there is an error creating an HTTP response.
|
||||
#[error("error creating response {0}")]
|
||||
Response(String),
|
||||
}
|
||||
|
||||
impl ServerFnError<NoCustomError> {
|
||||
@@ -177,6 +175,45 @@ impl<CustErr> From<CustErr> for ServerFnError<CustErr> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: std::error::Error> From<E> for ServerFnError {
|
||||
fn from(value: E) -> Self {
|
||||
ServerFnError::ServerError(value.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<CustErr> Display for ServerFnError<CustErr>
|
||||
where
|
||||
CustErr: Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
ServerFnError::Registration(s) => format!(
|
||||
"error while trying to register the server function: {s}"
|
||||
),
|
||||
ServerFnError::Request(s) => format!(
|
||||
"error reaching server to call server function: {s}"
|
||||
),
|
||||
ServerFnError::ServerError(s) =>
|
||||
format!("error running server function: {s}"),
|
||||
ServerFnError::Deserialization(s) =>
|
||||
format!("error deserializing server function results: {s}"),
|
||||
ServerFnError::Serialization(s) =>
|
||||
format!("error serializing server function arguments: {s}"),
|
||||
ServerFnError::Args(s) => format!(
|
||||
"error deserializing server function arguments: {s}"
|
||||
),
|
||||
ServerFnError::MissingArg(s) => format!("missing argument {s}"),
|
||||
ServerFnError::Response(s) =>
|
||||
format!("error generating HTTP response: {s}"),
|
||||
ServerFnError::WrappedServerError(e) => format!("{e}"),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A serializable custom server function error type.
|
||||
///
|
||||
/// This is implemented for all types that implement [`FromStr`] + [`Display`].
|
||||
@@ -261,6 +298,87 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<E> std::error::Error for ServerFnError<E>
|
||||
where
|
||||
E: std::error::Error + 'static,
|
||||
ServerFnError<E>: std::fmt::Display,
|
||||
{
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
ServerFnError::WrappedServerError(e) => Some(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type for errors that can occur when using server functions.
|
||||
///
|
||||
/// Unlike [`ServerFnError`], this implements [`std::error::Error`]. This means
|
||||
/// it can be used in situations in which the `Error` trait is required, but it’s
|
||||
/// not possible to create a blanket implementation that converts other errors into
|
||||
/// this type.
|
||||
///
|
||||
/// [`ServerFnError`] and [`ServerFnErrorErr`] mutually implement [`From`], so
|
||||
/// it is easy to convert between the two types.
|
||||
#[derive(Error, Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ServerFnErrorErr<E = NoCustomError> {
|
||||
/// A user-defined custom error type, which defaults to [`NoCustomError`].
|
||||
#[error("internal error: {0}")]
|
||||
WrappedServerError(E),
|
||||
/// Error while trying to register the server function (only occurs in case of poisoned RwLock).
|
||||
#[error("error while trying to register the server function: {0}")]
|
||||
Registration(String),
|
||||
/// Occurs on the client if there is a network error while trying to run function on server.
|
||||
#[error("error reaching server to call server function: {0}")]
|
||||
Request(String),
|
||||
/// Occurs when there is an error while actually running the function on the server.
|
||||
#[error("error running server function: {0}")]
|
||||
ServerError(String),
|
||||
/// Occurs on the client if there is an error deserializing the server's response.
|
||||
#[error("error deserializing server function results: {0}")]
|
||||
Deserialization(String),
|
||||
/// Occurs on the client if there is an error serializing the server function arguments.
|
||||
#[error("error serializing server function arguments: {0}")]
|
||||
Serialization(String),
|
||||
/// Occurs on the server if there is an error deserializing one of the arguments that's been sent.
|
||||
#[error("error deserializing server function arguments: {0}")]
|
||||
Args(String),
|
||||
/// Occurs on the server if there's a missing argument.
|
||||
#[error("missing argument {0}")]
|
||||
MissingArg(String),
|
||||
/// Occurs on the server if there is an error creating an HTTP response.
|
||||
#[error("error creating response {0}")]
|
||||
Response(String),
|
||||
}
|
||||
|
||||
impl<CustErr> From<ServerFnError<CustErr>> for ServerFnErrorErr<CustErr> {
|
||||
fn from(value: ServerFnError<CustErr>) -> Self {
|
||||
match value {
|
||||
ServerFnError::Registration(value) => {
|
||||
ServerFnErrorErr::Registration(value)
|
||||
}
|
||||
ServerFnError::Request(value) => ServerFnErrorErr::Request(value),
|
||||
ServerFnError::ServerError(value) => {
|
||||
ServerFnErrorErr::ServerError(value)
|
||||
}
|
||||
ServerFnError::Deserialization(value) => {
|
||||
ServerFnErrorErr::Deserialization(value)
|
||||
}
|
||||
ServerFnError::Serialization(value) => {
|
||||
ServerFnErrorErr::Serialization(value)
|
||||
}
|
||||
ServerFnError::Args(value) => ServerFnErrorErr::Args(value),
|
||||
ServerFnError::MissingArg(value) => {
|
||||
ServerFnErrorErr::MissingArg(value)
|
||||
}
|
||||
ServerFnError::WrappedServerError(value) => {
|
||||
ServerFnErrorErr::WrappedServerError(value)
|
||||
}
|
||||
ServerFnError::Response(value) => ServerFnErrorErr::Response(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Associates a particular server function error with the server function
|
||||
/// found at a particular path.
|
||||
///
|
||||
@@ -337,3 +455,9 @@ impl<CustErr> From<ServerFnUrlError<CustErr>> for ServerFnError<CustErr> {
|
||||
error.error
|
||||
}
|
||||
}
|
||||
|
||||
impl<CustErr> From<ServerFnUrlError<CustErr>> for ServerFnErrorErr<CustErr> {
|
||||
fn from(error: ServerFnUrlError<CustErr>) -> Self {
|
||||
error.error.into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use super::Res;
|
||||
use crate::error::{ServerFnError, ServerFnErrorSerde, SERVER_FN_ERROR_HEADER};
|
||||
use crate::error::{
|
||||
ServerFnError, ServerFnErrorErr, ServerFnErrorSerde, SERVER_FN_ERROR_HEADER,
|
||||
};
|
||||
use actix_web::{
|
||||
http::{
|
||||
header,
|
||||
@@ -73,7 +75,7 @@ where
|
||||
builder
|
||||
.insert_header((header::CONTENT_TYPE, content_type))
|
||||
.streaming(
|
||||
data.map(|data| data.map_err(|e| server_fn_error!(e))),
|
||||
data.map(|data| data.map_err(ServerFnErrorErr::from)),
|
||||
),
|
||||
)))
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
//! crate under the hood.
|
||||
|
||||
use super::Res;
|
||||
use crate::error::{ServerFnError, ServerFnErrorSerde, SERVER_FN_ERROR_HEADER};
|
||||
use crate::error::{
|
||||
ServerFnError, ServerFnErrorErr, ServerFnErrorSerde, SERVER_FN_ERROR_HEADER,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use futures::{Stream, TryStreamExt};
|
||||
use http::{header, HeaderValue, Response, StatusCode};
|
||||
@@ -81,7 +83,7 @@ where
|
||||
.status(200)
|
||||
.header(http::header::CONTENT_TYPE, content_type)
|
||||
.body(Body::Async(Box::pin(
|
||||
data.map_err(|e| server_fn_error!(e)).map_err(Error::from),
|
||||
data.map_err(ServerFnErrorErr::from).map_err(Error::from),
|
||||
)))
|
||||
.map_err(|e| ServerFnError::Response(e.to_string()))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use super::Res;
|
||||
use crate::error::{ServerFnError, ServerFnErrorSerde, SERVER_FN_ERROR_HEADER};
|
||||
use crate::error::{
|
||||
ServerFnError, ServerFnErrorErr, ServerFnErrorSerde, SERVER_FN_ERROR_HEADER,
|
||||
};
|
||||
use axum::body::Body;
|
||||
use bytes::Bytes;
|
||||
use futures::{Stream, StreamExt};
|
||||
@@ -44,7 +46,7 @@ where
|
||||
+ 'static,
|
||||
) -> Result<Self, ServerFnError<CustErr>> {
|
||||
let body =
|
||||
Body::from_stream(data.map(|n| n.map_err(|e| server_fn_error!(e))));
|
||||
Body::from_stream(data.map(|n| n.map_err(ServerFnErrorErr::from)));
|
||||
let builder = http::Response::builder();
|
||||
builder
|
||||
.status(200)
|
||||
|
||||
@@ -10,8 +10,8 @@ use crate::{
|
||||
use wasm_bindgen::JsValue;
|
||||
use web_sys::Element;
|
||||
|
||||
/// Extends the [`Element`](Renderer::Element) type of a [`Renderer`], allowing you to add
|
||||
/// attributes and children to the element's built state at runtime, with a similar API to how they
|
||||
/// Extends an HTML element, allowing you to add attributes and children to the
|
||||
/// element's built state at runtime, with a similar API to how they
|
||||
/// can be added to the static view tree at compile time.
|
||||
///
|
||||
/// ```rust,ignore
|
||||
|
||||
@@ -128,7 +128,9 @@ where
|
||||
}
|
||||
|
||||
/// Any type that can be added to the `style` attribute or set as a style in
|
||||
/// the [`CssStyleDeclaration`]. This could be a plain string, or a property name-value pair.
|
||||
/// the [`CssStyleDeclaration`](web_sys::CssStyleDeclaration).
|
||||
///
|
||||
/// This could be a plain string, or a property name-value pair.
|
||||
pub trait IntoStyle: Send {
|
||||
/// The type after all async data have resolved.
|
||||
type AsyncOutput: IntoStyle;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
//! See [`Renderer`](super::Renderer) and [`Rndr`](super::Rndr) for additional information.
|
||||
//! See [`Renderer`](crate::renderer::Renderer) and [`Rndr`](crate::renderer::Rndr) for additional information.
|
||||
|
||||
use super::{CastFrom, RemoveEventHandler};
|
||||
use crate::{
|
||||
@@ -15,7 +15,7 @@ use std::{any::TypeId, borrow::Cow, cell::RefCell};
|
||||
use wasm_bindgen::{intern, prelude::Closure, JsCast, JsValue};
|
||||
use web_sys::{Comment, HtmlTemplateElement};
|
||||
|
||||
/// A [`Renderer`] that uses `web-sys` to manipulate DOM elements in the browser.
|
||||
/// A [`Renderer`](crate::renderer::Renderer) that uses `web-sys` to manipulate DOM elements in the browser.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct Dom;
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ pub mod dom;
|
||||
/// applications, so this "generic rendering" approach was removed before 0.7.0 release.
|
||||
///
|
||||
/// It is possible that we will try a different approach to achieve the same functionality in the
|
||||
/// future, so to the extent possible the rest of the crate tries to stick to using [`Renderer`]
|
||||
/// future, so to the extent possible the rest of the crate tries to stick to using
|
||||
/// [`Renderer`].
|
||||
/// methods rather than directly manipulating the DOM inline.
|
||||
pub type Rndr = dom::Dom;
|
||||
|
||||
|
||||
@@ -29,9 +29,6 @@ pub mod template;
|
||||
pub mod tuples;
|
||||
|
||||
/// The `Render` trait allows rendering something as part of the user interface.
|
||||
///
|
||||
/// It is generic over the renderer itself, as long as that implements the [`Renderer`]
|
||||
/// trait.
|
||||
pub trait Render: Sized {
|
||||
/// The “view state” for this type, which can be retained between updates.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user