diff --git a/README.md b/README.md index 10633d9..489328b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ use yew::html; html! { -} +}; ``` ## Getting started diff --git a/material-yew/Cargo.toml b/material-yew/Cargo.toml index c248310..d4e6706 100644 --- a/material-yew/Cargo.toml +++ b/material-yew/Cargo.toml @@ -14,7 +14,7 @@ description = "Yew wrapper for Material Web Components" [dependencies] wasm-bindgen = "0.2" -yew = { version = "0.18", default-features = false, features = ["web_sys"] } +yew = { version = "0.19"} js-sys = "0.3" paste = "1.0" gloo = "0.2" diff --git a/material-yew/src/button.rs b/material-yew/src/button.rs index 8a9285e..726ddea 100644 --- a/material-yew/src/button.rs +++ b/material-yew/src/button.rs @@ -1,7 +1,7 @@ use crate::bool_to_option; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-button.js")] extern "C" { @@ -19,11 +19,11 @@ loader_hack!(Button); /// Props for [`MatButton`] /// /// [MWC Documentation for properties](https://github.com/material-components/material-components-web-components/tree/master/packages/button#propertiesattributes) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct ButtonProps { pub label: String, #[prop_or_default] - pub icon: Option>, + pub icon: Option, #[prop_or_default] pub raised: bool, #[prop_or_default] @@ -43,16 +43,16 @@ component!( ButtonProps, |props: &ButtonProps| { html! { - + } }, Button, diff --git a/material-yew/src/checkbox.rs b/material-yew/src/checkbox.rs index 14f6127..83ef476 100644 --- a/material-yew/src/checkbox.rs +++ b/material-yew/src/checkbox.rs @@ -1,9 +1,9 @@ use crate::bool_to_option; use gloo::events::EventListener; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use web_sys::{Element, Node}; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-checkbox.js")] extern "C" { @@ -27,7 +27,6 @@ loader_hack!(Checkbox); /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/checkbox) pub struct MatCheckbox { - props: CheckboxProps, node_ref: NodeRef, change_listener: Option, } @@ -38,7 +37,7 @@ pub struct MatCheckbox { /// /// - [Properties](https://github.com/material-components/material-components-web-components/tree/master/packages/checkbox#propertiesattributes) /// - [Events](https://github.com/material-components/material-components-web-components/tree/master/packages/checkbox#events) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct CheckboxProps { #[prop_or_default] pub checked: bool, @@ -47,7 +46,7 @@ pub struct CheckboxProps { #[prop_or_default] pub disabled: bool, #[prop_or_default] - pub value: Cow<'static, str>, + pub value: Option, #[prop_or_default] pub reduced_touch_target: bool, /// Binds to `change` event on `mwc-checkbox` @@ -61,42 +60,34 @@ impl Component for MatCheckbox { type Message = (); type Properties = CheckboxProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { + fn create(_: &Context) -> Self { Checkbox::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), change_listener: None, } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - + } } - fn rendered(&mut self, _first_render: bool) { + fn rendered(&mut self, ctx: &Context, _first_render: bool) { + let props = ctx.props(); let element = self.node_ref.cast::().unwrap(); - element.set_checked(self.props.checked); + element.set_checked(props.checked); if self.change_listener.is_none() { - let callback = self.props.onchange.clone(); + let callback = props.onchange.clone(); let target = self.node_ref.cast::().unwrap(); self.change_listener = Some(EventListener::new(&target, "change", move |_| { callback.emit(element.checked()); diff --git a/material-yew/src/circular_progress.rs b/material-yew/src/circular_progress.rs index 53414f6..7e0a4c6 100644 --- a/material-yew/src/circular_progress.rs +++ b/material-yew/src/circular_progress.rs @@ -18,7 +18,7 @@ loader_hack!(CircularProgress); /// Props for [`MatCircularProgress`] /// /// [MWC Documentation for properties](https://github.com/material-components/material-components-web-components/tree/master/packages/circular-progress#propertiesattributes) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct CircularProgressProps { #[prop_or_default] pub indeterminate: bool, @@ -35,12 +35,12 @@ component!( CircularProgressProps, |props: &CircularProgressProps| { html! { - + } }, CircularProgress, diff --git a/material-yew/src/circular_progress_four_color.rs b/material-yew/src/circular_progress_four_color.rs index 8a69560..6c1a8ca 100644 --- a/material-yew/src/circular_progress_four_color.rs +++ b/material-yew/src/circular_progress_four_color.rs @@ -18,7 +18,7 @@ loader_hack!(CircularProgressFourColor); /// Props for [`MatCircularProgressFourColor`] /// /// [MWC Documentation for properties](https://github.com/material-components/material-components-web-components/tree/master/packages/circular-progress-four-color#propertiesattributes) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct CircularProgressFourColorProps { #[prop_or_default] pub indeterminate: bool, @@ -35,12 +35,12 @@ component!( CircularProgressFourColorProps, |props: &CircularProgressFourColorProps| { html! { - + } }, CircularProgressFourColor, diff --git a/material-yew/src/dialog.rs b/material-yew/src/dialog.rs index 78ea40d..2eaadf3 100644 --- a/material-yew/src/dialog.rs +++ b/material-yew/src/dialog.rs @@ -4,10 +4,10 @@ pub use dialog_action::*; use crate::{bool_to_option, event_details_into, WeakComponentLink}; use gloo::events::EventListener; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use web_sys::{Element, Node}; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-dialog.js")] extern "C" { @@ -42,7 +42,6 @@ loader_hack!(Dialog); /// In order to pass actions, [`MatDialogAction`] component should be /// used. pub struct MatDialog { - props: DialogProps, node_ref: NodeRef, opening_listener: Option, opened_listener: Option, @@ -56,7 +55,7 @@ pub struct MatDialog { /// /// - [Properties](https://github.com/material-components/material-components-web-components/tree/master/packages/dialog#propertiesattributes) /// - [Events](https://github.com/material-components/material-components-web-components/tree/master/packages/dialog#events) -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct DialogProps { #[prop_or_default] pub open: bool, @@ -65,17 +64,17 @@ pub struct DialogProps { #[prop_or_default] pub stacked: bool, #[prop_or_default] - pub heading: Option>, + pub heading: Option, #[prop_or_default] - pub scrim_click_action: Option>, + pub scrim_click_action: Option, #[prop_or_default] - pub escape_key_action: Option>, + pub escape_key_action: Option, #[prop_or_default] - pub default_action: Option>, + pub default_action: Option, #[prop_or_default] - pub action_attribute: Option>, + pub action_attribute: Option, #[prop_or_default] - pub initial_focus_attribute: Option>, + pub initial_focus_attribute: Option, /// Binds to `opening` event on `mwc-dialog` /// /// See events docs to learn more. @@ -113,11 +112,13 @@ impl Component for MatDialog { type Message = (); type Properties = DialogProps; - fn create(props: Self::Properties, link: ComponentLink) -> Self { - props.dialog_link.borrow_mut().replace(link); + fn create(ctx: &Context) -> Self { + ctx.props() + .dialog_link + .borrow_mut() + .replace(ctx.link().clone()); Dialog::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), opening_listener: None, opened_listener: None, @@ -126,58 +127,52 @@ impl Component for MatDialog { } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - { self.props.children.clone() } + open={props.open} + hideActions={bool_to_option(props.hide_action)} + stacked={bool_to_option(props.stacked)} + heading={props.heading.clone()} + scrimClickAction={props.scrim_click_action.clone()} + escapeKeyAction={props.escape_key_action.clone()} + defaultAction={props.default_action.clone()} + actionAttribute={props.action_attribute.clone()} + initialFocusAttribute={props.initial_focus_attribute.clone()} + ref={self.node_ref.clone()} + > + {props.children.clone()} - } + } } - fn rendered(&mut self, _first_render: bool) { + fn rendered(&mut self, ctx: &Context, _first_render: bool) { + let props = ctx.props(); let element = self.node_ref.cast::().unwrap(); if self.opening_listener.is_none() { - let onopening = self.props.onopening.clone(); + let onopening = props.onopening.clone(); self.opening_listener = Some(EventListener::new(&element, "opening", move |_| { onopening.emit(()) })); } if self.opened_listener.is_none() { - let onopened = self.props.onopened.clone(); + let onopened = props.onopened.clone(); self.opened_listener = Some(EventListener::new(&element, "opened", move |_| { onopened.emit(()) })); } if self.closing_listener.is_none() { - let onclosing = self.props.onclosing.clone(); + let onclosing = props.onclosing.clone(); self.closing_listener = Some(EventListener::new(&element, "closing", move |event| { onclosing.emit(action_from_event(event)) })); } if self.closed_listener.is_none() { - let onclosed = self.props.onclosed.clone(); + let onclosed = props.onclosed.clone(); self.closed_listener = Some(EventListener::new(&element, "closed", move |event| { onclosed.emit(action_from_event(event)) })); diff --git a/material-yew/src/dialog/dialog_action.rs b/material-yew/src/dialog/dialog_action.rs index a631dc8..cb471de 100644 --- a/material-yew/src/dialog/dialog_action.rs +++ b/material-yew/src/dialog/dialog_action.rs @@ -1,9 +1,9 @@ -use std::borrow::Cow; use std::fmt; use yew::prelude::*; +use yew::virtual_dom::AttrValue; /// Dialog action type. -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum ActionType { /// Binds `to slot` of `primaryAction` Primary, @@ -12,27 +12,26 @@ pub enum ActionType { } impl ActionType { - fn to_cow_string(&self) -> Cow<'static, str> { - let s = match self { + fn as_str(&self) -> &'static str { + match self { ActionType::Primary => "primaryAction", ActionType::Secondary => "secondaryAction", - }; - Cow::from(s) + } } } impl fmt::Display for ActionType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.to_cow_string()) + write!(f, "{}", self.as_str()) } } /// Props for [`MatDialogAction`] -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct ActionProps { pub action_type: ActionType, #[prop_or_default] - pub action: Option>, + pub action: Option, pub children: Children, } @@ -41,47 +40,37 @@ pub struct ActionProps { /// If the child passed is an element (a `VTag`), then it is modified to include /// the appropriate attributes. Otherwise, the child is wrapped in a `span` /// containing said attributes. -pub struct MatDialogAction { - props: ActionProps, -} +pub struct MatDialogAction {} impl Component for MatDialogAction { type Message = (); type Properties = ActionProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { - Self { props } - } - - fn update(&mut self, _msg: Self::Message) -> bool { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true + fn create(_: &Context) -> Self { + Self {} } - fn view(&self) -> Html { - let children = self.props.children.iter().map(|child| { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); + let children = props.children.iter().map(|child| { match child { Html::VTag(mut vtag) => { - vtag.add_attribute("slot", self.props.action_type.to_string()); - if let Some(action) = self.props.action.as_ref() { + vtag.add_attribute("slot", props.action_type.to_string()); + if let Some(action) = props.action.as_ref() { vtag.add_attribute("dialogAction", action.to_owned()); - } + } Html::VTag(vtag) - } + } _ => html! { - - { child } + + {child} - } - } - }).collect::(); + } + } + }).collect::(); html! { - { children } + {children} } } } diff --git a/material-yew/src/drawer.rs b/material-yew/src/drawer.rs index 6cbb8b3..ae279e6 100644 --- a/material-yew/src/drawer.rs +++ b/material-yew/src/drawer.rs @@ -10,10 +10,10 @@ pub use drawer_title::*; use crate::{bool_to_option, WeakComponentLink}; use gloo::events::EventListener; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use web_sys::Node; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-drawer.js")] extern "C" { @@ -40,7 +40,6 @@ loader_hack!(Drawer); /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/drawer) pub struct MatDrawer { - props: DrawerProps, node_ref: NodeRef, opened_listener: Option, closed_listener: Option, @@ -52,14 +51,14 @@ pub struct MatDrawer { /// /// - [Properties](https://github.com/material-components/material-components-web-components/tree/master/packages/drawer#propertiesattributes) /// - [Events](https://github.com/material-components/material-components-web-components/tree/master/packages/drawer#events) -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct DrawerProps { #[prop_or_default] pub open: bool, #[prop_or_default] pub has_header: bool, #[prop_or_default] - pub drawer_type: Cow<'static, str>, + pub drawer_type: Option, /// Binds to `opened` event on `mwc-drawer` /// /// See events docs to learn more. @@ -79,41 +78,42 @@ impl Component for MatDrawer { type Message = (); type Properties = DrawerProps; - fn create(props: Self::Properties, link: ComponentLink) -> Self { - props.drawer_link.borrow_mut().replace(link); + fn create(ctx: &Context) -> Self { + ctx.props() + .drawer_link + .borrow_mut() + .replace(ctx.link().clone()); Drawer::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), opened_listener: None, closed_listener: None, } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - - { self.props.children.clone() } + + {props.children.clone()} - } + } } - fn rendered(&mut self, _first_render: bool) { + fn rendered(&mut self, ctx: &Context, _first_render: bool) { + let props = ctx.props(); let element = self.node_ref.cast::().unwrap(); - element.set_type(&JsValue::from(self.props.drawer_type.as_ref())); - element.set_open(self.props.open); + element.set_type(&JsValue::from( + props + .drawer_type + .as_ref() + .map(|s| s.as_ref()) + .unwrap_or_default(), + )); + element.set_open(props.open); if self.opened_listener.is_none() { - let onopen_callback = self.props.onopened.clone(); + let onopen_callback = props.onopened.clone(); self.opened_listener = Some(EventListener::new( &element, "MDCDrawer:opened", @@ -124,7 +124,7 @@ impl Component for MatDrawer { } if self.closed_listener.is_none() { - let onclose_callback = self.props.onclosed.clone(); + let onclose_callback = props.onclosed.clone(); self.closed_listener = Some(EventListener::new( &element, "MDCDrawer:closed", diff --git a/material-yew/src/drawer/drawer_app_content.rs b/material-yew/src/drawer/drawer_app_content.rs index 6ea948b..245e71a 100644 --- a/material-yew/src/drawer/drawer_app_content.rs +++ b/material-yew/src/drawer/drawer_app_content.rs @@ -3,7 +3,7 @@ use yew::prelude::*; const SLOT: &str = "appContent"; /// Props for [`MatDrawerAppContent`] -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct DrawerAppContentProps { pub children: Children, } @@ -13,30 +13,19 @@ pub struct DrawerAppContentProps { /// If the child passed is an element (a `VTag`), then it is modified to include /// the appropriate attributes. Otherwise, the child is wrapped in a `span` /// containing said attributes. -pub struct MatDrawerAppContent { - props: DrawerAppContentProps, -} +pub struct MatDrawerAppContent {} impl Component for MatDrawerAppContent { type Message = (); type Properties = DrawerAppContentProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { - Self { props } - } - - fn update(&mut self, _msg: Self::Message) -> bool { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true + fn create(_: &Context) -> Self { + Self {} } - fn view(&self) -> Html { - let children = self - .props + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); + let children = props .children .iter() .map(|child| { @@ -47,9 +36,9 @@ impl Component for MatDrawerAppContent { } _ => { html! { - - { child } - + + {child} + } } } @@ -57,7 +46,7 @@ impl Component for MatDrawerAppContent { .collect::(); html! { - { children } + {children} } } } diff --git a/material-yew/src/drawer/drawer_header.rs b/material-yew/src/drawer/drawer_header.rs index a116dfc..f5a5f99 100644 --- a/material-yew/src/drawer/drawer_header.rs +++ b/material-yew/src/drawer/drawer_header.rs @@ -3,7 +3,7 @@ use yew::prelude::*; const SLOT: &str = "header"; /// Props for [`MatDrawerHeader`] -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct DrawerHeaderProps { pub children: Children, } @@ -13,30 +13,19 @@ pub struct DrawerHeaderProps { /// If the child passed is an element (a `VTag`), then it is modified to include /// the appropriate attributes. Otherwise, the child is wrapped in a `span` /// containing said attributes. -pub struct MatDrawerHeader { - props: DrawerHeaderProps, -} +pub struct MatDrawerHeader {} impl Component for MatDrawerHeader { type Message = (); type Properties = DrawerHeaderProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { - Self { props } - } - - fn update(&mut self, _msg: Self::Message) -> bool { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true + fn create(_: &Context) -> Self { + Self {} } - fn view(&self) -> Html { - let children = self - .props + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); + let children = props .children .iter() .map(|child| { @@ -47,9 +36,9 @@ impl Component for MatDrawerHeader { } _ => { html! { - - { child } - + + {child} + } } } @@ -57,7 +46,7 @@ impl Component for MatDrawerHeader { .collect::(); html! { - { children } + {children} } } } diff --git a/material-yew/src/drawer/drawer_subtitle.rs b/material-yew/src/drawer/drawer_subtitle.rs index 660b311..678e69f 100644 --- a/material-yew/src/drawer/drawer_subtitle.rs +++ b/material-yew/src/drawer/drawer_subtitle.rs @@ -3,7 +3,7 @@ use yew::prelude::*; const SLOT: &str = "subtitle"; /// Props for [`MatDrawerSubtitle`] -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct DrawerSubtitleProps { pub children: Children, } @@ -13,30 +13,19 @@ pub struct DrawerSubtitleProps { /// If the child passed is an element (a `VTag`), then it is modified to include /// the appropriate attributes. Otherwise, the child is wrapped in a `span` /// containing said attributes. -pub struct MatDrawerSubtitle { - props: DrawerSubtitleProps, -} +pub struct MatDrawerSubtitle {} impl Component for MatDrawerSubtitle { type Message = (); type Properties = DrawerSubtitleProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { - Self { props } - } - - fn update(&mut self, _msg: Self::Message) -> bool { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true + fn create(_: &Context) -> Self { + Self {} } - fn view(&self) -> Html { - let children = self - .props + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); + let children = props .children .iter() .map(|child| { @@ -47,9 +36,9 @@ impl Component for MatDrawerSubtitle { } _ => { html! { - - { child } - + + {child} + } } } @@ -57,7 +46,7 @@ impl Component for MatDrawerSubtitle { .collect::(); html! { - { children } + {children} } } } diff --git a/material-yew/src/drawer/drawer_title.rs b/material-yew/src/drawer/drawer_title.rs index 3d072e1..79477c1 100644 --- a/material-yew/src/drawer/drawer_title.rs +++ b/material-yew/src/drawer/drawer_title.rs @@ -3,7 +3,7 @@ use yew::prelude::*; const SLOT: &str = "title"; /// Props for [`MatDrawerTitle`] -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct DrawerTitleProps { pub children: Children, } @@ -13,30 +13,19 @@ pub struct DrawerTitleProps { /// If the child passed is an element (a `VTag`), then it is modified to include /// the appropriate attributes. Otherwise, the child is wrapped in a `span` /// containing said attributes. -pub struct MatDrawerTitle { - props: DrawerTitleProps, -} +pub struct MatDrawerTitle {} impl Component for MatDrawerTitle { type Message = (); type Properties = DrawerTitleProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { - Self { props } - } - - fn update(&mut self, _msg: Self::Message) -> bool { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true + fn create(_: &Context) -> Self { + Self {} } - fn view(&self) -> Html { - let children = self - .props + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); + let children = props .children .iter() .map(|child| { @@ -47,9 +36,9 @@ impl Component for MatDrawerTitle { } _ => { html! { - - { child } - + + {child} + } } } @@ -57,7 +46,7 @@ impl Component for MatDrawerTitle { .collect::(); html! { - { children } + {children} } } } diff --git a/material-yew/src/fab.rs b/material-yew/src/fab.rs index 32ee6a6..bf83955 100644 --- a/material-yew/src/fab.rs +++ b/material-yew/src/fab.rs @@ -1,7 +1,7 @@ use crate::bool_to_option; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-fab.js")] extern "C" { @@ -17,12 +17,12 @@ loader_hack!(Fab); /// Props for [`MatFab`] /// /// [MWC Documentation for properties](https://github.com/material-components/material-components-web-components/tree/master/packages/fab#propertiesattributes) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct FabProps { #[prop_or_default] - pub icon: Cow<'static, str>, + pub icon: Option, #[prop_or_default] - pub label: Cow<'static, str>, + pub label: Option, #[prop_or_default] pub mini: bool, #[prop_or_default] @@ -40,14 +40,14 @@ component!( FabProps, |props: &FabProps| { html! { - { props.children.clone() } + {props.children.clone()} } }, Fab, diff --git a/material-yew/src/form_field.rs b/material-yew/src/form_field.rs index 3d054bd..383e319 100644 --- a/material-yew/src/form_field.rs +++ b/material-yew/src/form_field.rs @@ -1,7 +1,7 @@ use crate::bool_to_option; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-formfield.js")] extern "C" { @@ -17,11 +17,11 @@ loader_hack!(Formfield); /// Props for [`MatFormfield`] /// /// [MWC Documentation for properties](https://github.com/material-components/material-components-web-components/tree/master/packages/formfield#propertiesattributes) -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct FormfieldProps { pub children: Children, #[prop_or_default] - pub label: Cow<'static, str>, + pub label: Option, #[prop_or_default] pub align_end: bool, #[prop_or_default] @@ -35,12 +35,12 @@ component!( FormfieldProps, |props: &FormfieldProps| { html! { - { props.children.clone() } + {props.children.clone()} } }, Formfield, diff --git a/material-yew/src/icon.rs b/material-yew/src/icon.rs index db4b02f..5c782cd 100644 --- a/material-yew/src/icon.rs +++ b/material-yew/src/icon.rs @@ -15,7 +15,7 @@ loader_hack!(Icon); /// Props for [`MatIcon`] /// /// [MWC Documentation for properties](https://github.com/material-components/material-components-web-components/tree/master/packages/icon#propertiesattributes) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct IconProps { pub children: Children, } @@ -25,7 +25,7 @@ component!( IconProps, |props: &IconProps| { html! { - { props.children.clone() } + {props.children.clone()} } }, Icon, diff --git a/material-yew/src/icon_button.rs b/material-yew/src/icon_button.rs index 4fd6946..32e2f87 100644 --- a/material-yew/src/icon_button.rs +++ b/material-yew/src/icon_button.rs @@ -1,6 +1,6 @@ -use std::borrow::Cow; use wasm_bindgen::prelude::*; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-icon-button.js")] extern "C" { @@ -16,12 +16,12 @@ loader_hack!(IconButton); /// Props for [`MatIconButton`] /// /// [MWC Documentation for properties](https://github.com/material-components/material-components-web-components/tree/master/packages/icon-button#propertiesattributes) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct IconButtonProps { #[prop_or_default] - pub label: Cow<'static, str>, + pub label: Option, #[prop_or_default] - pub icon: Cow<'static, str>, + pub icon: Option, #[prop_or_default] pub disabled: bool, #[prop_or_default] @@ -33,11 +33,11 @@ component!( IconButtonProps, |props: &IconButtonProps| { html! { - { props.children.clone() } + {props.children.clone()} } }, IconButton, diff --git a/material-yew/src/icon_button_toggle.rs b/material-yew/src/icon_button_toggle.rs index 4be89aa..935304f 100644 --- a/material-yew/src/icon_button_toggle.rs +++ b/material-yew/src/icon_button_toggle.rs @@ -6,10 +6,10 @@ pub use on_icon::*; use crate::bool_to_option; use gloo::events::EventListener; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use web_sys::Node; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-icon-button-toggle.js")] extern "C" { @@ -30,7 +30,6 @@ loader_hack!(IconButtonToggle); /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/icon-button-toggle) pub struct MatIconButtonToggle { - props: IconButtonToggleProps, node_ref: NodeRef, change_listener: Option, } @@ -41,16 +40,16 @@ pub struct MatIconButtonToggle { /// /// - [Properties](https://github.com/material-components/material-components-web-components/tree/master/packages/icon-button-toggle#propertiesattributes) /// - [Events](https://github.com/material-components/material-components-web-components/tree/master/packages/icon-button-toggle#events) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct IconButtonToggleProps { #[prop_or_default] pub on: bool, #[prop_or_default] - pub on_icon: Cow<'static, str>, + pub on_icon: Option, #[prop_or_default] - pub off_icon: Cow<'static, str>, + pub off_icon: Option, #[prop_or_default] - pub label: Cow<'static, str>, + pub label: Option, #[prop_or_default] pub disabled: bool, /// Binds to `MDCIconButtonToggle:change`. @@ -68,42 +67,34 @@ impl Component for MatIconButtonToggle { type Message = (); type Properties = IconButtonToggleProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { + fn create(_: &Context) -> Self { IconButtonToggle::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), change_listener: None, } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - { self.props.children.clone() } + {props.children.clone()} } } - fn rendered(&mut self, _first_render: bool) { + fn rendered(&mut self, ctx: &Context, _first_render: bool) { + let props = ctx.props(); if self.change_listener.is_none() { let element = self.node_ref.cast::().unwrap(); - let callback = self.props.onchange.clone(); + let callback = props.onchange.clone(); self.change_listener = Some(EventListener::new( &element.clone(), "MDCIconButtonToggle:change", diff --git a/material-yew/src/icon_button_toggle/off_icon.rs b/material-yew/src/icon_button_toggle/off_icon.rs index 347464b..4794c04 100644 --- a/material-yew/src/icon_button_toggle/off_icon.rs +++ b/material-yew/src/icon_button_toggle/off_icon.rs @@ -3,7 +3,7 @@ use yew::prelude::*; const SLOT: &str = "offIcon"; /// Props for [`MatOffIconButtonToggle`] -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct OffIconButtonToggleProps { pub children: Children, } @@ -13,30 +13,19 @@ pub struct OffIconButtonToggleProps { /// If the child passed is an element (a `VTag`), then it is modified to include /// the appropriate attributes. Otherwise, the child is wrapped in a `span` /// containing said attributes. -pub struct MatOffIconButtonToggle { - props: OffIconButtonToggleProps, -} +pub struct MatOffIconButtonToggle {} impl Component for MatOffIconButtonToggle { type Message = (); type Properties = OffIconButtonToggleProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { - Self { props } - } - - fn update(&mut self, _msg: Self::Message) -> bool { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true + fn create(_: &Context) -> Self { + Self {} } - fn view(&self) -> Html { - let children = self - .props + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); + let children = props .children .iter() .map(|child| { @@ -47,9 +36,9 @@ impl Component for MatOffIconButtonToggle { } _ => { html! { - - { child } - + + {child} + } } } @@ -57,7 +46,7 @@ impl Component for MatOffIconButtonToggle { .collect::(); html! { - { children } + {children} } } } diff --git a/material-yew/src/icon_button_toggle/on_icon.rs b/material-yew/src/icon_button_toggle/on_icon.rs index 8f94fbd..16f0d8b 100644 --- a/material-yew/src/icon_button_toggle/on_icon.rs +++ b/material-yew/src/icon_button_toggle/on_icon.rs @@ -3,7 +3,7 @@ use yew::prelude::*; const SLOT: &str = "onIcon"; /// Props for [`MatOnIconButtonToggle`] -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct OnIconButtonToggleProps { pub children: Children, } @@ -13,30 +13,19 @@ pub struct OnIconButtonToggleProps { /// If the child passed is an element (a `VTag`), then it is modified to include /// the appropriate attributes. Otherwise, the child is wrapped in a `span` /// containing said attributes. -pub struct MatOnIconButtonToggle { - props: OnIconButtonToggleProps, -} +pub struct MatOnIconButtonToggle {} impl Component for MatOnIconButtonToggle { type Message = (); type Properties = OnIconButtonToggleProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { - Self { props } - } - - fn update(&mut self, _msg: Self::Message) -> bool { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true + fn create(_: &Context) -> Self { + Self {} } - fn view(&self) -> Html { - let children = self - .props + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); + let children = props .children .iter() .map(|child| { @@ -47,9 +36,9 @@ impl Component for MatOnIconButtonToggle { } _ => { html! { - - { child } - + + {child} + } } } @@ -57,7 +46,7 @@ impl Component for MatOnIconButtonToggle { .collect::(); html! { - { children } + {children} } } } diff --git a/material-yew/src/lib.rs b/material-yew/src/lib.rs index 48237f8..abd29f7 100644 --- a/material-yew/src/lib.rs +++ b/material-yew/src/lib.rs @@ -1,5 +1,7 @@ #![doc(html_root_url = "/docs")] - +// See: https://github.com/rustwasm/wasm-bindgen/issues/2774 +// Can remove when wasm-bindgen is updated. +#![allow(clippy::unused_unit)] //! A Material components library for [Yew](https://yew.rs). It wrpas around [Material Web Components](https://github.com/material-components/material-components-web-components) exposing Yew components. //! //! Example usage: @@ -9,7 +11,7 @@ //! //! html! { //! -//! } +//! }; //! ``` //! //! All the main components from the modules are re-exported. @@ -45,44 +47,35 @@ macro_rules! component { #[doc = "The `mwc-" $mwc_name "` component"] #[doc = ""] #[doc = "[MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/"$mwc_name")"] - pub struct $comp { - props: $props - } - } + pub struct $comp; + } impl yew::Component for $comp { type Message = (); type Properties = $props; - fn create(props: Self::Properties, _: ComponentLink) -> Self { + fn create(_: &Context) -> Self { $mwc_to_initialize::ensure_loaded(); - Self { props } - } - - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { - $html(&self.props) - } - } - }; + Self + } + + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); + $html(props) + } + } + }; } -fn bool_to_option(value: bool) -> Option> { - value.then(|| Cow::from("true")) +fn bool_to_option(value: bool) -> Option { + value.then(|| AttrValue::Static("true")) } -fn to_option_string(s: impl Display) -> Option> { +fn to_option_string(s: impl Display) -> Option { let s = s.to_string(); - match s.as_str() { - "" => None, - _ => Some(Cow::from(s)), + if s.is_empty() { + None + } else { + Some(AttrValue::Owned(s)) } } @@ -241,10 +234,10 @@ pub mod menu; #[doc(hidden)] pub use menu::MatMenu; -use std::borrow::Cow; use std::fmt::Display; #[doc(hidden)] pub use utils::WeakComponentLink; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/core.js")] extern "C" { diff --git a/material-yew/src/linear_progress.rs b/material-yew/src/linear_progress.rs index 298a31b..23b73bc 100644 --- a/material-yew/src/linear_progress.rs +++ b/material-yew/src/linear_progress.rs @@ -16,7 +16,7 @@ loader_hack!(LinearProgress); /// Props for [`MatLinearProgress`] /// /// [MWC Documentation for properties](https://github.com/material-components/material-components-web-components/tree/master/packages/linear-progress#propertiesattributes) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct LinearProgressProps { #[prop_or_default] pub indeterminate: bool, @@ -35,13 +35,13 @@ component!( LinearProgressProps, |props: &LinearProgressProps| { html! { - + } }, LinearProgress, diff --git a/material-yew/src/list.rs b/material-yew/src/list.rs index f94217c..c7f99f6 100644 --- a/material-yew/src/list.rs +++ b/material-yew/src/list.rs @@ -24,10 +24,10 @@ pub use graphic_type::GraphicType; use crate::{bool_to_option, event_into_details, WeakComponentLink}; use gloo::events::EventListener; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use web_sys::Node; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-list.js")] extern "C" { @@ -57,7 +57,6 @@ loader_hack!(List); /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/list) pub struct MatList { - props: ListProps, node_ref: NodeRef, action_listener: Option, selected_listener: Option, @@ -69,7 +68,7 @@ pub struct MatList { /// /// - [Properties](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-list-1) /// - [Events](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-list-2) -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct ListProps { #[prop_or_default] pub activatable: bool, @@ -80,9 +79,9 @@ pub struct ListProps { #[prop_or_default] pub wrap_focus: bool, #[prop_or_default] - pub item_roles: Option>, + pub item_roles: Option, #[prop_or_default] - pub inner_role: Option>, + pub inner_role: Option, #[prop_or_default] pub noninteractive: bool, /// Binds to `action` event on `mwc-list` @@ -106,47 +105,42 @@ impl Component for MatList { type Message = (); type Properties = ListProps; - fn create(props: Self::Properties, link: ComponentLink) -> Self { - props.list_link.borrow_mut().replace(link); + fn create(ctx: &Context) -> Self { + ctx.props() + .list_link + .borrow_mut() + .replace(ctx.link().clone()); List::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), action_listener: None, selected_listener: None, } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - - { self.props.children.clone() } - + + {props.children.clone()} + } } - fn rendered(&mut self, _first_render: bool) { + fn rendered(&mut self, ctx: &Context, _first_render: bool) { + let props = ctx.props(); let list = self.node_ref.cast::().unwrap(); if self.selected_listener.is_none() { - let onselected = self.props.onselected.clone(); + let onselected = props.onselected.clone(); self.selected_listener = Some(EventListener::new(&list, "selected", move |event| { let val = SelectedDetail::from(event_into_details(event)); onselected.emit(val); @@ -154,7 +148,7 @@ impl Component for MatList { } if self.action_listener.is_none() { - let onaction = self.props.onaction.clone(); + let onaction = props.onaction.clone(); self.action_listener = Some(EventListener::new(&list.clone(), "action", move |_| { let val: JsValue = list.index(); let index = ListIndex::from(val); diff --git a/material-yew/src/list/action_detail.rs b/material-yew/src/list/action_detail.rs index c7cc97d..2296387 100644 --- a/material-yew/src/list/action_detail.rs +++ b/material-yew/src/list/action_detail.rs @@ -8,6 +8,7 @@ use wasm_bindgen::JsCast; /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-list-2) #[derive(Debug)] pub struct ActionDetail { + #[allow(dead_code)] index: ListIndex, } diff --git a/material-yew/src/list/check_list_item.rs b/material-yew/src/list/check_list_item.rs index 12b1362..6fc89bf 100644 --- a/material-yew/src/list/check_list_item.rs +++ b/material-yew/src/list/check_list_item.rs @@ -20,7 +20,6 @@ loader_hack!(CheckListItem); /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/list#checklist) pub struct MatCheckListItem { - props: CheckListItemProps, node_ref: NodeRef, request_selected_listener: Option, } @@ -29,7 +28,7 @@ pub struct MatCheckListItem { /// /// MWC Documentation for [properties](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-check-list-item) /// and [events](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-check-list-item-1) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct CheckListItemProps { #[prop_or_default] pub left: bool, @@ -46,40 +45,32 @@ impl Component for MatCheckListItem { type Message = (); type Properties = CheckListItemProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { + fn create(_: &Context) -> Self { CheckListItem::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), request_selected_listener: None, } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - { self.props.children.clone() } + {props.children.clone()} } } - fn rendered(&mut self, _first_render: bool) { + fn rendered(&mut self, ctx: &Context, _first_render: bool) { + let props = ctx.props(); if self.request_selected_listener.is_none() { self.request_selected_listener = Some(request_selected_listener( &self.node_ref, - self.props.on_request_selected.clone(), + props.on_request_selected.clone(), )); } } diff --git a/material-yew/src/list/graphic_type.rs b/material-yew/src/list/graphic_type.rs index f15a895..849e567 100644 --- a/material-yew/src/list/graphic_type.rs +++ b/material-yew/src/list/graphic_type.rs @@ -1,11 +1,10 @@ -use std::borrow::Cow; use std::fmt; /// Equivalent to typescript type /// `'avatar'|'icon'|'medium'|'large'|'control'|null` /// /// See `GraphicType` [here](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-list-item-1) -#[derive(Clone, Debug)] +#[derive(Clone, PartialEq, Debug)] pub enum GraphicType { Avatar, Icon, @@ -16,22 +15,21 @@ pub enum GraphicType { } impl GraphicType { - pub fn to_cow_string(&self) -> Cow<'static, str> { + pub fn as_str(&self) -> &'static str { use GraphicType::*; - let s = match self { + match self { Avatar => "avatar", Icon => "icon", Medium => "medium", Large => "large", Control => "control", Null => "null", - }; - Cow::from(s) + } } } impl fmt::Display for GraphicType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.to_cow_string()) + write!(f, "{}", self.as_str()) } } diff --git a/material-yew/src/list/list_item.rs b/material-yew/src/list/list_item.rs index c2fa993..9a4bc56 100644 --- a/material-yew/src/list/list_item.rs +++ b/material-yew/src/list/list_item.rs @@ -2,9 +2,9 @@ use crate::list::request_selected::request_selected_listener; use crate::list::{GraphicType, RequestSelectedDetail}; use crate::{bool_to_option, to_option_string}; use gloo::events::EventListener; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-list-item.js")] extern "C" { @@ -21,7 +21,6 @@ loader_hack!(ListItem); /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-list-item) pub struct MatListItem { - props: ListItemProps, node_ref: NodeRef, request_selected_listener: Option, } @@ -30,10 +29,10 @@ pub struct MatListItem { /// /// MWC Documentation [properties](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-list-item-1) /// and [events](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-list-item-2) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct ListItemProps { #[prop_or_default] - pub value: Cow<'static, str>, + pub value: Option, #[prop_or_default] pub group: bool, #[prop_or(- 1)] @@ -64,48 +63,40 @@ impl Component for MatListItem { type Message = (); type Properties = ListItemProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { + fn create(_: &Context) -> Self { ListItem::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), request_selected_listener: None, } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - { self.props.children.clone() } + {props.children.clone()} } } - fn rendered(&mut self, _first_render: bool) { + fn rendered(&mut self, ctx: &Context, _first_render: bool) { + let props = ctx.props(); if self.request_selected_listener.is_none() { self.request_selected_listener = Some(request_selected_listener( &self.node_ref, - self.props.on_request_selected.clone(), + props.on_request_selected.clone(), )); } } diff --git a/material-yew/src/list/radio_list_item.rs b/material-yew/src/list/radio_list_item.rs index 62e477f..7c73238 100644 --- a/material-yew/src/list/radio_list_item.rs +++ b/material-yew/src/list/radio_list_item.rs @@ -2,9 +2,9 @@ use crate::bool_to_option; use crate::list::request_selected::request_selected_listener; use crate::list::{GraphicType, RequestSelectedDetail}; use gloo::events::EventListener; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-radio-list-item.js")] extern "C" { @@ -21,7 +21,6 @@ loader_hack!(RadioListItem); /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-radio-list-item) pub struct MatRadioListItem { - props: RadioListItemProps, node_ref: NodeRef, request_selected_listener: Option, } @@ -30,12 +29,12 @@ pub struct MatRadioListItem { /// /// MWC Documentation [properties](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-radio-list-item-1) /// and [events](https://github.com/material-components/material-components-web-components/tree/master/packages/list#mwc-radio-list-item-2) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct RadioListItemProps { #[prop_or_default] pub left: bool, #[prop_or_default] - pub group: Option>, + pub group: Option, #[prop_or(GraphicType::Control)] pub graphic: GraphicType, /// Binds to `request-selected` event on `mwc-list-item`. @@ -48,40 +47,32 @@ impl Component for MatRadioListItem { type Message = (); type Properties = RadioListItemProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { + fn create(_: &Context) -> Self { RadioListItem::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), request_selected_listener: None, } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - { self.props.children.clone() } + {props.children.clone()} } } - fn rendered(&mut self, _first_render: bool) { + fn rendered(&mut self, ctx: &Context, _first_render: bool) { + let props = ctx.props(); if self.request_selected_listener.is_none() { self.request_selected_listener = Some(request_selected_listener( &self.node_ref, - self.props.on_request_selected.clone(), + props.on_request_selected.clone(), )); } } diff --git a/material-yew/src/menu.rs b/material-yew/src/menu.rs index 31cc3d6..c3aa741 100644 --- a/material-yew/src/menu.rs +++ b/material-yew/src/menu.rs @@ -5,10 +5,10 @@ pub use models::*; use crate::list::{ListIndex, SelectedDetail}; use crate::{bool_to_option, event_into_details, to_option_string, WeakComponentLink}; use gloo::events::EventListener; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use web_sys::Node; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-menu.js")] extern "C" { @@ -48,7 +48,6 @@ loader_hack!(Menu); /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/menu) pub struct MatMenu { - props: MenuProps, node_ref: NodeRef, opened_listener: Option, closed_listener: Option, @@ -60,7 +59,7 @@ pub struct MatMenu { /// /// MWC Documentation [properties](https://github.com/material-components/material-components-web-components/tree/master/packages/menu#propertiesattributes) /// and [events](https://github.com/material-components/material-components-web-components/tree/master/packages/menu#events) -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct MenuProps { /// Changing this prop re-renders the component. /// For general usage, consider using `show` method provided by @@ -92,7 +91,7 @@ pub struct MenuProps { #[prop_or_default] pub wrap_focus: bool, #[prop_or_default] - pub inner_role: Cow<'static, str>, + pub inner_role: Option, #[prop_or_default] pub multi: bool, #[prop_or_default] @@ -135,11 +134,13 @@ impl Component for MatMenu { type Message = (); type Properties = MenuProps; - fn create(props: Self::Properties, link: ComponentLink) -> Self { - props.menu_link.borrow_mut().replace(link); + fn create(ctx: &Context) -> Self { + ctx.props() + .menu_link + .borrow_mut() + .replace(ctx.link().clone()); Menu::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), opened_listener: None, closed_listener: None, @@ -148,70 +149,63 @@ impl Component for MatMenu { } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - - { self.props.children.clone() } - + + {props.children.clone()} + } } - fn rendered(&mut self, first_render: bool) { + fn rendered(&mut self, ctx: &Context, first_render: bool) { + let props = ctx.props(); let menu = self.node_ref.cast::().unwrap(); if first_render { - if let Some(anchor) = self.props.anchor.as_ref() { + if let Some(anchor) = props.anchor.as_ref() { menu.set_anchor(anchor); } } if self.opened_listener.is_none() { - let onopened = self.props.onopened.clone(); + let onopened = props.onopened.clone(); self.opened_listener = Some(EventListener::new(&menu, "opened", move |_| { onopened.emit(()); })); } if self.closed_listener.is_none() { - let onclosed = self.props.onclosed.clone(); + let onclosed = props.onclosed.clone(); self.closed_listener = Some(EventListener::new(&menu, "closed", move |_| { onclosed.emit(()); })); } if self.selected_listener.is_none() { - let onselected = self.props.onselected.clone(); + let onselected = props.onselected.clone(); self.selected_listener = Some(EventListener::new(&menu, "selected", move |event| { onselected.emit(SelectedDetail::from(event_into_details(event))); })); } if self.action_listener.is_none() { - let onaction = self.props.onaction.clone(); + let onaction = props.onaction.clone(); self.action_listener = Some(EventListener::new(&menu.clone(), "action", move |_| { let val: JsValue = menu.index(); diff --git a/material-yew/src/menu/models.rs b/material-yew/src/menu/models.rs index 3d1308c..7293a6d 100644 --- a/material-yew/src/menu/models.rs +++ b/material-yew/src/menu/models.rs @@ -1,7 +1,7 @@ /// The `Corner` type /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/menu#propertiesattributes) -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum Corner { TopLeft, TopRight, @@ -33,7 +33,7 @@ impl ToString for Corner { /// The `MenuCorner` type /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/menu#propertiesattributes) -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum MenuCorner { Start, End, @@ -53,7 +53,7 @@ impl ToString for MenuCorner { /// The `DefaultFocusState` type /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/menu#propertiesattributes) -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum DefaultFocusState { None, ListRoot, diff --git a/material-yew/src/radio.rs b/material-yew/src/radio.rs index 5c95d5d..f66e5e2 100644 --- a/material-yew/src/radio.rs +++ b/material-yew/src/radio.rs @@ -1,9 +1,9 @@ use crate::bool_to_option; use gloo::events::EventListener; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use web_sys::Node; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-radio.js")] extern "C" { @@ -27,7 +27,6 @@ loader_hack!(Radio); /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/radio) pub struct MatRadio { - props: RadioProps, node_ref: NodeRef, change_listener: Option, } @@ -38,16 +37,16 @@ pub struct MatRadio { /// /// - [Properties](https://github.com/material-components/material-components-web-components/tree/master/packages/radio#propertiesattributes) /// - [Events](https://github.com/material-components/material-components-web-components/tree/master/packages/radio#events) -#[derive(Debug, Properties, Clone)] +#[derive(Debug, Properties, PartialEq, Clone)] pub struct RadioProps { #[prop_or_default] pub checked: bool, #[prop_or_default] pub disabled: bool, #[prop_or_default] - pub name: Cow<'static, str>, + pub name: Option, #[prop_or_default] - pub value: Cow<'static, str>, + pub value: Option, #[prop_or_default] pub global: bool, #[prop_or_default] @@ -65,43 +64,35 @@ impl Component for MatRadio { type Message = (); type Properties = RadioProps; - fn create(props: Self::Properties, _: ComponentLink) -> Self { + fn create(_: &Context) -> Self { Radio::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), change_listener: None, } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - + } } - fn rendered(&mut self, _first_render: bool) { + fn rendered(&mut self, ctx: &Context, _first_render: bool) { + let props = ctx.props(); let element = self.node_ref.cast::().unwrap(); - element.set_checked(self.props.checked); + element.set_checked(props.checked); if self.change_listener.is_none() { - let callback = self.props.onchange.clone(); + let callback = props.onchange.clone(); self.change_listener = Some(EventListener::new(&element.clone(), "change", move |_| { callback.emit(element.checked()); diff --git a/material-yew/src/select.rs b/material-yew/src/select.rs index 7a5d499..0844dad 100644 --- a/material-yew/src/select.rs +++ b/material-yew/src/select.rs @@ -7,10 +7,10 @@ use crate::text_inputs::{ use crate::utils::WeakComponentLink; use crate::{bool_to_option, event_into_details, to_option_string}; use gloo::events::EventListener; -use std::borrow::Cow; use wasm_bindgen::prelude::*; use web_sys::Node; use yew::prelude::*; +use yew::virtual_dom::AttrValue; #[wasm_bindgen(module = "/build/mwc-select.js")] extern "C" { @@ -37,7 +37,6 @@ loader_hack!(Select); /// /// [MWC Documentation](https://github.com/material-components/material-components-web-components/tree/master/packages/select) pub struct MatSelect { - props: Props, node_ref: NodeRef, validity_transform_closure: Option ValidityStateJS>>, @@ -53,28 +52,28 @@ pub struct MatSelect { /// /// - [Properties](https://github.com/material-components/material-components-web-components/tree/master/packages/select#propertiesattributes) /// - [Events](https://github.com/material-components/material-components-web-components/tree/master/packages/select#events) -#[derive(Properties, Clone)] +#[derive(Properties, PartialEq, Clone)] pub struct Props { #[prop_or_default] - pub value: Cow<'static, str>, + pub value: Option, #[prop_or_default] - pub label: Cow<'static, str>, + pub label: Option, #[prop_or_default] pub natural_menu_width: bool, #[prop_or_default] - pub icon: Cow<'static, str>, + pub icon: Option, #[prop_or_default] pub disabled: bool, #[prop_or_default] pub outlined: bool, #[prop_or_default] - pub helper: Cow<'static, str>, + pub helper: Option, #[prop_or_default] pub required: bool, #[prop_or_default] - pub validation_message: Cow<'static, str>, + pub validation_message: Option, #[prop_or_default] - pub items: Cow<'static, str>, + pub items: Option, #[prop_or(- 1)] pub index: i64, #[prop_or_default] @@ -115,11 +114,13 @@ impl Component for MatSelect { type Message = (); type Properties = Props; - fn create(props: Self::Properties, link: ComponentLink) -> Self { - props.select_link.borrow_mut().replace(link); + fn create(ctx: &Context) -> Self { + ctx.props() + .select_link + .borrow_mut() + .replace(ctx.link().clone()); Select::ensure_loaded(); Self { - props, node_ref: NodeRef::default(), validity_transform_closure: None, opened_listener: None, @@ -129,75 +130,68 @@ impl Component for MatSelect { } } - fn update(&mut self, _msg: Self::Message) -> ShouldRender { - false - } - - fn change(&mut self, props: Self::Properties) -> bool { - self.props = props; - true - } - - fn view(&self) -> Html { + fn view(&self, ctx: &Context) -> Html { + let props = ctx.props(); html! { - - { self.props.children.clone() } - + + {props.children.clone()} + } } //noinspection DuplicatedCode - fn rendered(&mut self, first_render: bool) { + fn rendered(&mut self, ctx: &Context, first_render: bool) { + let props = ctx.props(); let element = self.node_ref.cast::