This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew_macro/classes/
mod.rs

1use proc_macro2::TokenStream;
2use quote::{quote, quote_spanned, ToTokens};
3use syn::parse::{Parse, ParseStream};
4use syn::punctuated::Punctuated;
5use syn::spanned::Spanned;
6use syn::{Expr, ExprLit, Lit, LitStr, Token};
7
8/// List of HTML classes.
9pub struct Classes(Punctuated<ClassExpr, Token![,]>);
10
11impl Parse for Classes {
12    fn parse(input: ParseStream) -> syn::Result<Self> {
13        input
14            .parse_terminated(ClassExpr::parse, Token![,])
15            .map(Self)
16    }
17}
18
19impl ToTokens for Classes {
20    fn to_tokens(&self, tokens: &mut TokenStream) {
21        let n = self.0.len();
22        let push_classes = self.0.iter().map(|x| match x {
23            ClassExpr::Lit(class) => quote! {
24                unsafe { __yew_classes.unchecked_push(#class) };
25            },
26            ClassExpr::Expr(class) => quote_spanned! {class.span()=>
27                __yew_classes.push(#class);
28            },
29        });
30        tokens.extend(quote! {
31            {
32                let mut __yew_classes = ::yew::html::Classes::with_capacity(#n);
33                #(#push_classes)*
34                __yew_classes
35            }
36        });
37    }
38}
39
40enum ClassExpr {
41    Lit(LitStr),
42    Expr(Box<Expr>),
43}
44
45impl Parse for ClassExpr {
46    fn parse(input: ParseStream) -> syn::Result<Self> {
47        match input.parse()? {
48            Expr::Lit(ExprLit {
49                lit: Lit::Str(lit_str),
50                ..
51            }) => {
52                let value = lit_str.value();
53                let classes = value.split_whitespace().collect::<Vec<_>>();
54                if classes.len() > 1 {
55                    let fix = classes
56                        .into_iter()
57                        .map(|class| format!("\"{class}\""))
58                        .collect::<Vec<_>>()
59                        .join(", ");
60                    let msg = format!(
61                        "string literals must not contain more than one class (hint: use `{fix}`)"
62                    );
63
64                    Err(syn::Error::new(lit_str.span(), msg))
65                } else {
66                    Ok(Self::Lit(lit_str))
67                }
68            }
69            expr => Ok(Self::Expr(Box::new(expr))),
70        }
71    }
72}