use crate::element::{AnyValueEq, DynamicChildren, Element, IntoElement, Key};
use crate::reactive::{memo, signal, Signal};
use ferroui_base::{ObjectType, Ref};
use std::rc::Rc;
pub fn for_each<T, I, K, E>(
each: impl Fn() -> I + 'static,
key: impl Fn(&T) -> K + 'static,
view: impl Fn(T) -> E + 'static,
) -> Element
where
I: IntoIterator<Item = T>,
T: Clone + PartialEq + 'static,
K: Into<Key>,
E: IntoElement,
{
let view = Rc::new(view);
Element::Dynamic(DynamicChildren {
render: Rc::new(move || {
each()
.into_iter()
.map(|item| {
let key = key(&item).into();
let value: Rc<dyn AnyValueEq> = Rc::new(item.clone());
let view = view.clone();
let render: Rc<dyn Fn() -> Element> = Rc::new(move || view(item.clone()).into_element());
(Some(key), Some(value), render)
})
.collect()
}),
})
}
pub fn show<E: IntoElement>(when: impl Fn() -> bool + 'static, then: impl Fn() -> E + 'static) -> Element {
show_else(when, then, || Element::Empty)
}
pub fn show_else<E: IntoElement, O: IntoElement>(
when: impl Fn() -> bool + 'static,
then: impl Fn() -> E + 'static,
otherwise: impl Fn() -> O + 'static,
) -> Element {
let condition = memo(move |_| when());
let then: Rc<dyn Fn() -> Element> = Rc::new(move || then().into_element());
let otherwise: Rc<dyn Fn() -> Element> = Rc::new(move || otherwise().into_element());
Element::Dynamic(DynamicChildren {
render: Rc::new(move || {
let render = if condition.get() { then.clone() } else { otherwise.clone() };
vec![(None, None, render)]
}),
})
}
pub fn dynamic<E: IntoElement>(render: impl Fn() -> E + 'static) -> Element {
Element::Dynamic(DynamicChildren {
render: Rc::new(move || {
let element = render().into_element();
let children = match element {
Element::Fragment(items) => items,
Element::Empty => Vec::new(),
element => vec![element],
};
children
.into_iter()
.map(|child| {
let key = child.key().cloned();
let render: Rc<dyn Fn() -> Element> = Rc::new(move || child.clone());
(key, None, render)
})
.collect()
}),
})
}
pub struct NodeRef<T: ObjectType> {
control: Signal<Option<Ref<T>>>,
}
impl<T: ObjectType> Clone for NodeRef<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ObjectType> Copy for NodeRef<T> {}
impl<T: ObjectType> NodeRef<T> {
pub fn new() -> Self {
Self { control: signal(None) }
}
pub fn get(&self) -> Option<Ref<T>> {
self.control.get()
}
pub fn get_untracked(&self) -> Option<Ref<T>> {
self.control.get_untracked()
}
pub(crate) fn set(&self, control: Ref<T>) {
self.control.set(Some(control));
}
}
impl<T: ObjectType> Default for NodeRef<T> {
fn default() -> Self {
Self::new()
}
}