Compare commits

..

1 Commits

Author SHA1 Message Date
Greg Johnston
12a052eaaf chore: specify Tailwind version in Trunk.toml (closes #4315) 2025-09-21 13:47:46 -04:00
31 changed files with 148 additions and 358 deletions

59
Cargo.lock generated
View File

@@ -279,9 +279,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.100"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
[[package]]
name = "async-executor"
@@ -903,14 +903,12 @@ dependencies = [
[[package]]
name = "dioxus-cli-config"
version = "0.7.0-rc.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8cec511d8a05ed60071bb0088f07ec40325faf27a608fa19d65befdd842b57f"
source = "git+https://github.com/dioxuslabs/dioxus#eef4db67b1164934eb29b7ac4d4bcd693bba25a5"
[[package]]
name = "dioxus-core"
version = "0.7.0-rc.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07b55eccaa5c4f35f1755ea18a5716fe8ecba60ff1f25c52be6ceda2e6a52eb6"
source = "git+https://github.com/dioxuslabs/dioxus#eef4db67b1164934eb29b7ac4d4bcd693bba25a5"
dependencies = [
"const_format",
"dioxus-core-types",
@@ -931,14 +929,12 @@ dependencies = [
[[package]]
name = "dioxus-core-types"
version = "0.7.0-rc.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0ef2a94b4ceb8f7a39f56a539d07e82b0358a49a0b95028ad48635975df29d7"
source = "git+https://github.com/dioxuslabs/dioxus#eef4db67b1164934eb29b7ac4d4bcd693bba25a5"
[[package]]
name = "dioxus-devtools"
version = "0.7.0-rc.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60af4e129968ab1713471ed0b29c3eefa4e8e09252429487d7a581e93c7ecfe5"
source = "git+https://github.com/dioxuslabs/dioxus#eef4db67b1164934eb29b7ac4d4bcd693bba25a5"
dependencies = [
"dioxus-cli-config",
"dioxus-core",
@@ -956,8 +952,7 @@ dependencies = [
[[package]]
name = "dioxus-devtools-types"
version = "0.7.0-rc.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64274704b6a8d018112473cdce0b3db1dcccfa79bde445223592fe4e396ff5ef"
source = "git+https://github.com/dioxuslabs/dioxus#eef4db67b1164934eb29b7ac4d4bcd693bba25a5"
dependencies = [
"dioxus-core",
"serde",
@@ -967,8 +962,7 @@ dependencies = [
[[package]]
name = "dioxus-signals"
version = "0.7.0-rc.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1d0e70a8da969c0404f5ef8cf6f47042bea55608b582079f3ea3d9fff46125c"
source = "git+https://github.com/dioxuslabs/dioxus#eef4db67b1164934eb29b7ac4d4bcd693bba25a5"
dependencies = [
"dioxus-core",
"futures-channel",
@@ -1057,7 +1051,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys 0.61.0",
]
[[package]]
@@ -1245,8 +1239,7 @@ dependencies = [
[[package]]
name = "generational-box"
version = "0.7.0-rc.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb058e0358ff765e719ab3e61629c5090fedb6a6ccf66479de21440a33d7f084"
source = "git+https://github.com/dioxuslabs/dioxus#eef4db67b1164934eb29b7ac4d4bcd693bba25a5"
dependencies = [
"parking_lot",
"tracing",
@@ -1880,7 +1873,7 @@ checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
[[package]]
name = "leptos"
version = "0.8.10"
version = "0.8.9"
dependencies = [
"any_spawner",
"base64",
@@ -2001,7 +1994,7 @@ dependencies = [
[[package]]
name = "leptos_dom"
version = "0.8.7"
version = "0.8.6"
dependencies = [
"js-sys",
"leptos",
@@ -2034,7 +2027,7 @@ dependencies = [
[[package]]
name = "leptos_integration_utils"
version = "0.8.6"
version = "0.8.5"
dependencies = [
"futures",
"hydration_context",
@@ -2047,7 +2040,7 @@ dependencies = [
[[package]]
name = "leptos_macro"
version = "0.8.9"
version = "0.8.8"
dependencies = [
"attribute-derive",
"cfg-if",
@@ -2091,7 +2084,7 @@ dependencies = [
[[package]]
name = "leptos_router"
version = "0.8.8"
version = "0.8.7"
dependencies = [
"any_spawner",
"either_of",
@@ -2155,12 +2148,12 @@ checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "libloading"
version = "0.8.9"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
dependencies = [
"cfg-if",
"windows-link 0.2.0",
"windows-targets 0.53.3",
]
[[package]]
@@ -2875,7 +2868,7 @@ dependencies = [
[[package]]
name = "reactive_graph"
version = "0.2.8"
version = "0.2.7"
dependencies = [
"any_spawner",
"async-lock",
@@ -3144,7 +3137,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
"windows-sys 0.61.0",
]
[[package]]
@@ -3645,8 +3638,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "subsecond"
version = "0.7.0-rc.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b14ed4d86ab065ffbfdb994fd3e44daf5244b02cb643bd52949d74b703f36605"
source = "git+https://github.com/dioxuslabs/dioxus#eef4db67b1164934eb29b7ac4d4bcd693bba25a5"
dependencies = [
"js-sys",
"libc",
@@ -3664,8 +3656,7 @@ dependencies = [
[[package]]
name = "subsecond-types"
version = "0.7.0-rc.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "275920a8a5634e47e12253971db85946798795bbe4d9dfc1debf23533d823983"
source = "git+https://github.com/dioxuslabs/dioxus#eef4db67b1164934eb29b7ac4d4bcd693bba25a5"
dependencies = [
"serde",
]
@@ -3744,7 +3735,7 @@ dependencies = [
[[package]]
name = "tachys"
version = "0.2.9"
version = "0.2.8"
dependencies = [
"any_spawner",
"async-trait",
@@ -3813,7 +3804,7 @@ dependencies = [
"getrandom 0.3.3",
"once_cell",
"rustix",
"windows-sys 0.52.0",
"windows-sys 0.61.0",
]
[[package]]
@@ -4620,7 +4611,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.52.0",
"windows-sys 0.61.0",
]
[[package]]

View File

@@ -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.10" }
leptos = { path = "./leptos", version = "0.8.9" }
leptos_config = { path = "./leptos_config", version = "0.8.7" }
leptos_dom = { path = "./leptos_dom", version = "0.8.7" }
leptos_dom = { path = "./leptos_dom", version = "0.8.6" }
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.8.5" }
leptos_integration_utils = { path = "./integrations/utils", version = "0.8.6" }
leptos_macro = { path = "./leptos_macro", version = "0.8.9" }
leptos_router = { path = "./router", version = "0.8.8" }
leptos_integration_utils = { path = "./integrations/utils", version = "0.8.5" }
leptos_macro = { path = "./leptos_macro", version = "0.8.8" }
leptos_router = { path = "./router", version = "0.8.7" }
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.8" }
reactive_graph = { path = "./reactive_graph", version = "0.2.7" }
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.7" }
server_fn_macro = { path = "./server_fn_macro", version = "0.8.7" }
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.8.5" }
tachys = { path = "./tachys", version = "0.2.9" }
tachys = { path = "./tachys", version = "0.2.8" }
wasm_split_helpers = { path = "./wasm_split", version = "0.1.2" }
wasm_split_macros = { path = "./wasm_split_macros", version = "0.1.3" }
@@ -125,7 +125,7 @@ glib = { default-features = false, version = "0.20.12" }
async-trait = { default-features = false, version = "0.1.89" }
typed-builder-macro = { default-features = false, version = "0.21.0" }
linear-map = { default-features = false, version = "1.2.0" }
anyhow = { default-features = false, version = "1.0.100" }
anyhow = { default-features = false, version = "1.0.99" }
walkdir = { default-features = false, version = "2.5.0" }
actix-ws = { default-features = false, version = "0.3.0" }
tower-http = { default-features = false, version = "0.6.4" }
@@ -170,9 +170,9 @@ async-lock = { default-features = false, version = "3.4.1" }
base16 = { default-features = false, version = "0.2.1" }
digest = { default-features = false, version = "0.10.7" }
sha2 = { default-features = false, version = "0.10.8" }
subsecond = { default-features = false, version = "0.7.0-rc.0" }
dioxus-cli-config = { default-features = false, version = "0.7.0-rc.0" }
dioxus-devtools = { default-features = false, version = "0.7.0-rc.0" }
subsecond = { default-features = false, git = "https://github.com/dioxuslabs/dioxus" }
dioxus-cli-config = { default-features = false, git = "https://github.com/dioxuslabs/dioxus" }
dioxus-devtools = { default-features = false, git = "https://github.com/dioxuslabs/dioxus" }
[profile.release]
codegen-units = 1

View File

@@ -1,13 +0,0 @@
@check_issue_4251
Feature: Check that issue 4251 does not reappear
Scenario: Clicking a link to the same page youre currently on should not add the page to the history stack.
Given I see the app
And I can access regression test 4324
When I select the link This page
And I select the link This page
And I select the link This page
Then I see the result is the string Issue4324
When I press the back button
And I select the link 4324
Then I see the result is the string Issue4324

View File

@@ -1,11 +0,0 @@
@check_issue_4324
Feature: Check that issue 4324 does not reappear
Scenario: Navigating to the same page after clicking "Back" should set the URL correctly
Given I see the app
And I can access regression test 4324
Then I see the path is /4324/
When I press the back button
Then I see the path is /
When I select the link 4324
Then I see the path is /4324/

View File

@@ -43,13 +43,3 @@ pub async fn element_value_is(
assert_eq!(value.as_deref(), Some(expected));
Ok(())
}
pub async fn path_is(client: &Client, expected_path: &str) -> Result<()> {
let url = client
.current_url()
.await
.expect("could not access current URL");
let path = url.path();
assert_eq!(expected_path, path);
Ok(())
}

View File

@@ -45,12 +45,3 @@ async fn i_refresh_the_browser(world: &mut AppWorld) -> Result<()> {
Ok(())
}
#[given(regex = "^I press the back button$")]
#[when(regex = "^I press the back button$")]
async fn i_go_back(world: &mut AppWorld) -> Result<()> {
let client = &world.client;
client.back().await?;
Ok(())
}

View File

@@ -43,10 +43,3 @@ async fn i_see_the_value(
check::element_value_is(client, &id, &value).await?;
Ok(())
}
#[then(regex = r"^I see the path is (.*)$")]
async fn i_see_the_path(world: &mut AppWorld, path: String) -> Result<()> {
let client = &world.client;
check::path_is(client, &path).await?;
Ok(())
}

View File

@@ -1,7 +1,7 @@
use crate::{
issue_4005::Routes4005, issue_4088::Routes4088, issue_4217::Routes4217,
issue_4285::Routes4285, issue_4296::Routes4296, issue_4324::Routes4324,
pr_4015::Routes4015, pr_4091::Routes4091,
issue_4285::Routes4285, issue_4296::Routes4296, pr_4015::Routes4015,
pr_4091::Routes4091,
};
use leptos::prelude::*;
use leptos_meta::{MetaTags, *};
@@ -47,7 +47,6 @@ pub fn App() -> impl IntoView {
<Routes4005/>
<Routes4285/>
<Routes4296/>
<Routes4324/>
</Routes>
</main>
</Router>
@@ -74,7 +73,6 @@ fn HomePage() -> impl IntoView {
<li><a href="/4005/">"4005"</a></li>
<li><a href="/4285/">"4285"</a></li>
<li><a href="/4296/">"4296"</a></li>
<li><a href="/4324/">"4324"</a></li>
</ul>
</nav>
}

View File

@@ -1,21 +0,0 @@
use leptos::prelude::*;
#[allow(unused_imports)]
use leptos_router::{
components::Route, path, Lazy, MatchNestedRoutes, NavigateOptions,
};
#[component]
pub fn Routes4324() -> impl MatchNestedRoutes + Clone {
view! {
<Route path=path!("4324") view=Issue4324/>
}
.into_inner()
}
#[component]
pub fn Issue4324() -> impl IntoView {
view! {
<a href="/4324/">"This page"</a>
<p id="result">"Issue4324"</p>
}
}

View File

@@ -4,7 +4,6 @@ mod issue_4088;
mod issue_4217;
mod issue_4285;
mod issue_4296;
mod issue_4324;
mod pr_4015;
mod pr_4091;

View File

@@ -4,7 +4,7 @@ authors = ["Greg Johnston"]
license = "MIT"
repository = "https://github.com/leptos-rs/leptos"
description = "Utilities to help build server integrations for the Leptos web framework."
version = "0.8.6"
version = "0.8.5"
rust-version.workspace = true
edition.workspace = true

View File

@@ -68,8 +68,7 @@ pub trait ExtendResponse: Sized {
let nonce =
use_nonce().map(|n| n.to_string()).unwrap_or_default();
if let Some(manifest) = use_context::<WasmSplitManifest>() {
let (pkg_path, manifest, wasm_split_file) =
&*manifest.0.read_value();
let (pkg_path, manifest) = &*manifest.0.read_value();
let prefetches = prefetches.0.read_value();
let all_prefetches = prefetches.iter().flat_map(|key| {
@@ -91,7 +90,7 @@ pub trait ExtendResponse: Sized {
.to_html();
}
_ = view! {
<Link rel="modulepreload" href=format!("{pkg_path}/{wasm_split_file}") crossorigin=nonce/>
<Link rel="modulepreload" href=format!("{pkg_path}/__wasm_split.js") crossorigin=nonce/>
}
.to_html();
}

View File

@@ -1,6 +1,6 @@
[package]
name = "leptos"
version = "0.8.10"
version = "0.8.9"
authors = ["Greg Johnston"]
license = "MIT"
repository = "https://github.com/leptos-rs/leptos"

View File

@@ -65,56 +65,16 @@ pub fn HydrationScripts(
if let Some(splits) = SPLIT_MANIFEST.get_or_init(|| {
let root = root.clone().unwrap_or_default();
let (wasm_split_js, wasm_split_manifest) = if options.hash_files {
let hash_path = std::env::current_exe()
.map(|path| {
path.parent().map(|p| p.to_path_buf()).unwrap_or_default()
})
.unwrap_or_default()
.join(options.hash_file.as_ref());
let hashes = std::fs::read_to_string(&hash_path)
.expect("failed to read hash file");
let mut split =
"__wasm_split.______________________.js".to_string();
let mut manifest = "__wasm_split_manifest.json".to_string();
for line in hashes.lines() {
let line = line.trim();
if !line.is_empty() {
if let Some((file, hash)) = line.split_once(':') {
if file == "manifest" {
manifest.clear();
manifest.push_str("__wasm_split_manifest.");
manifest.push_str(hash.trim());
manifest.push_str(".json");
}
if file == "split" {
split.clear();
split.push_str("__wasm_split.");
split.push_str(hash.trim());
split.push_str(".js");
}
}
}
}
(split, manifest)
} else {
(
"__wasm_split.______________________.js".to_string(),
"__wasm_split_manifest.json".to_string(),
)
};
let site_dir = &options.site_root;
let pkg_dir = &options.site_pkg_dir;
let path = PathBuf::from(site_dir.to_string());
let path = path.join(pkg_dir.to_string()).join(wasm_split_manifest);
let path = path
.join(pkg_dir.to_string())
.join("__wasm_split_manifest.json");
let file = std::fs::read_to_string(path).ok()?;
let manifest = WasmSplitManifest(ArcStoredValue::new((
format!("{root}/{pkg_dir}"),
serde_json::from_str(&file).expect("could not read manifest file"),
wasm_split_js,
)));
Some(manifest)

View File

@@ -395,8 +395,7 @@ pub fn prefetch_lazy_fn_on_server(id: &'static str) {
#[derive(Clone, Debug, Default)]
pub struct WasmSplitManifest(
pub reactive_graph::owner::ArcStoredValue<(
String, // the pkg root
std::collections::HashMap<String, Vec<String>>, // preloads
String, // the name of the __wasm_split.js file
String,
std::collections::HashMap<String, Vec<String>>,
)>,
);

View File

@@ -1,6 +1,6 @@
[package]
name = "leptos_dom"
version = "0.8.7"
version = "0.8.6"
authors = ["Greg Johnston"]
license = "MIT"
repository = "https://github.com/leptos-rs/leptos"

View File

@@ -1,6 +1,6 @@
[package]
name = "leptos_macro"
version = "0.8.9"
version = "0.8.8"
authors = ["Greg Johnston"]
license = "MIT"
repository = "https://github.com/leptos-rs/leptos"

View File

@@ -25,8 +25,9 @@ use std::{
use syn::{
punctuated::Pair::{End, Punctuated},
spanned::Spanned,
Expr::{self, Tuple},
ExprArray, ExprLit, ExprPath, ExprRange, Lit, LitStr, RangeLimits, Stmt,
Expr,
Expr::Tuple,
ExprArray, ExprLit, ExprRange, Lit, LitStr, RangeLimits, Stmt,
};
#[derive(Clone, Copy, PartialEq, Eq)]
@@ -1870,28 +1871,6 @@ pub(crate) fn ident_from_tag_name(tag_name: &NodeName) -> Ident {
}
}
pub(crate) fn full_path_from_tag_name(tag_name: &NodeName) -> Option<ExprPath> {
match tag_name {
NodeName::Path(path) => Some(path.clone()),
NodeName::Block(_) => {
let span = tag_name.span();
proc_macro_error2::emit_error!(
span,
"blocks not allowed in tag-name position"
);
None
}
_ => {
let span = tag_name.span();
proc_macro_error2::emit_error!(
span,
"punctuated names not allowed in slots"
);
None
}
}
}
pub(crate) fn directive_call_from_attribute_node(
attr: &KeyedAttribute,
directive_name: &str,

View File

@@ -1,6 +1,6 @@
use super::{
component_builder::maybe_optimised_component_children,
convert_to_snake_case, full_path_from_tag_name,
convert_to_snake_case, ident_from_tag_name,
};
use crate::view::{fragment_to_tokens, utils::filter_prefixed_attrs, TagType};
use proc_macro2::{Ident, TokenStream, TokenTree};
@@ -24,7 +24,7 @@ pub(crate) fn slot_to_tokens(
node.name().to_string()
});
let component_path = full_path_from_tag_name(node.name());
let component_name = ident_from_tag_name(node.name());
let Some(parent_slots) = parent_slots else {
proc_macro_error2::emit_error!(
@@ -190,7 +190,7 @@ pub(crate) fn slot_to_tokens(
let slot = quote_spanned! {node.span()=>
{
let slot = #component_path::builder()
let slot = #component_name::builder()
#(#props)*
#(#slots)*
#children

View File

@@ -1,6 +1,6 @@
[package]
name = "reactive_graph"
version = "0.2.8"
version = "0.2.7"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"

View File

@@ -209,25 +209,6 @@ impl Owner {
this
}
/// Returns the parent of this `Owner`, if any.
///
/// None when:
/// - This is a root owner
/// - The parent has been dropped
pub fn parent(&self) -> Option<Owner> {
self.inner
.read()
.or_poisoned()
.parent
.as_ref()
.and_then(|p| p.upgrade())
.map(|inner| Owner {
inner,
#[cfg(feature = "hydration")]
shared_context: self.shared_context.clone(),
})
}
/// Creates a new `Owner` that is the child of the current `Owner`, if any.
pub fn child(&self) -> Self {
let parent = Some(Arc::downgrade(&self.inner));

View File

@@ -1,6 +1,6 @@
[package]
name = "leptos_router"
version = "0.8.8"
version = "0.8.7"
authors = ["Greg Johnston", "Ben Wishovich"]
license = "MIT"
readme = "../README.md"

View File

@@ -185,15 +185,11 @@ impl LocationProvider for BrowserUrl {
let is_back = self.is_back.clone();
move || match Self::current() {
Ok(new_url) => {
let mut stack = path_stack.write_value();
let stack = path_stack.read_value();
let is_navigating_back = stack.len() == 1
|| (stack.len() >= 2
&& stack.get(stack.len() - 2) == Some(&new_url));
if is_navigating_back {
stack.pop();
}
is_back.set(is_navigating_back);
url.set(new_url);

View File

@@ -1,6 +1,6 @@
[package]
name = "tachys"
version = "0.2.9"
version = "0.2.8"
authors = ["Greg Johnston"]
license = "MIT"
readme = "../README.md"

View File

@@ -205,14 +205,6 @@ where
self.add_any_attr(enterkeyhint(value))
}
/// The `exportparts` attribute enables the sharing of parts of an element's shadow DOM with a containing document.
fn exportparts(
self,
value: V,
) -> <Self as AddAnyAttr>::Output<Attr<Exportparts, V>> {
self.add_any_attr(exportparts(value))
}
/// The `hidden` global attribute is a Boolean attribute indicating that the element is not yet, or is no longer, relevant.
fn hidden(self, value: V) -> <Self as AddAnyAttr>::Output<Attr<Hidden, V>> {
self.add_any_attr(hidden(value))

View File

@@ -212,7 +212,7 @@ html_self_closing_elements! {
/// The `<img>` HTML element embeds an image into the document.
img HtmlImageElement [alt, attributionsrc, crossorigin, decoding, elementtiming, fetchpriority, height, ismap, loading, referrerpolicy, sizes, src, srcset, usemap, width] true,
/// The `<input>` HTML element is used to create interactive controls for web-based forms in order to accept data from the user; a wide variety of types of input data and control widgets are available, depending on the device and user agent. The `<input>` element is one of the most powerful and complex in all of HTML due to the sheer number of combinations of input types and attributes.
input HtmlInputElement [accept, alt, autocomplete, capture, checked, dirname, disabled, form, formaction, formenctype, formmethod, formnovalidate, formtarget, height, list, max, maxlength, min, minlength, multiple, name, pattern, placeholder, popovertarget, popovertargetaction, readonly, required, size, src, step, r#type, value, width] true,
input HtmlInputElement [accept, alt, autocomplete, capture, checked, disabled, form, formaction, formenctype, formmethod, formnovalidate, formtarget, height, list, max, maxlength, min, minlength, multiple, name, pattern, placeholder, popovertarget, popovertargetaction, readonly, required, size, src, step, r#type, value, width] true,
/// The `<link>` HTML element specifies relationships between the current document and an external resource. This element is most commonly used to link to CSS, but is also used to establish site icons (both "favicon" style icons and icons for the home screen and apps on mobile devices) among other things.
link HtmlLinkElement [r#as, blocking, crossorigin, fetchpriority, href, hreflang, imagesizes, imagesrcset, integrity, media, rel, referrerpolicy, sizes, r#type] true,
/// The `<meta>` HTML element represents Metadata that cannot be represented by other HTML meta-related elements, like base, link, script, style or title.

View File

@@ -323,9 +323,7 @@ where
fn rebuild(self, state: &mut Self::State) {
let (el, prev_cleanup) = state;
if let Some(prev) = prev_cleanup.take() {
if let Some(remove) = prev.into_inner() {
remove();
}
(prev.into_inner())(el);
}
*prev_cleanup = Some(if E::CAPTURE {
self.attach_capture(el)

View File

@@ -258,9 +258,7 @@ where
prop(self.key(), signal).rebuild(attr_state);
if let Some(prev) = prev_cleanup.take() {
if let Some(remove) = prev.into_inner() {
remove();
}
(prev.into_inner())(el);
}
*prev_cleanup = Some(self.attach(el));
}

View File

@@ -296,20 +296,19 @@ impl Dom {
// return the remover
RemoveEventHandler::new({
let name = name.to_owned();
let el = el.clone();
// safe to construct this here, because it will only run in the browser
// so it will always be accessed or dropped from the main thread
let cb = send_wrapper::SendWrapper::new(move || {
let cb = send_wrapper::SendWrapper::new(cb);
move |el: &Element| {
or_debug!(
el.remove_event_listener_with_callback(
intern(&name),
cb.as_ref().unchecked_ref()
),
&el,
el,
"removeEventListener"
)
});
move || cb()
}
})
}
@@ -335,21 +334,20 @@ impl Dom {
// return the remover
RemoveEventHandler::new({
let name = name.to_owned();
let el = el.clone();
// safe to construct this here, because it will only run in the browser
// so it will always be accessed or dropped from the main thread
let cb = send_wrapper::SendWrapper::new(move || {
let cb = send_wrapper::SendWrapper::new(cb);
move |el: &Element| {
or_debug!(
el.remove_event_listener_with_callback_and_bool(
intern(&name),
cb.as_ref().unchecked_ref(),
true
),
&el,
el,
"removeEventListener"
)
});
move || cb()
}
})
}
@@ -450,19 +448,17 @@ impl Dom {
// return the remover
RemoveEventHandler::new({
let key = key.to_owned();
let el = el.clone();
// safe to construct this here, because it will only run in the browser
// so it will always be accessed or dropped from the main thread
let el_cb = send_wrapper::SendWrapper::new((el, cb));
move || {
let (el, cb) = el_cb.take();
drop(cb);
let cb = send_wrapper::SendWrapper::new(cb);
move |el: &Element| {
drop(cb.take());
or_debug!(
js_sys::Reflect::delete_property(
&el,
el,
&JsValue::from_str(&key)
),
&el,
el,
"delete property"
);
}

View File

@@ -1,5 +1,5 @@
use crate::view::{Mountable, ToTemplate};
use std::{borrow::Cow, fmt::Debug, marker::PhantomData};
use std::{borrow::Cow, fmt::Debug};
use wasm_bindgen::JsValue;
/// A DOM renderer.
@@ -120,33 +120,16 @@ pub trait Renderer: Send + Sized + Debug + 'static {
should store it in some other data structure to clean it up \
later to avoid dropping it immediately, or leak it with \
std::mem::forget() to never drop it."]
#[allow(clippy::type_complexity)]
pub struct RemoveEventHandler<T>(
Option<Box<dyn FnOnce() + Send + Sync>>,
// only here to keep the generic, removing which would be a breaking change
// TODO remove generic in 0.9
PhantomData<fn() -> T>,
);
pub struct RemoveEventHandler<T>(Box<dyn FnOnce(&T) + Send + Sync>);
impl<T> RemoveEventHandler<T> {
/// Creates a new container with a function that will be called when it is dropped.
pub(crate) fn new(remove: impl FnOnce() + Send + Sync + 'static) -> Self {
Self(Some(Box::new(remove)), PhantomData)
pub(crate) fn new(remove: impl FnOnce(&T) + Send + Sync + 'static) -> Self {
Self(Box::new(remove))
}
#[allow(clippy::type_complexity)]
pub(crate) fn into_inner(
mut self,
) -> Option<Box<dyn FnOnce() + Send + Sync>> {
self.0.take()
}
}
impl<T> Drop for RemoveEventHandler<T> {
fn drop(&mut self) {
if let Some(cb) = self.0.take() {
cb()
}
pub(crate) fn into_inner(self) -> Box<dyn FnOnce(&T) + Send + Sync> {
self.0
}
}

View File

@@ -378,91 +378,83 @@ impl Stream for StreamBuilder {
let next_chunk = this.chunks.pop_front();
match next_chunk {
None => {
if this.pending_ooo.is_empty() {
if this.sync_buf.is_empty() {
Poll::Ready(None)
} else {
Poll::Ready(Some(mem::take(&mut this.sync_buf)))
}
} else {
// check if *any* pending out-of-order chunk is ready
for mut chunk in mem::take(&mut this.pending_ooo) {
match chunk.as_mut().poll(cx) {
Poll::Ready(OooChunk {
id,
chunks,
replace,
nonce,
}) => {
let opening = format!("<!--s-{id}o-->");
let placeholder_at =
this.sync_buf.find(&opening);
if let Some(start) = placeholder_at {
let closing = format!("<!--s-{id}c-->");
let end = this
.sync_buf
.find(&closing)
.unwrap();
let chunks_iter =
chunks.into_iter().rev();
// now, handle out-of-order chunks
if let Some(mut pending) = this.pending_ooo.pop_front() {
match pending.as_mut().poll(cx) {
Poll::Ready(OooChunk {
id,
chunks,
replace,
nonce,
}) => {
let opening = format!("<!--s-{id}o-->");
let placeholder_at =
this.sync_buf.find(&opening);
if let Some(start) = placeholder_at {
let closing = format!("<!--s-{id}c-->");
let end =
this.sync_buf.find(&closing).unwrap();
let chunks_iter = chunks.into_iter().rev();
// TODO can probably make this more efficient
let (before, replaced) =
this.sync_buf.split_at(start);
let (_, after) = replaced.split_at(
end - start + closing.len(),
);
let mut buf = String::new();
buf.push_str(before);
// TODO can probably make this more efficient
let (before, replaced) =
this.sync_buf.split_at(start);
let (_, after) = replaced
.split_at(end - start + closing.len());
let mut buf = String::new();
buf.push_str(before);
let mut held_chunks = VecDeque::new();
for chunk in chunks_iter {
if let StreamChunk::Sync(ready) =
chunk
{
buf.push_str(&ready);
} else {
held_chunks.push_front(chunk);
}
let mut held_chunks = VecDeque::new();
for chunk in chunks_iter {
if let StreamChunk::Sync(ready) = chunk
{
buf.push_str(&ready);
} else {
held_chunks.push_front(chunk);
}
buf.push_str(after);
this.sync_buf = buf;
for chunk in held_chunks {
}
buf.push_str(after);
this.sync_buf = buf;
for chunk in held_chunks {
this.chunks.push_front(chunk);
}
} else {
OooChunk::push_start(
&id,
&mut this.sync_buf,
);
for chunk in chunks.into_iter().rev() {
if let StreamChunk::Sync(ready) = chunk
{
this.sync_buf.push_str(&ready);
} else {
this.chunks.push_front(chunk);
}
} else {
OooChunk::push_start(
&id,
&mut this.sync_buf,
);
for chunk in chunks.into_iter().rev() {
if let StreamChunk::Sync(ready) =
chunk
{
this.sync_buf.push_str(&ready);
} else {
this.chunks.push_front(chunk);
}
}
OooChunk::push_end_with_nonce(
replace,
&id,
&mut this.sync_buf,
nonce.as_deref(),
);
}
OooChunk::push_end_with_nonce(
replace,
&id,
&mut this.sync_buf,
nonce.as_deref(),
);
}
Poll::Pending => {
this.pending_ooo.push_back(chunk);
self.poll_next(cx)
}
Poll::Pending => {
this.pending_ooo.push_back(pending);
if this.sync_buf.is_empty() {
Poll::Pending
} else {
Poll::Ready(Some(mem::take(
&mut this.sync_buf,
)))
}
}
}
if this.sync_buf.is_empty() {
Poll::Pending
} else {
Poll::Ready(Some(mem::take(&mut this.sync_buf)))
}
} else if this.sync_buf.is_empty() {
Poll::Ready(None)
} else {
Poll::Ready(Some(mem::take(&mut this.sync_buf)))
}
}
Some(StreamChunk::Sync(value)) => {