1use serde_json::Value;
8
9use crate::types::Props;
10
11fn str_prop<'a>(props: &'a Props, key: &str) -> Option<&'a str> {
12 props.get(key).and_then(Value::as_str)
13}
14
15pub fn is_vertical(props: &Props) -> bool {
17 str_prop(props, "orientation") == Some("vertical")
18}
19
20pub fn is_rail(props: &Props) -> bool {
22 is_vertical(props) && str_prop(props, "variant") == Some("bar")
23}
24
25pub fn item_count(props: &Props) -> usize {
27 props.get("items").and_then(Value::as_array).map_or(0, |a| a.iter().filter(|o| o.is_object()).count())
28}
29
30pub fn rail_height(props: &Props, tab_bar: f32) -> f32 {
32 item_count(props) as f32 * tab_bar
33}
34
35pub fn rail_item(index: usize, width: f32, tab_bar: f32) -> (f32, f32, f32, f32) {
37 (0.0, index as f32 * tab_bar, width, tab_bar)
38}
39
40pub fn badge_text(count: Option<&Value>) -> Option<String> {
43 let n = count.and_then(Value::as_f64).filter(|n| n.is_finite())?.floor();
44 if n <= 0.0 {
45 None
46 } else if n > 99.0 {
47 Some("99+".into())
48 } else {
49 Some(format!("{n}"))
50 }
51}
52
53pub fn option_badge(variant: Option<&str>, option: &Value) -> Option<String> {
55 if variant != Some("bar") {
56 return None;
57 }
58 badge_text(option.get("count"))
59}
60
61pub fn item_accessibility_label(label: &str, badge: Option<&str>) -> String {
64 match badge {
65 Some(b) => format!("{label}, {b}"),
66 None => label.to_string(),
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use serde_json::json;
74
75 #[test]
76 fn badges_hide_at_zero_and_cap_at_99() {
77 assert_eq!(badge_text(None), None);
78 assert_eq!(badge_text(Some(&json!(0))), None);
79 assert_eq!(badge_text(Some(&json!(3))), Some("3".into()));
80 assert_eq!(badge_text(Some(&json!(99))), Some("99".into()));
81 assert_eq!(badge_text(Some(&json!(100))), Some("99+".into()));
82 assert_eq!(badge_text(Some(&json!("3"))), None);
83 assert_eq!(option_badge(Some("segmented"), &json!({"count": 3})), None);
84 assert_eq!(option_badge(Some("bar"), &json!({"count": 3})).as_deref(), Some("3"));
85 assert_eq!(item_accessibility_label("Chats", Some("3")), "Chats, 3");
86 }
87}