1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
//! Traits used to handle model messages and update element state accordingly. //! //! # Elements //! //! Elements are an interactive views, they contain their own state and interact //! with users via messages and update their state accordingly. Elements must //! implement the `Element` and `View` traits. //! //! ## App Element //! //! App element are normal elements but two main difference, the `Config` type is //! `Url` type, and the `PMsg` generic type have to be the same type as //! `Message` type, and this actully make sense becuase `PMsg` ment to hold the //! parent element message type and app elements doesn't have parent. //! //! # TODO Examples //! # TODO Helper types use crate::prelude::*; /// Trait used to create element and handle element messages and update /// element state accordingly. /// /// Element messages can be emitted by HTML events or by other elements, /// handling these messages is done inside the method `update`, both `init` /// function and `update` method receive `orders` argument which provide many /// useful methods to interact with the runtime library [Seed], for example we /// can subscribe to messages of some type, we can send messages to other /// elemenrs, we can perform async blocks and many more things (see [`Orders`]). /// /// [Seed]: https://seed-rs.org /// [`Orders`]: crate::prelude::Orders pub trait Element { /// Element message type Message: 'static; /// Configuration used to initialize this element type Config; /// Create and initialize the element /// /// # Arguments /// - `config` configuration used to create the element. /// - `orders` used to interacte with the runtime. fn init(config: Self::Config, orders: &mut impl Orders<Self::Message>) -> Self; /// update method that recive `Self::Message` and update the model state accordingly. fn update(&mut self, _: Self::Message, _: &mut impl Orders<Self::Message>); } /// Extension trait for `Element` when it's used on App element /// /// This trait provides functions that mounts the app element on HTML node by /// integrating app element with `seed::app::App` pub trait AppElementExt where Self: Element<Config = Url> + View<Node<<Self as Element>::Message>> + Sized, { /// Start app element /// /// # Example /// ``` /// use savory_core::prelude::*; /// use wasm_bindgen::prelude::*; /// /// pub struct MyApp; /// /// pub enum Msg { /// FooMessage, /// } /// /// impl Element for MyApp { /// type Message = Msg; /// type Config = Url; /// /// fn init(url: Url, orders: &mut impl Orders<Msg>) -> Self { /// // initialize the app goes here /// todo!() /// } /// /// fn update(&mut self, msg: Msg, orders: &mut impl Orders<Msg>) { /// // handling app messages goes here /// todo!() /// } /// } /// /// impl View<Node<Msg>> for MyApp { /// fn view(&self) -> Node<Msg> { /// // viewing the app goes here /// todo!() /// } /// } /// /// #[wasm_bindgen(start)] /// pub fn view() { /// MyApp::start(); /// } /// ``` fn start() -> seed::app::App<Self::Message, Self, Node<Self::Message>> { Self::start_at("app") } /// Start app element at specifec element that matchs the `id` passed fn start_at(id: &str) -> seed::app::App<Self::Message, Self, Node<Self::Message>> { seed::app::App::start( id, |url, orders| Self::init(url, orders), |msg, app, orders| app.update(msg, orders), |app| app.view(), ) } } impl<T> AppElementExt for T where Self: Element<Config = Url> + View<Node<<Self as Element>::Message>> + Sized { }