Skip to main content

orbital_core_components/material/
styles.rs

1use turf::inline_style_sheet_values;
2
3/// Compiled material surface stylesheet and stable BEM class names.
4pub fn material_styles() -> &'static str {
5    let (style_sheet, _) = inline_style_sheet_values! {
6        .orbital-material {
7            position: relative;
8            box-sizing: border-box;
9            overflow: hidden;
10            width: var(--orbital-material-width, 100%);
11            max-width: var(--orbital-material-max-width, 100%);
12            margin: var(--orbital-material-margin, 0);
13            border-radius: var(--orb-radius-md);
14            color: var(--orb-color-text-primary);
15        }
16
17        .orbital-material--solid {
18            background-color: var(--orb-color-surface-canvas);
19        }
20
21        .orbital-material--frost {
22            background: color-mix(in oklab, var(--orb-color-surface-canvas) 78%, transparent);
23            backdrop-filter: saturate(108%) blur(12px);
24        }
25
26        .orbital-material--shell {
27            background-color: var(--orb-color-surface-shell);
28            backdrop-filter: saturate(128%) blur(16px);
29        }
30
31        .orbital-material--scrim {
32            background: color-mix(in oklab, black 38%, transparent);
33        }
34
35        .orbital-material--outlined {
36            background-color: var(--orb-color-surface-canvas);
37            border: var(--orb-stroke-thin) solid var(--orb-color-border-default);
38        }
39
40        .orbital-material--square {
41            border-radius: 0;
42        }
43
44        .orbital-material--elev-flat {
45            box-shadow: none;
46        }
47
48        // Flat elevation with outlined stroke separators for co-planar shell chrome.
49        // Shell chrome composes edge-specific outline modifiers at Flat elevation.
50        .orbital-material--elev-flat.orbital-material--outline-bottom {
51            border-bottom: var(--orb-stroke-thin) solid var(--orb-color-border-default);
52        }
53
54        .orbital-material--elev-flat.orbital-material--outline-end {
55            border-inline-end: var(--orb-stroke-thin) solid var(--orb-color-border-default);
56        }
57
58        .orbital-material--elev-resting {
59            box-shadow: var(--orb-elev-raised-sm);
60        }
61
62        .orbital-material--elev-raised {
63            box-shadow: var(--orb-elev-raised-md);
64        }
65
66        .orbital-material--elev-floating {
67            box-shadow: var(--orb-elev-floating);
68        }
69
70        .orbital-material--elev-modal {
71            box-shadow: var(--orb-elev-modal);
72        }
73    };
74
75    style_sheet
76}
77
78pub fn material_modifier_classes(
79    variant: orbital_base_components::MaterialVariant,
80    elevation: orbital_base_components::MaterialElevation,
81    corners: orbital_base_components::MaterialCorners,
82) -> String {
83    format!(
84        "{} {} {}",
85        variant.modifier_class(),
86        elevation.modifier_class(),
87        corners.modifier_class()
88    )
89}
90
91/// Shell edge outline applied at [`MaterialElevation::Flat`] for co-planar regions.
92#[derive(Clone, Copy, Debug, PartialEq, Eq)]
93pub enum MaterialOutlineEdge {
94    Bottom,
95    End,
96}
97
98impl MaterialOutlineEdge {
99    pub const fn modifier_class(self) -> &'static str {
100        match self {
101            Self::Bottom => "orbital-material--outline-bottom",
102            Self::End => "orbital-material--outline-end",
103        }
104    }
105}
106
107/// Outline edge modifier for Flat shell chrome, or empty when elevated / already outlined.
108pub fn material_flat_outline_modifier(
109    variant: orbital_base_components::MaterialVariant,
110    elevation: orbital_base_components::MaterialElevation,
111    edge: MaterialOutlineEdge,
112) -> Option<&'static str> {
113    if elevation == orbital_base_components::MaterialElevation::Flat
114        && variant != orbital_base_components::MaterialVariant::Outlined
115    {
116        Some(edge.modifier_class())
117    } else {
118        None
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::{material_flat_outline_modifier, material_styles, MaterialOutlineEdge};
125    use orbital_base_components::{MaterialElevation, MaterialVariant};
126
127    #[test]
128    fn flat_outline_modifiers_use_outlined_stroke() {
129        let css = material_styles();
130        assert!(css.contains(".orbital-material--elev-flat.orbital-material--outline-bottom"));
131        assert!(css.contains(".orbital-material--elev-flat.orbital-material--outline-end"));
132        assert!(css.contains("var(--orb-color-border-default)"));
133    }
134
135    #[test]
136    fn flat_outline_modifier_only_for_flat_non_outlined() {
137        assert_eq!(
138            material_flat_outline_modifier(
139                MaterialVariant::Solid,
140                MaterialElevation::Flat,
141                MaterialOutlineEdge::Bottom
142            ),
143            Some("orbital-material--outline-bottom")
144        );
145        assert_eq!(
146            material_flat_outline_modifier(
147                MaterialVariant::Outlined,
148                MaterialElevation::Flat,
149                MaterialOutlineEdge::Bottom
150            ),
151            None
152        );
153        assert_eq!(
154            material_flat_outline_modifier(
155                MaterialVariant::Solid,
156                MaterialElevation::Resting,
157                MaterialOutlineEdge::End
158            ),
159            None
160        );
161    }
162
163    #[test]
164    fn shell_variant_uses_neutral_background2() {
165        let css = material_styles();
166        assert!(css.contains(".orbital-material--shell"));
167        assert!(css.contains("var(--orb-color-surface-shell)"));
168    }
169}