mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-28 10:11:56 -05:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8d80e0733 | ||
|
|
0f2168b92c |
26
Cargo.lock
generated
26
Cargo.lock
generated
@@ -1788,7 +1788,7 @@ checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
|
||||
|
||||
[[package]]
|
||||
name = "leptos"
|
||||
version = "0.8.8"
|
||||
version = "0.8.6"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"base64",
|
||||
@@ -1869,7 +1869,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_axum"
|
||||
version = "0.8.6"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"axum",
|
||||
@@ -1892,7 +1892,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_config"
|
||||
version = "0.8.7"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"config",
|
||||
"regex",
|
||||
@@ -1906,7 +1906,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_dom"
|
||||
version = "0.8.6"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"leptos",
|
||||
@@ -1952,7 +1952,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_macro"
|
||||
version = "0.8.7"
|
||||
version = "0.8.6"
|
||||
dependencies = [
|
||||
"attribute-derive",
|
||||
"cfg-if",
|
||||
@@ -1972,7 +1972,7 @@ dependencies = [
|
||||
"rustc_version",
|
||||
"serde",
|
||||
"server_fn",
|
||||
"server_fn_macro 0.8.7",
|
||||
"server_fn_macro 0.8.6",
|
||||
"syn 2.0.104",
|
||||
"tracing",
|
||||
"trybuild",
|
||||
@@ -1996,7 +1996,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_router"
|
||||
version = "0.8.6"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"either_of",
|
||||
@@ -2746,7 +2746,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reactive_graph"
|
||||
version = "0.2.6"
|
||||
version = "0.2.5"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"async-lock",
|
||||
@@ -2789,7 +2789,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reactive_stores_macro"
|
||||
version = "0.2.6"
|
||||
version = "0.2.5"
|
||||
dependencies = [
|
||||
"convert_case 0.8.0",
|
||||
"proc-macro-error2",
|
||||
@@ -3283,7 +3283,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "server_fn"
|
||||
version = "0.8.6"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"actix-web",
|
||||
"actix-ws",
|
||||
@@ -3346,7 +3346,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "server_fn_macro"
|
||||
version = "0.8.7"
|
||||
version = "0.8.6"
|
||||
dependencies = [
|
||||
"const_format",
|
||||
"convert_case 0.8.0",
|
||||
@@ -3361,7 +3361,7 @@ dependencies = [
|
||||
name = "server_fn_macro_default"
|
||||
version = "0.8.5"
|
||||
dependencies = [
|
||||
"server_fn_macro 0.8.7",
|
||||
"server_fn_macro 0.8.6",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
@@ -3573,7 +3573,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tachys"
|
||||
version = "0.2.7"
|
||||
version = "0.2.6"
|
||||
dependencies = [
|
||||
"any_spawner",
|
||||
"async-trait",
|
||||
|
||||
20
Cargo.toml
20
Cargo.toml
@@ -50,26 +50,26 @@ any_spawner = { path = "./any_spawner/", version = "0.3.0" }
|
||||
const_str_slice_concat = { path = "./const_str_slice_concat", version = "0.1" }
|
||||
either_of = { path = "./either_of/", version = "0.1.6" }
|
||||
hydration_context = { path = "./hydration_context", version = "0.3.0" }
|
||||
leptos = { path = "./leptos", version = "0.8.8" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.8.7" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.8.6" }
|
||||
leptos = { path = "./leptos", version = "0.8.6" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.8.5" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.8.5" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.8.5" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.8.5" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.8.7" }
|
||||
leptos_router = { path = "./router", version = "0.8.6" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.8.6" }
|
||||
leptos_router = { path = "./router", version = "0.8.5" }
|
||||
leptos_router_macro = { path = "./router_macro", version = "0.8.5" }
|
||||
leptos_server = { path = "./leptos_server", version = "0.8.5" }
|
||||
leptos_meta = { path = "./meta", version = "0.8.5" }
|
||||
next_tuple = { path = "./next_tuple", version = "0.1.0" }
|
||||
oco_ref = { path = "./oco", version = "0.2.1" }
|
||||
or_poisoned = { path = "./or_poisoned", version = "0.1.0" }
|
||||
reactive_graph = { path = "./reactive_graph", version = "0.2.6" }
|
||||
reactive_graph = { path = "./reactive_graph", version = "0.2.5" }
|
||||
reactive_stores = { path = "./reactive_stores", version = "0.2.5" }
|
||||
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.2.6" }
|
||||
server_fn = { path = "./server_fn", version = "0.8.6" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.8.7" }
|
||||
reactive_stores_macro = { path = "./reactive_stores_macro", version = "0.2.5" }
|
||||
server_fn = { path = "./server_fn", version = "0.8.5" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.8.6" }
|
||||
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.8.5" }
|
||||
tachys = { path = "./tachys", version = "0.2.7" }
|
||||
tachys = { path = "./tachys", version = "0.2.6" }
|
||||
wasm_split_helpers = { path = "./wasm_split", version = "0.1.2" }
|
||||
wasm_split_macros = { path = "./wasm_split_macros", version = "0.1.2" }
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
@check_issue_4005
|
||||
Feature: Check that issue 4005 does not reappear
|
||||
|
||||
Scenario: The second item is selected.
|
||||
Given I see the app
|
||||
And I can access regression test 4005
|
||||
Then I see the value of select is 2
|
||||
@@ -1,9 +0,0 @@
|
||||
@check_issue_4217
|
||||
Feature: Check that issue 4217 does not reappear
|
||||
|
||||
Scenario: All items are selected.
|
||||
Given I see the app
|
||||
And I can access regression test 4217
|
||||
Then I see option1 is selected
|
||||
And I see option2 is selected
|
||||
And I see option3 is selected
|
||||
25
examples/regression/e2e/tests/fixtures/check.rs
vendored
25
examples/regression/e2e/tests/fixtures/check.rs
vendored
@@ -18,28 +18,3 @@ pub async fn element_exists(client: &Client, id: &str) -> Result<()> {
|
||||
.expect(&format!("could not find element with id `{id}`"));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn select_option_is_selected(
|
||||
client: &Client,
|
||||
id: &str,
|
||||
) -> Result<()> {
|
||||
let el = find::element_by_id(client, id)
|
||||
.await
|
||||
.expect(&format!("could not find element with id `{id}`"));
|
||||
let selected = el.prop("selected").await?;
|
||||
assert_eq!(selected.as_deref(), Some("true"));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn element_value_is(
|
||||
client: &Client,
|
||||
id: &str,
|
||||
expected: &str,
|
||||
) -> Result<()> {
|
||||
let el = find::element_by_id(client, id)
|
||||
.await
|
||||
.expect(&format!("could not find element with id `{id}`"));
|
||||
let value = el.prop("value").await?;
|
||||
assert_eq!(value.as_deref(), Some(expected));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -25,21 +25,3 @@ async fn i_see_the_navbar(world: &mut AppWorld) -> Result<()> {
|
||||
check::element_exists(client, "nav").await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(regex = r"^I see ([\d\w]+) is selected$")]
|
||||
async fn i_see_the_select(world: &mut AppWorld, id: String) -> Result<()> {
|
||||
let client = &world.client;
|
||||
check::select_option_is_selected(client, &id).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(regex = r"^I see the value of (\w+) is (.*)$")]
|
||||
async fn i_see_the_value(
|
||||
world: &mut AppWorld,
|
||||
id: String,
|
||||
value: String,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
check::element_value_is(client, &id, &value).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use crate::{
|
||||
issue_4005::Routes4005, issue_4088::Routes4088, issue_4217::Routes4217,
|
||||
pr_4015::Routes4015, pr_4091::Routes4091,
|
||||
};
|
||||
use crate::{issue_4088::Routes4088, pr_4015::Routes4015, pr_4091::Routes4091};
|
||||
use leptos::prelude::*;
|
||||
use leptos_meta::{MetaTags, *};
|
||||
use leptos_router::{
|
||||
@@ -40,8 +37,6 @@ pub fn App() -> impl IntoView {
|
||||
<Routes4091/>
|
||||
<Routes4015/>
|
||||
<Routes4088/>
|
||||
<Routes4217/>
|
||||
<Routes4005/>
|
||||
</Routes>
|
||||
</main>
|
||||
</Router>
|
||||
@@ -64,8 +59,6 @@ fn HomePage() -> impl IntoView {
|
||||
<li><a href="/4091/">"4091"</a></li>
|
||||
<li><a href="/4015/">"4015"</a></li>
|
||||
<li><a href="/4088/">"4088"</a></li>
|
||||
<li><a href="/4217/">"4217"</a></li>
|
||||
<li><a href="/4005/">"4005"</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
use leptos::prelude::*;
|
||||
#[allow(unused_imports)]
|
||||
use leptos_router::{
|
||||
components::Route, path, MatchNestedRoutes, NavigateOptions,
|
||||
};
|
||||
|
||||
#[component]
|
||||
pub fn Routes4005() -> impl MatchNestedRoutes + Clone {
|
||||
view! {
|
||||
<Route path=path!("4005") view=Issue4005/>
|
||||
}
|
||||
.into_inner()
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Issue4005() -> impl IntoView {
|
||||
view! {
|
||||
<select id="select" prop:value="2">
|
||||
<option value="1">"Option 1"</option>
|
||||
<option value="2">"Option 2"</option>
|
||||
<option value="3">"Option 3"</option>
|
||||
</select>
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
use leptos::prelude::*;
|
||||
#[allow(unused_imports)]
|
||||
use leptos_router::{
|
||||
components::Route, path, MatchNestedRoutes, NavigateOptions,
|
||||
};
|
||||
|
||||
#[component]
|
||||
pub fn Routes4217() -> impl MatchNestedRoutes + Clone {
|
||||
view! {
|
||||
<Route path=path!("4217") view=Issue4217/>
|
||||
}
|
||||
.into_inner()
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Issue4217() -> impl IntoView {
|
||||
view! {
|
||||
<select multiple=true>
|
||||
<option id="option1" value="1" selected>"Option 1"</option>
|
||||
<option id="option2" value="2" selected>"Option 2"</option>
|
||||
<option id="option3" value="3" selected>"Option 3"</option>
|
||||
</select>
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
pub mod app;
|
||||
mod issue_4005;
|
||||
mod issue_4088;
|
||||
mod issue_4217;
|
||||
mod pr_4015;
|
||||
mod pr_4091;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
description = "Axum integrations for the Leptos web framework."
|
||||
version = "0.8.6"
|
||||
version = "0.8.5"
|
||||
rust-version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos"
|
||||
version = "0.8.8"
|
||||
version = "0.8.6"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
|
||||
@@ -27,6 +27,7 @@ pub fn AutoReload(
|
||||
None => options.reload_port,
|
||||
};
|
||||
let protocol = match options.reload_ws_protocol {
|
||||
leptos_config::ReloadWSProtocol::Auto => "null",
|
||||
leptos_config::ReloadWSProtocol::WS => "'ws://'",
|
||||
leptos_config::ReloadWSProtocol::WSS => "'wss://'",
|
||||
};
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
let host = window.location.hostname;
|
||||
|
||||
if (protocol === null) {
|
||||
protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
|
||||
}
|
||||
|
||||
let ws = new WebSocket(`${protocol}${host}:${reload_port}/live_reload`);
|
||||
ws.onmessage = (ev) => {
|
||||
let msg = JSON.parse(ev.data);
|
||||
|
||||
@@ -5,7 +5,7 @@ license = "MIT"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
description = "Configuration for the Leptos web framework."
|
||||
readme = "../README.md"
|
||||
version = "0.8.7"
|
||||
version = "0.8.5"
|
||||
rust-version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ impl LeptosOptions {
|
||||
None => None,
|
||||
},
|
||||
reload_ws_protocol: ws_from_str(
|
||||
env_w_default("LEPTOS_RELOAD_WS_PROTOCOL", "ws")?.as_str(),
|
||||
env_w_default("LEPTOS_RELOAD_WS_PROTOCOL", "auto")?.as_str(),
|
||||
)?,
|
||||
not_found_path: env_w_default("LEPTOS_NOT_FOUND_PATH", "/404")?
|
||||
.into(),
|
||||
@@ -283,22 +283,24 @@ impl TryFrom<String> for Env {
|
||||
pub enum ReloadWSProtocol {
|
||||
WS,
|
||||
WSS,
|
||||
Auto,
|
||||
}
|
||||
|
||||
impl Default for ReloadWSProtocol {
|
||||
fn default() -> Self {
|
||||
Self::WS
|
||||
Self::Auto
|
||||
}
|
||||
}
|
||||
|
||||
fn ws_from_str(input: &str) -> Result<ReloadWSProtocol, LeptosConfigError> {
|
||||
let sanitized = input.to_lowercase();
|
||||
match sanitized.as_ref() {
|
||||
"auto" => Ok(ReloadWSProtocol::Auto),
|
||||
"ws" | "WS" => Ok(ReloadWSProtocol::WS),
|
||||
"wss" | "WSS" => Ok(ReloadWSProtocol::WSS),
|
||||
_ => Err(LeptosConfigError::EnvVarError(format!(
|
||||
"{input} is not a supported websocket protocol. Use only `ws` or \
|
||||
`wss`.",
|
||||
"{input} is not a supported websocket protocol. Use only `auto`, \
|
||||
`ws` or `wss`.",
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos_dom"
|
||||
version = "0.8.6"
|
||||
version = "0.8.5"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
|
||||
@@ -258,7 +258,15 @@ pub fn request_idle_callback_with_handle(
|
||||
///
|
||||
/// <div class="warning">The task is called outside of the ownership tree, this means that if you want to access for example the context you need to reestablish the owner.</div>
|
||||
pub fn queue_microtask(task: impl FnOnce() + 'static) {
|
||||
tachys::renderer::dom::queue_microtask(task);
|
||||
use js_sys::{Function, Reflect};
|
||||
|
||||
let task = Closure::once_into_js(task);
|
||||
let window = web_sys::window().expect("window not available");
|
||||
let queue_microtask =
|
||||
Reflect::get(&window, &JsValue::from_str("queueMicrotask"))
|
||||
.expect("queueMicrotask not available");
|
||||
let queue_microtask = queue_microtask.unchecked_into::<Function>();
|
||||
_ = queue_microtask.call1(&JsValue::UNDEFINED, &task);
|
||||
}
|
||||
|
||||
/// Handle that is generated by [set_timeout_with_handle] and can be used to clear the timeout.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos_macro"
|
||||
version = "0.8.7"
|
||||
version = "0.8.6"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
|
||||
@@ -44,8 +44,7 @@ denylist = ["tracing"]
|
||||
max_combination_size = 2
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition", "--cfg", "docsrs"]
|
||||
all-features = true
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(leptos_debuginfo)'] }
|
||||
|
||||
@@ -386,7 +386,6 @@ T: Send + Sync + 'static,
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-wasm-bindgen")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serde-wasm-bindgen")))]
|
||||
impl<T> ArcOnceResource<T, JsonSerdeWasmCodec>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -419,7 +418,6 @@ fut: impl Future<Output = T> + Send + 'static
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "miniserde")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "miniserde")))]
|
||||
impl<T> ArcOnceResource<T, MiniserdeCodec>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -453,7 +451,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-lite")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serde-lite")))]
|
||||
impl<T> ArcOnceResource<T, SerdeLite<JsonSerdeCodec>>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -487,7 +484,6 @@ fut: impl Future<Output = T> + Send + 'static
|
||||
}
|
||||
|
||||
#[cfg(feature = "rkyv")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rkyv")))]
|
||||
impl<T> ArcOnceResource<T, RkyvCodec>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -752,7 +748,6 @@ T: Send + Sync + 'static,
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-wasm-bindgen")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serde-wasm-bindgen")))]
|
||||
impl<T> OnceResource<T, JsonSerdeWasmCodec>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -785,7 +780,6 @@ fut: impl Future<Output = T> + Send + 'static
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "miniserde")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "miniserde")))]
|
||||
impl<T> OnceResource<T, MiniserdeCodec>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -819,7 +813,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-lite")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serde-lite")))]
|
||||
impl<T> OnceResource<T, SerdeLite<JsonSerdeCodec>>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -853,7 +846,6 @@ fut: impl Future<Output = T> + Send + 'static
|
||||
}
|
||||
|
||||
#[cfg(feature = "rkyv")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rkyv")))]
|
||||
impl<T> OnceResource<T, RkyvCodec>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
|
||||
@@ -709,7 +709,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "rkyv")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rkyv")))]
|
||||
impl<T> ArcResource<T, RkyvCodec>
|
||||
where
|
||||
RkyvCodec: Encoder<T> + Decoder<T>,
|
||||
@@ -1049,7 +1048,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-wasm-bindgen")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serde-wasm-bindgen")))]
|
||||
impl<T> Resource<T, JsonSerdeWasmCodec>
|
||||
where
|
||||
JsonSerdeWasmCodec: Encoder<T> + Decoder<T>,
|
||||
@@ -1107,7 +1105,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "miniserde")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "miniserde")))]
|
||||
impl<T> Resource<T, MiniserdeCodec>
|
||||
where
|
||||
MiniserdeCodec: Encoder<T> + Decoder<T>,
|
||||
@@ -1167,7 +1164,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-lite")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serde-lite")))]
|
||||
impl<T> Resource<T, SerdeLite<JsonSerdeCodec>>
|
||||
where
|
||||
SerdeLite<JsonSerdeCodec>: Encoder<T> + Decoder<T>,
|
||||
@@ -1226,7 +1222,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "rkyv")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rkyv")))]
|
||||
impl<T> Resource<T, RkyvCodec>
|
||||
where
|
||||
RkyvCodec: Encoder<T> + Decoder<T>,
|
||||
|
||||
@@ -80,7 +80,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-lite")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serde-lite")))]
|
||||
impl<T> SharedValue<T, SerdeLite<JsonSerdeCodec>>
|
||||
where
|
||||
SerdeLite<JsonSerdeCodec>: Encoder<T> + Decoder<T>,
|
||||
@@ -103,7 +102,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde-wasm-bindgen")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "serde-wasm-bindgen")))]
|
||||
impl<T> SharedValue<T, JsonSerdeWasmCodec>
|
||||
where
|
||||
JsonSerdeWasmCodec: Encoder<T> + Decoder<T>,
|
||||
@@ -126,7 +124,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "miniserde")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "miniserde")))]
|
||||
impl<T> SharedValue<T, MiniserdeCodec>
|
||||
where
|
||||
MiniserdeCodec: Encoder<T> + Decoder<T>,
|
||||
@@ -149,7 +146,6 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "rkyv")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "rkyv")))]
|
||||
impl<T> SharedValue<T, RkyvCodec>
|
||||
where
|
||||
RkyvCodec: Encoder<T> + Decoder<T>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "reactive_graph"
|
||||
version = "0.2.6"
|
||||
version = "0.2.5"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "reactive_stores_macro"
|
||||
version = "0.2.6"
|
||||
version = "0.2.5"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos_router"
|
||||
version = "0.8.6"
|
||||
version = "0.8.5"
|
||||
authors = ["Greg Johnston", "Ben Wishovich"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
|
||||
@@ -5,7 +5,7 @@ license = "MIT"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
description = "RPC for any web framework."
|
||||
readme = "../README.md"
|
||||
version = "0.8.6"
|
||||
version = "0.8.5"
|
||||
rust-version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
|
||||
@@ -568,7 +568,7 @@ pub trait FromServerFnError: std::fmt::Debug + Sized + 'static {
|
||||
/// Converts a [`ServerFnErrorErr`] into the application-specific custom error type.
|
||||
fn from_server_fn_error(value: ServerFnErrorErr) -> Self;
|
||||
|
||||
/// Converts the custom error type to a [`String`].
|
||||
/// Serializes the custom error type to bytes, according to the encoding given by `Self::Encoding`.
|
||||
fn ser(&self) -> Bytes {
|
||||
Self::Encoder::encode(self).unwrap_or_else(|e| {
|
||||
Self::Encoder::encode(&Self::from_server_fn_error(
|
||||
@@ -581,7 +581,7 @@ pub trait FromServerFnError: std::fmt::Debug + Sized + 'static {
|
||||
})
|
||||
}
|
||||
|
||||
/// Deserializes the custom error type from a [`&str`].
|
||||
/// Deserializes the custom error type, according to the encoding given by `Self::Encoding`.
|
||||
fn de(data: Bytes) -> Self {
|
||||
Self::Encoder::decode(data).unwrap_or_else(|e| {
|
||||
ServerFnErrorErr::Deserialization(e.to_string()).into_app_error()
|
||||
|
||||
@@ -319,6 +319,12 @@ pub trait ServerFn: Send + Sized {
|
||||
)
|
||||
});
|
||||
|
||||
if err.is_some() {
|
||||
res.set_content_type(
|
||||
<<Self::Error as FromServerFnError>::Encoder>::CONTENT_TYPE,
|
||||
);
|
||||
}
|
||||
|
||||
// if it accepts HTML, we'll redirect to the Referer
|
||||
#[cfg(feature = "form-redirects")]
|
||||
if accepts_html {
|
||||
|
||||
@@ -72,6 +72,8 @@ mod axum {
|
||||
let inner = self.call(req);
|
||||
Box::pin(async move {
|
||||
inner.await.unwrap_or_else(|e| {
|
||||
// TODO: this needs to set the Content-Type correctly depending on the error type
|
||||
// note that this only applies to middleware errors
|
||||
let err =
|
||||
ser(ServerFnErrorErr::MiddlewareError(e.to_string()));
|
||||
Response::<Body>::error_response(&path, err)
|
||||
@@ -149,6 +151,8 @@ mod actix {
|
||||
let inner = self.call(req);
|
||||
Box::pin(async move {
|
||||
inner.await.unwrap_or_else(|e| {
|
||||
// TODO: this needs to set the Content-Type correctly depending on the error type
|
||||
// note that this only applies to middleware errors
|
||||
let err =
|
||||
ser(ServerFnErrorErr::MiddlewareError(e.to_string()));
|
||||
ActixResponse::error_response(&path, err).take()
|
||||
|
||||
@@ -4,8 +4,7 @@ use crate::error::{
|
||||
};
|
||||
use actix_web::{
|
||||
http::{
|
||||
header,
|
||||
header::{HeaderValue, LOCATION},
|
||||
header::{self, HeaderValue, CONTENT_TYPE, LOCATION},
|
||||
StatusCode,
|
||||
},
|
||||
HttpResponse,
|
||||
@@ -80,6 +79,12 @@ impl Res for ActixResponse {
|
||||
))
|
||||
}
|
||||
|
||||
fn set_content_type(&mut self, content_type: &str) {
|
||||
self.0
|
||||
.headers_mut()
|
||||
.append(CONTENT_TYPE, HeaderValue::from_str(content_type).unwrap());
|
||||
}
|
||||
|
||||
fn redirect(&mut self, path: &str) {
|
||||
if let Ok(path) = HeaderValue::from_str(path) {
|
||||
*self.0.status_mut() = StatusCode::FOUND;
|
||||
|
||||
@@ -19,7 +19,10 @@ use crate::error::{
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use futures::{Stream, TryStreamExt};
|
||||
use http::{header, HeaderValue, Response, StatusCode};
|
||||
use http::{
|
||||
header::{self, CONTENT_TYPE},
|
||||
HeaderValue, Response, StatusCode,
|
||||
};
|
||||
use std::pin::Pin;
|
||||
use throw_error::Error;
|
||||
|
||||
@@ -100,6 +103,11 @@ impl Res for Response<Body> {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn set_content_type(&mut self, content_type: &str) {
|
||||
self.headers_mut()
|
||||
.append(CONTENT_TYPE, HeaderValue::from_str(content_type).unwrap());
|
||||
}
|
||||
|
||||
fn redirect(&mut self, path: &str) {
|
||||
if let Ok(path) = HeaderValue::from_str(path) {
|
||||
self.headers_mut().insert(header::LOCATION, path);
|
||||
|
||||
@@ -6,7 +6,10 @@ use crate::error::{
|
||||
use axum::body::Body;
|
||||
use bytes::Bytes;
|
||||
use futures::{Stream, TryStreamExt};
|
||||
use http::{header, HeaderValue, Response, StatusCode};
|
||||
use http::{
|
||||
header::{self, CONTENT_TYPE},
|
||||
HeaderValue, Response, StatusCode,
|
||||
};
|
||||
|
||||
impl<E> TryRes<E> for Response<Body>
|
||||
where
|
||||
@@ -60,6 +63,11 @@ impl Res for Response<Body> {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn set_content_type(&mut self, content_type: &str) {
|
||||
self.headers_mut()
|
||||
.append(CONTENT_TYPE, HeaderValue::from_str(content_type).unwrap());
|
||||
}
|
||||
|
||||
fn redirect(&mut self, path: &str) {
|
||||
if let Ok(path) = HeaderValue::from_str(path) {
|
||||
self.headers_mut().insert(header::LOCATION, path);
|
||||
|
||||
@@ -37,9 +37,16 @@ where
|
||||
|
||||
/// Represents the response as created by the server;
|
||||
pub trait Res {
|
||||
/// Converts an error into a response, with a `500` status code and the error text as its body.
|
||||
/// Converts an error into a response, with a `500` status code and the error as its body.
|
||||
fn error_response(path: &str, err: Bytes) -> Self;
|
||||
|
||||
/// Sets the `Content-Type` header on the response.
|
||||
fn set_content_type(&mut self, content_type: &str) {
|
||||
// TODO 0.9: remove this method and default implementation
|
||||
// it is included here to make this change non-breaking
|
||||
_ = content_type;
|
||||
}
|
||||
|
||||
/// Redirect the response by setting a 302 code and Location header.
|
||||
fn redirect(&mut self, path: &str);
|
||||
}
|
||||
@@ -103,6 +110,11 @@ impl Res for BrowserMockRes {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn set_content_type(&mut self, content_type: &str) {
|
||||
_ = content_type;
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn redirect(&mut self, _path: &str) {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ license = "MIT"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
description = "RPC for any web framework."
|
||||
readme = "../README.md"
|
||||
version = "0.8.7"
|
||||
version = "0.8.6"
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tachys"
|
||||
version = "0.2.7"
|
||||
version = "0.2.6"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
|
||||
@@ -329,8 +329,6 @@ where
|
||||
fn build(self) -> Self::State {
|
||||
let el = Rndr::create_element(self.tag.tag(), E::NAMESPACE);
|
||||
|
||||
let attrs = self.attributes.build(&el);
|
||||
|
||||
let children = if E::SELF_CLOSING {
|
||||
None
|
||||
} else {
|
||||
@@ -339,6 +337,8 @@ where
|
||||
Some(children)
|
||||
};
|
||||
|
||||
let attrs = self.attributes.build(&el);
|
||||
|
||||
ElementState {
|
||||
el,
|
||||
attrs,
|
||||
|
||||
@@ -202,7 +202,7 @@ macro_rules! prop_type {
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let value = self.into();
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
@@ -212,14 +212,14 @@ macro_rules! prop_type {
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let value = self.into();
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = self.into();
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ macro_rules! prop_type {
|
||||
let was_some = self.is_some();
|
||||
let value = self.into();
|
||||
if was_some {
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
}
|
||||
(el.clone(), value)
|
||||
}
|
||||
@@ -258,7 +258,7 @@ macro_rules! prop_type {
|
||||
let was_some = self.is_some();
|
||||
let value = self.into();
|
||||
if was_some {
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
}
|
||||
(el.clone(), value)
|
||||
}
|
||||
@@ -266,7 +266,7 @@ macro_rules! prop_type {
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = self.into();
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ macro_rules! prop_type_str {
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let value = JsValue::from(&*self);
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
@@ -304,14 +304,14 @@ macro_rules! prop_type_str {
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let value = JsValue::from(&*self);
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = JsValue::from(&*self);
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ macro_rules! prop_type_str {
|
||||
let was_some = self.is_some();
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
if was_some {
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
}
|
||||
(el.clone(), value)
|
||||
}
|
||||
@@ -352,7 +352,7 @@ macro_rules! prop_type_str {
|
||||
let was_some = self.is_some();
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
if was_some {
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
}
|
||||
(el.clone(), value)
|
||||
}
|
||||
@@ -360,7 +360,7 @@ macro_rules! prop_type_str {
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ impl IntoProperty for Arc<str> {
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let value = JsValue::from_str(self.as_ref());
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
@@ -402,14 +402,14 @@ impl IntoProperty for Arc<str> {
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let value = JsValue::from_str(self.as_ref());
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = JsValue::from_str(self.as_ref());
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ impl IntoProperty for Option<Arc<str>> {
|
||||
let was_some = self.is_some();
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
if was_some {
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
}
|
||||
(el.clone(), value)
|
||||
}
|
||||
@@ -448,7 +448,7 @@ impl IntoProperty for Option<Arc<str>> {
|
||||
let was_some = self.is_some();
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
if was_some {
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
}
|
||||
(el.clone(), value)
|
||||
}
|
||||
@@ -456,7 +456,7 @@ impl IntoProperty for Option<Arc<str>> {
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = JsValue::from(self.map(|n| JsValue::from_str(&n)));
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ impl IntoProperty for Oco<'static, str> {
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let value = JsValue::from_str(self.as_ref());
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
@@ -271,14 +271,14 @@ impl IntoProperty for Oco<'static, str> {
|
||||
key: &str,
|
||||
) -> Self::State {
|
||||
let value = JsValue::from_str(self.as_ref());
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
(el.clone(), value)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State, key: &str) {
|
||||
let (el, prev) = state;
|
||||
let value = JsValue::from_str(self.as_ref());
|
||||
Rndr::set_property_or_value(el, key, &value);
|
||||
Rndr::set_property(el, key, &value);
|
||||
*prev = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,46 +36,6 @@ pub type ClassList = web_sys::DomTokenList;
|
||||
pub type CssStyleDeclaration = web_sys::CssStyleDeclaration;
|
||||
pub type TemplateElement = web_sys::HtmlTemplateElement;
|
||||
|
||||
/// A microtask is a short function which will run after the current task has
|
||||
/// completed its work and when there is no other code waiting to be run before
|
||||
/// control of the execution context is returned to the browser's event loop.
|
||||
///
|
||||
/// Microtasks are especially useful for libraries and frameworks that need
|
||||
/// to perform final cleanup or other just-before-rendering tasks.
|
||||
///
|
||||
/// [MDN queueMicrotask](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)
|
||||
pub fn queue_microtask(task: impl FnOnce() + 'static) {
|
||||
use js_sys::{Function, Reflect};
|
||||
|
||||
let task = Closure::once_into_js(task);
|
||||
let window = window();
|
||||
let queue_microtask =
|
||||
Reflect::get(&window, &JsValue::from_str("queueMicrotask"))
|
||||
.expect("queueMicrotask not available");
|
||||
let queue_microtask = queue_microtask.unchecked_into::<Function>();
|
||||
_ = queue_microtask.call1(&JsValue::UNDEFINED, &task);
|
||||
}
|
||||
|
||||
fn queue(fun: Box<dyn FnOnce()>) {
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
thread_local! {
|
||||
static PENDING: Cell<bool> = const { Cell::new(false) };
|
||||
static QUEUE: RefCell<Vec<Box<dyn FnOnce()>>> = RefCell::new(Vec::new());
|
||||
}
|
||||
|
||||
QUEUE.with_borrow_mut(|q| q.push(fun));
|
||||
if !PENDING.replace(true) {
|
||||
queue_microtask(|| {
|
||||
let tasks = QUEUE.take();
|
||||
for task in tasks {
|
||||
task();
|
||||
}
|
||||
PENDING.set(false);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Dom {
|
||||
pub fn intern(text: &str) -> &str {
|
||||
intern(text)
|
||||
@@ -251,20 +211,6 @@ impl Dom {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_property_or_value(el: &Element, key: &str, value: &JsValue) {
|
||||
if key == "value" {
|
||||
queue(Box::new({
|
||||
let el = el.clone();
|
||||
let value = value.clone();
|
||||
move || {
|
||||
Self::set_property(&el, "value", &value);
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
Self::set_property(el, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_property(el: &Element, key: &str, value: &JsValue) {
|
||||
or_debug!(
|
||||
js_sys::Reflect::set(
|
||||
|
||||
Reference in New Issue
Block a user