mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
feat: iterating over items in children with ChildrenFragment, ChildrenFragmentFn, ChildrenFragmentMut
This commit is contained in:
parent
f5d203f0c9
commit
0dd1932b7f
3 changed files with 158 additions and 1 deletions
|
@ -7,22 +7,39 @@ use tachys::{
|
|||
renderer::dom::Dom,
|
||||
view::{
|
||||
any_view::{AnyView, IntoAny},
|
||||
fragment::{Fragment, IntoFragment},
|
||||
RenderHtml,
|
||||
},
|
||||
};
|
||||
|
||||
/// The most common type for the `children` property on components,
|
||||
/// which can only be called once.
|
||||
///
|
||||
/// This does not support iterating over individual nodes within the children.
|
||||
/// To iterate over children, use [`ChildrenFragment`].
|
||||
pub type Children = Box<dyn FnOnce() -> AnyView<Dom> + Send>;
|
||||
|
||||
/// A type for the `children` property on components that can be called only once,
|
||||
/// and provides a collection of all the children passed to this component.
|
||||
pub type ChildrenFragment = Box<dyn FnOnce() -> Fragment<Dom> + Send>;
|
||||
|
||||
/// A type for the `children` property on components that can be called
|
||||
/// more than once.
|
||||
pub type ChildrenFn = Arc<dyn Fn() -> AnyView<Dom> + Send + Sync>;
|
||||
|
||||
/// A type for the `children` property on components that can be called more than once,
|
||||
/// and provides a collection of all the children passed to this component.
|
||||
pub type ChildrenFragmentFn = Arc<dyn Fn() -> Fragment<Dom> + Send>;
|
||||
|
||||
/// A type for the `children` property on components that can be called
|
||||
/// more than once, but may mutate the children.
|
||||
pub type ChildrenFnMut = Box<dyn FnMut() -> AnyView<Dom> + Send>;
|
||||
|
||||
/// A type for the `children` property on components that can be called more than once,
|
||||
/// but may mutate the children, and provides a collection of all the children
|
||||
/// passed to this component.
|
||||
pub type ChildrenFragmentMut = Box<dyn FnMut() -> Fragment<Dom> + Send>;
|
||||
|
||||
// This is to still support components that accept `Box<dyn Fn() -> AnyView>` as a children.
|
||||
type BoxedChildrenFn = Box<dyn Fn() -> AnyView<Dom> + Send>;
|
||||
|
||||
|
@ -147,6 +164,39 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<F, C> ToChildren<F> for ChildrenFragment
|
||||
where
|
||||
F: FnOnce() -> C + Send + 'static,
|
||||
C: IntoFragment<Dom>,
|
||||
{
|
||||
#[inline]
|
||||
fn to_children(f: F) -> Self {
|
||||
Box::new(move || f().into_fragment())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, C> ToChildren<F> for ChildrenFragmentFn
|
||||
where
|
||||
F: Fn() -> C + Send + 'static,
|
||||
C: IntoFragment<Dom>,
|
||||
{
|
||||
#[inline]
|
||||
fn to_children(f: F) -> Self {
|
||||
Arc::new(move || f().into_fragment())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, C> ToChildren<F> for ChildrenFragmentMut
|
||||
where
|
||||
F: FnMut() -> C + Send + 'static,
|
||||
C: IntoFragment<Dom>,
|
||||
{
|
||||
#[inline]
|
||||
fn to_children(mut f: F) -> Self {
|
||||
Box::new(move || f().into_fragment())
|
||||
}
|
||||
}
|
||||
|
||||
/// New-type wrapper for a function that returns a view with `From` and `Default` traits implemented
|
||||
/// to enable optional props in for example `<Show>` and `<Suspense>`.
|
||||
#[derive(Clone)]
|
||||
|
|
106
tachys/src/view/fragment.rs
Normal file
106
tachys/src/view/fragment.rs
Normal file
|
@ -0,0 +1,106 @@
|
|||
use super::any_view::{AnyView, IntoAny};
|
||||
use crate::renderer::Renderer;
|
||||
|
||||
/// A typed-erased collection of different views.
|
||||
pub struct Fragment<R: Renderer> {
|
||||
/// The nodes contained in the fragment.
|
||||
pub nodes: Vec<AnyView<R>>,
|
||||
}
|
||||
|
||||
pub trait IntoFragment<R: Renderer> {
|
||||
fn into_fragment(self) -> Fragment<R>;
|
||||
}
|
||||
|
||||
impl<R: Renderer> FromIterator<AnyView<R>> for Fragment<R> {
|
||||
fn from_iter<T: IntoIterator<Item = AnyView<R>>>(iter: T) -> Self {
|
||||
Fragment::new(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Renderer> From<AnyView<R>> for Fragment<R> {
|
||||
fn from(view: AnyView<R>) -> Self {
|
||||
Fragment::new(vec![view])
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Renderer> From<Fragment<R>> for AnyView<R> {
|
||||
fn from(value: Fragment<R>) -> Self {
|
||||
value.nodes.into_any()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Renderer> Fragment<R> {
|
||||
/// Creates a new [`Fragment`].
|
||||
#[inline(always)]
|
||||
pub fn new(nodes: Vec<AnyView<R>>) -> Self {
|
||||
Self { nodes }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> IntoFragment<R> for Vec<T>
|
||||
where
|
||||
T: IntoAny<R>,
|
||||
R: Renderer,
|
||||
{
|
||||
fn into_fragment(self) -> Fragment<R> {
|
||||
Fragment::new(self.into_iter().map(IntoAny::into_any).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, T, R> IntoFragment<R> for [T; N]
|
||||
where
|
||||
T: IntoAny<R>,
|
||||
R: Renderer,
|
||||
{
|
||||
fn into_fragment(self) -> Fragment<R> {
|
||||
Fragment::new(self.into_iter().map(IntoAny::into_any).collect())
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tuples {
|
||||
($($ty:ident),*) => {
|
||||
impl<$($ty),*, Rndr> IntoFragment<Rndr> for ($($ty,)*)
|
||||
where
|
||||
$($ty: IntoAny<Rndr>),*,
|
||||
Rndr: Renderer
|
||||
{
|
||||
fn into_fragment(self) -> Fragment<Rndr> {
|
||||
#[allow(non_snake_case)]
|
||||
let ($($ty,)*) = self;
|
||||
Fragment::new(vec![$($ty.into_any(),)*])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tuples!(A);
|
||||
tuples!(A, B);
|
||||
tuples!(A, B, C);
|
||||
tuples!(A, B, C, D);
|
||||
tuples!(A, B, C, D, E);
|
||||
tuples!(A, B, C, D, E, F);
|
||||
tuples!(A, B, C, D, E, F, G);
|
||||
tuples!(A, B, C, D, E, F, G, H);
|
||||
tuples!(A, B, C, D, E, F, G, H, I);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
|
||||
tuples!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
|
||||
tuples!(
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y
|
||||
);
|
||||
tuples!(
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y,
|
||||
Z
|
||||
);
|
|
@ -1,4 +1,4 @@
|
|||
use self::add_attr::AddAnyAttr;
|
||||
use self::{add_attr::AddAnyAttr, fragment::Fragment};
|
||||
use crate::{hydration::Cursor, renderer::Renderer, ssr::StreamBuilder};
|
||||
use parking_lot::RwLock;
|
||||
use std::{cell::RefCell, future::Future, rc::Rc, sync::Arc};
|
||||
|
@ -7,6 +7,7 @@ pub mod add_attr;
|
|||
pub mod any_view;
|
||||
pub mod either;
|
||||
pub mod error_boundary;
|
||||
pub mod fragment;
|
||||
pub mod iterators;
|
||||
pub mod keyed;
|
||||
mod primitives;
|
||||
|
|
Loading…
Reference in a new issue