1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4#[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#[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#[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}