yew_google_material/icons/
mod.rs

1//! # GIcon
2//! helps to connect yew app with `https://fonts.google.com/icons`
3//!
4//! To use icons with the help of this crate you need to add some additional code to `index.html` inside `<head></head>`
5//! 
6//! There are three types of Icons. Add this if you want to use icons Outlined style:
7//! ```
8//! <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
9//! ```
10//! To use icons Rounded style:
11//! ```
12//! <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
13//! ```
14//! To use icons Sharp style:
15//! ```
16//! <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
17//! ```
18//! Then choose on of the icons in the catalog of `<https://fonts.google.com/icons>`, i.e. 'search', 'star', 'menu', etc. and see example below. 
19//! ## Examples
20//! ```
21//! // with <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
22//! 
23//! use yew::prelude::*;
24//! use yew_google_material::prelude::*;
25//! 
26//! <GIcon 
27//!     size="16px"
28//!     transition="all 0.2s"
29//!     icon="search" 
30//!     icon_style={GIconStyle::Outlined} 
31//!     fill=true
32//!     wght="200"
33//!     grade="0"
34//!     opsz="24"
35//!     color="#fff"
36//! />
37//! ```
38//! Note, you that you can animate icon attributes with transition. The default value is "unset", but for animation it is recomended to set "all 0.2s" or as you wish.
39//! 
40//! Or you can add an icon with default options with another icons style:
41//! ```
42//! // with <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
43//! 
44//! use yew::prelude::*;
45//! use yew_google_material::prelude::*;
46//! 
47//! <GIcon 
48//!     icon="star" 
49//!     icon_style={GIconStyle::Rounded} 
50//! />
51//! ```
52
53use stylist::Style;
54use yew::prelude::*;
55use crate::GIconStyle;
56use web_sys::Element;
57
58#[derive(Debug, Properties, PartialEq, Clone)]
59pub struct GIconProps {
60    pub icon: AttrValue,
61    pub icon_style: GIconStyle,
62    #[prop_or_else(|| false )]
63    pub fill: bool,
64    #[prop_or_else(|| AttrValue::from("300"))]
65    pub wght: AttrValue,
66    #[prop_or_else(|| AttrValue::from("100"))]
67    pub grade: AttrValue,
68    #[prop_or_else(|| AttrValue::from("24"))]
69    pub opsz: AttrValue,
70    #[prop_or_else(|| AttrValue::from(r#"inherit"#))]
71    pub color: AttrValue,
72    #[prop_or_else(|| AttrValue::from(r#"24px"#))]
73    pub size: AttrValue,
74    #[prop_or_else(|| AttrValue::from("unset"))]
75    pub transition: AttrValue,
76    #[prop_or_default]
77    pub leading_icon: bool, 
78    #[prop_or_default]
79    pub trailing_icon: bool, 
80}
81
82#[function_component(GIcon)]
83pub fn icon(props: &GIconProps) -> Html {
84    let universal_slyle = match props.icon_style {
85        GIconStyle::Outlined => "material-symbols-outlined",
86        GIconStyle::Rounded => "material-symbols-rounded",
87        GIconStyle::Sharp => "material-symbols-sharp",
88    };
89    let fill = if props.fill { 1_u8 } else { 0_u8 };
90    let wght = {
91        match props.wght.parse::<u16>() {
92            Ok(x) => {if x >= 100 && x <= 700 {x} else {panic!("Wrong Google Material Icon wght setting")}},
93            Err(_) => panic!("Wrong Google Material Icon wght setting"),
94        }
95    };
96    let grade = {
97        match props.grade.parse::<i16>() {
98            Ok(x) => {if x >= -50 && x <= 200 {x} else {panic!("Wrong Google Material Icon grade setting")}},
99            Err(_) => panic!("Wrong Google Material Icon grade setting"),
100        }
101    };
102    let opsz = {
103        match props.opsz.parse::<u8>() {
104            Ok(x) => {if x >= 20 && x <= 48 {x} else {panic!("Wrong Google Material Icon opsz setting")}},
105            Err(_) => panic!("Wrong Google Material Icon opsz setting"),
106        }
107    };
108
109    let color = props.color.clone();
110    let transition = props.transition.clone();
111    let size = props.size.clone();
112    let leading_icon = props.leading_icon.clone();
113    let trailing_icon = props.trailing_icon.clone();
114
115    let style_str = format!(
116        r#"
117            .{universal_slyle} {{
118                display: block;
119                transition: {transition};
120                color: {color};
121                font-size: {size};
122                font-variation-settings:
123                'FILL' {fill},
124                'wght' {wght},
125                'GRAD' {grade},
126                'opsz' {opsz}
127                }}
128        "#
129    );
130
131    let node_ref = NodeRef::default();
132    let node_ref_clone = node_ref.clone();
133
134    let style = Style::new(style_str).expect("Failed to create style");
135
136    use_effect(move || {
137        if leading_icon || trailing_icon {
138            let gicon = node_ref_clone.cast::<Element>().unwrap();
139            if leading_icon {
140                gicon.set_class_name("g_has_leading_icon");
141            }
142            if trailing_icon {
143                gicon.set_class_name("g_has_trailing_icon");
144            }
145        };
146        ()
147    });
148
149    html! {
150        <gicon ref={node_ref} style="line-height: 0">
151            <div class={style} style="line-height: 0">
152                <span class={universal_slyle}>{props.icon.clone()}</span>
153            </div>
154        </gicon>
155    }
156}