diff --git a/examples/actix_ssr_router/src/lib.rs b/examples/actix_ssr_router/src/lib.rs index 913510c7dfc..0f039a5964c 100644 --- a/examples/actix_ssr_router/src/lib.rs +++ b/examples/actix_ssr_router/src/lib.rs @@ -115,27 +115,7 @@ fn render_post(post: &content::Post) -> Html { } }; - let view_content = { - let mut show_hero = false; - let parts: Vec = post - .content - .iter() - .map(|part| match part { - PostPart::Section(section) => { - let html = render_section(section, show_hero); - show_hero = true; - html - } - PostPart::Quote(quote) => { - show_hero = false; - render_quote(quote) - } - }) - .collect(); - html! { - {for parts} - } - }; + let mut show_hero = false; html! {
@@ -157,7 +137,23 @@ fn render_post(post: &content::Post) -> Html {
-
{ view_content }
+
+ for part in post.content.iter() { + match part { + PostPart::Section(section) => { + let rendered = render_section(section, show_hero); + // show hero between sections + show_hero = true; + { rendered } + } + PostPart::Quote(quote) => { + // don't show hero after a quote + show_hero = false; + { render_quote(quote) } + } + } + } +
} } diff --git a/examples/axum_ssr_router/src/lib.rs b/examples/axum_ssr_router/src/lib.rs index 913510c7dfc..0f039a5964c 100644 --- a/examples/axum_ssr_router/src/lib.rs +++ b/examples/axum_ssr_router/src/lib.rs @@ -115,27 +115,7 @@ fn render_post(post: &content::Post) -> Html { } }; - let view_content = { - let mut show_hero = false; - let parts: Vec = post - .content - .iter() - .map(|part| match part { - PostPart::Section(section) => { - let html = render_section(section, show_hero); - show_hero = true; - html - } - PostPart::Quote(quote) => { - show_hero = false; - render_quote(quote) - } - }) - .collect(); - html! { - {for parts} - } - }; + let mut show_hero = false; html! {
@@ -157,7 +137,23 @@ fn render_post(post: &content::Post) -> Html {
-
{ view_content }
+
+ for part in post.content.iter() { + match part { + PostPart::Section(section) => { + let rendered = render_section(section, show_hero); + // show hero between sections + show_hero = true; + { rendered } + } + PostPart::Quote(quote) => { + // don't show hero after a quote + show_hero = false; + { render_quote(quote) } + } + } + } +
} } diff --git a/examples/boids/src/boid.rs b/examples/boids/src/boid.rs index 7b6d94c190e..4c388dc8c6e 100644 --- a/examples/boids/src/boid.rs +++ b/examples/boids/src/boid.rs @@ -1,8 +1,6 @@ -use std::fmt::Write; use std::iter; use rand::RngExt; -use yew::{Html, html}; use crate::math::{self, Mean, Vector2D, WeightedMean}; use crate::settings::Settings; @@ -10,10 +8,10 @@ use crate::simulation::SIZE; #[derive(Clone, Debug, PartialEq)] pub struct Boid { - position: Vector2D, - velocity: Vector2D, - radius: f64, - hue: f64, + pub position: Vector2D, + pub velocity: Vector2D, + pub radius: f64, + pub hue: f64, } impl Boid { @@ -123,32 +121,6 @@ impl Boid { boid.update(settings, visible_boids); } } - - pub fn render(&self) -> Html { - let color = format!("hsl({:.3}rad, 100%, 50%)", self.hue); - - let mut points = String::new(); - for offset in iter_shape_points(self.radius, self.velocity.angle()) { - let Vector2D { x, y } = self.position + offset; - - // Write to string will never fail. - let _ = write!(points, "{x:.2},{y:.2} "); - } - - html! { } - } -} - -fn iter_shape_points(radius: f64, rotation: f64) -> impl Iterator { - const SHAPE: [(f64, f64); 3] = [ - (0. * math::FRAC_TAU_3, 2.0), - (1. * math::FRAC_TAU_3, 1.0), - (2. * math::FRAC_TAU_3, 1.0), - ]; - SHAPE - .iter() - .copied() - .map(move |(angle, radius_mul)| Vector2D::from_polar(angle + rotation, radius_mul * radius)) } #[derive(Debug)] diff --git a/examples/boids/src/simulation.rs b/examples/boids/src/simulation.rs index b41766c2c2a..cdecb2adba2 100644 --- a/examples/boids/src/simulation.rs +++ b/examples/boids/src/simulation.rs @@ -1,8 +1,10 @@ +use std::fmt::Write; + use gloo::timers::callback::Interval; use yew::{Component, Context, Html, Properties, html}; use crate::boid::Boid; -use crate::math::Vector2D; +use crate::math::{self, Vector2D}; use crate::settings::Settings; pub const SIZE: Vector2D = Vector2D::new(1600.0, 1000.0); @@ -103,7 +105,25 @@ impl Component for Simulation { html! { - { for self.boids.iter().map(Boid::render) } + for boid in &self.boids { + + let color = format!("hsl({:.3}rad, 100%, 50%)", boid.hue); + let mut points = String::new(); + for offset in [ + (0. * math::FRAC_TAU_3, 2.0), + (1. * math::FRAC_TAU_3, 1.0), + (2. * math::FRAC_TAU_3, 1.0), + ] + .iter() + .copied() + .map(move |(angle, radius_mul)| Vector2D::from_polar(angle + boid.velocity.angle(), radius_mul * boid.radius)) { + let Vector2D { x, y } = boid.position + offset; + // Write to string will never fail. + let _ = write!(points, "{x:.2},{y:.2} "); + }; + + + } } } diff --git a/examples/file_upload/src/main.rs b/examples/file_upload/src/main.rs index a2a32d9c014..873743e6b8f 100644 --- a/examples/file_upload/src/main.rs +++ b/examples/file_upload/src/main.rs @@ -97,33 +97,28 @@ impl Component for App { })} />
- { for self.files.iter().map(Self::view_file) } -
- - } - } -} - -impl App { - fn view_file(file: &FileDetails) -> Html { - let file_type = file.file_type.to_string(); - let src = format!("data:{};base64,{}", file_type, STANDARD.encode(&file.data)); - html! { -
-

{ &file.name }

-
- if file.file_type.contains("image") { - - } else if file.file_type.contains("video") { - + for file in &self.files { + let file_type = file.file_type.to_string(); + let src = format!("data:{};base64,{}", file_type, STANDARD.encode(&file.data)); +
+

{ &file.name }

+
+ if file.file_type.contains("image") { + + } else if file.file_type.contains("video") { + + } +
+
}
} } } + fn main() { yew::Renderer::::new().render(); } diff --git a/examples/function_router/src/pages/post.rs b/examples/function_router/src/pages/post.rs index dc12a0a769d..7f7daf2b12d 100644 --- a/examples/function_router/src/pages/post.rs +++ b/examples/function_router/src/pages/post.rs @@ -101,20 +101,23 @@ pub fn Post(props: &Props) -> Html { // don't show hero for the first section let mut show_hero = false; - let parts = post.content.iter().map(|part| match part { - PostPart::Section(section) => { - let html = render_section(section, show_hero); - // show hero between sections - show_hero = true; - html - } - PostPart::Quote(quote) => { - // don't show hero after a quote - show_hero = false; - render_quote(quote) + html! { + for part in post.content.iter() { + match part { + PostPart::Section(section) => { + let rendered = render_section(section, show_hero); + // show hero between sections + show_hero = true; + {rendered} + } + PostPart::Quote(quote) => { + // don't show hero after a quote + show_hero = false; + {render_quote(quote)} + } + } } - }); - html! {{for parts}} + } }; html! { diff --git a/examples/function_router/src/pages/post_list.rs b/examples/function_router/src/pages/post_list.rs index 56107744548..881e112db6b 100644 --- a/examples/function_router/src/pages/post_list.rs +++ b/examples/function_router/src/pages/post_list.rs @@ -15,23 +15,25 @@ pub fn PostList() -> Html { let posts = { let start_seed = (current_page - 1) * ITEMS_PER_PAGE; - let mut cards = (0..ITEMS_PER_PAGE).map(|seed_offset| { - html! { -
  • - -
  • - } - }); + let half = ITEMS_PER_PAGE / 2; html! {
      - { for cards.by_ref().take(ITEMS_PER_PAGE as usize / 2) } + for seed_offset in 0..half { +
    • + +
    • + }
      - { for cards } + for seed_offset in half..ITEMS_PER_PAGE { +
    • + +
    • + }
    diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs index faabe7f4bcd..0666ff192ed 100644 --- a/examples/game_of_life/src/main.rs +++ b/examples/game_of_life/src/main.rs @@ -1,5 +1,4 @@ use gloo::timers::callback::Interval; -use yew::html::Scope; use yew::{Component, Context, Html, classes, html}; mod conway; @@ -20,21 +19,6 @@ pub struct App { _interval: Interval, } -impl App { - fn view_cellule(&self, row: usize, col: usize, link: &Scope) -> Html { - let status = if self.conway.alive(row, col) { - "cellule-live" - } else { - "cellule-dead" - }; - html! { -
    -
    - } - } -} - impl Component for App { type Message = Msg; type Properties = (); @@ -96,9 +80,12 @@ impl Component for App {
    for (row, cellules) in self.conway.cellules.chunks(self.conway.width).enumerate() { - let cells = cellules.iter().enumerate().map(|(col, _)| self.view_cellule(row, col, ctx.link()));
    - { for cells } + for (col, _) in cellules.iter().enumerate() { +
    +
    + }
    }
    diff --git a/examples/keyed_list/src/main.rs b/examples/keyed_list/src/main.rs index 09904ed58be..0c0f2fa61c1 100644 --- a/examples/keyed_list/src/main.rs +++ b/examples/keyed_list/src/main.rs @@ -6,6 +6,8 @@ use web_sys::{HtmlElement, HtmlInputElement}; use yew::html::Scope; use yew::prelude::*; +use crate::person::PersonComponent; + mod person; mod random; @@ -274,7 +276,28 @@ impl App {

    { "Ids: " }{ ids }


    - { for self.persons.iter().map(|p| p.render(self.keyed)) } + for p in &self.persons { + match p { + PersonType::Inline(info) => { + if self.keyed { +
    + { info.render() } +
    + } else { +
    + { info.render() } +
    + } + } + PersonType::Component(info) => { + if self.keyed { + + } else { + + } + } + } + }
    } diff --git a/examples/keyed_list/src/person.rs b/examples/keyed_list/src/person.rs index 03a9686749f..ed6e9997c6b 100644 --- a/examples/keyed_list/src/person.rs +++ b/examples/keyed_list/src/person.rs @@ -34,7 +34,7 @@ impl PersonInfo { } } - fn render(&self) -> Html { + pub fn render(&self) -> Html { html! {
    @@ -49,7 +49,7 @@ impl PersonInfo { #[derive(Debug, Eq, PartialEq, Properties)] pub struct PersonProps { - info: PersonInfo, + pub info: PersonInfo, } pub struct PersonComponent; @@ -91,31 +91,4 @@ impl PersonType { Self::Component(info) } } - - pub fn render(&self, keyed: bool) -> Html { - match self { - Self::Inline(info) => { - if keyed { - html! { -
    - { info.render() } -
    - } - } else { - html! { -
    - { info.render() } -
    - } - } - } - Self::Component(info) => { - if keyed { - html! { } - } else { - html! { } - } - } - } - } } diff --git a/examples/nested_list/src/list.rs b/examples/nested_list/src/list.rs index a05048e9f95..f6a91fb2090 100644 --- a/examples/nested_list/src/list.rs +++ b/examples/nested_list/src/list.rs @@ -57,26 +57,21 @@ impl Component for List {
    { &ctx.props().header }
    - { Self::view_items(&ctx.props().children) } + for (i, mut c) in ctx + .props() + .children + .iter() + .filter(|c| !c.props.hide) + .cloned() + .enumerate() + { + let props = c.get_mut(); + props.name = format!("#{} - {}", i + 1, props.name).into(); + { c } + }
    } } } - -impl List { - fn view_items(children: &IArray>) -> Html { - children - .iter() - .filter(|c| !c.props.hide) - .cloned() - .enumerate() - .map(|(i, mut c)| { - let props = c.get_mut(); - props.name = format!("#{} - {}", i + 1, props.name).into(); - c - }) - .collect::() - } -} diff --git a/examples/router/src/components/pagination.rs b/examples/router/src/components/pagination.rs index cfc3220423d..dc8b850749d 100644 --- a/examples/router/src/components/pagination.rs +++ b/examples/router/src/components/pagination.rs @@ -69,11 +69,10 @@ impl Pagination { if len > max_links { let last_link = self.render_link(pages.next_back().unwrap(), props); // remove 1 for the ellipsis and 1 for the last link - let links = pages - .take(max_links - 2) - .map(|page| self.render_link(page, props)); html! { - { for links } + for page in pages.take(max_links - 2) { + { self.render_link(page, props) } + }
  • { ELLIPSIS }
  • { last_link } } diff --git a/examples/router/src/pages/post.rs b/examples/router/src/pages/post.rs index a0483b1a450..343201633f3 100644 --- a/examples/router/src/pages/post.rs +++ b/examples/router/src/pages/post.rs @@ -31,6 +31,9 @@ impl Component for Post { fn view(&self, _ctx: &Context) -> Html { let Self { post } = self; + // don't show hero for the first section + let mut show_hero = false; + html! {
    The hero's background @@ -54,7 +57,21 @@ impl Component for Post {
    - { self.view_content() } + for part in &post.content { + match part { + PostPart::Section(section) => { + let rendered = self.render_section(section, show_hero); + // show hero between sections + show_hero = true; + { rendered } + } + PostPart::Quote(quote) => { + // don't show hero after a quote + show_hero = false; + { self.render_quote(quote) } + } + } + }
    } } @@ -109,24 +126,4 @@ impl Post { } } - - fn view_content(&self) -> Html { - // don't show hero for the first section - let mut show_hero = false; - - let parts = self.post.content.iter().map(|part| match part { - PostPart::Section(section) => { - let html = self.render_section(section, show_hero); - // show hero between sections - show_hero = true; - html - } - PostPart::Quote(quote) => { - // don't show hero after a quote - show_hero = false; - self.render_quote(quote) - } - }); - html! {{for parts}} - } } diff --git a/examples/router/src/pages/post_list.rs b/examples/router/src/pages/post_list.rs index 6d709878131..e19f75aecf1 100644 --- a/examples/router/src/pages/post_list.rs +++ b/examples/router/src/pages/post_list.rs @@ -47,14 +47,37 @@ impl Component for PostList { true } - fn view(&self, ctx: &Context) -> Html { + fn view(&self, _ctx: &Context) -> Html { let page = self.page; + let start_seed = (page - 1) * ITEMS_PER_PAGE; + let mut cards = (0..ITEMS_PER_PAGE).map(|seed_offset| { + html! { +
  • + +
  • + } + }); html! {

    { "Posts" }

    { "All of our quality writing in one place" }

    - { self.view_posts(ctx) } +
    +
    +
      + for card in cards.by_ref().take(ITEMS_PER_PAGE as usize / 2) { + { card } + } +
    +
    +
    +
      + for card in cards { + { card } + } +
    +
    +
    ) -> Html { - let start_seed = (self.page - 1) * ITEMS_PER_PAGE; - let mut cards = (0..ITEMS_PER_PAGE).map(|seed_offset| { - html! { -
  • - -
  • - } - }); - html! { -
    -
    -
      - { for cards.by_ref().take(ITEMS_PER_PAGE as usize / 2) } -
    -
    -
    -
      - { for cards } -
    -
    -
    - } - } -} diff --git a/examples/timer_functional/src/main.rs b/examples/timer_functional/src/main.rs index d0b25a8bff0..d477d7cb626 100644 --- a/examples/timer_functional/src/main.rs +++ b/examples/timer_functional/src/main.rs @@ -122,16 +122,6 @@ fn App() -> Html { timeout_handle: None, }); - let mut key = 0; - let messages: Html = state - .messages - .iter() - .map(|message| { - key += 1; - html! {

    { message }

    } - }) - .collect(); - let has_job = state.interval_handle.is_some() || state.timeout_handle.is_some(); let on_add_timeout = { @@ -163,7 +153,7 @@ fn App() -> Html { }; let on_cancel = Callback::from({ - let (_, dispatcher) = state.into_inner(); + let dispatcher = state.dispatcher(); move |_: MouseEvent| { dispatcher.dispatch(TimerAction::Cancel); @@ -179,7 +169,9 @@ fn App() -> Html {
    - { messages } + for (key, message) in state.messages.iter().enumerate() { +

    { message }

    + }
    ) diff --git a/examples/todomvc/src/main.rs b/examples/todomvc/src/main.rs index cbf9aa90db2..7b79b9fb471 100644 --- a/examples/todomvc/src/main.rs +++ b/examples/todomvc/src/main.rs @@ -3,7 +3,6 @@ use state::{Entry, Filter, State}; use strum::IntoEnumIterator; use web_sys::HtmlInputElement as InputElement; use yew::events::{FocusEvent, KeyboardEvent}; -use yew::html::Scope; use yew::{Classes, Component, Context, Html, NodeRef, TargetCast, classes, html}; mod state; @@ -88,17 +87,39 @@ impl Component for App { } fn view(&self, ctx: &Context) -> Html { + let link = ctx.link(); let hidden_class = if self.state.entries.is_empty() { "hidden" } else { "" }; + let new_todo_onkeypress = link.batch_callback(|e: KeyboardEvent| { + if e.key() == "Enter" { + let input: InputElement = e.target_unchecked_into(); + let value = input.value(); + input.set_value(""); + Some(Msg::Add(value)) + } else { + None + } + }); html! {

    { "todos" }

    - { self.view_input(ctx.link()) } + // You can use standard Rust comments. One line: + //
  • + + /* Or multiline: +
      +
    • +
    + */
    @@ -126,9 +192,23 @@ impl Component for App { { " item(s) left" }
      - { for Filter::iter().map(|flt| self.view_filter(flt, ctx.link())) } + for filter in Filter::iter() { + let cls = if self.state.filter == filter { + "selected" + } else { + "not-selected" + }; +
    • + + { filter } + +
    • + }
    - @@ -143,108 +223,6 @@ impl Component for App { } } -impl App { - fn view_filter(&self, filter: Filter, link: &Scope) -> Html { - let cls = if self.state.filter == filter { - "selected" - } else { - "not-selected" - }; - html! { -
  • - - { filter } - -
  • - } - } - - fn view_input(&self, link: &Scope) -> Html { - let onkeypress = link.batch_callback(|e: KeyboardEvent| { - if e.key() == "Enter" { - let input: InputElement = e.target_unchecked_into(); - let value = input.value(); - input.set_value(""); - Some(Msg::Add(value)) - } else { - None - } - }); - html! { - // You can use standard Rust comments. One line: - //
  • - - /* Or multiline: -
      -
    • -
    - */ - } - } - - fn view_entry(&self, (idx, entry): (usize, &Entry), link: &Scope) -> Html { - let mut class = Classes::from("todo"); - if entry.editing { - class.push(" editing"); - } - if entry.completed { - class.push(" completed"); - } - html! { -
  • -
    - - -
    - { self.view_entry_edit_input((idx, entry), link) } -
  • - } - } - - fn view_entry_edit_input(&self, (idx, entry): (usize, &Entry), link: &Scope) -> Html { - let edit = move |input: InputElement| { - let value = input.value(); - input.set_value(""); - Msg::Edit((idx, value)) - }; - - let onblur = link.callback(move |e: FocusEvent| edit(e.target_unchecked_into())); - - let onkeypress = link.batch_callback(move |e: KeyboardEvent| { - (e.key() == "Enter").then(|| edit(e.target_unchecked_into())) - }); - - if entry.editing { - html! { - - } - } else { - html! { } - } - } -} - fn main() { yew::Renderer::::new().render(); }