Skip to main content

use_layer/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4/// Semantic UI layer roles.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
6pub enum LayerRole {
7    Base,
8    Raised,
9    Sticky,
10    Dropdown,
11    Popover,
12    Tooltip,
13    Modal,
14    Toast,
15    Overlay,
16}
17
18impl LayerRole {
19    pub fn index(self) -> LayerIndex {
20        match self {
21            Self::Base => LayerIndex::new(0),
22            Self::Raised => LayerIndex::new(100),
23            Self::Sticky => LayerIndex::new(200),
24            Self::Dropdown => LayerIndex::new(1_000),
25            Self::Popover => LayerIndex::new(1_100),
26            Self::Tooltip => LayerIndex::new(1_200),
27            Self::Modal => LayerIndex::new(1_300),
28            Self::Toast => LayerIndex::new(1_400),
29            Self::Overlay => LayerIndex::new(1_500),
30        }
31    }
32
33    pub fn sits_above(self, other: Self) -> bool {
34        self.index() > other.index()
35    }
36}
37
38/// Numeric z-order index.
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
40pub struct LayerIndex(i32);
41
42impl LayerIndex {
43    pub fn new(value: i32) -> Self {
44        Self(value)
45    }
46
47    pub fn value(self) -> i32 {
48        self.0
49    }
50}
51
52/// Ordered layer stack metadata.
53#[derive(Debug, Clone, Default, PartialEq, Eq)]
54pub struct LayerStack {
55    layers: Vec<LayerRole>,
56}
57
58impl LayerStack {
59    pub fn new(layers: Vec<LayerRole>) -> Self {
60        Self { layers }
61    }
62
63    pub fn layers(&self) -> &[LayerRole] {
64        &self.layers
65    }
66
67    pub fn top(&self) -> Option<LayerRole> {
68        self.layers
69            .iter()
70            .copied()
71            .max_by_key(|layer| layer.index())
72    }
73
74    pub fn is_above(&self, layer: LayerRole, other: LayerRole) -> bool {
75        self.layers.contains(&layer) && self.layers.contains(&other) && layer.sits_above(other)
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::{LayerIndex, LayerRole, LayerStack};
82
83    #[test]
84    fn compares_layer_roles() {
85        assert!(LayerRole::Modal.sits_above(LayerRole::Popover));
86        assert!(!LayerRole::Base.sits_above(LayerRole::Raised));
87        assert_eq!(LayerRole::Tooltip.index().value(), 1_200);
88        assert!(LayerIndex::new(20) > LayerIndex::new(10));
89    }
90
91    #[test]
92    fn finds_top_layer_in_stack() {
93        let stack = LayerStack::new(vec![LayerRole::Base, LayerRole::Popover, LayerRole::Modal]);
94
95        assert_eq!(stack.top(), Some(LayerRole::Modal));
96        assert!(stack.is_above(LayerRole::Modal, LayerRole::Popover));
97        assert!(!stack.is_above(LayerRole::Toast, LayerRole::Modal));
98    }
99}