leptos/
children.rs

1use crate::into_view::{IntoView, View};
2use std::{
3    fmt::{self, Debug},
4    sync::Arc,
5};
6use tachys::view::{
7    any_view::{AnyView, IntoAny},
8    fragment::{Fragment, IntoFragment},
9    RenderHtml,
10};
11
12/// The most common type for the `children` property on components,
13/// which can only be called once.
14///
15/// This does not support iterating over individual nodes within the children.
16/// To iterate over children, use [`ChildrenFragment`].
17pub type Children = Box<dyn FnOnce() -> AnyView + Send>;
18
19/// A type for the `children` property on components that can be called only once,
20/// and provides a collection of all the children passed to this component.
21pub type ChildrenFragment = Box<dyn FnOnce() -> Fragment + Send>;
22
23/// A type for the `children` property on components that can be called
24/// more than once.
25pub type ChildrenFn = Arc<dyn Fn() -> AnyView + Send + Sync>;
26
27/// A type for the `children` property on components that can be called more than once,
28/// and provides a collection of all the children passed to this component.
29pub type ChildrenFragmentFn = Arc<dyn Fn() -> Fragment + Send>;
30
31/// A type for the `children` property on components that can be called
32/// more than once, but may mutate the children.
33pub type ChildrenFnMut = Box<dyn FnMut() -> AnyView + Send>;
34
35/// A type for the `children` property on components that can be called more than once,
36/// but may mutate the children, and provides a collection of all the children
37/// passed to this component.
38pub type ChildrenFragmentMut = Box<dyn FnMut() -> Fragment + Send>;
39
40// This is to still support components that accept `Box<dyn Fn() -> AnyView>` as a children.
41type BoxedChildrenFn = Box<dyn Fn() -> AnyView + Send>;
42
43/// This trait can be used when constructing a component that takes children without needing
44/// to know exactly what children type the component expects. This is used internally by the
45/// `view!` macro implementation, and can also be used explicitly when using the builder syntax.
46///
47///
48/// Different component types take different types for their `children` prop, some of which cannot
49/// be directly constructed. Using `ToChildren` allows the component user to pass children without
50/// explicity constructing the correct type.
51///
52/// ## Examples
53///
54/// ```
55/// # use leptos::prelude::*;
56/// # use leptos::html::p;
57/// # use leptos::IntoView;
58/// # use leptos_macro::component;
59/// # use leptos::children::ToChildren;
60/// use leptos::context::{Provider, ProviderProps};
61/// use leptos::control_flow::{Show, ShowProps};
62///
63/// #[component]
64/// fn App() -> impl IntoView {
65///     (
66///       Provider(
67///         ProviderProps::builder()
68///             .children(ToChildren::to_children(|| {
69///                 p().child("Foo")
70///             }))
71///             // ...
72///            .value("Foo")
73///            .build(),
74///        ),
75///        Show(
76///          ShowProps::builder()
77///             .children(ToChildren::to_children(|| {
78///                 p().child("Foo")
79///             }))
80///             // ...
81///             .when(|| true)
82///             .fallback(|| p().child("foo"))
83///             .build(),
84///        )
85///     )
86/// }
87pub trait ToChildren<F> {
88    /// Convert the provided type (generally a closure) to Self (generally a "children" type,
89    /// e.g., [Children]). See the implementations to see exactly which input types are supported
90    /// and which "children" type they are converted to.
91    fn to_children(f: F) -> Self;
92}
93
94impl<F, C> ToChildren<F> for Children
95where
96    F: FnOnce() -> C + Send + 'static,
97    C: RenderHtml + Send + 'static,
98{
99    #[inline]
100    fn to_children(f: F) -> Self {
101        Box::new(move || f().into_any())
102    }
103}
104
105impl<F, C> ToChildren<F> for ChildrenFn
106where
107    F: Fn() -> C + Send + Sync + 'static,
108    C: RenderHtml + Send + 'static,
109{
110    #[inline]
111    fn to_children(f: F) -> Self {
112        Arc::new(move || f().into_any())
113    }
114}
115
116impl<F, C> ToChildren<F> for ChildrenFnMut
117where
118    F: Fn() -> C + Send + 'static,
119    C: RenderHtml + Send + 'static,
120{
121    #[inline]
122    fn to_children(f: F) -> Self {
123        Box::new(move || f().into_any())
124    }
125}
126
127impl<F, C> ToChildren<F> for BoxedChildrenFn
128where
129    F: Fn() -> C + Send + 'static,
130    C: RenderHtml + Send + 'static,
131{
132    #[inline]
133    fn to_children(f: F) -> Self {
134        Box::new(move || f().into_any())
135    }
136}
137
138impl<F, C> ToChildren<F> for ChildrenFragment
139where
140    F: FnOnce() -> C + Send + 'static,
141    C: IntoFragment,
142{
143    #[inline]
144    fn to_children(f: F) -> Self {
145        Box::new(move || f().into_fragment())
146    }
147}
148
149impl<F, C> ToChildren<F> for ChildrenFragmentFn
150where
151    F: Fn() -> C + Send + 'static,
152    C: IntoFragment,
153{
154    #[inline]
155    fn to_children(f: F) -> Self {
156        Arc::new(move || f().into_fragment())
157    }
158}
159
160impl<F, C> ToChildren<F> for ChildrenFragmentMut
161where
162    F: FnMut() -> C + Send + 'static,
163    C: IntoFragment,
164{
165    #[inline]
166    fn to_children(mut f: F) -> Self {
167        Box::new(move || f().into_fragment())
168    }
169}
170
171/// New-type wrapper for a function that returns a view with `From` and `Default` traits implemented
172/// to enable optional props in for example `<Show>` and `<Suspense>`.
173#[derive(Clone)]
174pub struct ViewFn(Arc<dyn Fn() -> AnyView + Send + Sync + 'static>);
175
176impl Default for ViewFn {
177    fn default() -> Self {
178        Self(Arc::new(|| ().into_any()))
179    }
180}
181
182impl<F, C> From<F> for ViewFn
183where
184    F: Fn() -> C + Send + Sync + 'static,
185    C: RenderHtml + Send + 'static,
186{
187    fn from(value: F) -> Self {
188        Self(Arc::new(move || value().into_any()))
189    }
190}
191
192impl ViewFn {
193    /// Execute the wrapped function
194    pub fn run(&self) -> AnyView {
195        (self.0)()
196    }
197}
198
199/// New-type wrapper for a function, which will only be called once and returns a view with `From` and
200/// `Default` traits implemented to enable optional props in for example `<Show>` and `<Suspense>`.
201pub struct ViewFnOnce(Box<dyn FnOnce() -> AnyView + Send + 'static>);
202
203impl Default for ViewFnOnce {
204    fn default() -> Self {
205        Self(Box::new(|| ().into_any()))
206    }
207}
208
209impl<F, C> From<F> for ViewFnOnce
210where
211    F: FnOnce() -> C + Send + 'static,
212    C: RenderHtml + Send + 'static,
213{
214    fn from(value: F) -> Self {
215        Self(Box::new(move || value().into_any()))
216    }
217}
218
219impl ViewFnOnce {
220    /// Execute the wrapped function
221    pub fn run(self) -> AnyView {
222        (self.0)()
223    }
224}
225
226/// A typed equivalent to [`Children`], which takes a generic but preserves type information to
227/// allow the compiler to optimize the view more effectively.
228pub struct TypedChildren<T>(Box<dyn FnOnce() -> View<T> + Send>);
229
230impl<T> TypedChildren<T> {
231    /// Extracts the inner `children` function.
232    pub fn into_inner(self) -> impl FnOnce() -> View<T> + Send {
233        self.0
234    }
235}
236
237impl<F, C> ToChildren<F> for TypedChildren<C>
238where
239    F: FnOnce() -> C + Send + 'static,
240    C: IntoView,
241    C::AsyncOutput: Send,
242{
243    #[inline]
244    fn to_children(f: F) -> Self {
245        TypedChildren(Box::new(move || f().into_view()))
246    }
247}
248
249/// A typed equivalent to [`ChildrenFnMut`], which takes a generic but preserves type information to
250/// allow the compiler to optimize the view more effectively.
251pub struct TypedChildrenMut<T>(Box<dyn FnMut() -> View<T> + Send>);
252
253impl<T> Debug for TypedChildrenMut<T> {
254    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255        f.debug_tuple("TypedChildrenMut").finish()
256    }
257}
258
259impl<T> TypedChildrenMut<T> {
260    /// Extracts the inner `children` function.
261    pub fn into_inner(self) -> impl FnMut() -> View<T> + Send {
262        self.0
263    }
264}
265
266impl<F, C> ToChildren<F> for TypedChildrenMut<C>
267where
268    F: FnMut() -> C + Send + 'static,
269    C: IntoView,
270    C::AsyncOutput: Send,
271{
272    #[inline]
273    fn to_children(mut f: F) -> Self {
274        TypedChildrenMut(Box::new(move || f().into_view()))
275    }
276}
277
278/// A typed equivalent to [`ChildrenFn`], which takes a generic but preserves type information to
279/// allow the compiler to optimize the view more effectively.
280pub struct TypedChildrenFn<T>(Arc<dyn Fn() -> View<T> + Send + Sync>);
281
282impl<T> Debug for TypedChildrenFn<T> {
283    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284        f.debug_tuple("TypedChildrenFn").finish()
285    }
286}
287
288impl<T> Clone for TypedChildrenFn<T> {
289    // Manual implementation to avoid the `T: Clone` bound.
290    fn clone(&self) -> Self {
291        Self(self.0.clone())
292    }
293}
294
295impl<T> TypedChildrenFn<T> {
296    /// Extracts the inner `children` function.
297    pub fn into_inner(self) -> Arc<dyn Fn() -> View<T> + Send + Sync> {
298        self.0
299    }
300}
301
302impl<F, C> ToChildren<F> for TypedChildrenFn<C>
303where
304    F: Fn() -> C + Send + Sync + 'static,
305    C: IntoView,
306    C::AsyncOutput: Send,
307{
308    #[inline]
309    fn to_children(f: F) -> Self {
310        TypedChildrenFn(Arc::new(move || f().into_view()))
311    }
312}