Compare commits

..

1 Commits

Author SHA1 Message Date
Greg Johnston
8bcc277acb fix: <use_/> as typed top-level element in view 2023-07-21 06:40:48 -04:00
16 changed files with 32 additions and 147 deletions

View File

@@ -70,25 +70,6 @@ are a few guidelines that will make it a better experience for everyone:
`cargo-make` and using `cargo make check && cargo make test && cargo make
check-examples`.
## Before Submitting a PR
We have a fairly extensive CI setup that runs both lints (like `rustfmt` and `clippy`)
and tests on PRs. You can run most of these locally if you have `cargo-make` installed.
If you added an example, make sure to add it to the list in `examples/Makefile.toml`.
From the root directory of the repo, run
- `cargo +nightly fmt`
- `cargo +nightly make check`
- `cargo +nightly make test`
- `cargo +nightly make check-examples`
- `cargo +nightly make --profile=github-actions ci`
If you modified an example:
- `cd examples/your_example`
- `cargo +nightly fmt -- --config-path ../..`
- `cargo +nightly make --profile=github-actions verify-flow`
## Architecture
See [ARCHITECTURE.md](./ARCHITECTURE.md).

View File

@@ -36,12 +36,6 @@ struct ContactSearch {
```
> Note: The `Params` derive macro is located at `leptos::Params`, and the `Params` trait is at `leptos_router::Params`. If you avoid using glob imports like `use leptos::*;`, make sure youre importing the right one for the derive macro.
>
> If you are not using the `nightly` feature, you will get the error
> ```
> no function or associated item named `into_param` found for struct `std::string::String` in the current scope
> ```
> At the moment, supporting both `T: FromStr` and `Option<T>` for typed params requires a nightly feature. You can fix this by simply changing the struct to use `q: Option<String>` instead of `q: String`.
Now we can use them in a component. Imagine a URL that has both params and a query, like `/contacts/:id?q=Search`.

View File

@@ -139,7 +139,7 @@ view! { cx,
Remember—and this is _very important_—only functions are reactive. This means that
`{count}` and `{count()}` do very different things in your view. `{count}` passes
in a function, telling the framework to update the view every time `count` changes.
`{count()}` accesses the value of `count` once, and passes an `i32` into the view,
`{count()}` access the value of `count` once, and passes an `i32` into the view,
rendering it once, unreactively. You can see the difference in the CodeSandbox below!
Lets make one final change. `set_count(3)` is a pretty useless thing for a click handler to do. Lets replace “set this value to 3” with “increment this value by 1”:

View File

@@ -115,11 +115,11 @@ Calling it like this will create a list:
```rust
view! { cx,
<WrapsChildren>
<WrappedChildren>
"A"
"B"
"C"
</WrapsChildren>
</WrappedChildren>
}
```

View File

@@ -45,75 +45,3 @@ grep -v gtk |
jq -R -s -c 'split("\n")[:-1]')
echo "CARGO_MAKE_CRATE_WORKSPACE_MEMBERS = $examples"
'''
[tasks.test-info]
workspace = false
description = "report ci test runners for each example - Option [all]"
script = '''
BOLD="\e[1m"
GREEN="\e[0;32m"
ITALIC="\e[3m"
YELLOW="\e[0;33m"
RESET="\e[0m"
echo
echo "${YELLOW}CI test runners by example...${RESET}"
echo
examples=$(ls |
grep -v README.md |
grep -v Makefile.toml |
grep -v cargo-make |
grep -v gtk |
sort -u |
awk '{print $0 ", "}')
example_root_dir=$(pwd)
for example_dir in $examples
do
clean_name=$(echo $example_dir | sed 's%,%%')
cd $clean_name
c_tests=$(grep -rl --fixed-strings "#[test]" | wc -l)
rs_tests=$(grep -rl --fixed-strings "#[rstest]" | wc -l)
w_configs=$(grep -rl "\/wasm-test.toml\"" | wc -l)
pw_configs=$(grep -rl "\/playwright-test.toml\"" | wc -l)
cl_configs=$(grep -rl "\/cargo-leptos-test.toml\"" | wc -l)
test_runner=
if [ $c_tests -gt 0 ]; then
test_runner="-C"
fi
if [ $rs_tests -gt 0 ]; then
test_runner=$test_runner"-R"
fi
if [ $w_configs -gt 0 ]; then
test_runner=$test_runner"-W"
fi
if [ $pw_configs -gt 0 ]; then
test_runner=$test_runner"-P"
fi
if [ $cl_configs -gt 0 ]; then
test_runner=$test_runner"-L"
fi
if [ ! -z "$1" ]; then
# Show all examples
echo "$clean_name ${BOLD}${test_runner}${RESET}"
elif [ ! -z $test_runner ]; then
# Filter out examples that do not run tests in `ci`
echo "$clean_name ${BOLD}${test_runner}${RESET}"
fi
cd $example_root_dir
done
echo
echo "${ITALIC}Test Runners: C = Cargo Test, L = Cargo Leptos Test, P = Playwright Test, R = RS Test, W = WASM Test${RESET}"
echo
'''

View File

@@ -152,7 +152,6 @@ pub use leptos_config::{self, get_configuration, LeptosOptions};
any(feature = "csr", feature = "hydrate")
)))]
/// Utilities for server-side rendering HTML.
#[cfg(any(doc, not(feature = "csr")))]
pub mod ssr {
pub use leptos_dom::{ssr::*, ssr_in_order::*};
}

View File

@@ -76,10 +76,7 @@ where
let current_id = current_id;
let children = Rc::new(orig_children(cx).into_view(cx));
#[cfg(all(
feature = "ssr",
not(any(feature = "csr", feature = "hydrate"))
))]
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
let orig_children = Rc::clone(&orig_children);
move || {
#[cfg(any(feature = "csr", feature = "hydrate"))]
@@ -111,7 +108,6 @@ where
else {
HydrationCtx::continue_from(current_id);
#[cfg(feature = "ssr")]
cx.register_suspense(
context,
&current_id.to_string(),

View File

@@ -21,9 +21,7 @@ pub mod math;
mod node_ref;
/// Utilities for exporting nonces to be used for a Content Security Policy.
pub mod nonce;
#[cfg(not(feature = "csr"))]
pub mod ssr;
#[cfg(not(feature = "csr"))]
pub mod ssr_in_order;
pub mod svg;
mod transparent;

View File

@@ -234,7 +234,6 @@ impl View {
self.into_stream_chunks_helper(cx, &mut chunks, false);
chunks
}
#[tracing::instrument(level = "trace", skip_all)]
fn into_stream_chunks_helper(
self,

View File

@@ -80,7 +80,6 @@ mod context;
#[macro_use]
mod diagnostics;
mod effect;
#[cfg(not(feature = "csr"))]
mod hydration;
mod memo;
mod node;
@@ -102,7 +101,6 @@ mod watch;
pub use context::*;
pub use diagnostics::SpecialNonReactiveZone;
pub use effect::*;
#[cfg(not(feature = "csr"))]
pub use hydration::FragmentData;
pub use memo::*;
pub use resource::*;

View File

@@ -378,7 +378,7 @@ where
}
}
#[cfg(not(all(feature = "hydrate", not(feature = "csr"))))]
#[cfg(not(feature = "hydrate"))]
fn load_resource<S, T>(_cx: Scope, _id: ResourceId, r: Rc<ResourceState<S, T>>)
where
S: PartialEq + Clone + 'static,
@@ -391,7 +391,7 @@ where
});
}
#[cfg(all(feature = "hydrate", not(feature = "csr")))]
#[cfg(feature = "hydrate")]
fn load_resource<S, T>(cx: Scope, id: ResourceId, r: Rc<ResourceState<S, T>>)
where
S: PartialEq + Clone + 'static,

View File

@@ -1,8 +1,7 @@
#![forbid(unsafe_code)]
#[cfg(not(feature = "csr"))]
use crate::hydration::SharedContext;
use crate::{
hydration::SharedContext,
node::{NodeId, ReactiveNode, ReactiveNodeState, ReactiveNodeType},
AnyComputation, AnyResource, Effect, Memo, MemoState, ReadSignal,
ResourceId, ResourceState, RwSignal, Scope, ScopeDisposer, ScopeId,
@@ -45,7 +44,6 @@ type FxIndexSet<T> = IndexSet<T, BuildHasherDefault<FxHasher>>;
// and other data included in the reactive system.
#[derive(Default)]
pub(crate) struct Runtime {
#[cfg(not(feature = "csr"))]
pub shared_context: RefCell<SharedContext>,
pub observer: Cell<Option<NodeId>>,
pub scopes: RefCell<SlotMap<ScopeId, RefCell<Vec<ScopeProperty>>>>,
@@ -352,12 +350,9 @@ impl Runtime {
impl Debug for Runtime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut s = f.debug_struct("Runtime");
#[cfg(not(feature = "csr"))]
s.field("shared_context", &self.shared_context);
s.field("observer", &self.observer)
f.debug_struct("Runtime")
.field("shared_context", &self.shared_context)
.field("observer", &self.observer)
.field("scopes", &self.scopes)
.field("scope_parents", &self.scope_parents)
.field("scope_children", &self.scope_children)

View File

@@ -1,16 +1,17 @@
#![forbid(unsafe_code)]
use crate::{
console_warn,
hydration::FragmentData,
node::NodeId,
runtime::{with_runtime, RuntimeId},
PinnedFuture, ResourceId, StoredValueId,
suspense::StreamChunk,
PinnedFuture, ResourceId, StoredValueId, SuspenseContext,
};
#[cfg(not(feature = "csr"))]
use crate::{hydration::FragmentData, suspense::StreamChunk, SuspenseContext};
use futures::stream::FuturesUnordered;
#[cfg(not(feature = "csr"))]
use std::collections::{HashMap, VecDeque};
use std::fmt;
use std::{
collections::{HashMap, VecDeque},
fmt,
};
#[doc(hidden)]
#[must_use = "Scope will leak memory if the disposer function is never called"]
@@ -458,7 +459,6 @@ impl Scope {
/// Registers the given [`SuspenseContext`](crate::SuspenseContext) with the current scope,
/// calling the `resolver` when its resources are all resolved.
#[cfg(not(feature = "csr"))]
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
@@ -516,7 +516,6 @@ impl Scope {
///
/// The keys are hydration IDs. Values are tuples of two pinned
/// `Future`s that return content for out-of-order and in-order streaming, respectively.
#[cfg(not(feature = "csr"))]
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
@@ -530,7 +529,6 @@ impl Scope {
}
/// A future that will resolve when all blocking fragments are ready.
#[cfg(not(feature = "csr"))]
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
@@ -558,7 +556,6 @@ impl Scope {
///
/// Returns a tuple of two pinned `Future`s that return content for out-of-order
/// and in-order streaming, respectively.
#[cfg(not(feature = "csr"))]
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)

View File

@@ -1,20 +1,20 @@
use cfg_if::cfg_if;
use leptos::*;
#[cfg(all(feature = "ssr", not(feature = "csr")))]
#[cfg(feature = "ssr")]
use std::{cell::RefCell, rc::Rc};
/// Contains the current metadata for the document's `<body>`.
#[derive(Clone, Default)]
pub struct BodyContext {
#[cfg(all(feature = "ssr", not(feature = "csr")))]
#[cfg(feature = "ssr")]
class: Rc<RefCell<Option<TextProp>>>,
#[cfg(all(feature = "ssr", not(feature = "csr")))]
#[cfg(feature = "ssr")]
attributes: Rc<RefCell<Option<MaybeSignal<AdditionalAttributes>>>>,
}
impl BodyContext {
/// Converts the `<body>` metadata into an HTML string.
#[cfg(all(any(feature = "ssr", doc), not(feature = "csr")))]
#[cfg(any(feature = "ssr", doc))]
pub fn as_string(&self) -> Option<String> {
let class = self.class.borrow().as_ref().map(|val| {
format!(

View File

@@ -1,24 +1,24 @@
use cfg_if::cfg_if;
use leptos::*;
#[cfg(all(feature = "ssr", not(feature = "csr")))]
#[cfg(feature = "ssr")]
use std::{cell::RefCell, rc::Rc};
/// Contains the current metadata for the document's `<html>`.
#[derive(Clone, Default)]
pub struct HtmlContext {
#[cfg(all(feature = "ssr", not(feature = "csr")))]
#[cfg(feature = "ssr")]
lang: Rc<RefCell<Option<TextProp>>>,
#[cfg(all(feature = "ssr", not(feature = "csr")))]
#[cfg(feature = "ssr")]
dir: Rc<RefCell<Option<TextProp>>>,
#[cfg(all(feature = "ssr", not(feature = "csr")))]
#[cfg(feature = "ssr")]
class: Rc<RefCell<Option<TextProp>>>,
#[cfg(all(feature = "ssr", not(feature = "csr")))]
#[cfg(feature = "ssr")]
attributes: Rc<RefCell<Option<MaybeSignal<AdditionalAttributes>>>>,
}
impl HtmlContext {
/// Converts the `<html>` metadata into an HTML string.
#[cfg(all(any(feature = "ssr", doc), not(feature = "csr")))]
#[cfg(any(feature = "ssr", doc))]
pub fn as_string(&self) -> Option<String> {
let lang = self.lang.borrow().as_ref().map(|val| {
format!(
@@ -151,7 +151,7 @@ pub fn Html(
});
}
}
} else if #[cfg(all(feature = "ssr", not(feature = "csr")))] {
} else if #[cfg(feature = "ssr")] {
let meta = crate::use_head(cx);
*meta.html.lang.borrow_mut() = lang;
*meta.html.dir.borrow_mut() = dir;

View File

@@ -115,7 +115,7 @@ impl std::fmt::Debug for MetaTagsContext {
impl MetaTagsContext {
/// Converts metadata tags into an HTML string.
#[cfg(all(any(feature = "ssr", doc), not(feature = "csr")))]
#[cfg(any(feature = "ssr", docs))]
pub fn as_string(&self) -> String {
self.els
.borrow()
@@ -231,7 +231,7 @@ impl MetaContext {
Default::default()
}
#[cfg(all(any(doc, feature = "ssr"), not(feature = "csr")))]
#[cfg(feature = "ssr")]
/// Converts the existing metadata tags into HTML that can be injected into the document head.
///
/// This should be called *after* the apps component tree has been rendered into HTML, so that
@@ -284,7 +284,7 @@ impl MetaContext {
/// Extracts the metadata that should be used to close the `<head>` tag
/// and open the `<body>` tag. This is a helper function used in implementing
/// server-side HTML rendering across crates.
#[cfg(all(any(doc, feature = "ssr"), not(feature = "csr")))]
#[cfg(feature = "ssr")]
pub fn generate_head_metadata(cx: Scope) -> String {
let (head, body) = generate_head_metadata_separated(cx);
format!("{head}</head><{body}>")
@@ -293,7 +293,7 @@ pub fn generate_head_metadata(cx: Scope) -> String {
/// Extracts the metadata that should be inserted at the beginning of the `<head>` tag
/// and on the opening `<body>` tag. This is a helper function used in implementing
/// server-side HTML rendering across crates.
#[cfg(all(any(doc, feature = "ssr"), not(feature = "csr")))]
#[cfg(feature = "ssr")]
pub fn generate_head_metadata_separated(cx: Scope) -> (String, String) {
let meta = use_context::<MetaContext>(cx);
let head = meta