use crate::{Bus, Color, Css, Widget}; use dodrio::bumpalo; use std::rc::Rc; /// A generic [`Widget`]. /// /// It is useful to build composable user interfaces that do not leak /// implementation details in their __view logic__. /// /// If you have a [built-in widget], you should be able to use `Into` /// to turn it into an [`Element`]. /// /// [built-in widget]: mod@crate::widget #[allow(missing_debug_implementations)] pub struct Element<'a, Message> { pub(crate) widget: Box + 'a>, } impl<'a, Message> Element<'a, Message> { /// Create a new [`Element`] containing the given [`Widget`]. pub fn new(widget: impl Widget + 'a) -> Self { Self { widget: Box::new(widget), } } /// Applies a transformation to the produced message of the [`Element`]. /// /// This method is useful when you want to decouple different parts of your /// UI and make them __composable__. pub fn map(self, f: F) -> Element<'a, B> where Message: 'static, B: 'static, F: 'static + Fn(Message) -> B, { Element { widget: Box::new(Map::new(self.widget, f)), } } /// Marks the [`Element`] as _to-be-explained_. pub fn explain(self, _color: Color) -> Element<'a, Message> { self } /// Produces a VDOM node for the [`Element`]. pub fn node<'b>( &self, bump: &'b bumpalo::Bump, bus: &Bus, style_sheet: &mut Css<'b>, ) -> dodrio::Node<'b> { self.widget.node(bump, bus, style_sheet) } } struct Map<'a, A, B> { widget: Box + 'a>, mapper: Rc B>>, } impl<'a, A, B> Map<'a, A, B> { pub fn new(widget: Box + 'a>, mapper: F) -> Map<'a, A, B> where F: 'static + Fn(A) -> B, { Map { widget, mapper: Rc::new(Box::new(mapper)), } } } impl<'a, A, B> Widget for Map<'a, A, B> where A: 'static, B: 'static, { fn node<'b>( &self, bump: &'b bumpalo::Bump, bus: &Bus, style_sheet: &mut Css<'b>, ) -> dodrio::Node<'b> { self.widget .node(bump, &bus.map(self.mapper.clone()), style_sheet) } }