Merge branch 'main' into generated_routes

This commit is contained in:
benwis 2023-01-07 21:17:18 -08:00
commit dad84b5867
22 changed files with 381 additions and 117 deletions

View file

@ -1,10 +1,10 @@
use cfg_if::cfg_if;
use leptos_macro::component;
use std::rc::Rc;
use leptos_dom::{DynChild, Fragment, IntoView, Component};
use leptos_reactive::{provide_context, Scope, SuspenseContext};
use leptos_dom::{Component, DynChild, Fragment, IntoView};
#[cfg(not(any(feature = "csr", feature = "hydrate")))]
use leptos_dom::{HydrationCtx, HydrationKey};
use leptos_macro::component;
use leptos_reactive::{provide_context, Scope, SuspenseContext};
use std::rc::Rc;
/// If any [Resources](leptos_reactive::Resource) are read in the `children` of this
/// component, it will show the `fallback` while they are loading. Once all are resolved,
@ -88,8 +88,8 @@ where
} else {
// run the child; we'll probably throw this away, but it will register resource reads
let child = orig_child(cx).into_view(cx);
let initial = {
let initial = {
// no resources were read under this, so just return the child
if context.pending_resources.get() == 0 {
child.clone()
@ -97,10 +97,10 @@ where
// show the fallback, but also prepare to stream HTML
else {
let orig_child = Rc::clone(&orig_child);
cx.register_suspense(
context,
&id_before_suspense.to_string(),
&id_before_suspense.to_string(),
&current_id.to_string(),
{
let current_id = current_id.clone();
@ -117,17 +117,17 @@ where
}
}
);
// return the fallback for now, wrapped in fragment identifer
fallback().into_view(cx)
}
};
HydrationCtx::continue_from(current_id.clone());
initial
}
}
})
})
}
}

View file

@ -1,6 +1,6 @@
use leptos_dom::{Fragment, IntoView, View};
use leptos_macro::component;
use leptos_reactive::{ Scope, SignalSetter};
use leptos_reactive::{Scope, SignalSetter};
use std::{cell::RefCell, rc::Rc};
/// If any [Resource](leptos_reactive::Resource)s are read in the `children` of this
@ -66,7 +66,7 @@ pub fn Transition<F, E>(
#[prop(optional)]
set_pending: Option<SignalSetter<bool>>,
/// Will be displayed once all resources have resolved.
children: Box<dyn Fn(Scope) -> Fragment>
children: Box<dyn Fn(Scope) -> Fragment>,
) -> impl IntoView
where
F: Fn() -> E + 'static,
@ -78,7 +78,6 @@ where
crate::SuspenseProps::builder()
.fallback({
let prev_child = Rc::clone(&prev_children);
let set_pending = set_pending.clone();
move || {
if let Some(set_pending) = &set_pending {
set_pending.set(true);
@ -98,6 +97,6 @@ where
}
frag
}))
.build()
.build(),
)
}
}

View file

@ -43,6 +43,7 @@ fn view_fn(cx: Scope) -> impl IntoView {
let (is_a, set_is_a) = create_signal(cx, true);
let handle_toggle = move |_| {
trace!("toggling");
if is_a() {
set_b(a());
@ -91,5 +92,8 @@ fn Example(cx: Scope) -> impl IntoView {
view! { cx,
<h1>"Example"</h1>
<button on:click=move |_| set_value.update(|value| *value += 1)>
"Click me"
</button>
}
}

View file

@ -154,10 +154,7 @@ where
let component = DynChildRepr::new();
#[cfg(all(target_arch = "wasm32", feature = "web"))]
let (frag, closing) = (
component.document_fragment.clone(),
component.closing.node.clone(),
);
let closing = component.closing.node.clone();
let child = component.child.clone();
@ -189,7 +186,9 @@ where
// or to reuse it in the case of a text node
// TODO check does this still detect moves correctly?
let was_child_moved = prev_t.is_none() && child.get_closing_node().next_sibling().as_ref() != Some(&closing);
let was_child_moved = prev_t.is_none()
&& child.get_closing_node().next_sibling().as_ref()
!= Some(&closing);
// If the previous child was a text node, we would like to
// make use of it again if our current child is also a text

View file

@ -16,10 +16,20 @@ thread_local! {
pub fn add_event_listener<E>(
target: &web_sys::Element,
event_name: Cow<'static, str>,
cb: impl FnMut(E) + 'static,
mut cb: impl FnMut(E) + 'static,
) where
E: FromWasmAbi + 'static,
{
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
let span = ::tracing::Span::current();
let cb = move |e| {
let _guard = span.enter();
cb(e);
};
}
}
let cb = Closure::wrap(Box::new(cb) as Box<dyn FnMut(E)>).into_js_value();
let key = event_delegation_key(&event_name);
_ = js_sys::Reflect::set(target, &JsValue::from_str(&key), &cb);
@ -31,10 +41,20 @@ pub fn add_event_listener<E>(
pub fn add_event_listener_undelegated<E>(
target: &web_sys::Element,
event_name: &str,
cb: impl FnMut(E) + 'static,
mut cb: impl FnMut(E) + 'static,
) where
E: FromWasmAbi + 'static,
{
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
let span = ::tracing::Span::current();
let cb = move |e| {
let _guard = span.enter();
cb(e);
};
}
}
let event_name = intern(event_name);
let cb = Closure::wrap(Box::new(cb) as Box<dyn FnMut(E)>).into_js_value();
_ = target.add_event_listener_with_callback(event_name, cb.unchecked_ref());
@ -97,7 +117,20 @@ pub(crate) fn add_delegated_event_listener(event_name: Cow<'static, str>) {
}
};
crate::window_event_listener(&event_name, handler);
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
let span = ::tracing::Span::current();
let handler = move |e| {
let _guard = span.enter();
handler(e);
};
}
}
let handler = Box::new(handler) as Box<dyn FnMut(web_sys::Event)>;
let handler = Closure::wrap(handler).into_js_value();
_ = crate::window()
.add_event_listener_with_callback(&event_name, handler.unchecked_ref());
// register that we've created handler
events.insert(event_name);

View file

@ -71,21 +71,57 @@ pub fn event_target_checked(ev: &web_sys::Event) -> bool {
/// Runs the given function between the next repaint
/// using [`Window.requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame).
#[cfg_attr(debug_assertions, instrument(level = "trace", skip_all))]
pub fn request_animation_frame(cb: impl FnOnce() + 'static) {
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
let span = ::tracing::Span::current();
let cb = move || {
let _guard = span.enter();
cb();
};
}
}
let cb = Closure::once_into_js(cb);
_ = window().request_animation_frame(cb.as_ref().unchecked_ref());
}
/// Queues the given function during an idle period
/// using [`Window.requestIdleCallback`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestIdleCallback).
#[cfg_attr(debug_assertions, instrument(level = "trace", skip_all))]
pub fn request_idle_callback(cb: impl Fn() + 'static) {
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
let span = ::tracing::Span::current();
let cb = move || {
let _guard = span.enter();
cb();
};
}
}
let cb = Closure::wrap(Box::new(cb) as Box<dyn Fn()>).into_js_value();
_ = window().request_idle_callback(cb.as_ref().unchecked_ref());
}
/// Executes the given function after the given duration of time has passed.
/// [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout).
#[cfg_attr(
debug_assertions,
instrument(level = "trace", skip_all, fields(duration = ?duration))
)]
pub fn set_timeout(cb: impl FnOnce() + 'static, duration: Duration) {
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
let span = ::tracing::Span::current();
let cb = move || {
let _guard = span.enter();
cb();
};
}
}
let cb = Closure::once_into_js(Box::new(cb) as Box<dyn FnOnce()>);
_ = window().set_timeout_with_callback_and_timeout_and_arguments_0(
cb.as_ref().unchecked_ref(),
@ -107,10 +143,24 @@ impl IntervalHandle {
/// Repeatedly calls the given function, with a delay of the given duration between calls.
/// See [`setInterval()`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval).
#[cfg_attr(
debug_assertions,
instrument(level = "trace", skip_all, fields(duration = ?duration))
)]
pub fn set_interval(
cb: impl Fn() + 'static,
duration: Duration,
) -> Result<IntervalHandle, JsValue> {
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
let span = ::tracing::Span::current();
let cb = move || {
let _guard = span.enter();
cb();
};
}
}
let cb = Closure::wrap(Box::new(cb) as Box<dyn Fn()>).into_js_value();
let handle = window()
.set_interval_with_callback_and_timeout_and_arguments_0(
@ -121,10 +171,24 @@ pub fn set_interval(
}
/// Adds an event listener to the `Window`.
#[cfg_attr(
debug_assertions,
instrument(level = "trace", skip_all, fields(event_name = %event_name))
)]
pub fn window_event_listener(
event_name: &str,
cb: impl Fn(web_sys::Event) + 'static,
) {
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
let span = ::tracing::Span::current();
let cb = move |e| {
let _guard = span.enter();
cb(e);
};
}
}
if !is_server() {
let handler = Box::new(cb) as Box<dyn FnMut(web_sys::Event)>;

View file

@ -90,7 +90,12 @@ where
element: el,
};
HtmlElement { cx, element }
HtmlElement {
cx,
element,
#[cfg(debug_assertions)]
span: ::tracing::Span::current()
}
}
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
@ -192,6 +197,8 @@ cfg_if! {
/// Represents an HTML element.
#[derive(Clone)]
pub struct HtmlElement<El: ElementDescriptor> {
#[cfg(debug_assertions)]
pub(crate) span: ::tracing::Span,
pub(crate) cx: Scope,
pub(crate) element: El,
}
@ -236,6 +243,8 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
Self {
cx,
element,
#[cfg(debug_assertions)]
span: ::tracing::Span::current()
}
} else {
Self {
@ -272,6 +281,8 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
let Self {
cx,
element,
#[cfg(debug_assertions)]
span
} = self;
HtmlElement {
@ -281,6 +292,8 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
element: element.as_ref().clone(),
is_void: element.is_void(),
},
#[cfg(debug_assertions)]
span
}
} else {
let Self {
@ -571,10 +584,23 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
pub fn on<E: EventDescriptor + 'static>(
self,
event: E,
event_handler: impl FnMut(E::EventType) + 'static,
#[allow(unused_mut)] // used for tracing in debug
mut event_handler: impl FnMut(E::EventType) + 'static,
) -> Self {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
{
cfg_if! {
if #[cfg(debug_assertions)] {
let span = self.span.clone();
let onspan = ::tracing::span!(
parent: &self.span,
::tracing::Level::TRACE,
"on",
event = %event.name()
);
let _onguard = onspan.enter();
}
}
let event_name = event.name();
if event.bubbles() {
@ -865,6 +891,17 @@ macro_rules! generate_html_tags {
}
#[$meta]
#[cfg_attr(
debug_assertions,
instrument(
level = "trace",
name = "HtmlElement",
skip_all,
fields(
tag = %format!("<{}/>", stringify!($tag))
)
)
)]
pub fn $tag(cx: Scope) -> HtmlElement<[<$tag:camel $($trailing_)?>]> {
HtmlElement::new(cx, [<$tag:camel $($trailing_)?>]::default())
}

View file

@ -3,9 +3,9 @@ use std::{cell::RefCell, fmt::Display};
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use once_cell::unsync::Lazy as LazyCell;
/// We can tell if we start in hydration mode by checking to see if the
/// id "_0" is present in the DOM. If it is, we know we are hydrating from
/// the server, if not, we are starting off in CSR
// We can tell if we start in hydration mode by checking to see if the
// id "_0-0-0" is present in the DOM. If it is, we know we are hydrating from
// the server, if not, we are starting off in CSR
#[cfg(all(target_arch = "wasm32", feature = "web"))]
thread_local! {
static IS_HYDRATING: RefCell<LazyCell<bool>> = RefCell::new(LazyCell::new(|| {

View file

@ -206,7 +206,12 @@ impl Element {
is_void: false,
};
HtmlElement { cx, element }
HtmlElement {
cx,
element,
#[cfg(debug_assertions)]
span: ::tracing::Span::current()
}
}
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
@ -542,8 +547,19 @@ impl View {
pub fn on<E: ev::EventDescriptor + 'static>(
self,
event: E,
event_handler: impl FnMut(E::EventType) + 'static,
mut event_handler: impl FnMut(E::EventType) + 'static,
) -> Self {
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
trace!("calling on() {}", event.name());
let span = ::tracing::Span::current();
let event_handler = move |e| {
let _guard = span.enter();
event_handler(e);
};
}
}
self.on_impl(event, Box::new(event_handler))
}

View file

@ -176,6 +176,25 @@ mod server;
/// # });
/// ```
///
/// However, you can pass arbitrary class names using the syntax `class=("name", value)`.
/// ```rust
/// # use leptos::*;
/// # run_scope(create_runtime(), |cx| {
/// # if !cfg!(any(feature = "csr", feature = "hydrate")) {
/// let (count, set_count) = create_signal(cx, 2);
/// // this allows you to use CSS frameworks that include complex class names
/// view! { cx,
/// <div
/// class=("is-[this_-_really]-necessary-42", move || count() < 3)
/// >
/// "Now you see me, now you dont."
/// </div>
/// }
/// # ;
/// # }
/// # });
/// ```
///
/// 8. You can use the `_ref` attribute to store a reference to its DOM element in a
/// [NodeRef](leptos_reactive::NodeRef) to use later.
/// ```rust
@ -358,12 +377,12 @@ pub fn view(tokens: TokenStream) -> TokenStream {
/// ```
///
/// 5. You can access the children passed into the component with the `children` property, which takes
/// an argument of the form `Box<dyn Fn(Scope) -> Fragment>`.
/// an argument of the form `Box<dyn FnOnce(Scope) -> Fragment>`.
///
/// ```
/// # use leptos::*;
/// #[component]
/// fn ComponentWithChildren(cx: Scope, children: Box<dyn Fn(Scope) -> Fragment>) -> impl IntoView {
/// fn ComponentWithChildren(cx: Scope, children: Box<dyn FnOnce(Scope) -> Fragment>) -> impl IntoView {
/// view! {
/// cx,
/// <ul>

View file

@ -1,6 +1,6 @@
use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote, quote_spanned};
use syn::{spanned::Spanned, ExprPath};
use syn::{spanned::Spanned, ExprPath, Expr, ExprLit, Lit};
use syn_rsx::{Node, NodeAttribute, NodeElement, NodeName};
use crate::{is_component_node, Mode};
@ -412,7 +412,11 @@ fn set_class_attribute_ssr(
if a.value.as_ref().and_then(value_to_string).is_some() {
None
} else {
Some((a.key.span(), &a.value))
if fancy_class_name(&a.key.to_string(), cx, a).is_some() {
None
} else {
Some((a.key.span(), &a.value))
}
}
} else {
None
@ -429,6 +433,14 @@ fn set_class_attribute_ssr(
.filter_map(|node| {
if let Node::Attribute(node) = node {
let name = node.key.to_string();
if name == "class" {
return if let Some((_, name, value)) = fancy_class_name(&name, &cx, &node) {
let span = node.key.span();
Some((span, name, value))
} else {
None
}
}
if name.starts_with("class:") || name.starts_with("class-") {
let name = if name.starts_with("class:") {
name.replacen("class:", "", 1)
@ -752,6 +764,12 @@ fn attribute_to_tokens(cx: &Ident, node: &NodeAttribute) -> TokenStream {
}
} else {
let name = name.replacen("attr:", "", 1);
if let Some((fancy, _, _)) = fancy_class_name(&name, &cx, &node) {
return fancy;
}
// all other attributes
let value = match node.value.as_ref() {
Some(value) => {
let value = value.as_ref();
@ -866,7 +884,11 @@ fn ident_from_tag_name(tag_name: &NodeName) -> Ident {
.last()
.map(|segment| segment.ident.clone())
.expect("element needs to have a name"),
NodeName::Block(_) => panic!("blocks not allowed in tag-name position"),
NodeName::Block(_) => {
let span = tag_name.span();
proc_macro_error::emit_error!(span, "blocks not allowed in tag-name position");
Ident::new("", span)
}
_ => Ident::new(
&tag_name.to_string().replace(['-', ':'], "_"),
tag_name.span(),
@ -1044,3 +1066,44 @@ fn parse_event(event_name: &str) -> (&str, bool) {
(event_name, false)
}
}
fn fancy_class_name<'a>(name: &str, cx: &Ident, node: &'a NodeAttribute) -> Option<(TokenStream, String, &'a Expr)> {
// special case for complex class names:
// e.g., Tailwind `class=("mt-[calc(100vh_-_3rem)]", true)`
if name == "class" {
if let Some(expr) = node.value.as_ref() {
if let syn::Expr::Tuple(tuple) = expr.as_ref() {
if tuple.elems.len() == 2 {
let span = node.key.span();
let class = quote_spanned! {
span => .class
};
let class_name = &tuple.elems[0];
let class_name = if let Expr::Lit(ExprLit { lit: Lit::Str(s), .. }) = class_name {
s.value()
} else {
proc_macro_error::emit_error!(
class_name.span(),
"class name must be a string literal"
);
Default::default()
};
let value = &tuple.elems[1];
return Some((
quote! {
#class(#class_name, (#cx, #value))
},
class_name,
value
))
} else {
proc_macro_error::emit_error!(
tuple.span(),
"class tuples must have two elements."
)
}
}
}
}
None
}

View file

@ -53,7 +53,7 @@ use std::fmt::Debug;
level = "trace",
skip_all,
fields(
scope = %format!("{:?}", cx.id),
scope = ?cx.id,
ty = %std::any::type_name::<T>()
)
)
@ -107,7 +107,7 @@ where
level = "trace",
skip_all,
fields(
scope = %format!("{:?}", cx.id),
scope = ?cx.id,
ty = %std::any::type_name::<T>()
)
)
@ -128,7 +128,7 @@ where
level = "trace",
skip_all,
fields(
scope = %format!("{:?}", cx.id),
scope = ?cx.id,
ty = %std::any::type_name::<T>()
)
)
@ -172,9 +172,9 @@ where
level = "debug",
skip_all,
fields(
id = %format!("{id:?}"),
defined_at = %format!("{:?}", self.defined_at),
ty = %std::any::type_name::<T>()
id = ?id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
)]
@ -220,7 +220,7 @@ impl EffectId {
level = "debug",
skip_all,
fields(
id = %format!("{self:?}"),
id = ?self,
)
)
)]

View file

@ -60,7 +60,7 @@ use std::fmt::Debug;
level = "trace",
skip_all,
fields(
cx = %format!("{:?}", cx.id),
cx = ?cx.id,
)
)
)]
@ -155,8 +155,8 @@ impl<T> UntrackedGettableSignal<T> for Memo<T> {
name = "Memo::get_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.0.id),
defined_at = %format!("{:?}", self.1),
id = ?self.0.id,
defined_at = %self.1,
ty = %std::any::type_name::<T>()
)
)
@ -177,8 +177,8 @@ impl<T> UntrackedGettableSignal<T> for Memo<T> {
name = "Memo::with_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.0.id),
defined_at = %format!("{:?}", self.1),
id = ?self.0.id,
defined_at = %self.1,
ty = %std::any::type_name::<T>()
)
)
@ -217,8 +217,8 @@ where
level = "trace",
skip_all,
fields(
id = %format!("{:?}", self.0.id),
defined_at = %format!("{:?}", self.1)
id = ?self.0.id,
defined_at = %self.1
)
)
)]
@ -256,8 +256,8 @@ where
level = "trace",
skip_all,
fields(
id = %format!("{:?}", self.0.id),
defined_at = %format!("{:?}", self.1),
id = ?self.0.id,
defined_at = %self.1,
ty = %std::any::type_name::<T>()
)
)

View file

@ -89,7 +89,7 @@ where
level = "trace",
skip_all,
fields(
scope = %format!("{:?}", cx.id),
scope = ?cx.id,
ty = %std::any::type_name::<T>(),
signal_ty = %std::any::type_name::<S>(),
)
@ -208,7 +208,7 @@ where
level = "trace",
skip_all,
fields(
scope = %format!("{:?}", cx.id),
scope = ?cx.id,
ty = %std::any::type_name::<T>(),
signal_ty = %std::any::type_name::<S>(),
)

View file

@ -51,7 +51,7 @@ use thiserror::Error;
level = "trace",
skip_all,
fields(
scope = %format!("{:?}", cx.id),
scope = ?cx.id,
ty = %std::any::type_name::<T>()
)
)
@ -72,7 +72,7 @@ pub fn create_signal<T>(cx: Scope, value: T) -> (ReadSignal<T>, WriteSignal<T>)
level = "trace",
skip_all,
fields(
scope = %format!("{:?}", cx.id),
scope = ?cx.id,
)
)
)]
@ -154,8 +154,8 @@ impl<T> UntrackedGettableSignal<T> for ReadSignal<T> {
name = "ReadSignal::get_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -174,8 +174,8 @@ impl<T> UntrackedGettableSignal<T> for ReadSignal<T> {
name = "ReadSignal::with_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -214,8 +214,8 @@ where
name = "ReadSignal::with()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -254,8 +254,8 @@ where
name = "ReadSignal::get()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -391,8 +391,8 @@ where
name = "WriteSignal::set_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -409,8 +409,8 @@ where
name = "WriteSignal::updated_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -426,8 +426,8 @@ where
name = "WriteSignal::update_returning_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -468,8 +468,8 @@ where
level = "trace",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -506,8 +506,8 @@ where
name = "WriteSignal::update_returning()"
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -542,8 +542,8 @@ where
name = "WriteSignal::set()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -691,8 +691,8 @@ impl<T> UntrackedGettableSignal<T> for RwSignal<T> {
name = "RwSignal::get_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -712,8 +712,8 @@ impl<T> UntrackedGettableSignal<T> for RwSignal<T> {
name = "RwSignal::with_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -731,8 +731,8 @@ impl<T> UntrackedSettableSignal<T> for RwSignal<T> {
name = "RwSignal::set_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -749,8 +749,8 @@ impl<T> UntrackedSettableSignal<T> for RwSignal<T> {
name = "RwSignal::update_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -766,8 +766,8 @@ impl<T> UntrackedSettableSignal<T> for RwSignal<T> {
name = "RwSignal::update_returning_untracked()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -807,8 +807,8 @@ where
name = "RwSignal::with()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -838,8 +838,8 @@ where
name = "RwSignal::get()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -875,8 +875,8 @@ where
name = "RwSignal::update()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -911,8 +911,8 @@ where
name = "RwSignal::update_returning()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -942,8 +942,8 @@ where
name = "RwSignal::set()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -975,8 +975,8 @@ where
name = "RwSignal::read_only()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -1013,8 +1013,8 @@ where
name = "RwSignal::write_only()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -1050,8 +1050,8 @@ where
name = "RwSignal::split()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -1084,8 +1084,8 @@ where
name = "RwSignal::to_stream()",
skip_all,
fields(
id = %format!("{:?}", self.id),
defined_at = %format!("{:?}", self.defined_at),
id = ?self.id,
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)

View file

@ -125,7 +125,7 @@ where
level = "trace",
skip_all,
fields(
cx = %format!("{:?}", cx.id)
cx = ?cx.id
)
)
)]
@ -179,7 +179,7 @@ where
level = "trace",
skip_all,
fields(
defined_at = %format!("{:?}", self.defined_at),
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -220,7 +220,7 @@ where
level = "trace",
skip_all,
fields(
defined_at = %format!("{:?}", self.defined_at),
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)
@ -441,6 +441,18 @@ where
/// assert_eq!(above_3(&double_count), true);
/// # });
/// ```
#[cfg_attr(
debug_assertions,
instrument(
level = "trace",
name = "MaybeSignal::derive()",
skip_all,
fields(
cx = ?cx.id,
ty = %std::any::type_name::<T>()
)
)
)]
pub fn derive(cx: Scope, derived_signal: impl Fn() -> T + 'static) -> Self {
Self::Dynamic(Signal::derive(cx, derived_signal))
}
@ -477,6 +489,15 @@ where
/// assert_eq!(static_value(), "Bob");
/// });
/// ```
#[cfg_attr(
debug_assertions,
instrument(
level = "trace",
name = "MaybeSignal::derive()",
skip_all,
fields(ty = %std::any::type_name::<T>())
)
)]
pub fn with<U>(&self, f: impl FnOnce(&T) -> U) -> U {
match &self {
Self::Static(value) => f(value),
@ -508,6 +529,15 @@ where
/// assert_eq!(above_3(&static_value.into()), true);
/// # });
/// ```
#[cfg_attr(
debug_assertions,
instrument(
level = "trace",
name = "MaybeSignal::derive()",
skip_all,
fields(ty = %std::any::type_name::<T>())
)
)]
pub fn get(&self) -> T
where
T: Clone,

View file

@ -107,7 +107,7 @@ where
level = "trace",
skip_all,
fields(
cx = %format!("{:?}", cx.id),
cx = ?cx.id,
)
)
)]
@ -145,7 +145,7 @@ where
level = "trace",
skip_all,
fields(
defined_at = %format!("{:?}", self.defined_at),
defined_at = %self.defined_at,
ty = %std::any::type_name::<T>()
)
)

View file

@ -36,7 +36,7 @@ pub fn Form<A>(
#[prop(optional)]
on_response: Option<Rc<dyn Fn(&web_sys::Response)>>,
/// Component children; should include the HTML of the form elements.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
A: ToHref + 'static,
@ -134,7 +134,7 @@ pub fn ActionForm<I, O>(
/// manually using [leptos_server::Action::using_server_fn].
action: Action<I, Result<O, ServerFnError>>,
/// Component children; should include the HTML of the form elements.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
I: Clone + ServerFn + 'static,
@ -208,7 +208,7 @@ pub fn MultiActionForm<I, O>(
/// manually using [leptos_server::Action::using_server_fn].
action: MultiAction<I, Result<O, ServerFnError>>,
/// Component children; should include the HTML of the form elements.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
I: Clone + ServerFn + 'static,

View file

@ -58,7 +58,7 @@ pub fn A<H>(
#[prop(optional, into)]
class: Option<MaybeSignal<String>>,
/// The nodes or elements to be shown inside the link.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView
where
H: ToHref + 'static,

View file

@ -26,7 +26,7 @@ pub fn Route<E, F, P>(
view: F,
/// `children` may be empty or include nested routes.
#[prop(optional)]
children: Option<Box<dyn Fn(Scope) -> Fragment>>,
children: Option<Box<dyn FnOnce(Scope) -> Fragment>>,
) -> impl IntoView
where
E: IntoView,

View file

@ -32,7 +32,7 @@ pub fn Router(
/// The `<Router/>` should usually wrap your whole page. It can contain
/// any elements, and should include a [Routes](crate::Routes) component somewhere
/// to define and display [Route](crate::Route)s.
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView {
// create a new RouterContext and provide it to every component beneath the router
let router = RouterContext::new(cx, base, fallback);

View file

@ -22,7 +22,7 @@ use crate::{
pub fn Routes(
cx: Scope,
#[prop(optional)] base: Option<String>,
children: Box<dyn Fn(Scope) -> Fragment>,
children: Box<dyn FnOnce(Scope) -> Fragment>,
) -> impl IntoView {
let router = use_context::<RouterContext>(cx).unwrap_or_else(|| {
log::warn!("<Routes/> component should be nested within a <Router/>.");