mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-29 01:21:50 -05:00
Compare commits
19 Commits
v0.2.4
...
fix-resour
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0f745f4a9 | ||
|
|
e6b1298915 | ||
|
|
98a9ec8335 | ||
|
|
5329561687 | ||
|
|
89ca047f2f | ||
|
|
a94711fcf0 | ||
|
|
97d88c65ae | ||
|
|
e482e3748d | ||
|
|
8ab9c08448 | ||
|
|
56de70b714 | ||
|
|
38d97babd8 | ||
|
|
4cfecb5d82 | ||
|
|
08b5970b2b | ||
|
|
af20f80b2b | ||
|
|
c2fdd2cd70 | ||
|
|
286f3eebe4 | ||
|
|
509223ab2e | ||
|
|
665b0b8ed2 | ||
|
|
508ad52582 |
28
Cargo.toml
28
Cargo.toml
@@ -25,22 +25,22 @@ members = [
|
||||
exclude = ["benchmarks", "examples"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
|
||||
[workspace.dependencies]
|
||||
leptos = { path = "./leptos", default-features = false, version = "0.2.3" }
|
||||
leptos_dom = { path = "./leptos_dom", default-features = false, version = "0.2.3" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.2.3" }
|
||||
leptos_macro = { path = "./leptos_macro", default-features = false, version = "0.2.3" }
|
||||
leptos_reactive = { path = "./leptos_reactive", default-features = false, version = "0.2.3" }
|
||||
leptos_server = { path = "./leptos_server", default-features = false, version = "0.2.3" }
|
||||
server_fn = { path = "./server_fn", default-features = false, version = "0.2.3" }
|
||||
server_fn_macro = { path = "./server_fn_macro", default-features = false, version = "0.2.3" }
|
||||
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", default-features = false, version = "0.2.3" }
|
||||
leptos_config = { path = "./leptos_config", default-features = false, version = "0.2.3" }
|
||||
leptos_router = { path = "./router", version = "0.2.3" }
|
||||
leptos_meta = { path = "./meta", default-feature = false, version = "0.2.3" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.2.3" }
|
||||
leptos = { path = "./leptos", default-features = false, version = "0.2.4" }
|
||||
leptos_dom = { path = "./leptos_dom", default-features = false, version = "0.2.4" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.2.4" }
|
||||
leptos_macro = { path = "./leptos_macro", default-features = false, version = "0.2.4" }
|
||||
leptos_reactive = { path = "./leptos_reactive", default-features = false, version = "0.2.4" }
|
||||
leptos_server = { path = "./leptos_server", default-features = false, version = "0.2.4" }
|
||||
server_fn = { path = "./server_fn", default-features = false, version = "0.2.4" }
|
||||
server_fn_macro = { path = "./server_fn_macro", default-features = false, version = "0.2.4" }
|
||||
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", default-features = false, version = "0.2.4" }
|
||||
leptos_config = { path = "./leptos_config", default-features = false, version = "0.2.4" }
|
||||
leptos_router = { path = "./router", version = "0.2.4" }
|
||||
leptos_meta = { path = "./meta", default-feature = false, version = "0.2.4" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.2.4" }
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
||||
@@ -61,3 +61,19 @@ view! {
|
||||
<input prop:value=a on:input=on_input />
|
||||
}
|
||||
```
|
||||
|
||||
## Build configuration
|
||||
|
||||
### Cargo feature resolution in workspaces
|
||||
|
||||
A new [version](https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions) of Cargo's feature resolver was introduced for the 2021 edition of Rust.
|
||||
For single crate projects it will select a resolver version based on the Rust edition in `Cargo.toml`. As there is no Rust edition present for `Cargo.toml` in a workspace, Cargo will default to the pre 2021 edition resolver.
|
||||
This can cause issues resulting in non WASM compatible code being built for a WASM target. Seeing `mio` failing to build is often a sign that none WASM compatible code is being included in the build.
|
||||
|
||||
The resolver version can be set in the workspace `Cargo.toml` to remedy this issue.
|
||||
|
||||
```toml
|
||||
[workspace]
|
||||
members = ["member1", "member2"]
|
||||
resolver = "2"
|
||||
```
|
||||
|
||||
@@ -84,7 +84,7 @@ fn FancyMath(cx: Scope) -> impl IntoView {
|
||||
This kind of “provide a signal in a parent, consume it in a child” should be familiar
|
||||
from the chapter on [parent-child interactions](./view/08_parent_child.md). The same
|
||||
pattern you use to communicate between parents and children works for grandparents and
|
||||
grandchildren, or any ancestors and descendents: in other words, between “global” state
|
||||
grandchildren, or any ancestors and descendants: in other words, between “global” state
|
||||
in the root component of your app and any other components anywhere else in the app.
|
||||
|
||||
Because of the fine-grained nature of updates, this is usually all you need. However,
|
||||
|
||||
@@ -4,6 +4,6 @@ You’ll notice in the `<Suspense/>` example that if you keep reloading the data
|
||||
|
||||
`<Transition/>` behaves exactly the same as `<Suspense/>`, but instead of falling back every time, it only shows the fallback the first time. On all subsequent loads, it continues showing the old data until the new data are ready. This can be really handy to prevent the flickering effect, and to allow users to continue interacting with your application.
|
||||
|
||||
This example shows how you can create a simple tabbed contact list with `<Transition/>`. When you select a new tab, it continues showing the current contact until the new data laods. This can be a much better user experience than constantly falling back to a loading message.
|
||||
This example shows how you can create a simple tabbed contact list with `<Transition/>`. When you select a new tab, it continues showing the current contact until the new data loads. This can be a much better user experience than constantly falling back to a loading message.
|
||||
|
||||
<iframe src="https://codesandbox.io/p/sandbox/12-transition-sn38sd?selection=%5B%7B%22endColumn%22%3A15%2C%22endLineNumber%22%3A2%2C%22startColumn%22%3A15%2C%22startLineNumber%22%3A2%7D%5D&file=%2Fsrc%2Fmain.rs" width="100%" height="1000px"></iframe>
|
||||
|
||||
@@ -58,8 +58,8 @@ let id = move || {
|
||||
The untyped versions return `Memo<ParamsMap>`. Again, it’s memo to react to changes in the URL. [`ParamsMap`](https://docs.rs/leptos_router/0.2.3/leptos_router/struct.ParamsMap.html) behaves a lot like any other map type, with a `.get()` method that returns `Option<&String>`.
|
||||
|
||||
```rust
|
||||
let params = use_params::<ContactParams>(cx);
|
||||
let query = use_query::<ContactSearch>(cx);
|
||||
let params = use_params_map(cx);
|
||||
let query = use_query_map(cx);
|
||||
|
||||
// id: || -> Option<String>
|
||||
let id = move || {
|
||||
|
||||
@@ -16,7 +16,7 @@ The Leptos Router works with the path and query (`/blog/search?q=Search`). Given
|
||||
|
||||
## The Philosophy
|
||||
|
||||
In most cases, the path should drive what is displayed on the page. From the user’s perspective, for most appliations, most major changes in the state of the app should be reflected in the URL. If you copy and paste the URL and open it in another tab, you should find yourself more or less in the same place.
|
||||
In most cases, the path should drive what is displayed on the page. From the user’s perspective, for most applications, most major changes in the state of the app should be reflected in the URL. If you copy and paste the URL and open it in another tab, you should find yourself more or less in the same place.
|
||||
|
||||
In this sense, the router is really at the heart of the global state management for your application. More than anything else, it drives what is displayed on the page.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos" }
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
actix-files = { version = "0.6", optional = true }
|
||||
actix-web = { version = "4", optional = true, features = ["macros"] }
|
||||
broadcaster = "1"
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1"
|
||||
futures = "0.3"
|
||||
cfg-if = "1"
|
||||
|
||||
@@ -198,13 +198,13 @@ pub fn MultiuserCounter(cx: Scope) -> impl IntoView {
|
||||
let s = create_signal_from_stream(
|
||||
cx,
|
||||
source.subscribe("message").unwrap().map(|value| {
|
||||
value
|
||||
.expect("no message event")
|
||||
.1
|
||||
.data()
|
||||
.as_string()
|
||||
.expect("expected string value")
|
||||
}),
|
||||
match value {
|
||||
Ok(value) => {
|
||||
value.1.data().as_string().expect("expected string value")
|
||||
},
|
||||
Err(_) => "0".to_string(),
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
on_cleanup(cx, move || source.close());
|
||||
|
||||
@@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["stable"] }
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
|
||||
@@ -1,48 +1,44 @@
|
||||
use leptos::{ev, html::*, *};
|
||||
|
||||
pub struct Props {
|
||||
/// The starting value for the counter
|
||||
pub initial_value: i32,
|
||||
/// The change that should be applied each time the button is clicked.
|
||||
pub step: i32,
|
||||
}
|
||||
|
||||
/// A simple counter view.
|
||||
pub fn view(cx: Scope, props: Props) -> impl IntoView {
|
||||
let Props {
|
||||
initial_value,
|
||||
step,
|
||||
} = props;
|
||||
// A component is really just a function call: it runs once to create the DOM and reactive system
|
||||
pub fn counter(cx: Scope, initial_value: i32, step: i32) -> impl IntoView {
|
||||
let (value, set_value) = create_signal(cx, initial_value);
|
||||
|
||||
// elements are created by calling a function with a Scope argument
|
||||
// the function name is the same as the HTML tag name
|
||||
div(cx)
|
||||
.child((
|
||||
cx,
|
||||
// children can be added with .child()
|
||||
// this takes any type that implements IntoView as its argument
|
||||
// for example, a string or an HtmlElement<_>
|
||||
.child(
|
||||
button(cx)
|
||||
// typed events found in leptos::ev
|
||||
// 1) prevent typos in event names
|
||||
// 2) allow for correct type inference in callbacks
|
||||
.on(ev::click, move |_| set_value.update(|value| *value = 0))
|
||||
.child((cx, "Clear")),
|
||||
))
|
||||
.child((
|
||||
cx,
|
||||
.child("Clear"),
|
||||
)
|
||||
.child(
|
||||
button(cx)
|
||||
.on(ev::click, move |_| {
|
||||
set_value.update(|value| *value -= step)
|
||||
})
|
||||
.child((cx, "-1")),
|
||||
))
|
||||
.child((
|
||||
cx,
|
||||
.child("-1"),
|
||||
)
|
||||
.child(
|
||||
span(cx)
|
||||
.child((cx, "Value: "))
|
||||
.child("Value: ")
|
||||
// reactive values are passed to .child() as a tuple
|
||||
// (Scope, [child function]) so an effect can be created
|
||||
.child((cx, move || value.get()))
|
||||
.child((cx, "!")),
|
||||
))
|
||||
.child((
|
||||
cx,
|
||||
.child("!"),
|
||||
)
|
||||
.child(
|
||||
button(cx)
|
||||
.on(ev::click, move |_| {
|
||||
set_value.update(|value| *value += step)
|
||||
})
|
||||
.child((cx, "+1")),
|
||||
))
|
||||
.child("+1"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
use counter_without_macros as counter;
|
||||
use counter_without_macros::counter;
|
||||
use leptos::*;
|
||||
|
||||
pub fn main() {
|
||||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
mount_to_body(|cx| {
|
||||
counter::view(
|
||||
cx,
|
||||
counter::Props {
|
||||
initial_value: 0,
|
||||
step: 1,
|
||||
},
|
||||
)
|
||||
})
|
||||
mount_to_body(|cx| counter(cx, 0, 1))
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos" }
|
||||
log = "0.4"
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", features = ["stable"] }
|
||||
log = "0.4"
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -5,6 +5,6 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos" }
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
console_log = "0.2.0"
|
||||
console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
cfg-if = "1.0.0"
|
||||
leptos = { path = "../../../leptos/leptos", default-features = false, features = [
|
||||
|
||||
@@ -70,8 +70,8 @@ pub fn ExampleErrors(cx: Scope) -> impl IntoView {
|
||||
</p>
|
||||
<p>"The following <div> will always contain an error and cause this page to produce status 500. Check browser dev tools. "</p>
|
||||
<div>
|
||||
// note that the error boundries could be placed above in the Router or lower down
|
||||
// in a particular route. The generated errors on the entire page contribue to the
|
||||
// note that the error boundaries could be placed above in the Router or lower down
|
||||
// in a particular route. The generated errors on the entire page contribute to the
|
||||
// final status code sent by the server when producing ssr pages.
|
||||
<ErrorBoundary fallback=|cx, errors| view!{cx, <ErrorTemplate errors=errors/>}>
|
||||
<ReturnsError/>
|
||||
|
||||
@@ -9,7 +9,7 @@ leptos = { path = "../../leptos" }
|
||||
reqwasm = "0.5.0"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
log = "0.4"
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -9,7 +9,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
[dependencies]
|
||||
actix-files = { version = "0.6", optional = true }
|
||||
actix-web = { version = "4", optional = true, features = ["macros"] }
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1"
|
||||
cfg-if = "1"
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
console_log = "0.2.0"
|
||||
console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
cfg-if = "1.0.0"
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
|
||||
@@ -12,7 +12,7 @@ leptos_router = { version = "0.2.0-alpha2", features = ["stable", "csr"] }
|
||||
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
gloo-net = "0.2"
|
||||
gloo-storage = "0.2"
|
||||
serde = "1.0"
|
||||
|
||||
@@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos" }
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
web-sys = "0.3"
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
leptos = { path = "../../leptos" }
|
||||
leptos_router = { path = "../../router", features = ["csr"] }
|
||||
|
||||
@@ -8,7 +8,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.66"
|
||||
console_log = "0.2.0"
|
||||
console_log = "1.0.0"
|
||||
rand = { version = "0.8.5", features = ["min_const_gen"], optional = true }
|
||||
console_error_panic_hook = "0.1.7"
|
||||
futures = "0.3.25"
|
||||
|
||||
@@ -10,7 +10,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
actix-files = { version = "0.6", optional = true }
|
||||
actix-web = { version = "4", optional = true, features = ["macros"] }
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
cfg-if = "1"
|
||||
lazy_static = "1"
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
|
||||
@@ -8,7 +8,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
console_error_panic_hook = "0.1"
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
cfg-if = "1"
|
||||
lazy_static = "1"
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
|
||||
@@ -22,7 +22,7 @@ cfg-if = "1.0"
|
||||
|
||||
# dependecies for client (enable when csr or hydrate set)
|
||||
wasm-bindgen = { version = "0.2", optional = true }
|
||||
console_log = { version = "0.2", optional = true }
|
||||
console_log = { version = "1", optional = true }
|
||||
console_error_panic_hook = { version = "0.1", optional = true }
|
||||
|
||||
# dependecies for server (enable when ssr set)
|
||||
|
||||
@@ -16,6 +16,6 @@ gloo-net = { version = "0.2", features = ["http"] }
|
||||
|
||||
# dependecies for client (enable when csr or hydrate set)
|
||||
wasm-bindgen = { version = "0.2" }
|
||||
console_log = { version = "0.2"}
|
||||
console_log = { version = "1"}
|
||||
console_error_panic_hook = { version = "0.1"}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ actix-files = { version = "0.6.2", optional = true }
|
||||
actix-web = { version = "4.2.1", optional = true, features = ["macros"] }
|
||||
anyhow = "1.0.68"
|
||||
broadcaster = "1.0.0"
|
||||
console_log = "0.2.0"
|
||||
console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
futures = "0.3.25"
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
console_log = "0.2.0"
|
||||
console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
futures = "0.3.25"
|
||||
cfg-if = "1.0.0"
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
console_log = "0.2.0"
|
||||
console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
futures = "0.3.25"
|
||||
cfg-if = "1.0.0"
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos", default-features = false }
|
||||
log = "0.4"
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
uuid = { version = "1", features = ["v4", "js", "serde"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
||||
@@ -94,7 +94,7 @@ impl ResponseOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides an easy way to redirect the user from within a server function. Mimicing the Remix `redirect()`,
|
||||
/// Provides an easy way to redirect the user from within a server function. Mimicking the Remix `redirect()`,
|
||||
/// it sets a [StatusCode] of 302 and a [LOCATION](header::LOCATION) header with the provided value.
|
||||
/// If looking to redirect from the client, `leptos_router::use_navigate()` should be used instead.
|
||||
pub fn redirect(cx: leptos::Scope, path: &str) {
|
||||
@@ -340,7 +340,7 @@ where
|
||||
|
||||
/// Returns an Actix [Route](actix_web::Route) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], serving an in-order HTML stream of your application.
|
||||
/// This stream will pause at each `<Suspense/>` node and wait for it to resolve befores
|
||||
/// 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
|
||||
|
||||
@@ -95,7 +95,7 @@ impl ResponseOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides an easy way to redirect the user from within a server function. Mimicing the Remix `redirect()`,
|
||||
/// Provides an easy way to redirect the user from within a server function. Mimicking the Remix `redirect()`,
|
||||
/// it sets a StatusCode of 302 and a LOCATION header with the provided value.
|
||||
/// If looking to redirect from the client, `leptos_router::use_navigate()` should be used instead
|
||||
pub fn redirect(cx: leptos::Scope, path: &str) {
|
||||
@@ -128,7 +128,7 @@ pub async fn generate_request_parts(req: Request<Body>) -> RequestParts {
|
||||
|
||||
/// Decomposes an HTTP request into its parts, allowing you to read its headers
|
||||
/// and other data without consuming the body. Creates a new Request from the
|
||||
/// original parts for further processsing
|
||||
/// original parts for further processing
|
||||
pub async fn generate_request_and_parts(
|
||||
req: Request<Body>,
|
||||
) -> (Request<Body>, RequestParts) {
|
||||
@@ -148,7 +148,7 @@ pub async fn generate_request_and_parts(
|
||||
}
|
||||
|
||||
/// A struct to hold the http::request::Request and allow users to take ownership of it
|
||||
/// Requred by Request not being Clone. See this issue for eventual resolution: https://github.com/hyperium/http/pull/574
|
||||
/// Required by Request not being Clone. See this issue for eventual resolution: https://github.com/hyperium/http/pull/574
|
||||
#[derive(Debug, Default)]
|
||||
pub struct LeptosRequest<B>(Arc<RwLock<Option<Request<B>>>>);
|
||||
|
||||
@@ -198,8 +198,8 @@ impl<B> LeptosRequest<B> {
|
||||
}
|
||||
}
|
||||
/// Generate a wrapper for the http::Request::Request type that allows one to
|
||||
/// processs it, access the body, and use axum Extractors on it.
|
||||
/// Requred by Request not being Clone. See this issue for eventual resolution: https://github.com/hyperium/http/pull/574
|
||||
/// process it, access the body, and use axum Extractors on it.
|
||||
/// Required by Request not being Clone. See this issue for eventual resolution: https://github.com/hyperium/http/pull/574
|
||||
pub async fn generate_leptos_request<B>(req: Request<B>) -> LeptosRequest<B>
|
||||
where
|
||||
B: Default + std::fmt::Debug,
|
||||
@@ -495,7 +495,7 @@ where
|
||||
|
||||
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], serving an in-order HTML stream of your application.
|
||||
/// This stream will pause at each `<Suspense/>` node and wait for it to resolve befores
|
||||
/// 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
|
||||
@@ -735,7 +735,7 @@ async fn forward_stream(
|
||||
|
||||
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], serving an in-order HTML stream of your application.
|
||||
/// This stream will pause at each `<Suspense/>` node and wait for it to resolve befores
|
||||
/// 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.
|
||||
///
|
||||
/// This version allows us to pass Axum State/Extension/Extractor or other infro from Axum or network
|
||||
|
||||
@@ -10,7 +10,7 @@ pub fn html_parts(
|
||||
let pkg_path = &options.site_pkg_dir;
|
||||
let output_name = &options.output_name;
|
||||
|
||||
// Because wasm-pack adds _bg to the end of the WASM filename, and we want to mantain compatibility with it's default options
|
||||
// Because wasm-pack adds _bg to the end of the WASM filename, and we want to maintain compatibility with it's default options
|
||||
// we add _bg to the wasm files if cargo-leptos doesn't set the env var LEPTOS_OUTPUT_NAME
|
||||
// Otherwise we need to add _bg because wasm_pack always does. This is not the same as options.output_name, which is set regardless
|
||||
let mut wasm_output_name = output_name.clone();
|
||||
|
||||
@@ -90,7 +90,7 @@ impl ResponseOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides an easy way to redirect the user from within a server function. Mimicing the Remix `redirect()`,
|
||||
/// Provides an easy way to redirect the user from within a server function. Mimicking the Remix `redirect()`,
|
||||
/// it sets a StatusCode of 302 and a LOCATION header with the provided value.
|
||||
/// If looking to redirect from the client, `leptos_router::use_navigate()` should be used instead
|
||||
pub fn redirect(cx: leptos::Scope, path: &str) {
|
||||
@@ -385,7 +385,7 @@ where
|
||||
|
||||
/// Returns a Viz [Handler](viz::Handler) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], serving an HTML stream of your application.
|
||||
/// This stream will pause at each `<Suspense/>` node and wait for it to resolve befores
|
||||
/// 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
|
||||
@@ -617,7 +617,7 @@ async fn forward_stream(
|
||||
|
||||
/// Returns a Viz [Handler](viz::Handler) that listens for a `GET` request and tries
|
||||
/// to route it using [leptos_router], serving an in-order HTML stream of your application.
|
||||
/// This stream will pause at each `<Suspense/>` node and wait for it to resolve befores
|
||||
/// 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.
|
||||
///
|
||||
/// This version allows us to pass Viz State/Extractor or other infro from Viz or network
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
//! - [`hackernews`](https://github.com/leptos-rs/leptos/tree/main/examples/hackernews)
|
||||
//! and [`hackernews_axum`](https://github.com/leptos-rs/leptos/tree/main/examples/hackernews_axum)
|
||||
//! integrate calls to a real external REST API, routing, server-side rendering and hydration to create
|
||||
//! a fully-functional that works as intended even before WASM has loaded and begun to run.
|
||||
//! a fully-functional application that works as intended even before WASM has loaded and begun to run.
|
||||
//! - [`todo_app_sqlite`](https://github.com/leptos-rs/leptos/tree/main/examples/todo_app_sqlite),
|
||||
//! [`todo_app_sqlite_axum`](https://github.com/leptos-rs/leptos/tree/main/examples/todo_app_sqlite_axum), and
|
||||
//! [`todo_app_sqlite_viz`](https://github.com/leptos-rs/leptos/tree/main/examples/todo_app_sqlite_viz)
|
||||
|
||||
@@ -126,7 +126,7 @@ where
|
||||
}
|
||||
);
|
||||
|
||||
// return the fallback for now, wrapped in fragment identifer
|
||||
// return the fallback for now, wrapped in fragment identifier
|
||||
fallback().into_view(cx)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,6 +34,11 @@ leptos = { path = "../leptos" }
|
||||
[dependencies.web-sys]
|
||||
version = "0.3"
|
||||
features = [
|
||||
"DocumentFragment",
|
||||
"Element",
|
||||
"HtmlTemplateElement",
|
||||
"NodeList",
|
||||
"Window",
|
||||
"console",
|
||||
"Comment",
|
||||
"Document",
|
||||
|
||||
@@ -5,7 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
leptos = { path = "../../leptos" }
|
||||
console_log = "0.2"
|
||||
console_log = "1"
|
||||
log = "0.4"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
||||
|
||||
@@ -74,13 +74,13 @@ pub trait ElementDescriptor: ElementDescriptorBounds {
|
||||
/// The name of the element, i.e., `div`, `p`, `custom-element`.
|
||||
fn name(&self) -> Cow<'static, str>;
|
||||
|
||||
/// Determains if the tag is void, i.e., `<input>` and `<br>`.
|
||||
/// Determines if the tag is void, i.e., `<input>` and `<br>`.
|
||||
fn is_void(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// A unique `id` that should be generated for each new instance of
|
||||
/// this element, and be consistant for both SSR and CSR.
|
||||
/// this element, and be consistent for both SSR and CSR.
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
fn hydration_id(&self) -> &HydrationKey;
|
||||
}
|
||||
@@ -573,6 +573,23 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Checks to see if this element is mounted to the DOM as a child
|
||||
/// of `body`.
|
||||
///
|
||||
/// This method will always return [`None`] on non-wasm CSR targets.
|
||||
pub fn is_mounted(&self) -> bool {
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
{
|
||||
crate::document()
|
||||
.body()
|
||||
.unwrap()
|
||||
.contains(Some(self.element.as_ref()))
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
false
|
||||
}
|
||||
|
||||
/// Adds an attribute to this element.
|
||||
#[track_caller]
|
||||
pub fn attr(
|
||||
@@ -679,6 +696,108 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
|
||||
this
|
||||
}
|
||||
|
||||
/// Sets the class on the element as the class signal changes.
|
||||
#[track_caller]
|
||||
pub fn dyn_classes<I, C>(
|
||||
self,
|
||||
classes_signal: impl Fn() -> I + 'static,
|
||||
) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = C>,
|
||||
C: Into<Cow<'static, str>>,
|
||||
{
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
{
|
||||
use smallvec::SmallVec;
|
||||
|
||||
let class_list = self.element.as_ref().class_list();
|
||||
|
||||
leptos_reactive::create_effect(
|
||||
self.cx,
|
||||
move |prev_classes: Option<
|
||||
SmallVec<[Cow<'static, str>; 4]>,
|
||||
>| {
|
||||
let classes = classes_signal()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<SmallVec<[Cow<'static, str>; 4]>>(
|
||||
);
|
||||
|
||||
let mut new_classes = classes
|
||||
.iter()
|
||||
.flat_map(|classes| classes.split_whitespace());
|
||||
|
||||
if let Some(prev_classes) = prev_classes {
|
||||
let mut old_classes = prev_classes
|
||||
.iter()
|
||||
.flat_map(|classes| classes.split_whitespace());
|
||||
|
||||
// Remove old classes
|
||||
for prev_class in old_classes.clone() {
|
||||
if !new_classes.any(|c| c == prev_class) {
|
||||
class_list.remove_1(prev_class).unwrap_or_else(
|
||||
|err| {
|
||||
panic!(
|
||||
"failed to add class \
|
||||
`{prev_class}`, error: {err:#?}"
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add new classes
|
||||
for class in new_classes {
|
||||
if !old_classes.any(|c| c == class) {
|
||||
class_list.add_1(class).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"failed to remove class `{class}`, \
|
||||
error: {err:#?}"
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let new_classes = new_classes
|
||||
.map(ToOwned::to_owned)
|
||||
.collect::<SmallVec<[_; 4]>>();
|
||||
|
||||
for class in &new_classes {
|
||||
class_list.add_1(class).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"failed to add class `{class}`, error: \
|
||||
{err:#?}"
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
classes
|
||||
},
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
{
|
||||
let mut this = self;
|
||||
|
||||
let this = classes_signal()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.flat_map(|classes| {
|
||||
classes
|
||||
.split_whitespace()
|
||||
.map(ToString::to_string)
|
||||
.collect::<SmallVec<[_; 4]>>()
|
||||
})
|
||||
.fold(this, |this, class| this.class(class, true));
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a property on an element.
|
||||
#[track_caller]
|
||||
pub fn prop(
|
||||
|
||||
@@ -509,12 +509,14 @@ pub(crate) fn render_serializers(
|
||||
) -> impl Stream<Item = String> {
|
||||
serializers.map(|(id, json)| {
|
||||
let id = serde_json::to_string(&id).unwrap();
|
||||
let json = json.replace('<', "\\u003c");
|
||||
format!(
|
||||
r#"<script>
|
||||
var val = {json:?};
|
||||
if(__LEPTOS_RESOURCE_RESOLVERS.get({id})) {{
|
||||
__LEPTOS_RESOURCE_RESOLVERS.get({id})({json:?})
|
||||
__LEPTOS_RESOURCE_RESOLVERS.get({id})(val)
|
||||
}} else {{
|
||||
__LEPTOS_RESOLVED_RESOURCES.set({id}, {json:?});
|
||||
__LEPTOS_RESOLVED_RESOURCES.set({id}, val);
|
||||
}}
|
||||
</script>"#,
|
||||
)
|
||||
|
||||
@@ -130,6 +130,7 @@ impl ToTokens for Model {
|
||||
let mut body = body.to_owned();
|
||||
|
||||
body.sig.ident = format_ident!("__{}", body.sig.ident);
|
||||
#[allow(clippy::redundant_clone)] // false positive
|
||||
let body_name = body.sig.ident.clone();
|
||||
|
||||
let (_, generics, where_clause) = body.sig.generics.split_for_impl();
|
||||
@@ -153,6 +154,7 @@ impl ToTokens for Model {
|
||||
if cfg!(feature = "tracing") {
|
||||
(
|
||||
quote! {
|
||||
#[allow(clippy::let_with_type_underscore)]
|
||||
#[cfg_attr(
|
||||
debug_assertions,
|
||||
::leptos::leptos_dom::tracing::instrument(level = "trace", name = #trace_name, skip_all)
|
||||
|
||||
@@ -365,6 +365,7 @@ enum SsrElementChunks {
|
||||
View(TokenStream),
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn element_to_tokens_ssr(
|
||||
cx: &Ident,
|
||||
node: &NodeElement,
|
||||
@@ -817,7 +818,22 @@ fn element_to_tokens(
|
||||
};
|
||||
let attrs = node.attributes.iter().filter_map(|node| {
|
||||
if let Node::Attribute(node) = node {
|
||||
Some(attribute_to_tokens(cx, node))
|
||||
if node.key.to_string().trim().starts_with("class:") {
|
||||
None
|
||||
} else {
|
||||
Some(attribute_to_tokens(cx, node))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let class_attrs = node.attributes.iter().filter_map(|node| {
|
||||
if let Node::Attribute(node) = node {
|
||||
if node.key.to_string().trim().starts_with("class:") {
|
||||
Some(attribute_to_tokens(cx, node))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -875,6 +891,7 @@ fn element_to_tokens(
|
||||
quote! {
|
||||
#name
|
||||
#(#attrs)*
|
||||
#(#class_attrs)*
|
||||
#global_class_expr
|
||||
#(#children)*
|
||||
#view_marker
|
||||
|
||||
@@ -20,7 +20,7 @@ fn Component(
|
||||
#[test]
|
||||
fn component() {
|
||||
let cp = ComponentProps::builder().into("").strip_option(9).build();
|
||||
assert_eq!(cp.optional, false);
|
||||
assert!(!cp.optional);
|
||||
assert_eq!(cp.optional_no_strip, None);
|
||||
assert_eq!(cp.strip_option, Some(9));
|
||||
assert_eq!(cp.default, NonZeroUsize::new(10).unwrap());
|
||||
|
||||
@@ -10,9 +10,9 @@ description = "Reactive system for the Leptos web framework."
|
||||
[dependencies]
|
||||
slotmap = { version = "1", features = ["serde"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde-lite = { version = "0.3", optional = true }
|
||||
serde-lite = { version = "0.4", optional = true }
|
||||
futures = { version = "0.3" }
|
||||
js-sys = "0.3"
|
||||
js-sys = { version = "0.3", optional = true }
|
||||
miniserde = { version = "0.1", optional = true }
|
||||
rkyv = { version = "0.7.39", features = [
|
||||
"validation",
|
||||
@@ -31,17 +31,17 @@ base64 = "0.21"
|
||||
thiserror = "1"
|
||||
tokio = { version = "1", features = ["rt"], optional = true }
|
||||
tracing = "0.1"
|
||||
wasm-bindgen = "0.2"
|
||||
wasm-bindgen-futures = "0.4"
|
||||
web-sys = { version = "0.3", features = [
|
||||
wasm-bindgen = { version = "0.2", optional = true }
|
||||
wasm-bindgen-futures = { version = "0.4", optional = true }
|
||||
web-sys = { version = "0.3", optional = true, features = [
|
||||
"DocumentFragment",
|
||||
"Element",
|
||||
"HtmlTemplateElement",
|
||||
"NodeList",
|
||||
"Window",
|
||||
] }
|
||||
cfg-if = "1.0.0"
|
||||
indexmap = "1.9.2"
|
||||
cfg-if = "1"
|
||||
indexmap = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
log = "0.4"
|
||||
@@ -50,8 +50,18 @@ leptos = { path = "../leptos" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
csr = []
|
||||
hydrate = []
|
||||
csr = [
|
||||
"dep:js-sys",
|
||||
"dep:wasm-bindgen",
|
||||
"dep:wasm-bindgen-futures",
|
||||
"dep:web-sys",
|
||||
]
|
||||
hydrate = [
|
||||
"dep:js-sys",
|
||||
"dep:wasm-bindgen",
|
||||
"dep:wasm-bindgen-futures",
|
||||
"dep:web-sys",
|
||||
]
|
||||
ssr = ["dep:tokio"]
|
||||
stable = []
|
||||
serde = []
|
||||
|
||||
@@ -191,7 +191,8 @@ impl<T: Clone> SignalGetUntracked<T> for Memo<T> {
|
||||
)]
|
||||
fn get_untracked(&self) -> T {
|
||||
with_runtime(self.runtime, move |runtime| {
|
||||
match self.id.try_with_no_subscription(runtime, T::clone) {
|
||||
let f = move |maybe_value: &Option<T>| maybe_value.clone().unwrap();
|
||||
match self.id.try_with_no_subscription(runtime, f) {
|
||||
Ok(t) => t,
|
||||
Err(_) => panic_getting_dead_memo(
|
||||
#[cfg(debug_assertions)]
|
||||
|
||||
@@ -15,6 +15,7 @@ use std::{
|
||||
fmt::Debug,
|
||||
future::Future,
|
||||
marker::PhantomData,
|
||||
panic::Location,
|
||||
pin::Pin,
|
||||
rc::Rc,
|
||||
};
|
||||
@@ -377,13 +378,15 @@ where
|
||||
///
|
||||
/// If you want to get the value without cloning it, use [Resource::with].
|
||||
/// (`value.read(cx)` is equivalent to `value.with(cx, T::clone)`.)
|
||||
#[track_caller]
|
||||
pub fn read(&self, cx: Scope) -> Option<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
let location = std::panic::Location::caller();
|
||||
with_runtime(self.runtime, |runtime| {
|
||||
runtime.resource(self.id, |resource: &ResourceState<S, T>| {
|
||||
resource.read(cx)
|
||||
resource.read(cx, location)
|
||||
})
|
||||
})
|
||||
.ok()
|
||||
@@ -397,10 +400,12 @@ where
|
||||
///
|
||||
/// If you want to get the value by cloning it, you can use
|
||||
/// [Resource::read].
|
||||
#[track_caller]
|
||||
pub fn with<U>(&self, cx: Scope, f: impl FnOnce(&T) -> U) -> Option<U> {
|
||||
let location = std::panic::Location::caller();
|
||||
with_runtime(self.runtime, |runtime| {
|
||||
runtime.resource(self.id, |resource: &ResourceState<S, T>| {
|
||||
resource.with(cx, f)
|
||||
resource.with(cx, f, location)
|
||||
})
|
||||
})
|
||||
.ok()
|
||||
@@ -563,14 +568,25 @@ where
|
||||
S: Clone + 'static,
|
||||
T: 'static,
|
||||
{
|
||||
pub fn read(&self, cx: Scope) -> Option<T>
|
||||
#[track_caller]
|
||||
pub fn read(
|
||||
&self,
|
||||
cx: Scope,
|
||||
location: &'static Location<'static>,
|
||||
) -> Option<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
self.with(cx, T::clone)
|
||||
self.with(cx, T::clone, location)
|
||||
}
|
||||
|
||||
pub fn with<U>(&self, cx: Scope, f: impl FnOnce(&T) -> U) -> Option<U> {
|
||||
#[track_caller]
|
||||
pub fn with<U>(
|
||||
&self,
|
||||
cx: Scope,
|
||||
f: impl FnOnce(&T) -> U,
|
||||
location: &'static Location<'static>,
|
||||
) -> Option<U> {
|
||||
let suspense_cx = use_context::<SuspenseContext>(cx);
|
||||
|
||||
let v = self
|
||||
@@ -587,6 +603,19 @@ where
|
||||
if serializable {
|
||||
suspense_cx.has_local_only.set_value(false);
|
||||
}
|
||||
} else {
|
||||
#[cfg(all(feature = "hydrate", debug_assertions))]
|
||||
crate::macros::debug_warn!(
|
||||
"At {location}, you are reading a resource in `hydrate` mode \
|
||||
outside a <Suspense/> or <Transition/>. This can cause \
|
||||
hydration mismatch errors and loses out on a significant \
|
||||
performance optimization. To fix this issue, you can either: \
|
||||
\n1. Wrap the place where you read the resource in a \
|
||||
<Suspense/> or <Transition/> component, or \n2. Switch to \
|
||||
using create_local_resource(), which will wait to load the \
|
||||
resource until the app is hydrated on the client side. (This \
|
||||
will have worse performance in most cases.)",
|
||||
);
|
||||
}
|
||||
|
||||
let increment = move |_: Option<()>| {
|
||||
|
||||
@@ -414,7 +414,7 @@ impl Scope {
|
||||
|
||||
/// The set of all HTML fragments currently pending.
|
||||
///
|
||||
/// The keys are hydration IDs. Valeus are tuples of two pinned
|
||||
/// The keys are hydration IDs. Values are tuples of two pinned
|
||||
/// `Future`s that return content for out-of-order and in-order streaming, respectively.
|
||||
pub fn pending_fragments(
|
||||
&self,
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
//! # run_scope(create_runtime(), |cx| {
|
||||
//! spawn_local(async {
|
||||
//! let posts = read_posts(3, "my search".to_string()).await;
|
||||
//! log::debug!("posts = {posts{:#?}");
|
||||
//! log::debug!("posts = {posts:#?}");
|
||||
//! })
|
||||
//! # });
|
||||
//!
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos_meta"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
edition = "2021"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
|
||||
@@ -30,6 +30,9 @@ pub fn Meta(
|
||||
/// The [`name`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta#attr-name) attribute.
|
||||
#[prop(optional, into)]
|
||||
name: Option<TextProp>,
|
||||
/// The [`property`](https://ogp.me/) attribute.
|
||||
#[prop(optional, into)]
|
||||
property: Option<TextProp>,
|
||||
/// The [`http-equiv`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta#attr-http-equiv) attribute.
|
||||
#[prop(optional, into)]
|
||||
http_equiv: Option<TextProp>,
|
||||
@@ -45,6 +48,7 @@ pub fn Meta(
|
||||
leptos::leptos_dom::html::meta(cx)
|
||||
.attr("charset", move || charset.as_ref().map(|v| v.get()))
|
||||
.attr("name", move || name.as_ref().map(|v| v.get()))
|
||||
.attr("property", move || property.as_ref().map(|v| v.get()))
|
||||
.attr("http-equiv", move || http_equiv.as_ref().map(|v| v.get()))
|
||||
.attr("content", move || content.as_ref().map(|v| v.get()))
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos_router"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
edition = "2021"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
|
||||
@@ -120,7 +120,10 @@ where
|
||||
Ok(url) => {
|
||||
request_animation_frame(move || {
|
||||
if let Err(e) = navigate(
|
||||
&url.pathname,
|
||||
&format!(
|
||||
"{}{}",
|
||||
url.pathname, url.search,
|
||||
),
|
||||
Default::default(),
|
||||
) {
|
||||
warn!("{}", e);
|
||||
|
||||
@@ -3,10 +3,7 @@ use crate::{
|
||||
ParamsMap, RouterContext, SsrMode,
|
||||
};
|
||||
use leptos::{leptos_dom::Transparent, *};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
rc::Rc,
|
||||
};
|
||||
use std::{cell::Cell, rc::Rc};
|
||||
|
||||
thread_local! {
|
||||
static ROUTE_ID: Cell<usize> = Cell::new(0);
|
||||
@@ -121,7 +118,7 @@ impl RouteContext {
|
||||
id,
|
||||
base_path: base,
|
||||
child: Box::new(child),
|
||||
path: RefCell::new(path),
|
||||
path: create_rw_signal(cx, path),
|
||||
original_path: route.original_path.to_string(),
|
||||
params,
|
||||
outlet: Box::new(move |cx| Some(element(cx))),
|
||||
@@ -144,11 +141,11 @@ impl RouteContext {
|
||||
/// e.g., this will return `/article/0` rather than `/article/:id`.
|
||||
/// For the opposite behavior, see [RouteContext::original_path].
|
||||
pub fn path(&self) -> String {
|
||||
self.inner.path.borrow().to_string()
|
||||
self.inner.path.get_untracked()
|
||||
}
|
||||
|
||||
pub(crate) fn set_path(&mut self, path: String) {
|
||||
*self.inner.path.borrow_mut() = path;
|
||||
pub(crate) fn set_path(&self, path: String) {
|
||||
self.inner.path.set(path);
|
||||
}
|
||||
|
||||
/// Returns the original URL path of the current route,
|
||||
@@ -176,7 +173,7 @@ impl RouteContext {
|
||||
id: 0,
|
||||
base_path: path.to_string(),
|
||||
child: Box::new(|_| None),
|
||||
path: RefCell::new(path.to_string()),
|
||||
path: create_rw_signal(cx, path.to_string()),
|
||||
original_path: path.to_string(),
|
||||
params: create_memo(cx, |_| ParamsMap::new()),
|
||||
outlet: Box::new(move |cx| {
|
||||
@@ -188,7 +185,16 @@ impl RouteContext {
|
||||
|
||||
/// Resolves a relative route, relative to the current route's path.
|
||||
pub fn resolve_path(&self, to: &str) -> Option<String> {
|
||||
resolve_path(&self.inner.base_path, to, Some(&self.inner.path.borrow()))
|
||||
resolve_path(
|
||||
&self.inner.base_path,
|
||||
to,
|
||||
Some(&self.inner.path.get_untracked()),
|
||||
)
|
||||
.map(String::from)
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_path_tracked(&self, to: &str) -> Option<String> {
|
||||
resolve_path(&self.inner.base_path, to, Some(&self.inner.path.get()))
|
||||
.map(String::from)
|
||||
}
|
||||
|
||||
@@ -208,7 +214,7 @@ pub(crate) struct RouteContextInner {
|
||||
base_path: String,
|
||||
pub(crate) id: usize,
|
||||
pub(crate) child: Box<dyn Fn(Scope) -> Option<RouteContext>>,
|
||||
pub(crate) path: RefCell<String>,
|
||||
pub(crate) path: RwSignal<String>,
|
||||
pub(crate) original_path: String,
|
||||
pub(crate) params: Memo<ParamsMap>,
|
||||
pub(crate) outlet: Box<dyn Fn(Scope) -> Option<View>>,
|
||||
|
||||
@@ -221,55 +221,36 @@ impl RouterContextInner {
|
||||
if resolved_to != this.reference.get()
|
||||
|| options.state != (this.state).get()
|
||||
{
|
||||
if cfg!(feature = "server") {
|
||||
self.history.navigate(&LocationChange {
|
||||
value: resolved_to,
|
||||
{
|
||||
self.referrers.borrow_mut().push(LocationChange {
|
||||
value: self.reference.get(),
|
||||
replace: options.replace,
|
||||
scroll: options.scroll,
|
||||
state: options.state.clone(),
|
||||
state: self.state.get(),
|
||||
});
|
||||
} else {
|
||||
{
|
||||
self.referrers.borrow_mut().push(
|
||||
LocationChange {
|
||||
value: self.reference.get(),
|
||||
replace: options.replace,
|
||||
scroll: options.scroll,
|
||||
state: self.state.get(),
|
||||
},
|
||||
);
|
||||
}
|
||||
let len = self.referrers.borrow().len();
|
||||
}
|
||||
let len = self.referrers.borrow().len();
|
||||
|
||||
#[cfg(feature = "transition")]
|
||||
let transition = use_transition(self.cx);
|
||||
//transition.start({
|
||||
let set_reference = self.set_reference;
|
||||
let set_state = self.set_state;
|
||||
let referrers = self.referrers.clone();
|
||||
let this = Rc::clone(&self);
|
||||
//move || {
|
||||
let set_reference = self.set_reference;
|
||||
let set_state = self.set_state;
|
||||
let referrers = self.referrers.clone();
|
||||
let this = Rc::clone(&self);
|
||||
|
||||
let resolved = resolved_to.to_string();
|
||||
let state = options.state.clone();
|
||||
queue_microtask(move || {
|
||||
set_reference.update(move |r| *r = resolved);
|
||||
let resolved = resolved_to.to_string();
|
||||
let state = options.state.clone();
|
||||
set_reference.update(move |r| *r = resolved);
|
||||
|
||||
set_state.update({
|
||||
let next_state = state.clone();
|
||||
move |state| *state = next_state
|
||||
});
|
||||
if referrers.borrow().len() == len {
|
||||
this.navigate_end(LocationChange {
|
||||
value: resolved_to.to_string(),
|
||||
replace: false,
|
||||
scroll: true,
|
||||
state,
|
||||
})
|
||||
//}
|
||||
}
|
||||
});
|
||||
//});
|
||||
set_state.update({
|
||||
let next_state = state.clone();
|
||||
move |state| *state = next_state
|
||||
});
|
||||
if referrers.borrow().len() == len {
|
||||
this.navigate_end(LocationChange {
|
||||
value: resolved_to,
|
||||
replace: false,
|
||||
scroll: true,
|
||||
state,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ pub fn Routes(
|
||||
if next_match.route.key == prev_match.route.key
|
||||
&& next_match.route.id == prev_match.route.id =>
|
||||
{
|
||||
let mut prev_one = { prev.borrow()[i].clone() };
|
||||
let prev_one = { prev.borrow()[i].clone() };
|
||||
if next_match.path_match.path != prev_one.path() {
|
||||
prev_one
|
||||
.set_path(next_match.path_match.path.clone());
|
||||
|
||||
@@ -70,7 +70,7 @@ pub fn use_resolved_path(
|
||||
if path.starts_with('/') {
|
||||
Some(path)
|
||||
} else {
|
||||
route.resolve_path(&path).map(String::from)
|
||||
route.resolve_path_tracked(&path).map(String::from)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ cfg_if! {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_complext_query_string() {
|
||||
fn test_complex_query_string() {
|
||||
let url = Url::try_from("http://leptos.com?data=Data%3A+%24+%26+%2B%2B+7").unwrap();
|
||||
assert_params_map!{
|
||||
["data" => "Data: $ & ++ 7"],
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
//! # async fn main() {
|
||||
//! async {
|
||||
//! let posts = read_posts(3, "my search".to_string()).await;
|
||||
//! log::debug!("posts = {posts{:#?}");
|
||||
//! log::debug!("posts = {posts:#?}");
|
||||
//! }
|
||||
//! # }
|
||||
//!
|
||||
|
||||
@@ -14,7 +14,7 @@ use syn::{
|
||||
*,
|
||||
};
|
||||
|
||||
/// Discribes the custom context from the server that passed to the server function. Optionally, the first argument of a server function
|
||||
/// Describes the custom context from the server that passed to the server function. Optionally, the first argument of a server function
|
||||
/// can be a custom context of this type. This context can be used to access the server's state within the server function.
|
||||
pub struct ServerContext {
|
||||
/// The type of the context.
|
||||
|
||||
Reference in New Issue
Block a user