1use std::any::Any;
4use std::fmt;
5
6use smallvec::{smallvec, SmallVec};
7use sycamore_core::Children;
8
9use crate::*;
10
11pub struct View<T = HtmlNode> {
16 pub(crate) nodes: SmallVec<[T; 1]>,
18}
19
20impl<T> View<T> {
21 pub fn new() -> Self {
23 Self {
24 nodes: SmallVec::new(),
25 }
26 }
27
28 pub fn from_node(node: T) -> Self {
30 Self {
31 nodes: smallvec![node],
32 }
33 }
34
35 pub fn from_nodes(nodes: Vec<T>) -> Self {
37 Self {
38 nodes: nodes.into(),
39 }
40 }
41
42 pub fn from_dynamic<U: Into<Self> + 'static>(f: impl FnMut() -> U + 'static) -> Self
45 where
46 T: ViewNode,
47 {
48 T::create_dynamic_view(f)
49 }
50
51 pub fn as_web_sys(&self) -> Vec<web_sys::Node>
53 where
54 T: ViewHtmlNode,
55 {
56 self.nodes
57 .iter()
58 .map(|node| node.as_web_sys().clone())
59 .collect()
60 }
61}
62
63impl<T> Default for View<T> {
64 fn default() -> Self {
65 Self::new()
66 }
67}
68
69impl<T> fmt::Debug for View<T> {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 f.debug_struct("View").finish()
72 }
73}
74
75impl<T> From<Children<Self>> for View<T> {
76 fn from(children: Children<Self>) -> Self {
77 children.call()
78 }
79}
80
81impl<T> From<Vec<View<T>>> for View<T> {
82 fn from(nodes: Vec<View<T>>) -> Self {
83 View {
84 nodes: nodes.into_iter().flat_map(|v| v.nodes).collect(),
85 }
86 }
87}
88
89impl<T> From<Option<View<T>>> for View<T> {
90 fn from(node: Option<View<T>>) -> Self {
91 node.unwrap_or_default()
92 }
93}
94
95macro_rules! impl_view_from {
96 ($($ty:ty),*) => {
97 $(
98 impl<T: ViewHtmlNode> From<$ty> for View<T> {
99 fn from(t: $ty) -> Self {
100 View::from_node(T::create_text_node(t.into()))
101 }
102 }
103 )*
104 }
105}
106
107macro_rules! impl_view_from_to_string {
108 ($($ty:ty),*) => {
109 $(
110 impl<T: ViewHtmlNode> From<$ty> for View<T> {
111 fn from(t: $ty) -> Self {
112 View::from_node(T::create_text_node(t.to_string().into()))
113 }
114 }
115 )*
116 }
117}
118
119impl_view_from!(&'static str, String, Cow<'static, str>);
120impl_view_from_to_string!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64);
121
122impl<T: ViewNode, F: FnMut() -> U + 'static, U: Into<View<T>> + Any + 'static> From<F> for View<T> {
123 fn from(f: F) -> Self {
124 T::create_dynamic_view(f)
125 }
126}
127macro_rules! impl_from_tuple {
129 ($($name:ident),*) => {
130 paste::paste! {
131 impl<U, $($name),*> From<($($name,)*)> for View<U>
132 where
133 $($name: Into<View<U>>),*
134 {
135 fn from(t: ($($name,)*)) -> Self {
136 let ($([<$name:lower>]),*) = t;
137 #[allow(unused_mut)]
138 let mut nodes = SmallVec::new();
139 $(
140 nodes.extend([<$name:lower>].into().nodes);
141 )*
142 View { nodes }
143 }
144 }
145 }
146 };
147}
148
149impl_from_tuple!();
150impl_from_tuple!(A, B);
151impl_from_tuple!(A, B, C);
152impl_from_tuple!(A, B, C, D);
153impl_from_tuple!(A, B, C, D, E);
154impl_from_tuple!(A, B, C, D, E, F);
155impl_from_tuple!(A, B, C, D, E, F, G);
156impl_from_tuple!(A, B, C, D, E, F, G, H);
157impl_from_tuple!(A, B, C, D, E, F, G, H, I);
158impl_from_tuple!(A, B, C, D, E, F, G, H, I, J);
159
160pub trait ViewNode: Into<View<Self>> + Sized + 'static {
167 fn append_child(&mut self, child: Self);
170
171 fn append_view(&mut self, view: View<Self>) {
174 for node in view.nodes {
175 self.append_child(node);
176 }
177 }
178
179 fn create_dynamic_view<U: Into<View<Self>> + 'static>(
187 mut f: impl FnMut() -> U + 'static,
188 ) -> View<Self> {
189 f().into()
190 }
191}