mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-27 16:54:41 -05:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54764261b1 | ||
|
|
acd8fd52c3 | ||
|
|
51bd63a91a | ||
|
|
1d34ea7133 | ||
|
|
f51c676e0d | ||
|
|
cf0aa0e4d7 | ||
|
|
a8894460e2 | ||
|
|
df09d4a7f6 | ||
|
|
403d6ed84e | ||
|
|
30b0a579ca | ||
|
|
50a4c3b0d9 | ||
|
|
c76649d77b | ||
|
|
911be5007e | ||
|
|
b37900ec55 | ||
|
|
fda2a1348c | ||
|
|
c2ea59ca96 | ||
|
|
7af2a31e21 | ||
|
|
0e45694c6e | ||
|
|
ca5c179cb1 | ||
|
|
5227221c96 | ||
|
|
3f48b77256 | ||
|
|
99117f496f | ||
|
|
cf12ea3404 | ||
|
|
d555c1e0ce | ||
|
|
40ea20057f | ||
|
|
5587ccd1eb | ||
|
|
50a9df9eea | ||
|
|
c46b1c4e25 | ||
|
|
e6f86408a1 | ||
|
|
aa13ed9431 |
2
.github/workflows/autofix.yml
vendored
2
.github/workflows/autofix.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
run: cargo fmt --all
|
||||
- name: Clippy the workspace
|
||||
run: cargo all-features clippy --allow-dirty --fix --lib --no-deps
|
||||
- uses: autofix-ci/action@v1.3.1
|
||||
- uses: autofix-ci/action@v1.3.2
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
fail-fast: false
|
||||
|
||||
249
Cargo.lock
generated
249
Cargo.lock
generated
@@ -88,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -205,7 +205,7 @@ dependencies = [
|
||||
"actix-router",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -233,9 +233,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
@@ -327,7 +327,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -344,7 +344,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -367,7 +367,7 @@ dependencies = [
|
||||
"manyhow",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -383,7 +383,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"quote-use",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -509,9 +509,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
version = "3.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck"
|
||||
@@ -533,7 +533,7 @@ checksum = "efb7846e0cb180355c2dec69e721edafa36919850f1a9f52ffba4ebc0393cb71"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -559,15 +559,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.9"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
|
||||
checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.24"
|
||||
version = "1.2.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7"
|
||||
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@@ -586,9 +586,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
@@ -850,7 +850,7 @@ checksum = "e73f2692d4bd3cac41dca28934a39894200c9fabf49586d77d0e5954af1d7902"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -863,7 +863,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -883,7 +883,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
@@ -905,7 +905,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1006,9 +1006,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
@@ -1120,7 +1120,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1172,7 +1172,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -1240,7 +1240,7 @@ dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1356,9 +1356,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.3"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
@@ -1382,9 +1382,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "html-escape"
|
||||
@@ -1470,7 +1470,6 @@ version = "0.3.0"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"or_poisoned",
|
||||
"pin-project-lite",
|
||||
"serde",
|
||||
@@ -1500,9 +1499,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.27.6"
|
||||
version = "0.27.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d"
|
||||
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
|
||||
dependencies = [
|
||||
"http 1.3.1",
|
||||
"hyper",
|
||||
@@ -1533,9 +1532,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.13"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8"
|
||||
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
@@ -1675,7 +1674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.3",
|
||||
"hashbrown 0.15.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1812,7 +1811,7 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
"proc-macro-error",
|
||||
"server_fn_macro 0.6.15",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1831,7 +1830,6 @@ dependencies = [
|
||||
"leptos_macro",
|
||||
"leptos_meta",
|
||||
"leptos_router",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"send_wrapper",
|
||||
"serde_json",
|
||||
@@ -1855,7 +1853,6 @@ dependencies = [
|
||||
"leptos_macro",
|
||||
"leptos_meta",
|
||||
"leptos_router",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"server_fn",
|
||||
"tachys",
|
||||
@@ -1908,7 +1905,7 @@ dependencies = [
|
||||
"quote",
|
||||
"rstml",
|
||||
"serde",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
@@ -1948,7 +1945,7 @@ dependencies = [
|
||||
"serde",
|
||||
"server_fn",
|
||||
"server_fn_macro 0.8.2",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"tracing",
|
||||
"trybuild",
|
||||
"typed-builder",
|
||||
@@ -1962,7 +1959,6 @@ dependencies = [
|
||||
"futures",
|
||||
"indexmap",
|
||||
"leptos",
|
||||
"once_cell",
|
||||
"or_poisoned",
|
||||
"send_wrapper",
|
||||
"tracing",
|
||||
@@ -1981,7 +1977,6 @@ dependencies = [
|
||||
"js-sys",
|
||||
"leptos",
|
||||
"leptos_router_macro",
|
||||
"once_cell",
|
||||
"or_poisoned",
|
||||
"percent-encoding",
|
||||
"reactive_graph",
|
||||
@@ -2004,7 +1999,7 @@ dependencies = [
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2030,9 +2025,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.172"
|
||||
version = "0.2.173"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb"
|
||||
|
||||
[[package]]
|
||||
name = "linear-map"
|
||||
@@ -2100,7 +2095,7 @@ dependencies = [
|
||||
"manyhow-macros",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2122,9 +2117,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
version = "2.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
@@ -2150,7 +2145,7 @@ checksum = "d6c74ab4f1a0c0ab045260ee4727b23c00cc17e5eff5095262d08eef8c3c8d49"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2176,9 +2171,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.8"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
@@ -2191,7 +2186,7 @@ checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -2229,7 +2224,7 @@ checksum = "0ac7d860b767c6398e88fe93db73ce53eb496057aa6895ffa4d60cb02e1d1c6b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2270,9 +2265,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
@@ -2304,9 +2299,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.72"
|
||||
version = "0.10.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
|
||||
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
@@ -2325,7 +2320,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2336,9 +2331,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.108"
|
||||
version = "0.9.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
|
||||
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -2414,7 +2409,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2474,12 +2469,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.33"
|
||||
version = "0.2.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d"
|
||||
checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2534,7 +2529,7 @@ dependencies = [
|
||||
"proc-macro-error-attr2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2565,7 +2560,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"version_check",
|
||||
"yansi",
|
||||
]
|
||||
@@ -2587,7 +2582,7 @@ checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2673,7 +2668,7 @@ dependencies = [
|
||||
"proc-macro-utils",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2770,14 +2765,14 @@ dependencies = [
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.12"
|
||||
version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
|
||||
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -2828,9 +2823,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.18"
|
||||
version = "0.12.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e98ff6b0dbbe4d5a37318f433d4fc82babd21631f194d370409ceb2e40b2f0b5"
|
||||
checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
@@ -2843,13 +2838,10 @@ dependencies = [
|
||||
"hyper-rustls",
|
||||
"hyper-tls",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
@@ -2896,7 +2888,7 @@ checksum = "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65"
|
||||
dependencies = [
|
||||
"bytecheck",
|
||||
"bytes",
|
||||
"hashbrown 0.15.3",
|
||||
"hashbrown 0.15.4",
|
||||
"indexmap",
|
||||
"munge",
|
||||
"ptr_meta",
|
||||
@@ -2915,7 +2907,7 @@ checksum = "246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2950,16 +2942,16 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"proc-macro2-diagnostics",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"syn_derive",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
@@ -3146,7 +3138,7 @@ checksum = "7ce26a84e3d8d10853301cf6a75c58132b8f5d5e8fee65949ea8dd7758d6760b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3168,7 +3160,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3206,9 +3198,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -3247,7 +3239,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3271,7 +3263,6 @@ dependencies = [
|
||||
"inventory",
|
||||
"js-sys",
|
||||
"multer",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"postcard",
|
||||
"reqwest",
|
||||
@@ -3310,7 +3301,7 @@ dependencies = [
|
||||
"convert_case 0.6.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"xxhash-rust",
|
||||
]
|
||||
|
||||
@@ -3323,7 +3314,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"xxhash-rust",
|
||||
]
|
||||
|
||||
@@ -3332,7 +3323,7 @@ name = "server_fn_macro_default"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"server_fn_macro 0.8.2",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3399,7 +3390,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f62f06db0370222f7f498ef478fce9f8df5828848d1d3517e3331936d7074f55"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3422,9 +3413,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.0"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
@@ -3469,9 +3460,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
version = "2.0.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3487,7 +3478,7 @@ dependencies = [
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3507,7 +3498,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3541,7 +3532,6 @@ dependencies = [
|
||||
"linear-map",
|
||||
"next_tuple",
|
||||
"oco_ref",
|
||||
"once_cell",
|
||||
"or_poisoned",
|
||||
"parking_lot",
|
||||
"paste",
|
||||
@@ -3633,7 +3623,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3644,7 +3634,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3736,7 +3726,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3811,9 +3801,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.22"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
|
||||
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
@@ -3823,18 +3813,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.9"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.26"
|
||||
version = "0.22.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
||||
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
@@ -3846,9 +3836,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_write"
|
||||
version = "0.1.1"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
|
||||
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
@@ -3868,12 +3858,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tower-http"
|
||||
version = "0.6.4"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e"
|
||||
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"http-body",
|
||||
@@ -3919,20 +3910,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.28"
|
||||
version = "0.1.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
||||
checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.33"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
|
||||
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
@@ -3992,7 +3983,7 @@ checksum = "60d8d828da2a3d759d3519cdf29a5bac49c77d039ad36d0782edadbf9cd5415b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4116,9 +4107,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
@@ -4151,7 +4142,7 @@ dependencies = [
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -4186,7 +4177,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -4221,7 +4212,7 @@ checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4359,9 +4350,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.10"
|
||||
version = "0.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -4413,7 +4404,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -4434,7 +4425,7 @@ checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4454,7 +4445,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -4494,7 +4485,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -42,7 +42,7 @@ exclude = ["benchmarks", "examples", "projects"]
|
||||
[workspace.package]
|
||||
version = "0.8.2"
|
||||
edition = "2021"
|
||||
rust-version = "1.76"
|
||||
rust-version = "1.80"
|
||||
|
||||
[workspace.dependencies]
|
||||
# members
|
||||
@@ -85,7 +85,6 @@ rstml = { default-features = false, version = "0.12.1" }
|
||||
rustc_version = { default-features = false, version = "0.4.1" }
|
||||
guardian = { default-features = false, version = "1.3.0" }
|
||||
rustc-hash = { default-features = false, version = "2.1.1" }
|
||||
once_cell = { default-features = false, version = "1.21.3" }
|
||||
actix-web = { default-features = false, version = "4.11.0" }
|
||||
tracing = { default-features = false, version = "0.1.41" }
|
||||
slotmap = { default-features = false, version = "1.0.7" }
|
||||
|
||||
@@ -23,7 +23,6 @@ leptos = { path = "../../leptos" }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_router = { path = "../../router" }
|
||||
log = "0.4.22"
|
||||
once_cell = "1.19"
|
||||
gloo-net = { version = "0.6.0" }
|
||||
wasm-bindgen = "0.2.93"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@@ -38,7 +38,6 @@ strum = { version = "0.27.1", features = ["strum_macros", "derive"] }
|
||||
notify = { version = "8.0", optional = true }
|
||||
pin-project-lite = "0.2.14"
|
||||
dashmap = { version = "6.0", optional = true }
|
||||
once_cell = { version = "1.19", optional = true }
|
||||
async-broadcast = { version = "0.7.1", optional = true }
|
||||
bytecheck = "0.8.0"
|
||||
rkyv = { version = "0.8.8" }
|
||||
@@ -54,7 +53,6 @@ ssr = [
|
||||
"dep:leptos_axum",
|
||||
"dep:notify",
|
||||
"dep:dashmap",
|
||||
"dep:once_cell",
|
||||
"dep:async-broadcast",
|
||||
]
|
||||
|
||||
|
||||
@@ -424,7 +424,7 @@ pub fn FileUploadWithProgress() -> impl IntoView {
|
||||
use async_broadcast::{broadcast, Receiver, Sender};
|
||||
use dashmap::DashMap;
|
||||
use futures::Stream;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
struct File {
|
||||
total: usize,
|
||||
@@ -432,7 +432,8 @@ pub fn FileUploadWithProgress() -> impl IntoView {
|
||||
rx: Receiver<usize>,
|
||||
}
|
||||
|
||||
static FILES: Lazy<DashMap<String, File>> = Lazy::new(DashMap::new);
|
||||
static FILES: LazyLock<DashMap<String, File>> =
|
||||
LazyLock::new(DashMap::new);
|
||||
|
||||
pub async fn add_chunk(filename: &str, len: usize) {
|
||||
println!("[{filename}]\tadding {len}");
|
||||
|
||||
@@ -16,7 +16,6 @@ futures = { workspace = true, default-features = true }
|
||||
serde = { features = ["derive"] , workspace = true, default-features = true }
|
||||
wasm-bindgen = { workspace = true, optional = true , default-features = true }
|
||||
js-sys = { optional = true , workspace = true, default-features = true }
|
||||
once_cell = { workspace = true, default-features = true }
|
||||
pin-project-lite = { workspace = true, default-features = true }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -7,10 +7,12 @@ use super::{SerializedDataId, SharedContext};
|
||||
use crate::{PinnedFuture, PinnedStream};
|
||||
use core::fmt::Debug;
|
||||
use js_sys::Array;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{
|
||||
fmt::Display,
|
||||
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||
sync::{
|
||||
atomic::{AtomicBool, AtomicUsize, Ordering},
|
||||
LazyLock,
|
||||
},
|
||||
};
|
||||
use throw_error::{Error, ErrorId};
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsCast};
|
||||
@@ -79,8 +81,8 @@ pub struct HydrateSharedContext {
|
||||
id: AtomicUsize,
|
||||
is_hydrating: AtomicBool,
|
||||
during_hydration: AtomicBool,
|
||||
errors: Lazy<Vec<(SerializedDataId, ErrorId, Error)>>,
|
||||
incomplete: Lazy<Vec<SerializedDataId>>,
|
||||
errors: LazyLock<Vec<(SerializedDataId, ErrorId, Error)>>,
|
||||
incomplete: LazyLock<Vec<SerializedDataId>>,
|
||||
}
|
||||
|
||||
impl HydrateSharedContext {
|
||||
@@ -90,8 +92,8 @@ impl HydrateSharedContext {
|
||||
id: AtomicUsize::new(0),
|
||||
is_hydrating: AtomicBool::new(true),
|
||||
during_hydration: AtomicBool::new(true),
|
||||
errors: Lazy::new(serialized_errors),
|
||||
incomplete: Lazy::new(incomplete_chunks),
|
||||
errors: LazyLock::new(serialized_errors),
|
||||
incomplete: LazyLock::new(incomplete_chunks),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +106,8 @@ impl HydrateSharedContext {
|
||||
id: AtomicUsize::new(0),
|
||||
is_hydrating: AtomicBool::new(false),
|
||||
during_hydration: AtomicBool::new(true),
|
||||
errors: Lazy::new(serialized_errors),
|
||||
incomplete: Lazy::new(incomplete_chunks),
|
||||
errors: LazyLock::new(serialized_errors),
|
||||
incomplete: LazyLock::new(incomplete_chunks),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ tracing = { optional = true , workspace = true, default-features = true }
|
||||
tokio = { features = ["rt", "fs"] , workspace = true, default-features = true }
|
||||
send_wrapper = { workspace = true, default-features = true }
|
||||
dashmap = { workspace = true, default-features = true }
|
||||
once_cell = { workspace = true, default-features = true }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
|
||||
@@ -38,7 +38,6 @@ use leptos_router::{
|
||||
static_routes::{RegenerationFn, ResolvedStaticPath},
|
||||
ExpandOptionals, Method, PathSegment, RouteList, RouteListing, SsrMode,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::RwLock;
|
||||
use send_wrapper::SendWrapper;
|
||||
use server_fn::{
|
||||
@@ -51,7 +50,7 @@ use std::{
|
||||
future::Future,
|
||||
ops::{Deref, DerefMut},
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
sync::{Arc, LazyLock},
|
||||
};
|
||||
|
||||
/// This struct lets you define headers and override the status of the Response from an Element or a Server Function
|
||||
@@ -1210,8 +1209,8 @@ impl StaticRouteGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
static STATIC_HEADERS: Lazy<DashMap<String, ResponseOptions>> =
|
||||
Lazy::new(DashMap::new);
|
||||
static STATIC_HEADERS: LazyLock<DashMap<String, ResponseOptions>> =
|
||||
LazyLock::new(DashMap::new);
|
||||
|
||||
fn was_404(owner: &Owner) -> bool {
|
||||
let resp = owner.with(|| expect_context::<ResponseOptions>());
|
||||
|
||||
@@ -23,7 +23,6 @@ leptos_meta = { workspace = true, features = ["ssr", "nonce"] }
|
||||
leptos_router = { workspace = true, features = ["ssr"] }
|
||||
leptos_integration_utils = { workspace = true }
|
||||
tachys = { workspace = true }
|
||||
once_cell = { workspace = true, default-features = true }
|
||||
parking_lot = { workspace = true, default-features = true }
|
||||
tokio = { default-features = false , workspace = true }
|
||||
tower = { features = ["util"] , workspace = true, default-features = true }
|
||||
|
||||
@@ -69,12 +69,12 @@ use leptos_router::{
|
||||
static_routes::RegenerationFn, ExpandOptionals, PathSegment, RouteList,
|
||||
RouteListing, SsrMode,
|
||||
};
|
||||
#[cfg(feature = "default")]
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::RwLock;
|
||||
use server_fn::{error::ServerFnErrorErr, redirect::REDIRECT_HEADER};
|
||||
#[cfg(feature = "default")]
|
||||
use std::path::Path;
|
||||
#[cfg(feature = "default")]
|
||||
use std::sync::LazyLock;
|
||||
use std::{collections::HashSet, fmt::Debug, io, pin::Pin, sync::Arc};
|
||||
#[cfg(feature = "default")]
|
||||
use tower::util::ServiceExt;
|
||||
@@ -1522,8 +1522,8 @@ impl StaticRouteGenerator {
|
||||
}
|
||||
|
||||
#[cfg(feature = "default")]
|
||||
static STATIC_HEADERS: Lazy<DashMap<String, ResponseOptions>> =
|
||||
Lazy::new(DashMap::new);
|
||||
static STATIC_HEADERS: LazyLock<DashMap<String, ResponseOptions>> =
|
||||
LazyLock::new(DashMap::new);
|
||||
|
||||
#[cfg(feature = "default")]
|
||||
fn was_404(owner: &Owner) -> bool {
|
||||
|
||||
@@ -112,9 +112,9 @@ fn is_inert_element(orig_node: &Node<impl CustomNode>) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// also doesn't work if the top-level element is an SVG/MathML element
|
||||
// also doesn't work if the top-level element is a MathML element
|
||||
let el_name = el.name().to_string();
|
||||
if is_svg_element(&el_name) || is_math_ml_element(&el_name) {
|
||||
if is_math_ml_element(&el_name) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -300,7 +300,7 @@ fn inert_element_to_tokens(
|
||||
node: &Node<impl CustomNode>,
|
||||
escape_text: bool,
|
||||
global_class: Option<&TokenTree>,
|
||||
) -> Option<TokenStream> {
|
||||
) -> TokenStream {
|
||||
let mut html = InertElementBuilder::new(global_class);
|
||||
let mut nodes = VecDeque::from([Item::Node(node, escape_text)]);
|
||||
|
||||
@@ -396,9 +396,114 @@ fn inert_element_to_tokens(
|
||||
|
||||
html.finish();
|
||||
|
||||
Some(quote! {
|
||||
quote! {
|
||||
::leptos::tachys::html::InertElement::new(#html)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn inert_svg_element_to_tokens(
|
||||
node: &Node<impl CustomNode>,
|
||||
escape_text: bool,
|
||||
global_class: Option<&TokenTree>,
|
||||
) -> TokenStream {
|
||||
let mut html = InertElementBuilder::new(global_class);
|
||||
let mut nodes = VecDeque::from([Item::Node(node, escape_text)]);
|
||||
|
||||
while let Some(current) = nodes.pop_front() {
|
||||
match current {
|
||||
Item::ClosingTag(tag) => {
|
||||
// closing tag
|
||||
html.push_str("</");
|
||||
html.push_str(&tag);
|
||||
html.push('>');
|
||||
}
|
||||
Item::Node(current, escape) => {
|
||||
match current {
|
||||
Node::RawText(raw) => {
|
||||
let text = raw.to_string_best();
|
||||
let text = if escape {
|
||||
html_escape::encode_text(&text)
|
||||
} else {
|
||||
text.into()
|
||||
};
|
||||
html.push_str(&text);
|
||||
}
|
||||
Node::Text(text) => {
|
||||
let text = text.value_string();
|
||||
let text = if escape {
|
||||
html_escape::encode_text(&text)
|
||||
} else {
|
||||
text.into()
|
||||
};
|
||||
html.push_str(&text);
|
||||
}
|
||||
Node::Element(node) => {
|
||||
let self_closing = is_self_closing(node);
|
||||
let el_name = node.name().to_string();
|
||||
let escape = el_name != "script"
|
||||
&& el_name != "style"
|
||||
&& el_name != "textarea";
|
||||
|
||||
// opening tag
|
||||
html.push('<');
|
||||
html.push_str(&el_name);
|
||||
|
||||
for attr in node.attributes() {
|
||||
if let NodeAttribute::Attribute(attr) = attr {
|
||||
let attr_name = attr.key.to_string();
|
||||
// trim r# from raw identifiers like r#as
|
||||
let attr_name =
|
||||
attr_name.trim_start_matches("r#");
|
||||
if attr_name != "class" {
|
||||
html.push(' ');
|
||||
html.push_str(attr_name);
|
||||
}
|
||||
|
||||
if let Some(value) =
|
||||
attr.possible_value.to_value()
|
||||
{
|
||||
if let KVAttributeValue::Expr(Expr::Lit(
|
||||
lit,
|
||||
)) = &value.value
|
||||
{
|
||||
if let Lit::Str(txt) = &lit.lit {
|
||||
let value = txt.value();
|
||||
let value = html_escape::encode_double_quoted_attribute(&value);
|
||||
if attr_name == "class" {
|
||||
html.push_class(&value);
|
||||
} else {
|
||||
html.push_str("=\"");
|
||||
html.push_str(&value);
|
||||
html.push('"');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
html.push('>');
|
||||
|
||||
// render all children
|
||||
if !self_closing {
|
||||
nodes.push_front(Item::ClosingTag(el_name));
|
||||
let children = node.children.iter().rev();
|
||||
for child in children {
|
||||
nodes.push_front(Item::Node(child, escape));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html.finish();
|
||||
|
||||
quote! {
|
||||
::leptos::tachys::svg::InertElement::new(#html)
|
||||
}
|
||||
}
|
||||
|
||||
fn element_children_to_tokens(
|
||||
@@ -597,7 +702,17 @@ fn node_to_tokens(
|
||||
let escape = el_name != "script"
|
||||
&& el_name != "style"
|
||||
&& el_name != "textarea";
|
||||
inert_element_to_tokens(node, escape, global_class)
|
||||
|
||||
let el_name = el_node.name().to_string();
|
||||
if is_svg_element(&el_name) {
|
||||
Some(inert_svg_element_to_tokens(
|
||||
node,
|
||||
escape,
|
||||
global_class,
|
||||
))
|
||||
} else {
|
||||
Some(inert_element_to_tokens(node, escape, global_class))
|
||||
}
|
||||
} else {
|
||||
element_to_tokens(
|
||||
el_node,
|
||||
|
||||
@@ -20,7 +20,7 @@ use reactive_graph::{
|
||||
};
|
||||
use std::{
|
||||
future::{pending, Future, IntoFuture},
|
||||
ops::DerefMut,
|
||||
ops::{Deref, DerefMut},
|
||||
panic::Location,
|
||||
};
|
||||
|
||||
@@ -43,6 +43,14 @@ impl<T> Clone for ArcLocalResource<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for ArcLocalResource<T> {
|
||||
type Target = ArcAsyncDerived<T>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ArcLocalResource<T> {
|
||||
/// Creates the resource.
|
||||
///
|
||||
@@ -269,6 +277,14 @@ pub struct LocalResource<T> {
|
||||
defined_at: &'static Location<'static>,
|
||||
}
|
||||
|
||||
impl<T> Deref for LocalResource<T> {
|
||||
type Target = AsyncDerived<T>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for LocalResource<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
|
||||
@@ -10,7 +10,6 @@ edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
leptos = { workspace = true }
|
||||
once_cell = { workspace = true, default-features = true }
|
||||
or_poisoned = { workspace = true }
|
||||
indexmap = { workspace = true, default-features = true }
|
||||
send_wrapper = { workspace = true, default-features = true }
|
||||
|
||||
@@ -63,13 +63,12 @@ use leptos::{
|
||||
},
|
||||
IntoView,
|
||||
};
|
||||
use once_cell::sync::Lazy;
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
sync::{
|
||||
mpsc::{channel, Receiver, Sender},
|
||||
Arc,
|
||||
Arc, LazyLock,
|
||||
},
|
||||
};
|
||||
use wasm_bindgen::JsCast;
|
||||
@@ -101,7 +100,7 @@ pub struct MetaContext {
|
||||
/// Metadata associated with the `<title>` element.
|
||||
pub(crate) title: TitleContext,
|
||||
/// The hydration cursor for the location in the `<head>` for arbitrary tags will be rendered.
|
||||
pub(crate) cursor: Arc<Lazy<SendWrapper<Cursor>>>,
|
||||
pub(crate) cursor: Arc<LazyLock<SendWrapper<Cursor>>>,
|
||||
}
|
||||
|
||||
impl MetaContext {
|
||||
@@ -143,7 +142,7 @@ impl Default for MetaContext {
|
||||
))
|
||||
};
|
||||
|
||||
let cursor = Arc::new(Lazy::new(build_cursor));
|
||||
let cursor = Arc::new(LazyLock::new(build_cursor));
|
||||
Self {
|
||||
title: Default::default(),
|
||||
cursor,
|
||||
|
||||
@@ -21,7 +21,6 @@ fake = "2.9"
|
||||
tokio-tungstenite = "0.23.1"
|
||||
futures-util = "0.3.30"
|
||||
uuid = { version = "1.10", features = ["serde"] }
|
||||
once_cell = "1.19"
|
||||
futures = "0.3.30"
|
||||
|
||||
[[test]]
|
||||
@@ -33,6 +32,5 @@ harness = false # Allow Cucumber to print output instead of libtest
|
||||
ssr = []
|
||||
|
||||
[dependencies]
|
||||
once_cell = "1.19.0"
|
||||
regex = "1.10.6"
|
||||
serde.workspace = true
|
||||
|
||||
@@ -18,14 +18,14 @@ use chromiumoxide::{
|
||||
use cucumber::World;
|
||||
use futures::channel::mpsc::Sender;
|
||||
use futures_util::stream::StreamExt;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::sync::LazyLock;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, sync::Arc, time::Duration};
|
||||
use tokio::sync::RwLock;
|
||||
use tokio_tungstenite::connect_async;
|
||||
use uuid::Uuid;
|
||||
static EMAIL_ID_MAP: Lazy<RwLock<HashMap<String, String>>> =
|
||||
Lazy::new(|| RwLock::new(HashMap::new()));
|
||||
static EMAIL_ID_MAP: LazyLock<RwLock<HashMap<String, String>>> =
|
||||
LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct RequestPair {
|
||||
@@ -93,7 +93,7 @@ impl RequestPair {
|
||||
async fn main() -> Result<()> {
|
||||
// create a thread and store a
|
||||
// tokio-tungstenite client that connectsto http://127.0.0.1:1080/ws
|
||||
// and then stores the recieved messages in a once_cell::Lazy<RwLock<Vec<MailCrabMsg>>>
|
||||
// and then stores the recieved messages in a std::sync::LazyLock<RwLock<Vec<MailCrabMsg>>>
|
||||
// or a custom struct that matches the body or has specific impls for verify codes, links etc.
|
||||
let _ = tokio::spawn(async move {
|
||||
let (mut socket, _) = connect_async(
|
||||
@@ -152,7 +152,7 @@ async fn main() -> Result<()> {
|
||||
|
||||
tokio::task::spawn(async move {
|
||||
while let Some(event) = log_events.next().await {
|
||||
if let Some(EventEntryAdded { entry }) =
|
||||
if let Some(EventEntryAdded { entry }) =
|
||||
Arc::<EventEntryAdded>::into_inner(event) {
|
||||
console_logs.write().await.push(format!(" {entry:#?} "));
|
||||
} else {
|
||||
@@ -171,7 +171,7 @@ async fn main() -> Result<()> {
|
||||
} else {
|
||||
tracing::error!("tried to into inner but none")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -208,7 +208,7 @@ async fn main() -> Result<()> {
|
||||
thing.cookies_before_request = cookies;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
CookieEnum::AfterResp(req_id) => {
|
||||
let cookies = page
|
||||
@@ -293,8 +293,8 @@ async fn main() -> Result<()> {
|
||||
} else {
|
||||
tracing::error!(" uhh err here")
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
// We don't need to join on our join handles, they will run detached and clean up whenever.
|
||||
|
||||
@@ -22,7 +22,6 @@ url = { workspace = true, default-features = true }
|
||||
js-sys = { workspace = true, default-features = true }
|
||||
wasm-bindgen = { workspace = true , default-features = true }
|
||||
tracing = { optional = true , workspace = true, default-features = true }
|
||||
once_cell = { workspace = true, default-features = true }
|
||||
send_wrapper = { workspace = true, default-features = true }
|
||||
thiserror = { workspace = true , default-features = true }
|
||||
percent-encoding = { optional = true , workspace = true, default-features = true }
|
||||
|
||||
@@ -144,16 +144,12 @@ impl RouterContext {
|
||||
resolve_path("", path, None)
|
||||
};
|
||||
|
||||
let mut url = match resolved_to.map(|to| BrowserUrl::parse(&to)) {
|
||||
Some(Ok(url)) => url,
|
||||
Some(Err(e)) => {
|
||||
let mut url = match BrowserUrl::parse(&resolved_to) {
|
||||
Ok(url) => url,
|
||||
Err(e) => {
|
||||
leptos::logging::error!("Error parsing URL: {e:?}");
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
leptos::logging::error!("Error resolving relative URL.");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let query_mutations =
|
||||
mem::take(&mut *self.query_mutations.write_value());
|
||||
@@ -203,7 +199,7 @@ impl RouterContext {
|
||||
&'a self,
|
||||
path: &'a str,
|
||||
from: Option<&'a str>,
|
||||
) -> Option<Cow<'a, str>> {
|
||||
) -> Cow<'a, str> {
|
||||
let base = self.base.as_deref().unwrap_or_default();
|
||||
resolve_path(base, path, from)
|
||||
}
|
||||
@@ -580,18 +576,11 @@ pub fn Redirect<P>(
|
||||
|
||||
// redirect on the server
|
||||
if let Some(redirect_fn) = use_context::<ServerRedirectFunction>() {
|
||||
match resolve_path("", &path, Some(&use_matched().get_untracked())) {
|
||||
Some(path) => (redirect_fn.f)(&path),
|
||||
None => {
|
||||
if cfg!(feature = "ssr") {
|
||||
#[cfg(feature = "tracing")]
|
||||
tracing::warn!("Error resolving relative URL.");
|
||||
|
||||
#[cfg(not(feature = "tracing"))]
|
||||
eprintln!("Error resolving relative URL.");
|
||||
}
|
||||
}
|
||||
}
|
||||
(redirect_fn.f)(&resolve_path(
|
||||
"",
|
||||
&path,
|
||||
Some(&use_matched().get_untracked()),
|
||||
));
|
||||
}
|
||||
// redirect on the client
|
||||
else {
|
||||
|
||||
@@ -87,7 +87,7 @@ where
|
||||
fn inner(
|
||||
has_router: bool,
|
||||
method: Option<&'static str>,
|
||||
action: ArcMemo<Option<String>>,
|
||||
action: ArcMemo<String>,
|
||||
enctype: Option<String>,
|
||||
version: Option<RwSignal<usize>>,
|
||||
error: Option<RwSignal<Option<Box<dyn Error + Send + Sync>>>>,
|
||||
@@ -311,7 +311,7 @@ where
|
||||
let action = if has_router {
|
||||
use_resolved_path(move || action.to_href()())
|
||||
} else {
|
||||
ArcMemo::new(move |_| Some(action.to_href()()))
|
||||
ArcMemo::new(move |_| action.to_href()())
|
||||
};
|
||||
inner(
|
||||
has_router,
|
||||
|
||||
@@ -240,7 +240,7 @@ pub(crate) struct Matched(pub ArcMemo<String>);
|
||||
#[track_caller]
|
||||
pub(crate) fn use_resolved_path(
|
||||
path: impl Fn() -> String + Send + Sync + 'static,
|
||||
) -> ArcMemo<Option<String>> {
|
||||
) -> ArcMemo<String> {
|
||||
let router = use_context::<RouterContext>()
|
||||
.expect("called use_resolved_path outside a <Router>");
|
||||
// TODO make this work with flat routes too?
|
||||
@@ -248,14 +248,14 @@ pub(crate) fn use_resolved_path(
|
||||
ArcMemo::new(move |_| {
|
||||
let path = path();
|
||||
if path.starts_with('/') {
|
||||
Some(path)
|
||||
path
|
||||
} else {
|
||||
router
|
||||
.resolve_path(
|
||||
&path,
|
||||
matched.as_ref().map(|n| n.get()).as_deref(),
|
||||
)
|
||||
.map(|n| n.to_string())
|
||||
.to_string()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -66,6 +66,25 @@ where
|
||||
/// This is helpful for accessibility and for styling. For example, maybe you want to set the link a
|
||||
/// different color if it’s a link to the page you’re currently on.
|
||||
///
|
||||
/// ### Additional Attributes
|
||||
///
|
||||
/// You can add additional HTML attributes to the `<a>` element created by this component using the attribute
|
||||
/// spreading syntax for components. For example, to add a class, you can use `attr:class="my-link"`.
|
||||
/// Alternately, you can add any number of HTML attributes (include `class`) after a `{..}` marker.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use leptos::prelude::*; use leptos_router::components::A;
|
||||
/// # fn spread_example() -> impl IntoView {
|
||||
/// view! {
|
||||
/// <A href="/about" attr:class="my-link" {..} id="foo">"Some link"</A>
|
||||
/// <A href="/about" {..} class="my-link" id="bar">"Another link"</A>
|
||||
/// <A href="/about" {..} class:my-link=true id="baz">"One more"</A>
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// For more information on this attribute spreading syntax, [see here](https://book.leptos.dev/view/03_components.html#spreading-attributes-onto-components).
|
||||
///
|
||||
/// ### DOM Properties
|
||||
///
|
||||
/// `<a>` elements can take several additional DOM properties with special meanings.
|
||||
@@ -102,7 +121,7 @@ where
|
||||
H: ToHref + Send + Sync + 'static,
|
||||
{
|
||||
fn inner(
|
||||
href: ArcMemo<Option<String>>,
|
||||
href: ArcMemo<String>,
|
||||
target: Option<Oco<'static, str>>,
|
||||
exact: bool,
|
||||
children: Children,
|
||||
@@ -114,23 +133,21 @@ where
|
||||
let is_active = {
|
||||
let href = href.clone();
|
||||
move || {
|
||||
href.read().as_deref().is_some_and(|to| {
|
||||
let path = to.split(['?', '#']).next().unwrap_or_default();
|
||||
current_url.with(|loc| {
|
||||
let loc = loc.path();
|
||||
if exact {
|
||||
loc == path
|
||||
} else {
|
||||
is_active_for(path, loc, strict_trailing_slash)
|
||||
}
|
||||
})
|
||||
let path = normalize_path(&href.read());
|
||||
current_url.with(|loc| {
|
||||
let loc = loc.path();
|
||||
if exact {
|
||||
loc == path
|
||||
} else {
|
||||
is_active_for(&path, loc, strict_trailing_slash)
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
view! {
|
||||
<a
|
||||
href=move || href.get().unwrap_or_default()
|
||||
href=move || href.get()
|
||||
target=target
|
||||
aria-current=move || if is_active() { Some("page") } else { None }
|
||||
data-noscroll=!scroll
|
||||
@@ -172,9 +189,62 @@ fn is_active_for(
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve `".."` segments in the path. Assume path is either empty or starts with a `'/'``.
|
||||
fn normalize_path(path: &str) -> String {
|
||||
// Return only on the only condition where leading slash
|
||||
// is allowed to be missing.
|
||||
if path.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
let mut del = 0;
|
||||
let mut it = path
|
||||
.split(['?', '#'])
|
||||
.next()
|
||||
.unwrap_or_default()
|
||||
.split(['/'])
|
||||
.rev()
|
||||
.peekable();
|
||||
|
||||
let init = if it.peek() == Some(&"..") {
|
||||
String::from("/")
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let mut path = it
|
||||
.filter(|v| {
|
||||
if *v == ".." {
|
||||
del += 1;
|
||||
false
|
||||
} else if *v == "." {
|
||||
false
|
||||
} else if del > 0 {
|
||||
del -= 1;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
// We cannot reverse before the fold again bc the filter
|
||||
// would be forwards again.
|
||||
.fold(init, |mut p, v| {
|
||||
p.reserve(v.len() + 1);
|
||||
p.insert(0, '/');
|
||||
p.insert_str(0, v);
|
||||
p
|
||||
});
|
||||
path.truncate(path.len().saturating_sub(1));
|
||||
|
||||
// Path starts with '/' giving it an extra empty segment after the split
|
||||
// Which should not be removed.
|
||||
if !path.starts_with('/') {
|
||||
path.insert(0, '/');
|
||||
}
|
||||
path
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::is_active_for;
|
||||
use super::{is_active_for, normalize_path};
|
||||
|
||||
#[test]
|
||||
fn is_active_for_matched() {
|
||||
@@ -393,4 +463,37 @@ mod tests {
|
||||
// assert!(!is_same_level("/some/", "/some/level/"))
|
||||
// assert!(!is_same_level("/some/", "/some/level/deeper"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn normalize_path_test() {
|
||||
// Make sure it doesn't touch already normalized urls.
|
||||
assert!(normalize_path("") == "".to_string());
|
||||
assert!(normalize_path("/") == "/".to_string());
|
||||
assert!(normalize_path("/some") == "/some".to_string());
|
||||
assert!(normalize_path("/some/") == "/some/".to_string());
|
||||
|
||||
// Correctly removes ".." segments.
|
||||
assert!(normalize_path("/some/../another") == "/another".to_string());
|
||||
assert!(
|
||||
normalize_path("/one/two/../three/../../four")
|
||||
== "/four".to_string()
|
||||
);
|
||||
|
||||
// Correctly sets trailing slash if last segement is "..".
|
||||
assert!(normalize_path("/one/two/..") == "/one/".to_string());
|
||||
assert!(normalize_path("/one/two/../") == "/one/".to_string());
|
||||
|
||||
// Level outside of the url.
|
||||
assert!(normalize_path("/..") == "/".to_string());
|
||||
assert!(normalize_path("/../") == "/".to_string());
|
||||
|
||||
// Going into negative levels and coming back into the positives.
|
||||
assert!(
|
||||
normalize_path("/one/../../two/three") == "/two/three".to_string()
|
||||
);
|
||||
assert!(
|
||||
normalize_path("/one/../../two/three/")
|
||||
== "/two/three/".to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ pub fn resolve_path<'a>(
|
||||
base: &'a str,
|
||||
path: &'a str,
|
||||
from: Option<&'a str>,
|
||||
) -> Option<Cow<'a, str>> {
|
||||
) -> Cow<'a, str> {
|
||||
if has_scheme(path) {
|
||||
Some(path.into())
|
||||
path.into()
|
||||
} else {
|
||||
let base_path = normalize(base, false);
|
||||
let from_path = from.map(|from| normalize(from, false));
|
||||
@@ -25,7 +25,7 @@ pub fn resolve_path<'a>(
|
||||
let result_empty = result.is_empty();
|
||||
let prefix = if result_empty { "/".into() } else { result };
|
||||
|
||||
Some(prefix + normalize(path, result_empty))
|
||||
prefix + normalize(path, result_empty)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,9 @@ where
|
||||
// TODO loading fallback
|
||||
#[allow(clippy::type_complexity)]
|
||||
view: Rc<RefCell<EitherOf3State<(), Fal, AnyView>>>,
|
||||
// held to keep the Owner alive until the router is dropped
|
||||
#[allow(unused)]
|
||||
outer_owner: Owner,
|
||||
}
|
||||
|
||||
impl<Loc, Defs, FalFn, Fal> Render for NestedRoutesView<Loc, Defs, FalFn>
|
||||
@@ -109,7 +112,8 @@ where
|
||||
&outer_owner,
|
||||
);
|
||||
drop(url);
|
||||
outer_owner.with(|| EitherOf3::C(Outlet().into_any()))
|
||||
|
||||
EitherOf3::C(top_level_outlet(&outlets, &outer_owner))
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,6 +134,7 @@ where
|
||||
current_url,
|
||||
outlets,
|
||||
view,
|
||||
outer_owner,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,17 +217,14 @@ where
|
||||
|
||||
// if it was on the fallback, show the view instead
|
||||
if matches!(state.view.borrow().state, EitherOf3::B(_)) {
|
||||
self.outer_owner.with(|| {
|
||||
EitherOf3::<(), Fal, AnyView>::C(Outlet().into_any())
|
||||
.rebuild(&mut *state.view.borrow_mut());
|
||||
})
|
||||
EitherOf3::<(), Fal, AnyView>::C(top_level_outlet(
|
||||
&state.outlets,
|
||||
&self.outer_owner,
|
||||
))
|
||||
.rebuild(&mut *state.view.borrow_mut());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(outlet) = state.outlets.first() {
|
||||
self.outer_owner.with(|| outlet.provide_contexts());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,7 +350,7 @@ where
|
||||
.now_or_never()
|
||||
.expect("async routes not supported in SSR");
|
||||
|
||||
outer_owner.with(|| Either::Right(Outlet().into_any()))
|
||||
Either::Right(top_level_outlet(&outlets, &outer_owner))
|
||||
}
|
||||
};
|
||||
view.to_html_with_buf(
|
||||
@@ -402,7 +404,7 @@ where
|
||||
.now_or_never()
|
||||
.expect("async routes not supported in SSR");
|
||||
|
||||
outer_owner.with(|| Either::Right(Outlet().into_any()))
|
||||
Either::Right(top_level_outlet(&outlets, &outer_owner))
|
||||
}
|
||||
};
|
||||
view.to_html_async_with_buf::<OUT_OF_ORDER>(
|
||||
@@ -454,7 +456,7 @@ where
|
||||
join_all(mem::take(&mut loaders))
|
||||
.now_or_never()
|
||||
.expect("async routes not supported in SSR");
|
||||
outer_owner.with(|| EitherOf3::C(Outlet().into_any()))
|
||||
EitherOf3::C(top_level_outlet(&outlets, &outer_owner))
|
||||
}
|
||||
}
|
||||
.hydrate::<FROM_SERVER>(cursor, position),
|
||||
@@ -465,6 +467,7 @@ where
|
||||
current_url,
|
||||
outlets,
|
||||
view,
|
||||
outer_owner,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,8 +487,12 @@ pub(crate) struct RouteContext {
|
||||
pub matched: ArcRwSignal<String>,
|
||||
base: Option<Oco<'static, str>>,
|
||||
view_fn: Arc<Mutex<OutletViewFn>>,
|
||||
child: ChildRoute,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ChildRoute(Arc<Mutex<Option<RouteContext>>>);
|
||||
|
||||
impl Debug for RouteContext {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("RouteContext")
|
||||
@@ -500,12 +507,6 @@ impl Debug for RouteContext {
|
||||
}
|
||||
}
|
||||
|
||||
impl RouteContext {
|
||||
fn provide_contexts(&self) {
|
||||
provide_context(self.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for RouteContext {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
@@ -517,6 +518,7 @@ impl Clone for RouteContext {
|
||||
matched: self.matched.clone(),
|
||||
base: self.base.clone(),
|
||||
view_fn: Arc::clone(&self.view_fn),
|
||||
child: self.child.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -628,59 +630,67 @@ where
|
||||
Suspend::new(Box::pin(async { ().into_any() }))
|
||||
}))),
|
||||
base: base.clone(),
|
||||
child: ChildRoute(Arc::new(Mutex::new(None))),
|
||||
};
|
||||
if !outlets.is_empty() {
|
||||
let prev_index = outlets.len().saturating_sub(1);
|
||||
*outlets[prev_index].child.0.lock().or_poisoned() =
|
||||
Some(outlet.clone());
|
||||
}
|
||||
outlets.push(outlet.clone());
|
||||
|
||||
// send the initial view through the channel, and recurse through the children
|
||||
let (view, child) = self.into_view_and_child();
|
||||
|
||||
loaders.push(Box::pin(owner.with(|| {
|
||||
ScopedFuture::new({
|
||||
let owner = outlet.owner.clone();
|
||||
let url = outlet.url.clone();
|
||||
let matched = Matched(matched_including_parents);
|
||||
let view_fn = Arc::clone(&outlet.view_fn);
|
||||
async move {
|
||||
provide_context(params_including_parents);
|
||||
provide_context(url);
|
||||
provide_context(matched.clone());
|
||||
view.preload().await;
|
||||
*view_fn.lock().or_poisoned() =
|
||||
Box::new(move |owner_where_used| {
|
||||
owner.join_contexts(&owner_where_used);
|
||||
let view = view.clone();
|
||||
owner.with({
|
||||
let matched = matched.clone();
|
||||
move || {
|
||||
Suspend::new(Box::pin(async move {
|
||||
let view = SendWrapper::new(
|
||||
ScopedFuture::new(view.choose()),
|
||||
);
|
||||
let view = view.await;
|
||||
let view = MatchedRoute(
|
||||
matched.0.get_untracked(),
|
||||
view,
|
||||
);
|
||||
OwnedView::new(view).into_any()
|
||||
})
|
||||
as Pin<
|
||||
Box<
|
||||
dyn Future<Output = AnyView>
|
||||
+ Send,
|
||||
>,
|
||||
>)
|
||||
}
|
||||
})
|
||||
});
|
||||
trigger
|
||||
}
|
||||
})
|
||||
})));
|
||||
loaders.push(Box::pin(ScopedFuture::new({
|
||||
let url = outlet.url.clone();
|
||||
let matched = Matched(matched_including_parents);
|
||||
let view_fn = Arc::clone(&outlet.view_fn);
|
||||
let outlet = outlet.clone();
|
||||
let params = params_including_parents.clone();
|
||||
let url = url.clone();
|
||||
let matched = matched.clone();
|
||||
async move {
|
||||
view.preload().await;
|
||||
let child = outlet.child.clone();
|
||||
*view_fn.lock().or_poisoned() =
|
||||
Box::new(move |owner_where_used| {
|
||||
let view = view.clone();
|
||||
let child = child.clone();
|
||||
let params = params.clone();
|
||||
let url = url.clone();
|
||||
let matched = matched.clone();
|
||||
owner_where_used.with({
|
||||
let matched = matched.clone();
|
||||
move || {
|
||||
let child = child.clone();
|
||||
Suspend::new(Box::pin(async move {
|
||||
provide_context(child.clone());
|
||||
provide_context(params.clone());
|
||||
provide_context(url.clone());
|
||||
provide_context(matched.clone());
|
||||
let view = SendWrapper::new(
|
||||
ScopedFuture::new(view.choose()),
|
||||
);
|
||||
let view = view.await;
|
||||
let view = MatchedRoute(
|
||||
matched.0.get_untracked(),
|
||||
view,
|
||||
);
|
||||
|
||||
// and share the outlet with the parent via context
|
||||
// we share it with the *parent* because the <Outlet/> is rendered in or below the parent
|
||||
// wherever it appears, <Outlet/> will look for the closest RouteContext
|
||||
parent.with(|| outlet.provide_contexts());
|
||||
OwnedView::new(view).into_any()
|
||||
})
|
||||
as Pin<
|
||||
Box<
|
||||
dyn Future<Output = AnyView> + Send,
|
||||
>,
|
||||
>)
|
||||
}
|
||||
})
|
||||
});
|
||||
trigger
|
||||
}
|
||||
})));
|
||||
|
||||
// recursively continue building the tree
|
||||
// this is important because to build the view, we need access to the outlet
|
||||
@@ -785,64 +795,71 @@ where
|
||||
let (full_tx, full_rx) = oneshot::channel();
|
||||
let full_tx = Mutex::new(Some(full_tx));
|
||||
full_loaders.push(full_rx);
|
||||
let outlet = current.clone();
|
||||
|
||||
// send the new view, with the new owner, through the channel to the Outlet,
|
||||
// and notify the trigger so that the reactive view inside the Outlet tracking
|
||||
// the trigger runs again
|
||||
preloaders.push(Box::pin(owner.with(|| {
|
||||
ScopedFuture::new({
|
||||
let owner = owner.clone();
|
||||
let trigger = current.trigger.clone();
|
||||
let url = current.url.clone();
|
||||
let matched = Matched(matched_including_parents);
|
||||
let view_fn = Arc::clone(¤t.view_fn);
|
||||
async move {
|
||||
provide_context(params_including_parents);
|
||||
provide_context(url);
|
||||
provide_context(matched);
|
||||
view.preload().await;
|
||||
*view_fn.lock().or_poisoned() =
|
||||
Box::new(move |owner_where_used| {
|
||||
owner.join_contexts(&owner_where_used);
|
||||
let owner = owner.clone();
|
||||
let view = view.clone();
|
||||
let full_tx =
|
||||
full_tx.lock().or_poisoned().take();
|
||||
let old_owner = old_owner.take();
|
||||
Suspend::new(Box::pin(async move {
|
||||
let view = SendWrapper::new(
|
||||
owner.with(|| {
|
||||
ScopedFuture::new(
|
||||
async move {
|
||||
if set_is_routing {
|
||||
AsyncTransition::run(|| view.choose()).await
|
||||
} else {
|
||||
view.choose().await
|
||||
}
|
||||
}
|
||||
)
|
||||
}),
|
||||
);
|
||||
let view = view.await;
|
||||
if let Some(old_owner) = old_owner {
|
||||
old_owner.cleanup();
|
||||
}
|
||||
preloaders.push(Box::pin(ScopedFuture::new({
|
||||
let owner = owner.clone();
|
||||
let trigger = current.trigger.clone();
|
||||
let url = current.url.clone();
|
||||
let matched = Matched(matched_including_parents);
|
||||
let view_fn = Arc::clone(¤t.view_fn);
|
||||
let child = outlet.child.clone();
|
||||
async move {
|
||||
view.preload().await;
|
||||
let child = child.clone();
|
||||
*view_fn.lock().or_poisoned() =
|
||||
Box::new(move |owner_where_used| {
|
||||
let owner = owner.clone();
|
||||
let view = view.clone();
|
||||
let full_tx =
|
||||
full_tx.lock().or_poisoned().take();
|
||||
let old_owner = old_owner.take();
|
||||
let child = child.clone();
|
||||
let params =
|
||||
params_including_parents.clone();
|
||||
let url = url.clone();
|
||||
let matched = matched.clone();
|
||||
Suspend::new(Box::pin(async move {
|
||||
let view = SendWrapper::new(
|
||||
owner_where_used.with(|| {
|
||||
provide_context(child.clone());
|
||||
provide_context(params);
|
||||
provide_context(url);
|
||||
provide_context(matched);
|
||||
ScopedFuture::new(async move {
|
||||
if set_is_routing {
|
||||
AsyncTransition::run(
|
||||
|| view.choose(),
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
view.choose().await
|
||||
}
|
||||
})
|
||||
}),
|
||||
);
|
||||
let view = view.await;
|
||||
if let Some(old_owner) = old_owner {
|
||||
old_owner.cleanup();
|
||||
}
|
||||
|
||||
if let Some(tx) = full_tx {
|
||||
_ = tx.send(());
|
||||
}
|
||||
owner.with(|| {
|
||||
OwnedView::new(view).into_any()
|
||||
})
|
||||
}))
|
||||
});
|
||||
if let Some(tx) = full_tx {
|
||||
_ = tx.send(());
|
||||
}
|
||||
owner.with(|| {
|
||||
OwnedView::new(view).into_any()
|
||||
})
|
||||
}))
|
||||
});
|
||||
|
||||
drop(old_params);
|
||||
drop(old_url);
|
||||
drop(old_matched);
|
||||
trigger
|
||||
}
|
||||
})
|
||||
drop(old_params);
|
||||
drop(old_url);
|
||||
drop(old_matched);
|
||||
trigger
|
||||
}
|
||||
})));
|
||||
|
||||
// remove all the items lower in the tree
|
||||
@@ -911,20 +928,38 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn top_level_outlet(outlets: &[RouteContext], outer_owner: &Owner) -> AnyView {
|
||||
let outlet = outlets.first().unwrap();
|
||||
let child = outlet.child.clone();
|
||||
let view_fn = outlet.view_fn.clone();
|
||||
let trigger = outlet.trigger.clone();
|
||||
let owner = outer_owner.child();
|
||||
outer_owner.clone().with(|| {
|
||||
provide_context(child.clone());
|
||||
(move || {
|
||||
trigger.track();
|
||||
let mut view_fn = view_fn.lock().or_poisoned();
|
||||
view_fn(owner.clone())
|
||||
})
|
||||
.into_any()
|
||||
})
|
||||
}
|
||||
|
||||
/// Displays the child route nested in a parent route, allowing you to control exactly where
|
||||
/// that child route is displayed. Renders nothing if there is no nested child.
|
||||
#[component]
|
||||
pub fn Outlet() -> impl RenderHtml
|
||||
where
|
||||
{
|
||||
move || {
|
||||
let ctx = use_context::<RouteContext>()
|
||||
.expect("<Outlet/> used without RouteContext being provided.");
|
||||
let RouteContext {
|
||||
trigger, view_fn, ..
|
||||
} = ctx;
|
||||
trigger.track();
|
||||
let mut view_fn = view_fn.lock().or_poisoned();
|
||||
view_fn(Owner::current().unwrap())
|
||||
}
|
||||
let ChildRoute(child) = use_context()
|
||||
.expect("<Outlet/> used without RouteContext being provided.");
|
||||
let owner = Owner::new();
|
||||
let child = child.lock().or_poisoned().clone();
|
||||
child.map(|child| {
|
||||
move || {
|
||||
child.trigger.track();
|
||||
let mut view_fn = child.view_fn.lock().or_poisoned();
|
||||
view_fn(owner.clone())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ thiserror = { workspace = true, default-features = true }
|
||||
# registration system
|
||||
inventory = { optional = true, workspace = true, default-features = true }
|
||||
dashmap = { workspace = true, default-features = true }
|
||||
once_cell = { workspace = true, default-features = true }
|
||||
|
||||
## servers
|
||||
# actix
|
||||
|
||||
@@ -151,7 +151,6 @@ use error::{FromServerFnError, ServerFnErrorErr};
|
||||
use futures::{pin_mut, SinkExt, Stream, StreamExt};
|
||||
use http::Method;
|
||||
use middleware::{BoxedService, Layer, Service};
|
||||
use once_cell::sync::Lazy;
|
||||
use redirect::call_redirect_hook;
|
||||
use request::Req;
|
||||
use response::{ClientRes, Res, TryRes};
|
||||
@@ -169,7 +168,7 @@ use std::{
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
sync::{Arc, LazyLock},
|
||||
};
|
||||
#[doc(hidden)]
|
||||
pub use xxhash_rust;
|
||||
@@ -862,7 +861,7 @@ pub use inventory;
|
||||
#[macro_export]
|
||||
macro_rules! initialize_server_fn_map {
|
||||
($req:ty, $res:ty) => {
|
||||
once_cell::sync::Lazy::new(|| {
|
||||
std::sync::LazyLock::new(|| {
|
||||
$crate::inventory::iter::<ServerFnTraitObj<$req, $res>>
|
||||
.into_iter()
|
||||
.map(|obj| {
|
||||
@@ -981,7 +980,7 @@ impl<Req, Res> Clone for ServerFnTraitObj<Req, Res> {
|
||||
|
||||
#[allow(unused)] // used by server integrations
|
||||
type LazyServerFnMap<Req, Res> =
|
||||
Lazy<DashMap<(String, Method), ServerFnTraitObj<Req, Res>>>;
|
||||
LazyLock<DashMap<(String, Method), ServerFnTraitObj<Req, Res>>>;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
impl<Req: 'static, Res: 'static> inventory::Collect
|
||||
|
||||
@@ -75,6 +75,13 @@ impl DerefMut for BrowserRequest {
|
||||
#[derive(Debug)]
|
||||
pub struct BrowserFormData(pub(crate) SendWrapper<FormData>);
|
||||
|
||||
impl BrowserFormData {
|
||||
/// Returns the raw `web_sys::FormData` struct.
|
||||
pub fn take(self) -> FormData {
|
||||
self.0.take()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FormData> for BrowserFormData {
|
||||
fn from(value: FormData) -> Self {
|
||||
Self(SendWrapper::new(value))
|
||||
|
||||
@@ -5,14 +5,14 @@ use crate::{
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use futures::{Stream, StreamExt};
|
||||
use once_cell::sync::Lazy;
|
||||
use reqwest::{
|
||||
header::{ACCEPT, CONTENT_TYPE},
|
||||
Body,
|
||||
};
|
||||
pub use reqwest::{multipart::Form, Client, Method, Request, Url};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
pub(crate) static CLIENT: Lazy<Client> = Lazy::new(Client::new);
|
||||
pub(crate) static CLIENT: LazyLock<Client> = LazyLock::new(Client::new);
|
||||
|
||||
impl<E> ClientReq<E> for Request
|
||||
where
|
||||
|
||||
@@ -21,7 +21,6 @@ reactive_stores = { workspace = true, optional = true }
|
||||
slotmap = { optional = true, workspace = true, default-features = true }
|
||||
oco_ref = { workspace = true, optional = true }
|
||||
async-trait = { workspace = true, default-features = true }
|
||||
once_cell = { workspace = true, default-features = true }
|
||||
paste = { workspace = true, default-features = true }
|
||||
erased = { workspace = true, default-features = true }
|
||||
wasm-bindgen = { workspace = true, default-features = true }
|
||||
|
||||
@@ -540,11 +540,20 @@ impl IntoClass for (&'static str, bool) {
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let (name, include) = self;
|
||||
let (class_list, prev_include, prev_name) = state;
|
||||
if include != *prev_include {
|
||||
if name == *prev_name {
|
||||
if include != *prev_include {
|
||||
if include {
|
||||
Rndr::add_class(class_list, name);
|
||||
} else {
|
||||
Rndr::remove_class(class_list, name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if *prev_include {
|
||||
Rndr::remove_class(class_list, prev_name);
|
||||
}
|
||||
if include {
|
||||
Rndr::add_class(class_list, name);
|
||||
} else {
|
||||
Rndr::remove_class(class_list, name);
|
||||
}
|
||||
}
|
||||
*prev_include = include;
|
||||
|
||||
@@ -709,7 +709,7 @@ where
|
||||
|
||||
buf.push('<');
|
||||
buf.push_str(E::TAG);
|
||||
<At as ToTemplate>::to_template(
|
||||
<At as ToTemplate>::to_template_attribute(
|
||||
buf,
|
||||
&mut class,
|
||||
&mut style,
|
||||
|
||||
@@ -125,14 +125,14 @@ impl Render for InertElement {
|
||||
type State = InertElementState;
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
let el = Rndr::create_element_from_html(&self.html);
|
||||
let el = Rndr::create_element_from_html(self.html.clone());
|
||||
InertElementState(self.html, el)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let InertElementState(prev, el) = state;
|
||||
if &self.html != prev {
|
||||
let mut new_el = Rndr::create_element_from_html(&self.html);
|
||||
let mut new_el = Rndr::create_element_from_html(self.html.clone());
|
||||
el.insert_before_this(&mut new_el);
|
||||
el.unmount();
|
||||
*el = new_el;
|
||||
|
||||
@@ -209,6 +209,15 @@ where
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let (name, mut f) = self;
|
||||
|
||||
let prev_name = state.name;
|
||||
let prev_state = state.effect.take_value();
|
||||
if let Some((list, prev_include)) = &prev_state {
|
||||
if prev_name != name && *prev_include {
|
||||
Rndr::remove_class(list, prev_name);
|
||||
}
|
||||
}
|
||||
|
||||
// Name might've updated:
|
||||
state.name = name;
|
||||
let mut first_run = true;
|
||||
@@ -232,7 +241,7 @@ where
|
||||
}
|
||||
}
|
||||
},
|
||||
state.effect.take_value(),
|
||||
prev_state,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,12 @@ use crate::{
|
||||
view::{Mountable, ToTemplate},
|
||||
};
|
||||
use linear_map::LinearMap;
|
||||
use once_cell::unsync::Lazy;
|
||||
use rustc_hash::FxHashSet;
|
||||
use std::{any::TypeId, borrow::Cow, cell::RefCell};
|
||||
use std::{
|
||||
any::TypeId,
|
||||
borrow::Cow,
|
||||
cell::{LazyCell, RefCell},
|
||||
};
|
||||
use wasm_bindgen::{intern, prelude::Closure, JsCast, JsValue};
|
||||
use web_sys::{AddEventListenerOptions, Comment, HtmlTemplateElement};
|
||||
|
||||
@@ -21,6 +24,7 @@ pub struct Dom;
|
||||
|
||||
thread_local! {
|
||||
pub(crate) static GLOBAL_EVENTS: RefCell<FxHashSet<Cow<'static, str>>> = Default::default();
|
||||
pub static TEMPLATE_CACHE: RefCell<Vec<(Cow<'static, str>, web_sys::Element)>> = Default::default();
|
||||
}
|
||||
|
||||
pub type Node = web_sys::Node;
|
||||
@@ -57,7 +61,7 @@ impl Dom {
|
||||
|
||||
pub fn create_placeholder() -> Placeholder {
|
||||
thread_local! {
|
||||
static COMMENT: Lazy<Comment> = Lazy::new(|| {
|
||||
static COMMENT: LazyCell<Comment> = LazyCell::new(|| {
|
||||
document().create_comment("")
|
||||
});
|
||||
}
|
||||
@@ -281,9 +285,10 @@ impl Dom {
|
||||
let cb = send_wrapper::SendWrapper::new(cb);
|
||||
move |el: &Element| {
|
||||
or_debug!(
|
||||
el.remove_event_listener_with_callback(
|
||||
el.remove_event_listener_with_callback_and_bool(
|
||||
intern(&name),
|
||||
cb.as_ref().unchecked_ref()
|
||||
cb.as_ref().unchecked_ref(),
|
||||
true
|
||||
),
|
||||
el,
|
||||
"removeEventListener"
|
||||
@@ -451,8 +456,8 @@ impl Dom {
|
||||
V: ToTemplate + 'static,
|
||||
{
|
||||
thread_local! {
|
||||
static TEMPLATE_ELEMENT: Lazy<HtmlTemplateElement> =
|
||||
Lazy::new(|| document().create_element("template").unwrap().unchecked_into());
|
||||
static TEMPLATE_ELEMENT: LazyCell<HtmlTemplateElement> =
|
||||
LazyCell::new(|| document().create_element(Dom::intern("template")).unwrap().unchecked_into());
|
||||
static TEMPLATES: RefCell<LinearMap<TypeId, HtmlTemplateElement>> = Default::default();
|
||||
}
|
||||
|
||||
@@ -487,13 +492,66 @@ impl Dom {
|
||||
.unchecked_into()
|
||||
}
|
||||
|
||||
pub fn create_element_from_html(html: &str) -> Element {
|
||||
// TODO can be optimized to cache HTML strings or cache <template>?
|
||||
let tpl = document().create_element("template").unwrap();
|
||||
tpl.set_inner_html(html);
|
||||
let tpl = Self::clone_template(tpl.unchecked_ref());
|
||||
pub fn create_element_from_html(html: Cow<'static, str>) -> Element {
|
||||
let tpl = TEMPLATE_CACHE.with(|cache| {
|
||||
let mut cache = cache.borrow_mut();
|
||||
if let Some(tpl_content) = cache.iter().find_map(|(key, tpl)| {
|
||||
(html == *key)
|
||||
.then_some(Self::clone_template(tpl.unchecked_ref()))
|
||||
}) {
|
||||
tpl_content
|
||||
} else {
|
||||
let tpl = document()
|
||||
.create_element(Self::intern("template"))
|
||||
.unwrap();
|
||||
tpl.set_inner_html(&html);
|
||||
let tpl_content = Self::clone_template(tpl.unchecked_ref());
|
||||
cache.push((html, tpl));
|
||||
tpl_content
|
||||
}
|
||||
});
|
||||
tpl.first_element_child().unwrap_or(tpl)
|
||||
}
|
||||
|
||||
pub fn create_svg_element_from_html(html: Cow<'static, str>) -> Element {
|
||||
let tpl = TEMPLATE_CACHE.with(|cache| {
|
||||
let mut cache = cache.borrow_mut();
|
||||
if let Some(tpl_content) = cache.iter().find_map(|(key, tpl)| {
|
||||
(html == *key)
|
||||
.then_some(Self::clone_template(tpl.unchecked_ref()))
|
||||
}) {
|
||||
tpl_content
|
||||
} else {
|
||||
let tpl = document()
|
||||
.create_element(Self::intern("template"))
|
||||
.unwrap();
|
||||
let svg = document()
|
||||
.create_element_ns(
|
||||
Some(Self::intern("http://www.w3.org/2000/svg")),
|
||||
Self::intern("svg"),
|
||||
)
|
||||
.unwrap();
|
||||
let g = document()
|
||||
.create_element_ns(
|
||||
Some(Self::intern("http://www.w3.org/2000/svg")),
|
||||
Self::intern("g"),
|
||||
)
|
||||
.unwrap();
|
||||
g.set_inner_html(&html);
|
||||
svg.append_child(&g).unwrap();
|
||||
tpl.unchecked_ref::<TemplateElement>()
|
||||
.content()
|
||||
.append_child(&svg)
|
||||
.unwrap();
|
||||
let tpl_content = Self::clone_template(tpl.unchecked_ref());
|
||||
cache.push((html, tpl));
|
||||
tpl_content
|
||||
}
|
||||
});
|
||||
|
||||
let svg = tpl.first_element_child().unwrap();
|
||||
svg.first_element_child().unwrap_or(svg)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mountable for Node {
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
use crate::{
|
||||
html::{
|
||||
attribute::Attribute,
|
||||
attribute::{any_attribute::AnyAttribute, Attribute},
|
||||
element::{ElementType, ElementWithChildren, HtmlElement},
|
||||
},
|
||||
view::Render,
|
||||
hydration::Cursor,
|
||||
prelude::{AddAnyAttr, Mountable},
|
||||
renderer::{
|
||||
dom::{Element, Node},
|
||||
CastFrom, Rndr,
|
||||
},
|
||||
view::{Position, PositionState, Render, RenderHtml},
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
use std::{borrow::Cow, fmt::Debug};
|
||||
|
||||
macro_rules! svg_elements {
|
||||
($($tag:ident [$($attr:ty),*]),* $(,)?) => {
|
||||
@@ -185,3 +191,124 @@ impl ElementType for Use {
|
||||
}
|
||||
|
||||
impl ElementWithChildren for Use {}
|
||||
|
||||
/// An element that contains no interactivity, and whose contents can be known at compile time.
|
||||
pub struct InertElement {
|
||||
html: Cow<'static, str>,
|
||||
}
|
||||
|
||||
impl InertElement {
|
||||
/// Creates a new inert svg element.
|
||||
pub fn new(html: impl Into<Cow<'static, str>>) -> Self {
|
||||
Self { html: html.into() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Retained view state for [`InertElement`].
|
||||
pub struct InertElementState(Cow<'static, str>, Element);
|
||||
|
||||
impl Mountable for InertElementState {
|
||||
fn unmount(&mut self) {
|
||||
self.1.unmount();
|
||||
}
|
||||
|
||||
fn mount(&mut self, parent: &Element, marker: Option<&Node>) {
|
||||
self.1.mount(parent, marker)
|
||||
}
|
||||
|
||||
fn insert_before_this(&self, child: &mut dyn Mountable) -> bool {
|
||||
self.1.insert_before_this(child)
|
||||
}
|
||||
|
||||
fn elements(&self) -> Vec<crate::renderer::types::Element> {
|
||||
vec![self.1.clone()]
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for InertElement {
|
||||
type State = InertElementState;
|
||||
|
||||
fn build(self) -> Self::State {
|
||||
let el = Rndr::create_svg_element_from_html(self.html.clone());
|
||||
InertElementState(self.html, el)
|
||||
}
|
||||
|
||||
fn rebuild(self, state: &mut Self::State) {
|
||||
let InertElementState(prev, el) = state;
|
||||
if &self.html != prev {
|
||||
let mut new_el =
|
||||
Rndr::create_svg_element_from_html(self.html.clone());
|
||||
el.insert_before_this(&mut new_el);
|
||||
el.unmount();
|
||||
*el = new_el;
|
||||
*prev = self.html;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAnyAttr for InertElement {
|
||||
type Output<SomeNewAttr: Attribute> = Self;
|
||||
|
||||
fn add_any_attr<NewAttr: Attribute>(
|
||||
self,
|
||||
_attr: NewAttr,
|
||||
) -> Self::Output<NewAttr>
|
||||
where
|
||||
Self::Output<NewAttr>: RenderHtml,
|
||||
{
|
||||
panic!(
|
||||
"InertElement does not support adding attributes. It should only \
|
||||
be used as a child, and not returned at the top level."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderHtml for InertElement {
|
||||
type AsyncOutput = Self;
|
||||
type Owned = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
|
||||
fn html_len(&self) -> usize {
|
||||
self.html.len()
|
||||
}
|
||||
|
||||
fn dry_resolve(&mut self) {}
|
||||
|
||||
async fn resolve(self) -> Self {
|
||||
self
|
||||
}
|
||||
|
||||
fn to_html_with_buf(
|
||||
self,
|
||||
buf: &mut String,
|
||||
position: &mut Position,
|
||||
_escape: bool,
|
||||
_mark_branches: bool,
|
||||
_extra_attrs: Vec<AnyAttribute>,
|
||||
) {
|
||||
buf.push_str(&self.html);
|
||||
*position = Position::NextChild;
|
||||
}
|
||||
|
||||
fn hydrate<const FROM_SERVER: bool>(
|
||||
self,
|
||||
cursor: &Cursor,
|
||||
position: &PositionState,
|
||||
) -> Self::State {
|
||||
let curr_position = position.get();
|
||||
if curr_position == Position::FirstChild {
|
||||
cursor.child();
|
||||
} else if curr_position != Position::Current {
|
||||
cursor.sibling();
|
||||
}
|
||||
let el = crate::renderer::types::Element::cast_from(cursor.current())
|
||||
.unwrap();
|
||||
position.set(Position::NextChild);
|
||||
InertElementState(self.html, el)
|
||||
}
|
||||
|
||||
fn into_owned(self) -> Self::Owned {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoFragment for AnyView {
|
||||
fn into_fragment(self) -> Fragment {
|
||||
Fragment::new(vec![self])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoFragment for Vec<T>
|
||||
where
|
||||
T: IntoAny,
|
||||
|
||||
@@ -437,6 +437,17 @@ pub trait ToTemplate {
|
||||
inner_html: &mut String,
|
||||
position: &mut Position,
|
||||
);
|
||||
|
||||
/// Renders a view type to a template in attribute position.
|
||||
fn to_template_attribute(
|
||||
buf: &mut String,
|
||||
class: &mut String,
|
||||
style: &mut String,
|
||||
inner_html: &mut String,
|
||||
position: &mut Position,
|
||||
) {
|
||||
Self::to_template(buf, class, style, inner_html, position);
|
||||
}
|
||||
}
|
||||
|
||||
/// Keeps track of what position the item currently being hydrated is in, relative to its siblings
|
||||
|
||||
@@ -103,6 +103,15 @@ impl ToTemplate for () {
|
||||
) {
|
||||
buf.push_str("<!>");
|
||||
}
|
||||
|
||||
fn to_template_attribute(
|
||||
_buf: &mut String,
|
||||
_class: &mut String,
|
||||
_style: &mut String,
|
||||
_inner_html: &mut String,
|
||||
_position: &mut Position,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Render> Render for (A,) {
|
||||
|
||||
Reference in New Issue
Block a user