mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
Merge branch 'main' into generated_routes
This commit is contained in:
commit
dad84b5867
22 changed files with 381 additions and 117 deletions
|
@ -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(),
|
||||
¤t_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
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)>;
|
||||
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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(|| {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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 don’t."
|
||||
/// </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>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
)
|
||||
)]
|
||||
|
|
|
@ -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>()
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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>(),
|
||||
)
|
||||
|
|
|
@ -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>()
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>()
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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/>.");
|
||||
|
|
Loading…
Reference in a new issue