tailwind_rs_core/responsive/
breakpoints.rs1use serde::{Deserialize, Serialize};
6use std::str::FromStr;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum Breakpoint {
11 Base,
13 Sm,
15 Md,
17 Lg,
19 Xl,
21 Xl2,
23}
24
25impl Breakpoint {
26 pub fn min_width(&self) -> u32 {
28 match self {
29 Breakpoint::Base => 0,
30 Breakpoint::Sm => 640,
31 Breakpoint::Md => 768,
32 Breakpoint::Lg => 1024,
33 Breakpoint::Xl => 1280,
34 Breakpoint::Xl2 => 1536,
35 }
36 }
37
38 pub fn media_query(&self) -> &'static str {
40 match self {
41 Breakpoint::Base => "",
42 Breakpoint::Sm => "(min-width: 640px)",
43 Breakpoint::Md => "(min-width: 768px)",
44 Breakpoint::Lg => "(min-width: 1024px)",
45 Breakpoint::Xl => "(min-width: 1280px)",
46 Breakpoint::Xl2 => "(min-width: 1536px)",
47 }
48 }
49
50 pub fn prefix(&self) -> &'static str {
52 match self {
53 Breakpoint::Base => "",
54 Breakpoint::Sm => "sm:",
55 Breakpoint::Md => "md:",
56 Breakpoint::Lg => "lg:",
57 Breakpoint::Xl => "xl:",
58 Breakpoint::Xl2 => "2xl:",
59 }
60 }
61
62 pub fn all() -> Vec<Breakpoint> {
64 vec![
65 Breakpoint::Base,
66 Breakpoint::Sm,
67 Breakpoint::Md,
68 Breakpoint::Lg,
69 Breakpoint::Xl,
70 Breakpoint::Xl2,
71 ]
72 }
73
74 pub fn next(&self) -> Option<Breakpoint> {
76 match self {
77 Breakpoint::Base => Some(Breakpoint::Sm),
78 Breakpoint::Sm => Some(Breakpoint::Md),
79 Breakpoint::Md => Some(Breakpoint::Lg),
80 Breakpoint::Lg => Some(Breakpoint::Xl),
81 Breakpoint::Xl => Some(Breakpoint::Xl2),
82 Breakpoint::Xl2 => None,
83 }
84 }
85
86 pub fn previous(&self) -> Option<Breakpoint> {
88 match self {
89 Breakpoint::Base => None,
90 Breakpoint::Sm => Some(Breakpoint::Base),
91 Breakpoint::Md => Some(Breakpoint::Sm),
92 Breakpoint::Lg => Some(Breakpoint::Md),
93 Breakpoint::Xl => Some(Breakpoint::Lg),
94 Breakpoint::Xl2 => Some(Breakpoint::Xl),
95 }
96 }
97}
98
99impl FromStr for Breakpoint {
100 type Err = String;
101
102 fn from_str(s: &str) -> Result<Self, Self::Err> {
103 match s.to_lowercase().as_str() {
104 "" | "base" => Ok(Breakpoint::Base),
105 "sm" => Ok(Breakpoint::Sm),
106 "md" => Ok(Breakpoint::Md),
107 "lg" => Ok(Breakpoint::Lg),
108 "xl" => Ok(Breakpoint::Xl),
109 "2xl" | "xl2" => Ok(Breakpoint::Xl2),
110 _ => Err(format!("Invalid breakpoint: {}", s)),
111 }
112 }
113}
114
115impl std::fmt::Display for Breakpoint {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 match self {
118 Breakpoint::Base => write!(f, "base"),
119 Breakpoint::Sm => write!(f, "sm"),
120 Breakpoint::Md => write!(f, "md"),
121 Breakpoint::Lg => write!(f, "lg"),
122 Breakpoint::Xl => write!(f, "xl"),
123 Breakpoint::Xl2 => write!(f, "2xl"),
124 }
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn test_breakpoint_min_width() {
134 assert_eq!(Breakpoint::Base.min_width(), 0);
135 assert_eq!(Breakpoint::Sm.min_width(), 640);
136 assert_eq!(Breakpoint::Md.min_width(), 768);
137 assert_eq!(Breakpoint::Lg.min_width(), 1024);
138 assert_eq!(Breakpoint::Xl.min_width(), 1280);
139 assert_eq!(Breakpoint::Xl2.min_width(), 1536);
140 }
141
142 #[test]
143 fn test_breakpoint_media_query() {
144 assert_eq!(Breakpoint::Base.media_query(), "");
145 assert_eq!(Breakpoint::Sm.media_query(), "(min-width: 640px)");
146 assert_eq!(Breakpoint::Md.media_query(), "(min-width: 768px)");
147 assert_eq!(Breakpoint::Lg.media_query(), "(min-width: 1024px)");
148 assert_eq!(Breakpoint::Xl.media_query(), "(min-width: 1280px)");
149 assert_eq!(Breakpoint::Xl2.media_query(), "(min-width: 1536px)");
150 }
151
152 #[test]
153 fn test_breakpoint_prefix() {
154 assert_eq!(Breakpoint::Base.prefix(), "");
155 assert_eq!(Breakpoint::Sm.prefix(), "sm:");
156 assert_eq!(Breakpoint::Md.prefix(), "md:");
157 assert_eq!(Breakpoint::Lg.prefix(), "lg:");
158 assert_eq!(Breakpoint::Xl.prefix(), "xl:");
159 assert_eq!(Breakpoint::Xl2.prefix(), "2xl:");
160 }
161
162 #[test]
163 fn test_breakpoint_from_str() {
164 assert_eq!(Breakpoint::from_str("").unwrap(), Breakpoint::Base);
165 assert_eq!(Breakpoint::from_str("base").unwrap(), Breakpoint::Base);
166 assert_eq!(Breakpoint::from_str("sm").unwrap(), Breakpoint::Sm);
167 assert_eq!(Breakpoint::from_str("md").unwrap(), Breakpoint::Md);
168 assert_eq!(Breakpoint::from_str("lg").unwrap(), Breakpoint::Lg);
169 assert_eq!(Breakpoint::from_str("xl").unwrap(), Breakpoint::Xl);
170 assert_eq!(Breakpoint::from_str("2xl").unwrap(), Breakpoint::Xl2);
171 assert_eq!(Breakpoint::from_str("xl2").unwrap(), Breakpoint::Xl2);
172 }
173
174 #[test]
175 fn test_breakpoint_display() {
176 assert_eq!(format!("{}", Breakpoint::Base), "base");
177 assert_eq!(format!("{}", Breakpoint::Sm), "sm");
178 assert_eq!(format!("{}", Breakpoint::Md), "md");
179 assert_eq!(format!("{}", Breakpoint::Lg), "lg");
180 assert_eq!(format!("{}", Breakpoint::Xl), "xl");
181 assert_eq!(format!("{}", Breakpoint::Xl2), "2xl");
182 }
183
184 #[test]
185 fn test_breakpoint_all() {
186 let all = Breakpoint::all();
187 assert_eq!(all.len(), 6);
188 assert_eq!(all[0], Breakpoint::Base);
189 assert_eq!(all[1], Breakpoint::Sm);
190 assert_eq!(all[2], Breakpoint::Md);
191 assert_eq!(all[3], Breakpoint::Lg);
192 assert_eq!(all[4], Breakpoint::Xl);
193 assert_eq!(all[5], Breakpoint::Xl2);
194 }
195
196 #[test]
197 fn test_breakpoint_next() {
198 assert_eq!(Breakpoint::Base.next(), Some(Breakpoint::Sm));
199 assert_eq!(Breakpoint::Sm.next(), Some(Breakpoint::Md));
200 assert_eq!(Breakpoint::Md.next(), Some(Breakpoint::Lg));
201 assert_eq!(Breakpoint::Lg.next(), Some(Breakpoint::Xl));
202 assert_eq!(Breakpoint::Xl.next(), Some(Breakpoint::Xl2));
203 assert_eq!(Breakpoint::Xl2.next(), None);
204 }
205
206 #[test]
207 fn test_breakpoint_previous() {
208 assert_eq!(Breakpoint::Base.previous(), None);
209 assert_eq!(Breakpoint::Sm.previous(), Some(Breakpoint::Base));
210 assert_eq!(Breakpoint::Md.previous(), Some(Breakpoint::Sm));
211 assert_eq!(Breakpoint::Lg.previous(), Some(Breakpoint::Md));
212 assert_eq!(Breakpoint::Xl.previous(), Some(Breakpoint::Lg));
213 assert_eq!(Breakpoint::Xl2.previous(), Some(Breakpoint::Xl));
214 }
215}