use super::handle::Element;
pub trait IntoView {
fn into_view(self) -> View;
}
pub type Children = ::std::rc::Rc<dyn ::std::ops::Fn() -> View + 'static>;
pub fn mount_children(children: &Children) -> Element {
let ph = super::create_phantom_element();
let view = children();
view.attach_to(ph);
ph
}
pub struct EachFn<T: 'static>(pub ::std::rc::Rc<dyn ::std::ops::Fn() -> Vec<T> + 'static>);
impl<T: 'static> Clone for EachFn<T> {
fn clone(&self) -> Self {
EachFn(::std::rc::Rc::clone(&self.0))
}
}
impl<T: 'static, F: Fn() -> Vec<T> + 'static> From<F> for EachFn<T> {
fn from(f: F) -> Self {
EachFn(::std::rc::Rc::new(f))
}
}
impl<T: 'static> EachFn<T> {
pub fn call(&self) -> Vec<T> {
(self.0)()
}
}
pub struct KeyFn<T: 'static, K: 'static>(pub ::std::rc::Rc<dyn ::std::ops::Fn(&T) -> K + 'static>);
impl<T: 'static, K: 'static> Clone for KeyFn<T, K> {
fn clone(&self) -> Self {
KeyFn(::std::rc::Rc::clone(&self.0))
}
}
impl<T: 'static, K: 'static, F: Fn(&T) -> K + 'static> From<F> for KeyFn<T, K> {
fn from(f: F) -> Self {
KeyFn(::std::rc::Rc::new(f))
}
}
impl<T: 'static, K: 'static> KeyFn<T, K> {
pub fn call(&self, item: &T) -> K {
(self.0)(item)
}
}
pub struct ItemFn<T: 'static>(pub ::std::rc::Rc<dyn ::std::ops::Fn(T) -> Element + 'static>);
impl<T: 'static> Clone for ItemFn<T> {
fn clone(&self) -> Self {
ItemFn(::std::rc::Rc::clone(&self.0))
}
}
impl<T: 'static, F: Fn(T) -> Element + 'static> From<F> for ItemFn<T> {
fn from(f: F) -> Self {
ItemFn(::std::rc::Rc::new(f))
}
}
impl<T: 'static> ItemFn<T> {
pub fn call(&self, item: T) -> Element {
(self.0)(item)
}
}
pub struct WhenFn(pub ::std::rc::Rc<dyn ::std::ops::Fn() -> bool + 'static>);
impl Clone for WhenFn {
fn clone(&self) -> Self {
WhenFn(::std::rc::Rc::clone(&self.0))
}
}
impl<F: Fn() -> bool + 'static> From<F> for WhenFn {
fn from(f: F) -> Self {
WhenFn(::std::rc::Rc::new(f))
}
}
impl WhenFn {
pub fn call(&self) -> bool {
(self.0)()
}
}
#[derive(Clone, Default)]
pub struct Fallback(pub Option<::std::rc::Rc<dyn ::std::ops::Fn() -> Element + 'static>>);
impl<F: Fn() -> Element + 'static> From<F> for Fallback {
fn from(f: F) -> Self {
Fallback(Some(::std::rc::Rc::new(f)))
}
}
#[derive(Debug, Clone)]
pub enum View {
Element(Element),
Text(String),
Fragment(Vec<View>),
Empty,
}
impl View {
pub fn attach_to(self, parent: Element) -> Vec<Element> {
let mut out = Vec::new();
self.materialise_into(parent, &mut out);
out
}
fn materialise_into(self, parent: Element, out: &mut Vec<Element>) {
match self {
View::Element(h) => {
super::append_child(parent, h);
out.push(h);
}
View::Text(s) => {
let h = super::create_element(crate::element::ElementTag::RawText);
super::set_attribute(h, "text", &s);
super::append_child(parent, h);
out.push(h);
}
View::Fragment(children) => {
for child in children {
child.materialise_into(parent, out);
}
}
View::Empty => {}
}
}
pub fn elements(&self) -> Vec<Element> {
let mut out = Vec::new();
self.collect_into(&mut out);
out
}
fn collect_into(&self, out: &mut Vec<Element>) {
match self {
View::Element(h) => out.push(*h),
View::Fragment(children) => {
for c in children {
c.collect_into(out);
}
}
View::Text(_) | View::Empty => {}
}
}
}
impl IntoView for View {
fn into_view(self) -> View {
self
}
}
impl IntoView for Element {
fn into_view(self) -> View {
View::Element(self)
}
}
impl IntoView for () {
fn into_view(self) -> View {
View::Empty
}
}
impl<T: IntoView> IntoView for Option<T> {
fn into_view(self) -> View {
match self {
Some(v) => v.into_view(),
None => View::Empty,
}
}
}
impl IntoView for String {
fn into_view(self) -> View {
View::Text(self)
}
}
impl IntoView for &str {
fn into_view(self) -> View {
View::Text(self.to_owned())
}
}
impl IntoView for &String {
fn into_view(self) -> View {
View::Text(self.clone())
}
}
macro_rules! impl_into_view_via_display {
($($t:ty),+) => {
$(
impl IntoView for $t {
fn into_view(self) -> View {
View::Text(self.to_string())
}
}
)+
};
}
impl_into_view_via_display!(i8, i16, i32, i64, i128, isize);
impl_into_view_via_display!(u8, u16, u32, u64, u128, usize);
impl_into_view_via_display!(f32, f64, bool, char);
macro_rules! impl_into_view_tuple {
($($name:ident),+) => {
impl<$($name: IntoView),+> IntoView for ($($name,)+) {
#[allow(non_snake_case)]
fn into_view(self) -> View {
let ($($name,)+) = self;
View::Fragment(vec![$($name.into_view()),+])
}
}
};
}
impl_into_view_tuple!(A);
impl_into_view_tuple!(A, B);
impl_into_view_tuple!(A, B, C);
impl_into_view_tuple!(A, B, C, D);
impl_into_view_tuple!(A, B, C, D, E);
impl_into_view_tuple!(A, B, C, D, E, F);
impl_into_view_tuple!(A, B, C, D, E, F, G);
impl_into_view_tuple!(A, B, C, D, E, F, G, H);