diff --git a/Cargo.toml b/Cargo.toml index 36263164769..bc3ed7f88e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ members = [ "examples/web_worker_fib", "examples/ssr_router", "examples/suspense", + "examples/immutable", # Tools "tools/benchmark-struct", diff --git a/examples/README.md b/examples/README.md index a5567c0d26e..968613ea3fa 100644 --- a/examples/README.md +++ b/examples/README.md @@ -38,6 +38,7 @@ As an example, check out the TodoMVC example here: + + + + + Yew • Immutable + + + + + + + diff --git a/examples/immutable/index.scss b/examples/immutable/index.scss new file mode 100644 index 00000000000..a548fa82fb6 --- /dev/null +++ b/examples/immutable/index.scss @@ -0,0 +1,11 @@ +$font-stack: Roboto, sans-serif; +$primary-color: #f5f5f5; + +body { + font: 100% $font-stack; + color: black; + background-color: $primary-color; + margin: 0 auto; + min-width: 230px; + max-width: 550px; +} diff --git a/examples/immutable/src/array.rs b/examples/immutable/src/array.rs new file mode 100644 index 00000000000..7898b6e8504 --- /dev/null +++ b/examples/immutable/src/array.rs @@ -0,0 +1,54 @@ +use implicit_clone::unsync::*; +use wasm_bindgen::{JsCast, UnwrapThrowExt}; +use web_sys::{HtmlInputElement, KeyboardEvent}; +use yew::prelude::*; + +#[derive(Properties, PartialEq)] +struct FolksViewProps { + folks: IArray, +} + +#[function_component(FolksView)] +fn folks_view(props: &FolksViewProps) -> Html { + html! { + <> +

{"Hello to:"}

+ + + } +} + +#[function_component(ArrayExample)] +pub fn array_example() -> Html { + let folks = use_state(IArray::::default); + let onkeyup = { + let folks = folks.clone(); + Callback::from(move |e: KeyboardEvent| { + if e.key() == "Enter" { + let event: Event = e.dyn_into().unwrap_throw(); + let event_target = event.target().unwrap_throw(); + let target: HtmlInputElement = event_target.dyn_into().unwrap_throw(); + let name = target.value(); + target.set_value(""); + + folks.set( + folks + .iter() + .chain(std::iter::once(IString::from(name))) + .collect(), + ); + } + }) + }; + + html! { + <> +

{"Input"}

+ +

{"Output"}

+ + + } +} diff --git a/examples/immutable/src/main.rs b/examples/immutable/src/main.rs new file mode 100644 index 00000000000..6b2216241f6 --- /dev/null +++ b/examples/immutable/src/main.rs @@ -0,0 +1,29 @@ +mod array; +mod map; +mod string; + +use yew::prelude::*; + +use self::array::*; +use self::map::*; +use self::string::*; + +#[function_component] +fn App() -> Html { + html! { + <> +

{ "IString Example" }

+ +
+

{ "IArray Example" }

+ +
+

{ "IMap Example" }

+ + + } +} + +fn main() { + yew::Renderer::::new().render(); +} diff --git a/examples/immutable/src/map.rs b/examples/immutable/src/map.rs new file mode 100644 index 00000000000..174d3ce6457 --- /dev/null +++ b/examples/immutable/src/map.rs @@ -0,0 +1,83 @@ +use implicit_clone::unsync::*; +use wasm_bindgen::{JsCast, UnwrapThrowExt}; +use web_sys::{HtmlInputElement, KeyboardEvent}; +use yew::prelude::*; + +#[derive(Properties, PartialEq)] +struct DisplayProps { + values: IMap, +} + +#[function_component] +fn Display(props: &DisplayProps) -> Html { + html! { + <> +

{"Hello to:"}

+
    + { for props.values.iter().map(|(i, s)| html!(
  • {i}{" => "}{s}
  • )) } +
+ + } +} + +pub struct MapExample { + values: IMap, +} + +pub enum MapExampleMessage { + AddName(String), + Noop, +} + +impl Component for MapExample { + type Message = MapExampleMessage; + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self { + values: Default::default(), + } + } + + fn update(&mut self, _: &Context, msg: Self::Message) -> bool { + match msg { + MapExampleMessage::AddName(name) => { + self.values = self + .values + .iter() + .chain(std::iter::once(( + self.values.len() as u32, + IString::from(name), + ))) + .collect(); + true + } + MapExampleMessage::Noop => false, + } + } + + fn view(&self, ctx: &Context) -> Html { + let link = ctx.link(); + let onkeyup = link.callback(|e: KeyboardEvent| { + if e.key() == "Enter" { + let event: Event = e.dyn_into().unwrap_throw(); + let event_target = event.target().unwrap_throw(); + let target: HtmlInputElement = event_target.dyn_into().unwrap_throw(); + let value = target.value(); + target.set_value(""); + MapExampleMessage::AddName(value) + } else { + MapExampleMessage::Noop + } + }); + + html! { + <> +

{"Input"}

+ +

{"Output"}

+ + + } + } +} diff --git a/examples/immutable/src/string.rs b/examples/immutable/src/string.rs new file mode 100644 index 00000000000..86e5df5cb1f --- /dev/null +++ b/examples/immutable/src/string.rs @@ -0,0 +1,63 @@ +use implicit_clone::unsync::*; +use wasm_bindgen::{JsCast, UnwrapThrowExt}; +use web_sys::{HtmlInputElement, InputEvent}; +use yew::prelude::*; + +#[derive(Properties, PartialEq)] +struct DisplayProps { + name: IString, +} + +#[function_component] +fn Display(props: &DisplayProps) -> Html { + html! { +

{"Hello "}{&props.name}{"!"}

+ } +} + +pub struct StringExample { + name: IString, +} + +pub enum StringExampleMessage { + UpdateName(String), +} + +impl Component for StringExample { + type Message = StringExampleMessage; + type Properties = (); + + fn create(_ctx: &Context) -> Self { + Self { + name: "World".into(), + } + } + + fn update(&mut self, _: &Context, msg: Self::Message) -> bool { + match msg { + StringExampleMessage::UpdateName(name) => { + self.name = name.into(); + true + } + } + } + + fn view(&self, ctx: &Context) -> Html { + let link = ctx.link(); + let oninput = link.callback(|e: InputEvent| { + let event: Event = e.dyn_into().unwrap_throw(); + let event_target = event.target().unwrap_throw(); + let target: HtmlInputElement = event_target.dyn_into().unwrap_throw(); + StringExampleMessage::UpdateName(target.value()) + }); + + html! { + <> +

{"Input"}

+ +

{"Output"}

+ + + } + } +} diff --git a/packages/yew-macro/tests/html_macro/component-fail.stderr b/packages/yew-macro/tests/html_macro/component-fail.stderr index 2297008d628..e1e62501041 100644 --- a/packages/yew-macro/tests/html_macro/component-fail.stderr +++ b/packages/yew-macro/tests/html_macro/component-fail.stderr @@ -345,11 +345,11 @@ error[E0277]: the trait bound `{integer}: IntoPropValue` is not satisfie | ^ the trait `IntoPropValue` is not implemented for `{integer}` | = help: the following implementations were found: - <&'static str as IntoPropValue> + <&'static [(K, V)] as IntoPropValue>> + <&'static [T] as IntoPropValue>> <&'static str as IntoPropValue> - <&'static str as IntoPropValue>> <&'static str as IntoPropValue>> - and 27 others + and 31 others error[E0277]: the trait bound `{integer}: IntoPropValue` is not satisfied --> tests/html_macro/component-fail.rs:79:34 @@ -358,11 +358,11 @@ error[E0277]: the trait bound `{integer}: IntoPropValue` is not satisfie | ^ the trait `IntoPropValue` is not implemented for `{integer}` | = help: the following implementations were found: - <&'static str as IntoPropValue> + <&'static [(K, V)] as IntoPropValue>> + <&'static [T] as IntoPropValue>> <&'static str as IntoPropValue> - <&'static str as IntoPropValue>> <&'static str as IntoPropValue>> - and 27 others + and 31 others error[E0308]: mismatched types --> tests/html_macro/component-fail.rs:80:31 diff --git a/packages/yew-macro/tests/html_macro/element-fail.stderr b/packages/yew-macro/tests/html_macro/element-fail.stderr index c47e79d8d5d..de86b65d6d9 100644 --- a/packages/yew-macro/tests/html_macro/element-fail.stderr +++ b/packages/yew-macro/tests/html_macro/element-fail.stderr @@ -246,11 +246,11 @@ error[E0308]: mismatched types 40 | html! {