zino_dioxus/class/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! CSS classes for components.

use dioxus_core::{prelude::*, AttributeValue};
use smallvec::SmallVec;
use std::{borrow::Cow, fmt};

/// A class type for dioxus components.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Class {
    /// Optional namespace.
    namespace: Option<&'static str>,
    /// A list of classes.
    classes: SmallVec<[&'static str; 4]>,
}

impl Class {
    /// Creates a new instance.
    #[inline]
    pub fn new(class: &'static str) -> Self {
        Self {
            namespace: None,
            classes: class.split_whitespace().collect(),
        }
    }

    /// Creates a new instance with the specific namespace.
    #[inline]
    pub fn with_namespace(namespace: &'static str, class: &'static str) -> Self {
        Self {
            namespace: (!namespace.is_empty()).then_some(namespace),
            classes: class.split_whitespace().collect(),
        }
    }

    /// Adds a class to the list, omitting any that are already present.
    #[inline]
    pub fn add(&mut self, class: &'static str) {
        if !(class.is_empty() || self.contains(class)) {
            self.classes.push(class);
        }
    }

    /// Removes a class from the list.
    #[inline]
    pub fn remove(&mut self, class: &str) {
        self.classes.retain(|s| s != &class)
    }

    /// Toggles a class in the list.
    #[inline]
    pub fn toggle(&mut self, class: &'static str) {
        if let Some(index) = self.classes.iter().position(|&s| s == class) {
            self.classes.remove(index);
        } else {
            self.classes.push(class);
        }
    }

    /// Replaces a class in the list with a new class.
    #[inline]
    pub fn replace(&mut self, class: &str, new_class: &'static str) {
        if let Some(index) = self.classes.iter().position(|&s| s == class) {
            self.classes[index] = new_class;
        }
    }

    /// Returns `true` if a given class has been added.
    #[inline]
    pub fn contains(&self, class: &str) -> bool {
        self.classes.iter().any(|&s| s == class)
    }

    /// Returns `true` if the class list is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.classes.is_empty()
    }

    /// Returns the namespace.
    #[inline]
    pub fn namespace(&self) -> Option<&str> {
        self.namespace.filter(|s| !s.is_empty())
    }

    /// Formats `self` as a `Cow<str>`.
    pub fn format(&self) -> Cow<'_, str> {
        if self.classes.is_empty() {
            return Cow::Borrowed("");
        }

        let classes = self.classes.as_slice();
        if let Some(namespace) = self.namespace() {
            let class = if let [class] = classes {
                [namespace, class].join("-")
            } else {
                classes
                    .iter()
                    .filter(|s| !s.is_empty())
                    .map(|s| [namespace, s].join("-"))
                    .collect::<Vec<_>>()
                    .join(" ")
            };
            Cow::Owned(class)
        } else if let [class] = classes {
            Cow::Borrowed(class)
        } else {
            Cow::Owned(classes.join(" "))
        }
    }
}

impl From<&'static str> for Class {
    #[inline]
    fn from(class: &'static str) -> Self {
        Self::new(class)
    }
}

impl From<Vec<&'static str>> for Class {
    #[inline]
    fn from(classes: Vec<&'static str>) -> Self {
        Self {
            namespace: None,
            classes: SmallVec::from_vec(classes),
        }
    }
}

impl<const N: usize> From<[&'static str; N]> for Class {
    #[inline]
    fn from(classes: [&'static str; N]) -> Self {
        Self {
            namespace: None,
            classes: SmallVec::from_slice(&classes),
        }
    }
}

impl fmt::Display for Class {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let format = self.format();
        write!(f, "{format}")
    }
}

impl IntoAttributeValue for Class {
    #[inline]
    fn into_value(self) -> AttributeValue {
        AttributeValue::Text(self.format().into_owned())
    }
}