dioxus_material_symbols/lib.rs
1#![allow(non_snake_case)]
2#![warn(missing_docs)]
3
4//! # Dioxus Material Symbols
5//!
6//! This project provides a simple but configurable component to render Google's Material Symbols in Dioxus.
7
8use dioxus::prelude::*;
9
10/// Props for the [`MaterialIconStylesheet`](MaterialIconStylesheet) component
11#[derive(Props, PartialEq)]
12pub struct MaterialIconStylesheetProps<'a> {
13 /// Variant prop for the [`MaterialIconStylesheet`](MaterialIconStylesheet) component
14 ///
15 /// See [`MaterialIconVariant`](MaterialIconVariant) for more information.
16 #[props(default = MaterialIconVariant::Rounded)]
17 pub variant: MaterialIconVariant<'a>,
18}
19
20/// Variants (also called categories) of the Material Icon font
21///
22/// See all variants [here](https://fonts.google.com/icons).
23#[derive(PartialEq)]
24pub enum MaterialIconVariant<'a> {
25 /// Outlined
26 Outlined,
27 /// Rounded
28 Rounded,
29 /// Sharp
30 Sharp,
31 /// Self hosted font file
32 ///
33 /// Provide an url to a ttf or otf file.
34 /// You can download the files [here](https://github.com/google/material-design-icons/tree/master/font).
35 SelfHosted(&'a str),
36}
37
38/// Stylesheet component
39///
40/// This component includes the Material Symbols stylesheet.
41/// This is required to render all Material Symbols correctly.
42///
43/// You can provide a variant as a prop (e.g. Rounded).
44/// When you want to provide your own self-hosted font file,
45/// please use [`MaterialIconVariant::SelfHosted`](MaterialIconVariant::SelfHosted) and pass the
46/// file path or url to your .ttf or .otf file to it.
47/// See the [button example](https://github.com/lennartkloock/dioxus-material-symbols/blob/main/examples/button.rs).
48pub fn MaterialIconStylesheet<'a>(cx: Scope<'a, MaterialIconStylesheetProps<'a>>) -> Element<'a> {
49 let href = match &cx.props.variant {
50 MaterialIconVariant::SelfHosted(file) => {
51 return cx.render(rsx!(
52 style { format!(include_str!("./self-hosted-styles.css"), file) }
53 ));
54 }
55 MaterialIconVariant::Outlined => {
56 "https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined"
57 }
58 MaterialIconVariant::Rounded => {
59 "https://fonts.googleapis.com/icon?family=Material+Symbols+Rounded"
60 }
61 MaterialIconVariant::Sharp => {
62 "https://fonts.googleapis.com/icon?family=Material+Symbols+Sharp"
63 }
64 };
65 cx.render(rsx!(link {
66 href: "{href}",
67 rel: "stylesheet"
68 }))
69}
70
71/// Props for the [`MaterialIcon`](MaterialIcon) component
72#[derive(Props, PartialEq)]
73pub struct MaterialIconProps<'a> {
74 /// Name (e.g. `home`)
75 ///
76 /// Browse all symbols [here](https://fonts.google.com/symbols?selected=Material+Symbols).
77 pub name: &'a str,
78 /// Size in pixels
79 ///
80 /// Optional
81 pub size: Option<u32>,
82 /// Color
83 ///
84 /// Optional
85 #[props(into)]
86 pub color: Option<MaterialIconColor<'a>>,
87}
88
89/// Colors of Material Symbols
90///
91/// As described [here](https://developers.google.com/fonts/docs/material_symbols#styling_symbols_in_material_design).
92#[derive(PartialEq)]
93pub enum MaterialIconColor<'a> {
94 /// For using symbols as black on a light background.
95 Dark,
96 /// For using symbols as black on a light background.
97 DarkInactive,
98 /// For using symbols as white on a dark background.
99 Light,
100 /// For using symbols as white on a dark background.
101 LightInactive,
102 /// Custom color, any valid CSS color
103 ///
104 /// E.g.: `#0000ff` or `red`
105 Custom(&'a str),
106}
107
108impl<'a> From<&'a str> for MaterialIconColor<'a> {
109 fn from(value: &'a str) -> Self {
110 Self::Custom(value)
111 }
112}
113
114impl MaterialIconColor<'_> {
115 /// Converts the color to its corresponding CSS color
116 pub fn to_css_color(&self) -> &str {
117 match self {
118 MaterialIconColor::Dark => "rgba(0, 0, 0, 0.54)",
119 MaterialIconColor::DarkInactive => "rgba(0, 0, 0, 0.26)",
120 MaterialIconColor::Light => "rgba(255, 255, 255, 1)",
121 MaterialIconColor::LightInactive => "rgba(255, 255, 255, 0.3)",
122 MaterialIconColor::Custom(c) => c,
123 }
124 }
125}
126
127/// Material Icon component
128///
129/// This component can be used to render a Material Icon.
130pub fn MaterialIcon<'a>(cx: Scope<'a, MaterialIconProps<'a>>) -> Element<'a> {
131 // The `font-size` attribute has to be explicitly declared as `inherit` because the stylesheet sets a default of 24px
132 let css_size = cx
133 .props
134 .size
135 .map(|s| format!("{s}px"))
136 .unwrap_or_else(|| "inherit".to_string());
137 let css_color = cx
138 .props
139 .color
140 .as_ref()
141 .map(|c| format!("color: {};", c.to_css_color()))
142 .unwrap_or_default();
143 cx.render(rsx!(
144 span {
145 class: "material-symbols material-symbols-outlined material-symbols-rounded material-symbols-sharp md-48",
146 style: "font-size: {css_size}; {css_color} user-select: none;",
147 cx.props.name
148 }
149 ))
150}