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/// explicitly 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
94/// Compiler optimisation, can be used with certain type to avoid unique closures in the view!{} macro.
95pub struct ChildrenOptContainer<T>(pub T);
96
97impl<F, C> ToChildren<F> for Children
98where
99    F: FnOnce() -> C + Send + 'static,
100    C: RenderHtml + Send + 'static,
101{
102    #[inline]
103    fn to_children(f: F) -> Self {
104        Box::new(move || f().into_any())
105    }
106}
107
108impl<T> ToChildren<ChildrenOptContainer<T>> for Children
109where
110    T: IntoAny + Send + 'static,
111{
112    #[inline]
113    fn to_children(t: ChildrenOptContainer<T>) -> Self {
114        Box::new(move || t.0.into_any())
115    }
116}
117
118impl<F, C> ToChildren<F> for ChildrenFn
119where
120    F: Fn() -> C + Send + Sync + 'static,
121    C: RenderHtml + Send + 'static,
122{
123    #[inline]
124    fn to_children(f: F) -> Self {
125        Arc::new(move || f().into_any())
126    }
127}
128
129impl<T> ToChildren<ChildrenOptContainer<T>> for ChildrenFn
130where
131    T: IntoAny + Clone + Send + Sync + 'static,
132{
133    #[inline]
134    fn to_children(t: ChildrenOptContainer<T>) -> Self {
135        Arc::new(move || t.0.clone().into_any())
136    }
137}
138
139impl<F, C> ToChildren<F> for ChildrenFnMut
140where
141    F: Fn() -> C + Send + 'static,
142    C: RenderHtml + Send + 'static,
143{
144    #[inline]
145    fn to_children(f: F) -> Self {
146        Box::new(move || f().into_any())
147    }
148}
149
150impl<T> ToChildren<ChildrenOptContainer<T>> for ChildrenFnMut
151where
152    T: IntoAny + Clone + Send + 'static,
153{
154    #[inline]
155    fn to_children(t: ChildrenOptContainer<T>) -> Self {
156        Box::new(move || t.0.clone().into_any())
157    }
158}
159
160impl<F, C> ToChildren<F> for BoxedChildrenFn
161where
162    F: Fn() -> C + Send + 'static,
163    C: RenderHtml + Send + 'static,
164{
165    #[inline]
166    fn to_children(f: F) -> Self {
167        Box::new(move || f().into_any())
168    }
169}
170
171impl<T> ToChildren<ChildrenOptContainer<T>> for BoxedChildrenFn
172where
173    T: IntoAny + Clone + Send + 'static,
174{
175    #[inline]
176    fn to_children(t: ChildrenOptContainer<T>) -> Self {
177        Box::new(move || t.0.clone().into_any())
178    }
179}
180
181impl<F, C> ToChildren<F> for ChildrenFragment
182where
183    F: FnOnce() -> C + Send + 'static,
184    C: IntoFragment,
185{
186    #[inline]
187    fn to_children(f: F) -> Self {
188        Box::new(move || f().into_fragment())
189    }
190}
191
192impl<T> ToChildren<ChildrenOptContainer<T>> for ChildrenFragment
193where
194    T: IntoAny + Send + 'static,
195{
196    #[inline]
197    fn to_children(t: ChildrenOptContainer<T>) -> Self {
198        Box::new(move || Fragment::new(vec![t.0.into_any()]))
199    }
200}
201
202impl<F, C> ToChildren<F> for ChildrenFragmentFn
203where
204    F: Fn() -> C + Send + 'static,
205    C: IntoFragment,
206{
207    #[inline]
208    fn to_children(f: F) -> Self {
209        Arc::new(move || f().into_fragment())
210    }
211}
212
213impl<T> ToChildren<ChildrenOptContainer<T>> for ChildrenFragmentFn
214where
215    T: IntoAny + Clone + Send + 'static,
216{
217    #[inline]
218    fn to_children(t: ChildrenOptContainer<T>) -> Self {
219        Arc::new(move || Fragment::new(vec![t.0.clone().into_any()]))
220    }
221}
222
223impl<F, C> ToChildren<F> for ChildrenFragmentMut
224where
225    F: FnMut() -> C + Send + 'static,
226    C: IntoFragment,
227{
228    #[inline]
229    fn to_children(mut f: F) -> Self {
230        Box::new(move || f().into_fragment())
231    }
232}
233
234impl<T> ToChildren<ChildrenOptContainer<T>> for ChildrenFragmentMut
235where
236    T: IntoAny + Clone + Send + 'static,
237{
238    #[inline]
239    fn to_children(t: ChildrenOptContainer<T>) -> Self {
240        Box::new(move || Fragment::new(vec![t.0.clone().into_any()]))
241    }
242}
243
244/// New-type wrapper for a function that returns a view with `From` and `Default` traits implemented
245/// to enable optional props in for example `<Show>` and `<Suspense>`.
246#[derive(Clone)]
247pub struct ViewFn(Arc<dyn Fn() -> AnyView + Send + Sync + 'static>);
248
249impl Default for ViewFn {
250    fn default() -> Self {
251        Self(Arc::new(|| ().into_any()))
252    }
253}
254
255impl<F, C> From<F> for ViewFn
256where
257    F: Fn() -> C + Send + Sync + 'static,
258    C: RenderHtml + Send + 'static,
259{
260    fn from(value: F) -> Self {
261        Self(Arc::new(move || value().into_any()))
262    }
263}
264
265impl<C> From<View<C>> for ViewFn
266where
267    C: Clone + Send + Sync + 'static,
268    View<C>: IntoAny,
269{
270    fn from(value: View<C>) -> Self {
271        Self(Arc::new(move || value.clone().into_any()))
272    }
273}
274
275impl ViewFn {
276    /// Execute the wrapped function
277    pub fn run(&self) -> AnyView {
278        (self.0)()
279    }
280}
281
282/// New-type wrapper for a function, which will only be called once and returns a view with `From` and
283/// `Default` traits implemented to enable optional props in for example `<Show>` and `<Suspense>`.
284pub struct ViewFnOnce(Box<dyn FnOnce() -> AnyView + Send + 'static>);
285
286impl Default for ViewFnOnce {
287    fn default() -> Self {
288        Self(Box::new(|| ().into_any()))
289    }
290}
291
292impl<F, C> From<F> for ViewFnOnce
293where
294    F: FnOnce() -> C + Send + 'static,
295    C: RenderHtml + Send + 'static,
296{
297    fn from(value: F) -> Self {
298        Self(Box::new(move || value().into_any()))
299    }
300}
301
302impl<C> From<View<C>> for ViewFnOnce
303where
304    C: Send + Sync + 'static,
305    View<C>: IntoAny,
306{
307    fn from(value: View<C>) -> Self {
308        Self(Box::new(move || value.into_any()))
309    }
310}
311
312impl ViewFnOnce {
313    /// Execute the wrapped function
314    pub fn run(self) -> AnyView {
315        (self.0)()
316    }
317}
318
319/// A typed equivalent to [`Children`], which takes a generic but preserves type information to
320/// allow the compiler to optimize the view more effectively.
321pub struct TypedChildren<T>(Box<dyn FnOnce() -> View<T> + Send>);
322
323impl<T> TypedChildren<T> {
324    /// Extracts the inner `children` function.
325    pub fn into_inner(self) -> impl FnOnce() -> View<T> + Send {
326        self.0
327    }
328}
329
330impl<F, C> ToChildren<F> for TypedChildren<C>
331where
332    F: FnOnce() -> C + Send + 'static,
333    C: IntoView,
334    C::AsyncOutput: Send,
335{
336    #[inline]
337    fn to_children(f: F) -> Self {
338        TypedChildren(Box::new(move || f().into_view()))
339    }
340}
341
342impl<T> ToChildren<ChildrenOptContainer<T>> for TypedChildren<T>
343where
344    T: IntoView + 'static,
345{
346    #[inline]
347    fn to_children(t: ChildrenOptContainer<T>) -> Self {
348        TypedChildren(Box::new(move || t.0.into_view()))
349    }
350}
351
352/// A typed equivalent to [`ChildrenFnMut`], which takes a generic but preserves type information to
353/// allow the compiler to optimize the view more effectively.
354pub struct TypedChildrenMut<T>(Box<dyn FnMut() -> View<T> + Send>);
355
356impl<T> Debug for TypedChildrenMut<T> {
357    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358        f.debug_tuple("TypedChildrenMut").finish()
359    }
360}
361
362impl<T> TypedChildrenMut<T> {
363    /// Extracts the inner `children` function.
364    pub fn into_inner(self) -> impl FnMut() -> View<T> + Send {
365        self.0
366    }
367}
368
369impl<F, C> ToChildren<F> for TypedChildrenMut<C>
370where
371    F: FnMut() -> C + Send + 'static,
372    C: IntoView,
373    C::AsyncOutput: Send,
374{
375    #[inline]
376    fn to_children(mut f: F) -> Self {
377        TypedChildrenMut(Box::new(move || f().into_view()))
378    }
379}
380
381impl<T> ToChildren<ChildrenOptContainer<T>> for TypedChildrenMut<T>
382where
383    T: IntoView + Clone + 'static,
384{
385    #[inline]
386    fn to_children(t: ChildrenOptContainer<T>) -> Self {
387        TypedChildrenMut(Box::new(move || t.0.clone().into_view()))
388    }
389}
390
391/// A typed equivalent to [`ChildrenFn`], which takes a generic but preserves type information to
392/// allow the compiler to optimize the view more effectively.
393pub struct TypedChildrenFn<T>(Arc<dyn Fn() -> View<T> + Send + Sync>);
394
395impl<T> Debug for TypedChildrenFn<T> {
396    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
397        f.debug_tuple("TypedChildrenFn").finish()
398    }
399}
400
401impl<T> Clone for TypedChildrenFn<T> {
402    // Manual implementation to avoid the `T: Clone` bound.
403    fn clone(&self) -> Self {
404        Self(self.0.clone())
405    }
406}
407
408impl<T> TypedChildrenFn<T> {
409    /// Extracts the inner `children` function.
410    pub fn into_inner(self) -> Arc<dyn Fn() -> View<T> + Send + Sync> {
411        self.0
412    }
413}
414
415impl<F, C> ToChildren<F> for TypedChildrenFn<C>
416where
417    F: Fn() -> C + Send + Sync + 'static,
418    C: IntoView,
419    C::AsyncOutput: Send,
420{
421    #[inline]
422    fn to_children(f: F) -> Self {
423        TypedChildrenFn(Arc::new(move || f().into_view()))
424    }
425}
426
427impl<T> ToChildren<ChildrenOptContainer<T>> for TypedChildrenFn<T>
428where
429    T: IntoView + Clone + Sync + 'static,
430{
431    #[inline]
432    fn to_children(t: ChildrenOptContainer<T>) -> Self {
433        TypedChildrenFn(Arc::new(move || t.0.clone().into_view()))
434    }
435}