mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-28 11:21:55 -05:00
Compare commits
9 Commits
3200
...
0.7.0-docs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05055d5015 | ||
|
|
b9dd0ffbd2 | ||
|
|
3b2e541133 | ||
|
|
22a1aecaa9 | ||
|
|
5327fea1a7 | ||
|
|
1b4a16bc86 | ||
|
|
8ee7a2072e | ||
|
|
64debdc29a | ||
|
|
bb271c0727 |
49
.github/workflows/autofix.yml
vendored
49
.github/workflows/autofix.yml
vendored
@@ -1,49 +0,0 @@
|
||||
name: autofix.ci
|
||||
on:
|
||||
pull_request:
|
||||
# Running this workflow on main branch pushes requires write permission to apply changes.
|
||||
# Leave it alone for future uses.
|
||||
# push:
|
||||
# branches: ["main"]
|
||||
permissions:
|
||||
contents: read
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUST_BACKTRACE: 1
|
||||
jobs:
|
||||
autofix:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with: {toolchain: nightly, components: "rustfmt, clippy", target: "wasm32-unknown-unknown", rustflags: ""}
|
||||
- name: Install jq
|
||||
run: sudo apt-get install jq
|
||||
- run: |
|
||||
echo "Formatting the workspace"
|
||||
cargo fmt --all
|
||||
|
||||
echo "Running Clippy against each member's features (default features included)"
|
||||
for member in $(cargo metadata --no-deps --format-version 1 | jq -r '.packages[] | .name'); do
|
||||
echo "Working on member $member":
|
||||
echo -e "\tdefault-features/no-features:"
|
||||
# this will also run on members with no features or default features
|
||||
cargo clippy --allow-dirty --fix --lib --package "$member"
|
||||
|
||||
features=$(cargo metadata --no-deps --format-version 1 | jq -r ".packages[] | select(.name == \"$member\") | .features | keys[]")
|
||||
for feature in $features; do
|
||||
if [ "$feature" = "default" ]; then
|
||||
continue
|
||||
fi
|
||||
echo -e "\tfeature $feature"
|
||||
cargo clippy --allow-dirty --fix --lib --package "$member" --features "$feature"
|
||||
done
|
||||
done
|
||||
- uses: autofix-ci/action@v1.3.1
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
fail-fast: false
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,4 +14,3 @@ blob.rs
|
||||
|
||||
.vscode
|
||||
vendor
|
||||
hash.txt
|
||||
|
||||
48
Cargo.lock
generated
48
Cargo.lock
generated
@@ -278,7 +278,7 @@ dependencies = [
|
||||
"async-executor",
|
||||
"futures",
|
||||
"glib",
|
||||
"thiserror 2.0.3",
|
||||
"thiserror 2.0.0",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"wasm-bindgen-futures",
|
||||
@@ -400,9 +400,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.8"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49c41b948da08fb481a94546cd874843adc1142278b0af4badf9b1b78599d68d"
|
||||
checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
@@ -1171,9 +1171,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "gio-sys"
|
||||
version = "0.20.6"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b965df6f3534c84816b5c1a7d9efcb5671ae790822de5abe8e299797039529bc"
|
||||
checksum = "217f464cad5946ae4369c355155e2d16b488c08920601083cb4891e352ae777b"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
@@ -1184,9 +1184,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.20.6"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86bd3e4ee7998ab5a135d900db56930cc19ad16681adf245daff54f618b9d5e1"
|
||||
checksum = "358431b0e0eb15b9d02db52e1f19c805b953c5c168099deb3de88beab761768c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"futures-channel",
|
||||
@@ -1218,9 +1218,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "glib-sys"
|
||||
version = "0.20.6"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d0b1827e8621fc42c0dfb228e5d57ff6a71f9699e666ece8113f979ad87c2de"
|
||||
checksum = "8a5911863ab7ecd4a6f8d5976f12eeba076b23669c49b066d877e742544aa389"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"system-deps",
|
||||
@@ -1792,7 +1792,7 @@ dependencies = [
|
||||
"server_fn",
|
||||
"slotmap",
|
||||
"tachys",
|
||||
"thiserror 2.0.3",
|
||||
"thiserror 2.0.0",
|
||||
"throw_error",
|
||||
"tracing",
|
||||
"typed-builder",
|
||||
@@ -1870,7 +1870,7 @@ dependencies = [
|
||||
"serde",
|
||||
"temp-env",
|
||||
"tempfile",
|
||||
"thiserror 2.0.3",
|
||||
"thiserror 2.0.0",
|
||||
"tokio",
|
||||
"typed-builder",
|
||||
]
|
||||
@@ -1981,7 +1981,7 @@ dependencies = [
|
||||
"reactive_graph",
|
||||
"send_wrapper",
|
||||
"tachys",
|
||||
"thiserror 2.0.3",
|
||||
"thiserror 2.0.0",
|
||||
"tracing",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
@@ -2291,7 +2291,7 @@ version = "0.2.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.3",
|
||||
"thiserror 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2739,7 +2739,7 @@ dependencies = [
|
||||
"send_wrapper",
|
||||
"serde",
|
||||
"slotmap",
|
||||
"thiserror 2.0.3",
|
||||
"thiserror 2.0.0",
|
||||
"tokio",
|
||||
"tokio-test",
|
||||
"tracing",
|
||||
@@ -3156,9 +3156,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.215"
|
||||
version = "1.0.214"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||
checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@@ -3197,9 +3197,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.215"
|
||||
version = "1.0.214"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||
checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -3290,7 +3290,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_qs",
|
||||
"server_fn_macro_default",
|
||||
"thiserror 2.0.3",
|
||||
"thiserror 2.0.0",
|
||||
"throw_error",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
@@ -3627,11 +3627,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.3"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa"
|
||||
checksum = "15291287e9bff1bc6f9ff3409ed9af665bec7a5fc8ac079ea96be07bca0e2668"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.3",
|
||||
"thiserror-impl 2.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3647,9 +3647,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.3"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568"
|
||||
checksum = "22efd00f33f93fa62848a7cab956c3d38c8d43095efda1decfc2b3a5dc0b8972"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -11,7 +11,7 @@ edition.workspace = true
|
||||
[dependencies]
|
||||
async-executor = { version = "1.13.1", optional = true }
|
||||
futures = "0.3.31"
|
||||
glib = { version = "0.20.6", optional = true }
|
||||
glib = { version = "0.20.5", optional = true }
|
||||
thiserror = "2.0"
|
||||
tokio = { version = "1.41", optional = true, default-features = false, features = [
|
||||
"rt",
|
||||
|
||||
@@ -6,9 +6,7 @@ use leptos_axum::ResponseOptions;
|
||||
// A basic function to display errors served by the error boundaries.
|
||||
// Feel free to do more complicated things here than just displaying them.
|
||||
#[component]
|
||||
pub fn ErrorTemplate(
|
||||
#[prop(into)] errors: MaybeSignal<Errors>,
|
||||
) -> impl IntoView {
|
||||
pub fn ErrorTemplate(#[prop(into)] errors: Signal<Errors>) -> impl IntoView {
|
||||
// Get Errors from Signal
|
||||
// Downcast lets us take a type that implements `std::error::Error`
|
||||
let errors = Memo::new(move |_| {
|
||||
|
||||
@@ -12,7 +12,7 @@ lto = true
|
||||
|
||||
[dependencies]
|
||||
console_error_panic_hook = "0.1.7"
|
||||
leptos = { path = "../../leptos", features = ["islands"] }
|
||||
leptos = { path = "../../leptos", features = ["experimental-islands"] }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
leptos_meta = { path = "../../meta" }
|
||||
leptos_router = { path = "../../router" }
|
||||
|
||||
@@ -12,7 +12,7 @@ futures = "0.3.30"
|
||||
http = "1.1"
|
||||
leptos = { path = "../../leptos", features = [
|
||||
"tracing",
|
||||
"islands",
|
||||
"experimental-islands",
|
||||
] }
|
||||
server_fn = { path = "../../server_fn", features = ["serde-lite"] }
|
||||
leptos_axum = { path = "../../integrations/axum", optional = true }
|
||||
|
||||
@@ -12,7 +12,7 @@ futures = "0.3.30"
|
||||
http = "1.1"
|
||||
leptos = { path = "../../leptos", features = [
|
||||
"tracing",
|
||||
"islands",
|
||||
"experimental-islands",
|
||||
] }
|
||||
leptos_router = { path = "../../router" }
|
||||
server_fn = { path = "../../server_fn", features = ["serde-lite"] }
|
||||
|
||||
@@ -10,7 +10,7 @@ struct Then {
|
||||
// the type with Option<...> and marking the option as #[prop(optional)].
|
||||
#[slot]
|
||||
struct ElseIf {
|
||||
cond: MaybeSignal<bool>,
|
||||
cond: Signal<bool>,
|
||||
children: ChildrenFn,
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ struct Fallback {
|
||||
// Slots are added to components like any other prop.
|
||||
#[component]
|
||||
fn SlotIf(
|
||||
cond: MaybeSignal<bool>,
|
||||
cond: Signal<bool>,
|
||||
then: Then,
|
||||
#[prop(default=vec![])] else_if: Vec<ElseIf>,
|
||||
#[prop(optional)] fallback: Option<Fallback>,
|
||||
@@ -43,9 +43,9 @@ fn SlotIf(
|
||||
#[component]
|
||||
pub fn App() -> impl IntoView {
|
||||
let (count, set_count) = signal(0);
|
||||
let is_even = MaybeSignal::derive(move || count.get() % 2 == 0);
|
||||
let is_div5 = MaybeSignal::derive(move || count.get() % 5 == 0);
|
||||
let is_div7 = MaybeSignal::derive(move || count.get() % 7 == 0);
|
||||
let is_even = Signal::derive(move || count.get() % 2 == 0);
|
||||
let is_div5 = Signal::derive(move || count.get() % 5 == 0);
|
||||
let is_div7 = Signal::derive(move || count.get() % 7 == 0);
|
||||
|
||||
view! {
|
||||
<button on:click=move |_| set_count.update(|value| *value += 1)>"+1"</button>
|
||||
|
||||
@@ -10,7 +10,7 @@ crate-type = ["cdylib", "rlib"]
|
||||
actix-files = { version = "0.6.6", optional = true }
|
||||
actix-web = { version = "4.8", optional = true, features = ["macros"] }
|
||||
console_error_panic_hook = "0.1.7"
|
||||
js-sys = { version = "0.3.72" }
|
||||
js-sys = { version = "0.3.70", optional = true }
|
||||
leptos = { path = "../../leptos" }
|
||||
leptos_actix = { path = "../../integrations/actix", optional = true }
|
||||
leptos_router = { path = "../../router" }
|
||||
@@ -21,7 +21,7 @@ tokio = { version = "1.39", features = ["time", "rt"], optional = true }
|
||||
|
||||
[features]
|
||||
hydrate = [
|
||||
|
||||
"dep:js-sys",
|
||||
"leptos/hydrate",
|
||||
]
|
||||
ssr = [
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
@check_aria_current
|
||||
Feature: Check aria-current being applied to make links bolded
|
||||
|
||||
Background:
|
||||
|
||||
Given I see the app
|
||||
|
||||
Scenario: Should see the base case working
|
||||
Then I see the Out-of-Order link being bolded
|
||||
And I see the following links being bolded
|
||||
| Out-of-Order |
|
||||
| Nested |
|
||||
And I see the In-Order link not being bolded
|
||||
And I see the following links not being bolded
|
||||
| In-Order |
|
||||
| Single |
|
||||
|
||||
Scenario: Should see client-side render the correct bolded links
|
||||
When I select the link In-Order
|
||||
And I select the link Single
|
||||
Then I see the following links being bolded
|
||||
| In-Order |
|
||||
| Single |
|
||||
And I see the following links not being bolded
|
||||
| Out-of-Order |
|
||||
| Nested |
|
||||
|
||||
Scenario: Should see server-side render the correct bolded links
|
||||
When I select the link In-Order
|
||||
And I select the link Single
|
||||
And I reload the page
|
||||
Then I see the following links being bolded
|
||||
| In-Order |
|
||||
| Single |
|
||||
And I see the following links not being bolded
|
||||
| Out-of-Order |
|
||||
| Nested |
|
||||
|
||||
Scenario: Check that the base nested route links are working
|
||||
When I select the link Instrumented
|
||||
Then I see the Instrumented link being bolded
|
||||
And I see the Item Listing link not being bolded
|
||||
|
||||
Scenario: Should see going deep down into nested routes bold links
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| Target 421 |
|
||||
| field1 |
|
||||
|
||||
Scenario: Should see going deep down into nested routes in SSR bold links
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
And I reload the page
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| Target 421 |
|
||||
| field1 |
|
||||
|
||||
Scenario: Going deep down navigate around nested links bold correctly
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
And I select the link Inspect path2/field3
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| field3 |
|
||||
And I see the following links not being bolded
|
||||
| Target 421 |
|
||||
| field1 |
|
||||
|
||||
Scenario: Going deep down navigate around nested links bold correctly, SSR
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
And I select the link Inspect path2/field3
|
||||
And I reload the page
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| field3 |
|
||||
And I see the following links not being bolded
|
||||
| Target 421 |
|
||||
| field1 |
|
||||
|
||||
Scenario: Going deep down back out nested routes reset bolded states
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
And I select the link Counters
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Counters |
|
||||
And I see the following links not being bolded
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| Target 421 |
|
||||
|
||||
Scenario: Going deep down back out nested routes reset bolded states, SSR
|
||||
When I select the link Instrumented
|
||||
And I select the link Target 421
|
||||
And I select the link Counters
|
||||
And I reload the page
|
||||
Then I see the following links being bolded
|
||||
| Instrumented |
|
||||
| Counters |
|
||||
And I see the following links not being bolded
|
||||
| Item Listing |
|
||||
| Target 4## |
|
||||
| Target 42# |
|
||||
| Target 421 |
|
||||
@@ -81,20 +81,3 @@ pub async fn instrumented_counts(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn link_text_is_aria_current(client: &Client, text: &str) -> Result<()> {
|
||||
let link = find::link_with_text(client, text).await?;
|
||||
|
||||
link.attr("aria-current").await?
|
||||
.expect(format!("aria-current missing for {text}").as_str());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn link_text_is_not_aria_current(client: &Client, text: &str) -> Result<()> {
|
||||
let link = find::link_with_text(client, text).await?;
|
||||
|
||||
link.attr("aria-current").await?
|
||||
.map(|_| anyhow::bail!("aria-current mistakenly set for {text}"))
|
||||
.unwrap_or(Ok(()))
|
||||
}
|
||||
|
||||
@@ -124,12 +124,3 @@ async fn component_message(client: &Client, id: &str) -> Result<String> {
|
||||
|
||||
Ok(text)
|
||||
}
|
||||
|
||||
pub async fn link_with_text(client: &Client, text: &str) -> Result<Element> {
|
||||
let link = client
|
||||
.wait()
|
||||
.for_element(Locator::LinkText(text))
|
||||
.await
|
||||
.expect(format!("Link not found by `{}`", text).as_str());
|
||||
Ok(link)
|
||||
}
|
||||
|
||||
@@ -80,58 +80,6 @@ async fn i_see_the_second_count_is(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(regex = r"^I see the (.*) link being bolded$")]
|
||||
async fn i_see_the_link_being_bolded(
|
||||
world: &mut AppWorld,
|
||||
text: String,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
check::link_text_is_aria_current(client, &text).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(expr = "I see the following links being bolded")]
|
||||
async fn i_see_the_following_links_being_bolded(
|
||||
world: &mut AppWorld,
|
||||
step: &Step,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
if let Some(table) = step.table.as_ref() {
|
||||
for row in table.rows.iter() {
|
||||
check::link_text_is_aria_current(client, &row[0]).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(regex = r"^I see the (.*) link not being bolded$")]
|
||||
async fn i_see_the_link_being_not_bolded(
|
||||
world: &mut AppWorld,
|
||||
text: String,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
check::link_text_is_not_aria_current(client, &text).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(expr = "I see the following links not being bolded")]
|
||||
async fn i_see_the_following_links_not_being_bolded(
|
||||
world: &mut AppWorld,
|
||||
step: &Step,
|
||||
) -> Result<()> {
|
||||
let client = &world.client;
|
||||
if let Some(table) = step.table.as_ref() {
|
||||
for row in table.rows.iter() {
|
||||
check::link_text_is_not_aria_current(client, &row[0]).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[then(expr = "I see the following counters under section")]
|
||||
#[then(expr = "the following counters under section")]
|
||||
async fn i_see_the_following_counters_under_section(
|
||||
|
||||
@@ -38,7 +38,7 @@ pub fn TimerDemo() -> impl IntoView {
|
||||
pub fn use_interval<T, F>(interval_millis: T, f: F)
|
||||
where
|
||||
F: Fn() + Clone + 'static,
|
||||
T: Into<MaybeSignal<u64>> + 'static,
|
||||
T: Into<Signal<u64>> + 'static,
|
||||
{
|
||||
let interval_millis = interval_millis.into();
|
||||
Effect::new(move |prev_handle: Option<IntervalHandle>| {
|
||||
|
||||
@@ -11,7 +11,7 @@ edition.workspace = true
|
||||
[dependencies]
|
||||
any_spawner = { workspace = true, features = ["tokio"] }
|
||||
hydration_context = { workspace = true }
|
||||
axum = { version = "0.7.8", default-features = false, features = [
|
||||
axum = { version = "0.7.7", default-features = false, features = [
|
||||
"matched-path",
|
||||
] }
|
||||
dashmap = "6"
|
||||
@@ -30,7 +30,7 @@ tower-http = "0.6.1"
|
||||
tracing = { version = "0.1.40", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
axum = "0.7.8"
|
||||
axum = "0.7.7"
|
||||
tokio = { version = "1.41", features = ["net", "rt-multi-thread"] }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
//! - `default`: supports running in a typical native Tokio/Axum environment
|
||||
//! - `wasm`: with `default-features = false`, supports running in a JS Fetch-based
|
||||
//! environment
|
||||
//! - `islands`: activates Leptos [islands mode](https://leptos-rs.github.io/leptos/islands.html)
|
||||
//! - `experimental-islands`: activates Leptos [islands mode](https://leptos-rs.github.io/leptos/islands.html)
|
||||
//!
|
||||
//! ### Important Note
|
||||
//! Prior to 0.5, using `default-features = false` on `leptos_axum` simply did nothing. Now, it actively
|
||||
|
||||
@@ -86,7 +86,7 @@ tracing = [
|
||||
]
|
||||
nonce = ["base64", "rand"]
|
||||
spin = ["leptos-spin-macro"]
|
||||
islands = ["leptos_macro/islands", "dep:serde_json"]
|
||||
experimental-islands = ["leptos_macro/experimental-islands", "dep:serde_json"]
|
||||
trace-component-props = [
|
||||
"leptos_macro/trace-component-props",
|
||||
"leptos_dom/trace-component-props"
|
||||
@@ -104,7 +104,7 @@ denylist = [
|
||||
"rkyv", # was causing clippy issues on nightly
|
||||
"trace-component-props",
|
||||
"spin",
|
||||
"islands",
|
||||
"experimental-islands",
|
||||
]
|
||||
skip_feature_sets = [
|
||||
["csr", "ssr"],
|
||||
|
||||
@@ -223,14 +223,14 @@ mod tests {
|
||||
#[test]
|
||||
fn clone_callback() {
|
||||
let callback = Callback::new(move |_no_clone: NoClone| NoClone {});
|
||||
let _cloned = callback;
|
||||
let _cloned = callback.clone();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clone_unsync_callback() {
|
||||
let callback =
|
||||
UnsyncCallback::new(move |_no_clone: NoClone| NoClone {});
|
||||
let _cloned = callback;
|
||||
let _cloned = callback.clone();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -47,7 +47,7 @@ pub fn AutoReload(
|
||||
pub fn HydrationScripts(
|
||||
/// Configuration options for this project.
|
||||
options: LeptosOptions,
|
||||
/// Should be `true` to hydrate in `islands` mode.
|
||||
/// Should be `true` to hydrate in `experimental-islands` mode.
|
||||
#[prop(optional)]
|
||||
islands: bool,
|
||||
/// A base url, not including a trailing slash
|
||||
|
||||
@@ -318,10 +318,10 @@ pub mod task {
|
||||
}
|
||||
|
||||
// these reexports are used in islands
|
||||
#[cfg(feature = "islands")]
|
||||
#[cfg(feature = "experimental-islands")]
|
||||
#[doc(hidden)]
|
||||
pub use serde;
|
||||
#[cfg(feature = "islands")]
|
||||
#[cfg(feature = "experimental-islands")]
|
||||
#[doc(hidden)]
|
||||
pub use serde_json;
|
||||
#[cfg(feature = "tracing")]
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
#[test]
|
||||
fn generic_component_signal_inference() {
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[component]
|
||||
pub fn SimpleCounter(#[prop(into)] step: Signal<i32>) -> impl IntoView {
|
||||
_ = step;
|
||||
view! {
|
||||
<div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
let a = RwSignal::new(1);
|
||||
let (b, _) = signal(1);
|
||||
|
||||
view! {
|
||||
<SimpleCounter step=a/>
|
||||
<SimpleCounter step=b/>
|
||||
<SimpleCounter step=Signal::stored(1)/>
|
||||
};
|
||||
}
|
||||
2851
leptos/tests/test_examples/suspense-tests/Cargo.lock
generated
2851
leptos/tests/test_examples/suspense-tests/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -30,14 +30,14 @@ fn ws_from_str_test() {
|
||||
|
||||
#[test]
|
||||
fn env_w_default_test() {
|
||||
temp_env::with_var("LEPTOS_CONFIG_ENV_TEST", Some("custom"), || {
|
||||
_ = temp_env::with_var("LEPTOS_CONFIG_ENV_TEST", Some("custom"), || {
|
||||
assert_eq!(
|
||||
env_w_default("LEPTOS_CONFIG_ENV_TEST", "default").unwrap(),
|
||||
String::from("custom")
|
||||
);
|
||||
});
|
||||
|
||||
temp_env::with_var_unset("LEPTOS_CONFIG_ENV_TEST", || {
|
||||
_ = temp_env::with_var_unset("LEPTOS_CONFIG_ENV_TEST", || {
|
||||
assert_eq!(
|
||||
env_w_default("LEPTOS_CONFIG_ENV_TEST", "default").unwrap(),
|
||||
String::from("default")
|
||||
@@ -47,14 +47,14 @@ fn env_w_default_test() {
|
||||
|
||||
#[test]
|
||||
fn env_wo_default_test() {
|
||||
temp_env::with_var("LEPTOS_CONFIG_ENV_TEST", Some("custom"), || {
|
||||
_ = temp_env::with_var("LEPTOS_CONFIG_ENV_TEST", Some("custom"), || {
|
||||
assert_eq!(
|
||||
env_wo_default("LEPTOS_CONFIG_ENV_TEST").unwrap(),
|
||||
Some(String::from("custom"))
|
||||
);
|
||||
});
|
||||
|
||||
temp_env::with_var_unset("LEPTOS_CONFIG_ENV_TEST", || {
|
||||
_ = temp_env::with_var_unset("LEPTOS_CONFIG_ENV_TEST", || {
|
||||
assert_eq!(env_wo_default("LEPTOS_CONFIG_ENV_TEST").unwrap(), None);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ hydrate = []
|
||||
ssr = ["server_fn_macro/ssr", "leptos/ssr"]
|
||||
nightly = ["server_fn_macro/nightly"]
|
||||
tracing = ["dep:tracing"]
|
||||
islands = []
|
||||
experimental-islands = []
|
||||
trace-component-props = []
|
||||
actix = ["server_fn_macro/actix"]
|
||||
axum = ["server_fn_macro/axum"]
|
||||
|
||||
@@ -559,10 +559,10 @@ pub fn component(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
|
||||
}
|
||||
|
||||
/// Defines a component as an interactive island when you are using the
|
||||
/// `islands` feature of Leptos. Apart from the macro name,
|
||||
/// `experimental-islands` feature of Leptos. Apart from the macro name,
|
||||
/// the API is the same as the [`component`](macro@component) macro.
|
||||
///
|
||||
/// When you activate the `islands` feature, every `#[component]`
|
||||
/// When you activate the `experimental-islands` feature, every `#[component]`
|
||||
/// is server-only by default. This "default to server" behavior is important:
|
||||
/// you opt into shipping code to the client, rather than opting out. You can
|
||||
/// opt into client-side interactivity for any given component by changing from
|
||||
|
||||
@@ -197,7 +197,7 @@ enum InertElementBuilder<'a> {
|
||||
},
|
||||
}
|
||||
|
||||
impl ToTokens for InertElementBuilder<'_> {
|
||||
impl<'a> ToTokens for InertElementBuilder<'a> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
InertElementBuilder::GlobalClass { strs, .. } => {
|
||||
@@ -219,7 +219,7 @@ enum GlobalClassItem<'a> {
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl ToTokens for GlobalClassItem<'_> {
|
||||
impl<'a> ToTokens for GlobalClassItem<'a> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let addl_tokens = match self {
|
||||
GlobalClassItem::Global(v) => v.to_token_stream(),
|
||||
|
||||
@@ -70,7 +70,7 @@ pub enum Oco<'a, T: ?Sized + ToOwned + 'a> {
|
||||
Owned(<T as ToOwned>::Owned),
|
||||
}
|
||||
|
||||
impl<T: ?Sized + ToOwned> Oco<'_, T> {
|
||||
impl<'a, T: ?Sized + ToOwned> Oco<'a, T> {
|
||||
/// Converts the value into an owned value.
|
||||
pub fn into_owned(self) -> <T as ToOwned>::Owned {
|
||||
match self {
|
||||
@@ -339,7 +339,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, A: ?Sized, B: ?Sized> PartialEq<Oco<'b, B>> for Oco<'_, A>
|
||||
impl<'a, 'b, A: ?Sized, B: ?Sized> PartialEq<Oco<'b, B>> for Oco<'a, A>
|
||||
where
|
||||
A: PartialEq<B>,
|
||||
A: ToOwned,
|
||||
@@ -352,7 +352,7 @@ where
|
||||
|
||||
impl<T: ?Sized + ToOwned + Eq> Eq for Oco<'_, T> {}
|
||||
|
||||
impl<'b, A: ?Sized, B: ?Sized> PartialOrd<Oco<'b, B>> for Oco<'_, A>
|
||||
impl<'a, 'b, A: ?Sized, B: ?Sized> PartialOrd<Oco<'b, B>> for Oco<'a, A>
|
||||
where
|
||||
A: PartialOrd<B>,
|
||||
A: ToOwned,
|
||||
@@ -551,7 +551,7 @@ impl_slice_eq!(['a, 'b, T: PartialEq] (where [T]: ToOwned), Oco<'a, [T]>, &'b [T
|
||||
impl_slice_eq!([T: PartialEq] (where [T]: ToOwned), Oco<'_, [T]>, Vec<T>);
|
||||
impl_slice_eq!(['a, 'b, T: PartialEq] (where [T]: ToOwned), Oco<'a, [T]>, Cow<'b, [T]>);
|
||||
|
||||
impl<'b> Add<&'b str> for Oco<'_, str> {
|
||||
impl<'a, 'b> Add<&'b str> for Oco<'a, str> {
|
||||
type Output = Oco<'static, str>;
|
||||
|
||||
fn add(self, rhs: &'b str) -> Self::Output {
|
||||
@@ -559,7 +559,7 @@ impl<'b> Add<&'b str> for Oco<'_, str> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> Add<Cow<'b, str>> for Oco<'_, str> {
|
||||
impl<'a, 'b> Add<Cow<'b, str>> for Oco<'a, str> {
|
||||
type Output = Oco<'static, str>;
|
||||
|
||||
fn add(self, rhs: Cow<'b, str>) -> Self::Output {
|
||||
@@ -567,7 +567,7 @@ impl<'b> Add<Cow<'b, str>> for Oco<'_, str> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> Add<Oco<'b, str>> for Oco<'_, str> {
|
||||
impl<'a, 'b> Add<Oco<'b, str>> for Oco<'a, str> {
|
||||
type Output = Oco<'static, str>;
|
||||
|
||||
fn add(self, rhs: Oco<'b, str>) -> Self::Output {
|
||||
|
||||
@@ -21,6 +21,6 @@ CREATE TABLE IF NOT EXISTS google_tokens (
|
||||
access_secret TEXT NOT NULL,
|
||||
refresh_secret TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) CONFLICT REPLACE
|
||||
);
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ pub async fn refresh_token(email: String) -> Result<u64, ServerFnError> {
|
||||
.execute(&pool)
|
||||
.await?;
|
||||
sqlx::query(
|
||||
"INSERT OR REPLACE INTO google_tokens (user_id,access_secret,refresh_secret) \
|
||||
"INSERT INTO google_tokens (user_id,access_secret,refresh_secret) \
|
||||
VALUES (?,?,?)",
|
||||
)
|
||||
.bind(user.id)
|
||||
|
||||
@@ -96,7 +96,7 @@ async fn main() {
|
||||
let client = oauth2::basic::BasicClient::new(
|
||||
oauth2::ClientId::new(
|
||||
std::env::var("G_AUTH_CLIENT_ID")
|
||||
.expect("G_AUTH_CLIENT_ID Env var to be set."),
|
||||
.expect("G_AUTH_CLIENT Env var to be set."),
|
||||
),
|
||||
Some(oauth2::ClientSecret::new(
|
||||
std::env::var("G_AUTH_SECRET")
|
||||
|
||||
@@ -84,6 +84,7 @@ pub mod owner;
|
||||
#[cfg(feature = "serde")]
|
||||
mod serde;
|
||||
pub mod signal;
|
||||
mod trait_options;
|
||||
pub mod traits;
|
||||
pub mod transition;
|
||||
pub mod wrappers;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#[allow(deprecated)]
|
||||
use crate::wrappers::read::{MaybeProp, MaybeSignal};
|
||||
use crate::{
|
||||
computed::{ArcMemo, Memo},
|
||||
owner::Storage,
|
||||
@@ -7,7 +9,7 @@ use crate::{
|
||||
},
|
||||
traits::{Get, Set},
|
||||
wrappers::{
|
||||
read::{ArcSignal, MaybeProp, MaybeSignal, Signal},
|
||||
read::{ArcSignal, Signal, SignalTypes},
|
||||
write::SignalSetter,
|
||||
},
|
||||
};
|
||||
@@ -112,7 +114,8 @@ macro_rules! impl_get_fn_traits_get_arena {
|
||||
($($ty:ident),*) => {
|
||||
$(
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<T, S> FnOnce<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> {
|
||||
#[allow(deprecated)]
|
||||
impl<T, S> FnOnce<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>> {
|
||||
type Output = <Self as Get>::Value;
|
||||
|
||||
#[inline(always)]
|
||||
@@ -122,7 +125,8 @@ macro_rules! impl_get_fn_traits_get_arena {
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<T, S> FnMut<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> {
|
||||
#[allow(deprecated)]
|
||||
impl<T, S> FnMut<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>> {
|
||||
#[inline(always)]
|
||||
extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output {
|
||||
self.get()
|
||||
@@ -130,7 +134,8 @@ macro_rules! impl_get_fn_traits_get_arena {
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<T, S> Fn<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> {
|
||||
#[allow(deprecated)]
|
||||
impl<T, S> Fn<()> for $ty<T, S> where $ty<T, S>: Get, S: Storage<T> + Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>> {
|
||||
#[inline(always)]
|
||||
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
|
||||
self.get()
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#[allow(deprecated)]
|
||||
use crate::wrappers::read::{MaybeProp, MaybeSignal};
|
||||
use crate::{
|
||||
computed::{ArcMemo, Memo},
|
||||
owner::Storage,
|
||||
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
|
||||
traits::With,
|
||||
wrappers::read::{MaybeProp, MaybeSignal, Signal, SignalTypes},
|
||||
wrappers::read::{Signal, SignalTypes},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -73,6 +75,7 @@ impl<T: Serialize + 'static, St: Storage<T>> Serialize for ArcMemo<T, St> {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T, St> Serialize for MaybeSignal<T, St>
|
||||
where
|
||||
T: Clone + Send + Sync + Serialize,
|
||||
@@ -96,15 +99,8 @@ where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
match &self.0 {
|
||||
None | Some(MaybeSignal::Static(None)) => {
|
||||
None::<T>.serialize(serializer)
|
||||
}
|
||||
Some(MaybeSignal::Static(Some(value))) => {
|
||||
value.serialize(serializer)
|
||||
}
|
||||
Some(MaybeSignal::Dynamic(signal)) => {
|
||||
signal.with(|value| value.serialize(serializer))
|
||||
}
|
||||
None => None::<T>.serialize(serializer),
|
||||
Some(signal) => signal.with(|value| value.serialize(serializer)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,6 +142,7 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for ArcRwSignal<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<'de, T: Deserialize<'de>, St> Deserialize<'de> for MaybeSignal<T, St>
|
||||
where
|
||||
St: Storage<T>,
|
||||
|
||||
238
reactive_graph/src/trait_options.rs
Normal file
238
reactive_graph/src/trait_options.rs
Normal file
@@ -0,0 +1,238 @@
|
||||
use crate::{
|
||||
traits::{
|
||||
DefinedAt, Get, GetUntracked, Read, ReadUntracked, Track, With,
|
||||
WithUntracked,
|
||||
},
|
||||
unwrap_signal,
|
||||
};
|
||||
use std::panic::Location;
|
||||
|
||||
impl<T> DefinedAt for Option<T>
|
||||
where
|
||||
T: DefinedAt,
|
||||
{
|
||||
fn defined_at(&self) -> Option<&'static Location<'static>> {
|
||||
self.as_ref().map(DefinedAt::defined_at).unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Track for Option<T>
|
||||
where
|
||||
T: Track,
|
||||
{
|
||||
fn track(&self) {
|
||||
if let Some(signal) = self {
|
||||
signal.track();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An alternative [`ReadUntracked`](crate) trait that works with `Option<Readable>` types.
|
||||
pub trait ReadUntrackedOptional: Sized + DefinedAt {
|
||||
/// The guard type that will be returned, which can be dereferenced to the value.
|
||||
type Value;
|
||||
|
||||
/// Returns the guard, or `None` if the signal has already been disposed.
|
||||
#[track_caller]
|
||||
fn try_read_untracked(&self) -> Option<Self::Value>;
|
||||
|
||||
/// Returns the guard.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if you try to access a signal that has been disposed.
|
||||
#[track_caller]
|
||||
fn read_untracked(&self) -> Self::Value {
|
||||
self.try_read_untracked()
|
||||
.unwrap_or_else(unwrap_signal!(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ReadUntrackedOptional for Option<T>
|
||||
where
|
||||
Self: DefinedAt,
|
||||
T: ReadUntracked,
|
||||
{
|
||||
type Value = Option<<T as ReadUntracked>::Value>;
|
||||
|
||||
fn try_read_untracked(&self) -> Option<Self::Value> {
|
||||
Some(if let Some(signal) = self {
|
||||
Some(signal.try_read_untracked()?)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An alternative [`Read`](crate) trait that works with `Option<Readable>` types.
|
||||
pub trait ReadOptional: DefinedAt {
|
||||
/// The guard type that will be returned, which can be dereferenced to the value.
|
||||
type Value;
|
||||
|
||||
/// Subscribes to the signal, and returns the guard, or `None` if the signal has already been disposed.
|
||||
#[track_caller]
|
||||
fn try_read(&self) -> Option<Self::Value>;
|
||||
|
||||
/// Subscribes to the signal, and returns the guard.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if you try to access a signal that has been disposed.
|
||||
#[track_caller]
|
||||
fn read(&self) -> Self::Value {
|
||||
self.try_read().unwrap_or_else(unwrap_signal!(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ReadOptional for Option<T>
|
||||
where
|
||||
Self: DefinedAt,
|
||||
T: Read,
|
||||
{
|
||||
type Value = Option<<T as Read>::Value>;
|
||||
|
||||
fn try_read(&self) -> Option<Self::Value> {
|
||||
Some(if let Some(readable) = self {
|
||||
Some(readable.try_read()?)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An alternative [`WithUntracked`](crate) trait that works with `Option<Withable>` types.
|
||||
pub trait WithUntrackedOptional: DefinedAt {
|
||||
/// The type of the value contained in the signal.
|
||||
type Value: ?Sized;
|
||||
|
||||
/// Applies the closure to the value, and returns the result,
|
||||
/// or `None` if the signal has already been disposed.
|
||||
#[track_caller]
|
||||
fn try_with_untracked<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(Option<&Self::Value>) -> U,
|
||||
) -> Option<U>;
|
||||
|
||||
/// Applies the closure to the value, and returns the result.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if you try to access a signal that has been disposed.
|
||||
#[track_caller]
|
||||
fn with_untracked<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(Option<&Self::Value>) -> U,
|
||||
) -> U {
|
||||
self.try_with_untracked(fun)
|
||||
.unwrap_or_else(unwrap_signal!(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> WithUntrackedOptional for Option<T>
|
||||
where
|
||||
Self: DefinedAt,
|
||||
T: WithUntracked,
|
||||
<T as WithUntracked>::Value: Sized,
|
||||
{
|
||||
type Value = <T as WithUntracked>::Value;
|
||||
|
||||
fn try_with_untracked<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(Option<&Self::Value>) -> U,
|
||||
) -> Option<U> {
|
||||
if let Some(signal) = self {
|
||||
Some(signal.try_with_untracked(|val| fun(Some(val)))?)
|
||||
} else {
|
||||
Some(fun(None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An alternative [`With`](crate) trait that works with `Option<Withable>` types.
|
||||
pub trait WithOptional: DefinedAt {
|
||||
/// The type of the value contained in the signal.
|
||||
type Value: ?Sized;
|
||||
|
||||
/// Subscribes to the signal, applies the closure to the value, and returns the result,
|
||||
/// or `None` if the signal has already been disposed.
|
||||
#[track_caller]
|
||||
fn try_with<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(Option<&Self::Value>) -> U,
|
||||
) -> Option<U>;
|
||||
|
||||
/// Subscribes to the signal, applies the closure to the value, and returns the result.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if you try to access a signal that has been disposed.
|
||||
#[track_caller]
|
||||
fn with<U>(&self, fun: impl FnOnce(Option<&Self::Value>) -> U) -> U {
|
||||
self.try_with(fun).unwrap_or_else(unwrap_signal!(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> WithOptional for Option<T>
|
||||
where
|
||||
Self: DefinedAt,
|
||||
T: With,
|
||||
<T as With>::Value: Sized,
|
||||
{
|
||||
type Value = <T as With>::Value;
|
||||
|
||||
fn try_with<U>(
|
||||
&self,
|
||||
fun: impl FnOnce(Option<&Self::Value>) -> U,
|
||||
) -> Option<U> {
|
||||
if let Some(signal) = self {
|
||||
Some(signal.try_with(|val| fun(Some(val)))?)
|
||||
} else {
|
||||
Some(fun(None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> GetUntracked for Option<T>
|
||||
where
|
||||
Self: DefinedAt,
|
||||
T: GetUntracked,
|
||||
{
|
||||
type Value = Option<<T as GetUntracked>::Value>;
|
||||
|
||||
fn try_get_untracked(&self) -> Option<Self::Value> {
|
||||
Some(if let Some(signal) = self {
|
||||
Some(signal.try_get_untracked()?)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Get for Option<T>
|
||||
where
|
||||
Self: DefinedAt,
|
||||
T: Get,
|
||||
{
|
||||
type Value = Option<<T as Get>::Value>;
|
||||
|
||||
fn try_get(&self) -> Option<Self::Value> {
|
||||
Some(if let Some(signal) = self {
|
||||
Some(signal.try_get()?)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait to implement flatten() on Option<&Option<T>>.
|
||||
pub trait FlattenOptionRefOption {
|
||||
/// The type of the value contained in the double option.
|
||||
type Value;
|
||||
|
||||
/// Converts from `Option<&Option<T>>` to `Option<&T>`.
|
||||
fn flatten(&self) -> Option<&Self::Value>;
|
||||
}
|
||||
|
||||
impl<'a, T> FlattenOptionRefOption for Option<&'a Option<T>> {
|
||||
type Value = T;
|
||||
|
||||
fn flatten(&self) -> Option<&'a T> {
|
||||
self.map(Option::as_ref).flatten()
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,7 @@
|
||||
//! there isn't an `RwLock` so you can't wrap in a [`ReadGuard`](crate::signal::guards::ReadGuard),
|
||||
//! but you can still implement [`WithUntracked`] and [`Track`], the same traits will still be implemented.
|
||||
|
||||
pub use crate::trait_options::*;
|
||||
use crate::{
|
||||
effect::Effect,
|
||||
graph::{Observer, Source, Subscriber, ToAnySource},
|
||||
|
||||
@@ -606,6 +606,33 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> From<T> for ArcSignal<T, SyncStorage> {
|
||||
#[track_caller]
|
||||
fn from(value: T) -> Self {
|
||||
ArcSignal::stored(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Signal<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: T) -> Self {
|
||||
Self::stored(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Signal<T, LocalStorage>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: T) -> Self {
|
||||
Self::stored_local(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ArcSignal<T, SyncStorage>> for Signal<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -681,6 +708,34 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ArcReadSignal<T>> for Signal<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: ArcReadSignal<T>) -> Self {
|
||||
Self {
|
||||
inner: ArenaItem::new(SignalTypes::ReadSignal(value)),
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ArcReadSignal<T>> for Signal<T, LocalStorage>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: ArcReadSignal<T>) -> Self {
|
||||
Self {
|
||||
inner: ArenaItem::new_local(SignalTypes::ReadSignal(value)),
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<RwSignal<T>> for Signal<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -713,6 +768,38 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ArcRwSignal<T>> for Signal<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: ArcRwSignal<T>) -> Self {
|
||||
Self {
|
||||
inner: ArenaItem::new(SignalTypes::ReadSignal(
|
||||
value.read_only(),
|
||||
)),
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ArcRwSignal<T>> for Signal<T, LocalStorage>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: ArcRwSignal<T>) -> Self {
|
||||
Self {
|
||||
inner: ArenaItem::new_local(SignalTypes::ReadSignal(
|
||||
value.read_only(),
|
||||
)),
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Memo<T>> for Signal<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -741,6 +828,74 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ArcMemo<T>> for Signal<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: ArcMemo<T>) -> Self {
|
||||
Self {
|
||||
inner: ArenaItem::new(SignalTypes::Memo(value)),
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<ArcMemo<T, LocalStorage>> for Signal<T, LocalStorage>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: ArcMemo<T, LocalStorage>) -> Self {
|
||||
Self {
|
||||
inner: ArenaItem::new_local(SignalTypes::Memo(value)),
|
||||
#[cfg(debug_assertions)]
|
||||
defined_at: std::panic::Location::caller(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Signal<Option<T>>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: T) -> Self {
|
||||
Signal::stored(Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Signal<Option<T>, LocalStorage>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: T) -> Self {
|
||||
Signal::stored_local(Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Signal<T>> for Signal<Option<T>>
|
||||
where
|
||||
T: Clone + Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: Signal<T>) -> Self {
|
||||
Signal::derive(move || Some(value.get()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Signal<T, LocalStorage>> for Signal<Option<T>, LocalStorage>
|
||||
where
|
||||
T: Clone + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: Signal<T, LocalStorage>) -> Self {
|
||||
Signal::derive_local(move || Some(value.get()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Signal<String> {
|
||||
#[track_caller]
|
||||
fn from(value: &str) -> Self {
|
||||
@@ -813,6 +968,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<MaybeSignal<T>> for Signal<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -826,6 +982,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<MaybeSignal<T, LocalStorage>> for Signal<T, LocalStorage>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -839,6 +996,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<MaybeSignal<T>> for Signal<Option<T>>
|
||||
where
|
||||
T: Clone + Send + Sync + 'static,
|
||||
@@ -854,6 +1012,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<MaybeSignal<T, LocalStorage>> for Signal<Option<T>, LocalStorage>
|
||||
where
|
||||
T: Clone + Send + Sync + 'static,
|
||||
@@ -869,6 +1028,27 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<MaybeProp<T>> for Option<Signal<Option<T>>>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: MaybeProp<T>) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<MaybeProp<T, LocalStorage>>
|
||||
for Option<Signal<Option<T>, LocalStorage>>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
{
|
||||
#[track_caller]
|
||||
fn from(value: MaybeProp<T, LocalStorage>) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper for a value that is *either* `T` or [`Signal<T>`].
|
||||
///
|
||||
/// This allows you to create APIs that take either a reactive or a non-reactive value
|
||||
@@ -897,6 +1077,12 @@ pub mod read {
|
||||
/// assert_eq!(above_3(&memoized_double_count.into()), true);
|
||||
/// ```
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[deprecated(
|
||||
since = "0.7.0-rc1",
|
||||
note = "`MaybeSignal<T>` is deprecated in favour of `Signal<T>` which \
|
||||
is `Copy`, now has a more efficient From<T> implementation \
|
||||
and other benefits in 0.7."
|
||||
)]
|
||||
pub enum MaybeSignal<T, S = SyncStorage>
|
||||
where
|
||||
T: 'static,
|
||||
@@ -908,6 +1094,7 @@ pub mod read {
|
||||
Dynamic(Signal<T, S>),
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T: Clone, S> Clone for MaybeSignal<T, S>
|
||||
where
|
||||
S: Storage<T>,
|
||||
@@ -920,8 +1107,10 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T: Copy, S> Copy for MaybeSignal<T, S> where S: Storage<T> {}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T: Default, S> Default for MaybeSignal<T, S>
|
||||
where
|
||||
S: Storage<T>,
|
||||
@@ -931,6 +1120,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T, S> DefinedAt for MaybeSignal<T, S>
|
||||
where
|
||||
S: Storage<T>,
|
||||
@@ -942,6 +1132,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T, S> Track for MaybeSignal<T, S>
|
||||
where
|
||||
S: Storage<T> + Storage<SignalTypes<T, S>>,
|
||||
@@ -954,6 +1145,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T, S> ReadUntracked for MaybeSignal<T, S>
|
||||
where
|
||||
T: Clone,
|
||||
@@ -978,6 +1170,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> MaybeSignal<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
@@ -991,6 +1184,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> MaybeSignal<T, LocalStorage> {
|
||||
/// Wraps a derived signal, i.e., any computation that accesses one or more
|
||||
/// reactive signals.
|
||||
@@ -999,6 +1193,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<T> for MaybeSignal<T, SyncStorage>
|
||||
where
|
||||
SyncStorage: Storage<T>,
|
||||
@@ -1008,6 +1203,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> FromLocal<T> for MaybeSignal<T, LocalStorage>
|
||||
where
|
||||
LocalStorage: Storage<T>,
|
||||
@@ -1017,6 +1213,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<ReadSignal<T>> for MaybeSignal<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
@@ -1026,12 +1223,14 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<ReadSignal<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
|
||||
fn from(value: ReadSignal<T, LocalStorage>) -> Self {
|
||||
Self::Dynamic(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<RwSignal<T>> for MaybeSignal<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
@@ -1041,12 +1240,14 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<RwSignal<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
|
||||
fn from(value: RwSignal<T, LocalStorage>) -> Self {
|
||||
Self::Dynamic(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<Memo<T>> for MaybeSignal<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
@@ -1056,12 +1257,14 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<Memo<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
|
||||
fn from(value: Memo<T, LocalStorage>) -> Self {
|
||||
Self::Dynamic(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<ArcReadSignal<T>> for MaybeSignal<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
@@ -1071,12 +1274,14 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> FromLocal<ArcReadSignal<T>> for MaybeSignal<T, LocalStorage> {
|
||||
fn from_local(value: ArcReadSignal<T>) -> Self {
|
||||
ReadSignal::from_local(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<ArcRwSignal<T>> for MaybeSignal<T>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
@@ -1086,6 +1291,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> FromLocal<ArcRwSignal<T>> for MaybeSignal<T, LocalStorage>
|
||||
where
|
||||
T: 'static,
|
||||
@@ -1095,6 +1301,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<ArcMemo<T>> for MaybeSignal<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
@@ -1104,12 +1311,14 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> FromLocal<ArcMemo<T, LocalStorage>> for MaybeSignal<T, LocalStorage> {
|
||||
fn from_local(value: ArcMemo<T, LocalStorage>) -> Self {
|
||||
Memo::from_local(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T, S> From<Signal<T, S>> for MaybeSignal<T, S>
|
||||
where
|
||||
S: Storage<T>,
|
||||
@@ -1119,6 +1328,7 @@ pub mod read {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<S> From<&str> for MaybeSignal<String, S>
|
||||
where
|
||||
S: Storage<String> + Storage<Arc<RwLock<String>>>,
|
||||
@@ -1162,25 +1372,28 @@ pub mod read {
|
||||
/// ```
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct MaybeProp<T: 'static, S = SyncStorage>(
|
||||
pub(crate) Option<MaybeSignal<Option<T>, S>>,
|
||||
pub(crate) Option<Signal<Option<T>, S>>,
|
||||
)
|
||||
where
|
||||
S: Storage<Option<T>>;
|
||||
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>;
|
||||
|
||||
impl<T: Clone, S> Clone for MaybeProp<T, S>
|
||||
impl<T, S> Clone for MaybeProp<T, S>
|
||||
where
|
||||
S: Storage<Option<T>>,
|
||||
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy, S> Copy for MaybeProp<T, S> where S: Storage<Option<T>> {}
|
||||
impl<T, S> Copy for MaybeProp<T, S> where
|
||||
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, S> Default for MaybeProp<T, S>
|
||||
where
|
||||
S: Storage<Option<T>>,
|
||||
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self(None)
|
||||
@@ -1189,7 +1402,7 @@ pub mod read {
|
||||
|
||||
impl<T, S> DefinedAt for MaybeProp<T, S>
|
||||
where
|
||||
S: Storage<Option<T>>,
|
||||
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
|
||||
{
|
||||
fn defined_at(&self) -> Option<&'static Location<'static>> {
|
||||
// TODO this can be improved by adding a defined_at field
|
||||
@@ -1212,7 +1425,7 @@ pub mod read {
|
||||
impl<T, S> ReadUntracked for MaybeProp<T, S>
|
||||
where
|
||||
T: Clone,
|
||||
S: Storage<SignalTypes<Option<T>, S>> + Storage<Option<T>>,
|
||||
S: Storage<Option<T>> + Storage<SignalTypes<Option<T>, S>>,
|
||||
{
|
||||
type Value = ReadGuard<Option<T>, SignalReadGuard<Option<T>, S>>;
|
||||
|
||||
@@ -1240,43 +1453,49 @@ pub mod read {
|
||||
pub fn derive(
|
||||
derived_signal: impl Fn() -> Option<T> + Send + Sync + 'static,
|
||||
) -> Self {
|
||||
Self(Some(MaybeSignal::derive(derived_signal)))
|
||||
Self(Some(Signal::derive(derived_signal)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for MaybeProp<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
SyncStorage: Storage<Option<T>>,
|
||||
{
|
||||
fn from(value: T) -> Self {
|
||||
Self(Some(MaybeSignal::from(Some(value))))
|
||||
Self(Some(Signal::stored(Some(value))))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Option<T>> for MaybeProp<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
SyncStorage: Storage<Option<T>>,
|
||||
{
|
||||
fn from(value: Option<T>) -> Self {
|
||||
Self(Some(MaybeSignal::from(value)))
|
||||
Self(Some(Signal::stored(value)))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<MaybeSignal<Option<T>>> for MaybeProp<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
SyncStorage: Storage<Option<T>>,
|
||||
{
|
||||
fn from(value: MaybeSignal<Option<T>>) -> Self {
|
||||
Self(Some(value))
|
||||
Self(Some(value.into()))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<Option<MaybeSignal<Option<T>>>> for MaybeProp<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
SyncStorage: Storage<Option<T>>,
|
||||
{
|
||||
fn from(value: Option<MaybeSignal<Option<T>>>) -> Self {
|
||||
Self(value)
|
||||
Self(value.map(Into::into))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1309,10 +1528,11 @@ pub mod read {
|
||||
|
||||
impl<T> From<Signal<Option<T>>> for MaybeProp<T>
|
||||
where
|
||||
T: Send + Sync,
|
||||
SyncStorage: Storage<Option<T>>,
|
||||
{
|
||||
fn from(value: Signal<Option<T>>) -> Self {
|
||||
Self(Some(value.into()))
|
||||
Self(Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1321,7 +1541,7 @@ pub mod read {
|
||||
T: Send + Sync + Clone,
|
||||
{
|
||||
fn from(value: ReadSignal<T>) -> Self {
|
||||
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
|
||||
Self(Some(Signal::derive(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1330,7 +1550,7 @@ pub mod read {
|
||||
T: Send + Sync + Clone,
|
||||
{
|
||||
fn from(value: RwSignal<T>) -> Self {
|
||||
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
|
||||
Self(Some(Signal::derive(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1339,7 +1559,7 @@ pub mod read {
|
||||
T: Send + Sync + Clone,
|
||||
{
|
||||
fn from(value: Memo<T>) -> Self {
|
||||
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
|
||||
Self(Some(Signal::derive(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1348,13 +1568,13 @@ pub mod read {
|
||||
T: Send + Sync + Clone,
|
||||
{
|
||||
fn from(value: Signal<T>) -> Self {
|
||||
Self(Some(MaybeSignal::derive(move || Some(value.get()))))
|
||||
Self(Some(Signal::derive(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for MaybeProp<String> {
|
||||
fn from(value: &str) -> Self {
|
||||
Self(Some(MaybeSignal::from(Some(value.to_string()))))
|
||||
Self(Some(Signal::from(Some(value.to_string()))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1364,35 +1584,41 @@ pub mod read {
|
||||
pub fn derive_local(
|
||||
derived_signal: impl Fn() -> Option<T> + 'static,
|
||||
) -> Self {
|
||||
Self(Some(MaybeSignal::derive_local(derived_signal)))
|
||||
Self(Some(Signal::derive_local(derived_signal)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromLocal<T> for MaybeProp<T, LocalStorage> {
|
||||
fn from_local(value: T) -> Self {
|
||||
Self(Some(MaybeSignal::from_local(Some(value))))
|
||||
Self(Some(Signal::stored_local(Some(value))))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromLocal<Option<T>> for MaybeProp<T, LocalStorage> {
|
||||
fn from_local(value: Option<T>) -> Self {
|
||||
Self(Some(MaybeSignal::from_local(value)))
|
||||
Self(Some(Signal::stored_local(value)))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<MaybeSignal<Option<T>, LocalStorage>>
|
||||
for MaybeProp<T, LocalStorage>
|
||||
where
|
||||
T: Send + Sync,
|
||||
{
|
||||
fn from(value: MaybeSignal<Option<T>, LocalStorage>) -> Self {
|
||||
Self(Some(value))
|
||||
Self(Some(value.into()))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T> From<Option<MaybeSignal<Option<T>, LocalStorage>>>
|
||||
for MaybeProp<T, LocalStorage>
|
||||
where
|
||||
T: Send + Sync,
|
||||
{
|
||||
fn from(value: Option<MaybeSignal<Option<T>, LocalStorage>>) -> Self {
|
||||
Self(value)
|
||||
Self(value.map(Into::into))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1425,7 +1651,7 @@ pub mod read {
|
||||
|
||||
impl<T> From<Signal<Option<T>, LocalStorage>> for MaybeProp<T, LocalStorage> {
|
||||
fn from(value: Signal<Option<T>, LocalStorage>) -> Self {
|
||||
Self(Some(value.into()))
|
||||
Self(Some(value))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1434,7 +1660,7 @@ pub mod read {
|
||||
T: Send + Sync + Clone,
|
||||
{
|
||||
fn from(value: ReadSignal<T, LocalStorage>) -> Self {
|
||||
Self(Some(MaybeSignal::derive_local(move || Some(value.get()))))
|
||||
Self(Some(Signal::derive_local(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1443,7 +1669,7 @@ pub mod read {
|
||||
T: Send + Sync + Clone,
|
||||
{
|
||||
fn from(value: RwSignal<T, LocalStorage>) -> Self {
|
||||
Self(Some(MaybeSignal::derive_local(move || Some(value.get()))))
|
||||
Self(Some(Signal::derive_local(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1452,7 +1678,7 @@ pub mod read {
|
||||
T: Send + Sync + Clone,
|
||||
{
|
||||
fn from(value: Memo<T, LocalStorage>) -> Self {
|
||||
Self(Some(MaybeSignal::derive_local(move || Some(value.get()))))
|
||||
Self(Some(Signal::derive_local(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1461,13 +1687,13 @@ pub mod read {
|
||||
T: Send + Sync + Clone,
|
||||
{
|
||||
fn from(value: Signal<T, LocalStorage>) -> Self {
|
||||
Self(Some(MaybeSignal::derive_local(move || Some(value.get()))))
|
||||
Self(Some(Signal::derive_local(move || Some(value.get()))))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for MaybeProp<String, LocalStorage> {
|
||||
fn from(value: &str) -> Self {
|
||||
Self(Some(MaybeSignal::from_local(Some(value.to_string()))))
|
||||
Self(Some(Signal::stored_local(Some(value.to_string()))))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,10 @@ where
|
||||
} else {
|
||||
(base.as_ref(), path)
|
||||
};
|
||||
path.strip_prefix(base)?
|
||||
match path.strip_prefix(base) {
|
||||
Some(path) => path,
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -44,8 +44,8 @@ pub enum SsrMode {
|
||||
/// of the page will not be interactive until the suspended chunks have loaded.
|
||||
InOrder,
|
||||
/// **`Async`**: Load all resources on the server. Wait until all data are loaded, and render HTML in one sweep.
|
||||
/// - *Pros*: Better handling for meta tags (because you know async data even before you render the `<head>`). Faster complete load than **synchronous** because async resources begin loading on server.
|
||||
/// - *Cons*: Slower load time/TTFB: you need to wait for all async resources to load before displaying anything on the client.
|
||||
/// - *Pros*: Better handling for meta tags (because you know async data even before you render the `<head>`). Faster complete load than **synchronous** because async resources begin loading on server.
|
||||
/// - *Cons*: Slower load time/TTFB: you need to wait for all async resources to load before displaying anything on the client.
|
||||
Async,
|
||||
/// **`Static`**: Renders the page when the server starts up, or incrementally, using the
|
||||
/// configuration provided by a [`StaticRoute`].
|
||||
|
||||
2555
server_fn/Cargo.lock
generated
2555
server_fn/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -30,7 +30,7 @@ once_cell = "1.20"
|
||||
actix-web = { version = "4.9", optional = true }
|
||||
|
||||
# axum
|
||||
axum = { version = "0.7.8", optional = true, default-features = false, features = [
|
||||
axum = { version = "0.7.7", optional = true, default-features = false, features = [
|
||||
"multipart",
|
||||
] }
|
||||
tower = { version = "0.5.1", optional = true }
|
||||
|
||||
@@ -267,7 +267,7 @@ impl<T: IntoClass> IntoClass for Option<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoClass for &str {
|
||||
impl<'a> IntoClass for &'a str {
|
||||
type AsyncOutput = Self;
|
||||
type State = (crate::renderer::types::Element, Self);
|
||||
type Cloneable = Self;
|
||||
|
||||
@@ -308,7 +308,7 @@ impl InnerHtmlValue for Arc<str> {
|
||||
}
|
||||
}
|
||||
|
||||
impl InnerHtmlValue for &str {
|
||||
impl<'a> InnerHtmlValue for &'a str {
|
||||
type AsyncOutput = Self;
|
||||
type State = (crate::renderer::types::Element, Self);
|
||||
type Cloneable = Self;
|
||||
|
||||
@@ -606,7 +606,7 @@ impl<'a> IntoStyle for (&'a str, String) {
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<const V: &'static str> IntoStyle for (&str, Static<V>) {
|
||||
impl<'a, const V: &'static str> IntoStyle for (&'a str, Static<V>) {
|
||||
type AsyncOutput = Self;
|
||||
type State = ();
|
||||
type Cloneable = (Arc<str>, Static<V>);
|
||||
|
||||
@@ -519,6 +519,7 @@ mod stable {
|
||||
|
||||
macro_rules! class_signal_arena {
|
||||
($sig:ident) => {
|
||||
#[allow(deprecated)]
|
||||
impl<C, S> IntoClass for $sig<C, S>
|
||||
where
|
||||
$sig<C, S>: Get<Value = C>,
|
||||
@@ -588,6 +589,7 @@ mod stable {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<S> IntoClass for (&'static str, $sig<bool, S>)
|
||||
where
|
||||
$sig<bool, S>: Get<Value = bool>,
|
||||
@@ -825,12 +827,14 @@ mod stable {
|
||||
|
||||
use super::RenderEffect;
|
||||
use crate::html::class::IntoClass;
|
||||
#[allow(deprecated)]
|
||||
use reactive_graph::wrappers::read::MaybeSignal;
|
||||
use reactive_graph::{
|
||||
computed::{ArcMemo, Memo},
|
||||
owner::Storage,
|
||||
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
|
||||
traits::Get,
|
||||
wrappers::read::{ArcSignal, MaybeSignal, Signal},
|
||||
wrappers::read::{ArcSignal, Signal},
|
||||
};
|
||||
|
||||
class_signal_arena!(RwSignal);
|
||||
|
||||
@@ -89,13 +89,15 @@ where
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
mod stable {
|
||||
use crate::html::element::InnerHtmlValue;
|
||||
#[allow(deprecated)]
|
||||
use reactive_graph::wrappers::read::MaybeSignal;
|
||||
use reactive_graph::{
|
||||
computed::{ArcMemo, Memo},
|
||||
effect::RenderEffect,
|
||||
owner::Storage,
|
||||
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
|
||||
traits::Get,
|
||||
wrappers::read::{ArcSignal, MaybeSignal, Signal},
|
||||
wrappers::read::{ArcSignal, Signal},
|
||||
};
|
||||
|
||||
macro_rules! inner_html_signal {
|
||||
@@ -159,6 +161,7 @@ mod stable {
|
||||
|
||||
macro_rules! inner_html_signal_arena {
|
||||
($sig:ident) => {
|
||||
#[allow(deprecated)]
|
||||
impl<V, S> InnerHtmlValue for $sig<V, S>
|
||||
where
|
||||
$sig<V, S>: Get<Value = V>,
|
||||
|
||||
@@ -507,13 +507,15 @@ mod stable {
|
||||
RenderHtml,
|
||||
},
|
||||
};
|
||||
#[allow(deprecated)]
|
||||
use reactive_graph::wrappers::read::MaybeSignal;
|
||||
use reactive_graph::{
|
||||
computed::{ArcMemo, Memo},
|
||||
effect::RenderEffect,
|
||||
owner::Storage,
|
||||
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
|
||||
traits::Get,
|
||||
wrappers::read::{ArcSignal, MaybeSignal, Signal},
|
||||
wrappers::read::{ArcSignal, Signal},
|
||||
};
|
||||
|
||||
macro_rules! signal_impl {
|
||||
@@ -683,6 +685,7 @@ mod stable {
|
||||
|
||||
macro_rules! signal_impl_arena {
|
||||
($sig:ident $dry_resolve:literal) => {
|
||||
#[allow(deprecated)]
|
||||
impl<V, S> Render for $sig<V, S>
|
||||
where
|
||||
$sig<V, S>: Get<Value = V>,
|
||||
@@ -707,6 +710,7 @@ mod stable {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<V, S> AddAnyAttr for $sig<V, S>
|
||||
where
|
||||
$sig<V, S>: Get<Value = V>,
|
||||
@@ -728,6 +732,7 @@ mod stable {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<V, S> RenderHtml for $sig<V, S>
|
||||
where
|
||||
$sig<V, S>: Get<Value = V>,
|
||||
@@ -793,6 +798,7 @@ mod stable {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<V, S> AttributeValue for $sig<V, S>
|
||||
where
|
||||
$sig<V, S>: Get<Value = V>,
|
||||
|
||||
@@ -82,13 +82,15 @@ where
|
||||
#[cfg(not(feature = "nightly"))]
|
||||
mod stable {
|
||||
use crate::html::property::IntoProperty;
|
||||
#[allow(deprecated)]
|
||||
use reactive_graph::wrappers::read::MaybeSignal;
|
||||
use reactive_graph::{
|
||||
computed::{ArcMemo, Memo},
|
||||
effect::RenderEffect,
|
||||
owner::Storage,
|
||||
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
|
||||
traits::Get,
|
||||
wrappers::read::{ArcSignal, MaybeSignal, Signal},
|
||||
wrappers::read::{ArcSignal, Signal},
|
||||
};
|
||||
|
||||
macro_rules! property_signal {
|
||||
@@ -136,6 +138,7 @@ mod stable {
|
||||
|
||||
macro_rules! property_signal_arena {
|
||||
($sig:ident) => {
|
||||
#[allow(deprecated)]
|
||||
impl<V, S> IntoProperty for $sig<V, S>
|
||||
where
|
||||
$sig<V, S>: Get<Value = V>,
|
||||
|
||||
@@ -393,6 +393,7 @@ mod stable {
|
||||
|
||||
macro_rules! style_signal_arena {
|
||||
($sig:ident) => {
|
||||
#[allow(deprecated)]
|
||||
impl<C, S> IntoStyle for $sig<C, S>
|
||||
where
|
||||
$sig<C, S>: Get<Value = C>,
|
||||
@@ -458,6 +459,7 @@ mod stable {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<S, St> IntoStyle for (&'static str, $sig<S, St>)
|
||||
where
|
||||
$sig<S, St>: Get<Value = S>,
|
||||
@@ -534,12 +536,14 @@ mod stable {
|
||||
|
||||
use super::RenderEffect;
|
||||
use crate::html::style::IntoStyle;
|
||||
#[allow(deprecated)]
|
||||
use reactive_graph::wrappers::read::MaybeSignal;
|
||||
use reactive_graph::{
|
||||
computed::{ArcMemo, Memo},
|
||||
owner::Storage,
|
||||
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
|
||||
traits::Get,
|
||||
wrappers::read::{ArcSignal, MaybeSignal, Signal},
|
||||
wrappers::read::{ArcSignal, Signal},
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
||||
@@ -209,6 +209,7 @@ pub trait DomRenderer: Renderer {
|
||||
/// This works in a similar way to `TryFrom`. We implement it as a separate trait
|
||||
/// simply so we don't have to create wrappers for the `web_sys` types; it can't be
|
||||
/// implemented on them directly because of the orphan rules.
|
||||
|
||||
pub trait CastFrom<T>
|
||||
where
|
||||
Self: Sized,
|
||||
|
||||
@@ -197,6 +197,7 @@ where
|
||||
/// Renders a view to an out-of-order stream of HTML with branch markers. This can be used to support libraries that diff
|
||||
/// HTML pages against one another, by marking sections of the view that branch to different
|
||||
/// types with marker comments.
|
||||
|
||||
fn to_html_stream_out_of_order_branching(self) -> StreamBuilder
|
||||
where
|
||||
Self: Sized,
|
||||
@@ -371,7 +372,7 @@ pub trait ToTemplate {
|
||||
/// The `style` attribute content known at compile time.
|
||||
const STYLE: &'static str = "";
|
||||
/// The length of the template.
|
||||
const LEN: usize = Self::TEMPLATE.len();
|
||||
const LEN: usize = Self::TEMPLATE.as_bytes().len();
|
||||
|
||||
/// Renders a view type to a template. This does not take actual view data,
|
||||
/// but can be used for constructing part of an HTML `<template>` that corresponds
|
||||
|
||||
@@ -36,7 +36,7 @@ impl<'a> Render for &'a str {
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderHtml for &str {
|
||||
impl<'a> RenderHtml for &'a str {
|
||||
type AsyncOutput = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
@@ -102,7 +102,7 @@ impl RenderHtml for &str {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTemplate for &str {
|
||||
impl<'a> ToTemplate for &'a str {
|
||||
const TEMPLATE: &'static str = " <!>";
|
||||
|
||||
fn to_template(
|
||||
@@ -120,7 +120,7 @@ impl ToTemplate for &str {
|
||||
}
|
||||
}
|
||||
|
||||
impl Mountable for StrState<'_> {
|
||||
impl<'a> Mountable for StrState<'a> {
|
||||
fn unmount(&mut self) {
|
||||
self.node.unmount()
|
||||
}
|
||||
@@ -451,7 +451,7 @@ impl<'a> Render for Cow<'a, str> {
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderHtml for Cow<'_, str> {
|
||||
impl<'a> RenderHtml for Cow<'a, str> {
|
||||
type AsyncOutput = Self;
|
||||
|
||||
const MIN_LENGTH: usize = 0;
|
||||
@@ -494,7 +494,7 @@ impl RenderHtml for Cow<'_, str> {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTemplate for Cow<'_, str> {
|
||||
impl<'a> ToTemplate for Cow<'a, str> {
|
||||
const TEMPLATE: &'static str = <&str as ToTemplate>::TEMPLATE;
|
||||
|
||||
fn to_template(
|
||||
@@ -510,7 +510,7 @@ impl ToTemplate for Cow<'_, str> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Mountable for CowStrState<'_> {
|
||||
impl<'a> Mountable for CowStrState<'a> {
|
||||
fn unmount(&mut self) {
|
||||
self.node.unmount()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user