1pub mod prelude;
2#[macro_use] pub mod units;
3#[macro_use] pub mod properties;
4#[doc(hidden)] #[macro_use] mod shortcuts;
5#[macro_use] pub mod selector;
6mod append_property;
7pub mod color;
9pub mod font_face;
10pub mod media;
11
12pub use append_property::AppendProperty;
13pub use color::Color;
14pub use hobo_css_macros as macros;
15pub use macros::AppendProperty;
16#[doc(hidden)] pub use paste;
17pub use properties::*;
18pub use units::{Unit, F32};
19
20#[derive(Debug, PartialEq, Eq, Hash, Clone)]
26pub enum Rule {
27 Style(StyleRule),
28 Media(media::MediaSelector, Style),
29 FontFace(font_face::FontFace),
31}
32
33impl std::fmt::Display for Rule {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 match self {
36 Self::Style(x) => x.fmt(f),
37 Self::Media(selector, style) => write!(f, "@media {}{{{}}}", selector, style),
38 Self::FontFace(x) => x.fmt(f),
39 }
40 }
41}
42
43#[derive(Debug, PartialEq, Eq, Hash, Clone)]
44pub struct StyleRule(pub selector::Selector, pub Vec<Property>);
45
46impl std::fmt::Display for StyleRule {
47 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48 self.0.fmt(f)?;
49 "{".fmt(f)?;
50 for property in &self.1 {
51 property.fmt(f)?;
52 }
53 "}".fmt(f)
54 }
55}
56
57#[derive(Debug, PartialEq, Eq, Hash, Clone)]
58pub struct Style(pub Vec<Rule>);
59
60impl std::fmt::Display for Style {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 for rule in &self.0 {
63 rule.fmt(f)?;
64 }
65 Ok(())
66 }
67}
68
69impl Style {
70 pub fn append(&mut self, other: &mut Style) { self.0.append(&mut other.0); }
71}
72
73impl std::ops::Add for Style {
74 type Output = Self;
75
76 fn add(mut self, mut rhs: Self) -> Self {
77 self.0.append(&mut rhs.0);
78 self
79 }
80}
81
82#[macro_export]
83macro_rules! properties {
84 ($($e:expr),*$(,)?) => {{
85 let mut v = Vec::new();
86 $($crate::AppendProperty::append_property($e, &mut v);)*
87 v
88 }};
89}
90
91#[macro_export]
92macro_rules! class {
93 ($($rules:tt)*) => {$crate::style!(.& { $($rules)* })};
94}
95
96#[macro_export]
98macro_rules! rule {
99 (@font-face { $($prop:ident : $value:expr),*$(,)? }) => {{
100 use $crate::font_face::*;
101
102 $crate::Rule::FontFace($crate::font_face::FontFace {
103 $($prop: $value),*,
104 ..$crate::font_face::FontFace::default()
105 })
106 }};
107
108 ((@media $($selector:tt)+) { $($style:tt)* }) => {
110 $crate::Rule::Media(
111 $crate::macros::media_selector!($($selector)+),
112 $crate::style!($($style)*),
113 )
114 };
115
116 (($($selector:tt)+) { $($rules:tt)* }) => {
118 $crate::Rule::Style($crate::StyleRule(
119 $crate::macros::selector!($($selector)+),
120 $crate::properties!($($rules)*),
121 ))
122 };
123
124 (($($head:tt)+) $cur:tt $($tail:tt)*) => {
126 $crate::rule!(($($head)+ $cur) $($tail)*)
127 };
128
129 ($head:tt $($tail:tt)*) => {
131 $crate::rule!(($head) $($tail)*)
132 };
133}
134
135#[macro_export]
137#[doc(hidden)]
138macro_rules! __accumulate_style {
139 (
140 acc = $acc:expr,
141 rules = ()
142 ) => {{
143 $crate::Style($acc)
144 }};
145
146 (
147 acc = $acc:expr,
148 rules = ([$($rule:tt)+] $($rest:tt)*)
149 ) => {{
150 $acc.push($crate::rule!($($rule)+));
151 $crate::__accumulate_style!(acc = $acc, rules = ($($rest)*))
152 }};
153}
154
155#[macro_export]
157#[doc(hidden)]
158macro_rules! __style {
159 (
160 rules = ($($rules:tt)*),
161 new_rule = (),
162 rest = (),
163 ) => {{
164 let mut acc = Vec::new();
165 $crate::__accumulate_style!(acc = acc, rules = ($($rules)*))
166 }};
167
168 (
169 rules = ($($rules:tt)*),
170 new_rule = ($($new_rule:tt)*),
171 rest = ({ $($decls:tt)* }),
172 ) => {
173 $crate::__style!{
174 rules = ($($rules)* [$($new_rule)* { $($decls)* }]),
175 new_rule = (),
176 rest = (),
177 }
178 };
179
180 (
181 rules = ($($rules:tt)*),
182 new_rule = ($($new_rule:tt)*),
183 rest = ({ $($decls:tt)* } $($rest:tt)*),
184 ) => {
185 $crate::__style!{
186 rules = ($($rules)* [$($new_rule)* { $($decls)* }]),
187 new_rule = (),
188 rest = ($($rest)*),
189 }
190 };
191
192 (
193 rules = ($($rules:tt)*),
194 new_rule = ($($new_rule:tt)*),
195 rest = ($cur:tt $($rest:tt)*),
196 ) => {
197 $crate::__style!{
198 rules = ($($rules)*),
199 new_rule = ($($new_rule)* $cur),
200 rest = ($($rest)*),
201 }
202 };
203}
204
205#[macro_export]
206macro_rules! style {
207 ($($tt:tt)+) => {
208 $crate::__style! {
209 rules = (),
210 new_rule = (),
211 rest = ($($tt)+),
212 }
213 };
214}
215
216