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
//! Shortcut for terse component definitions. use crate::NeqAssign; use yew::{Component, ComponentLink, Html, Properties, ShouldRender}; use yew::virtual_dom::VNode; /// Allows immutable components to be declared using a single struct and two methods. /// /// This trait defers to its own message handling function versus using the `Emissive` trait like `PureComponent` does. /// /// If you pass more than one `Callback` as props, then the `Emissive` derive macro will only handle the first. /// While you could just implement Emissive manually, this trait facilitates keeping all your pure component /// functions under a single trait definition. /// /// This trait is blanket implemented for any `T: PureComponent + Emissive`, and is used with the `Pure` /// wrapper component. pub trait PureEmissiveComponent: Properties + PartialEq + Sized + 'static { /// The message to handled. type Message; /// Renders self to `Html`. fn render(&self) -> Html<Pure<Self>>; /// Sends a message. fn send_message(&self, _msg: Self::Message) {} } impl <T> PureEmissiveComponent for T where T: PureComponent + Emissive { type Message = <T as Emissive>::Message; fn render(&self) -> VNode<Pure<Self>> { <Self as PureComponent>::render(self) } fn send_message(&self, msg: Self::Message) { <Self as Emissive>::emit(self, msg) } } /// Allows immutable components to be declared using a single struct and a single method. pub trait PureComponent: Properties + Emissive + PartialEq + Sized + 'static { /// Renders self to `Html`. fn render(&self) -> Html<Pure<Self>>; } /// Derivable trait used to simplify calling callbacks in pure components. /// /// This trait is responsible for automating calling emit on a callback passed via props within types /// that implement `PureComponent`. /// /// # Note /// When deriving, the derive macro will attempt to locate a field with a `Callback<_>`. /// type and use the inner type of the callback to specify the `Message` type of `Emissive`. /// The derived `emit` function will call `self.<name of the callback struct>.emit(msg)`. /// /// If it cannot find a callback struct, the `Message` type will be set to `()` and `emit` will do nothing. pub trait Emissive { type Message; fn emit(&self, msg: Self::Message); } /// Wrapper component for pure components. /// /// Due to constraints in Rust's coherence rules, `Component` can't be implemented for any `T` that implements /// `PureComponent`, so instead this struct wraps a `T: PureComponent` and `Component` is implemented /// for this instead. /// /// # Example /// It is reasonable practice to use `Pure` as a prefix or `Impl` as a suffix to your pure component model /// and use an alias to provide a terser name to be used by other components: /// /// ``` /// use yew::Properties; /// use yew::Html; /// use yewtil::{PureComponent, Pure, Emissive}; /// /// #[derive(Properties, PartialEq, Emissive)] /// pub struct PureMyComponent { /// pub data: String /// } /// /// impl PureComponent for PureMyComponent { /// fn render(&self) -> Html<Pure<Self>> { ///# unimplemented!() /// // ... /// } /// } /// /// /// Use this from within `html!` macros. /// pub type MyComponent = Pure<PureMyComponent>; /// ``` #[derive(Debug)] pub struct Pure<T>(T); impl<T: PureEmissiveComponent + 'static> Component for Pure<T> { type Message = <T as PureEmissiveComponent>::Message; type Properties = T; fn create(props: Self::Properties, _link: ComponentLink<Self>) -> Self { Pure(props) } fn update(&mut self, msg: Self::Message) -> ShouldRender { self.0.send_message(msg); false } fn change(&mut self, props: Self::Properties) -> ShouldRender { self.0.neq_assign(props) } fn view(&self) -> Html<Self> { self.0.render() } }