ui_storybook/components/primitives/
surface.rs1use leptos::prelude::*;
10
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
14pub enum SurfaceKind {
15 #[default]
18 Base,
19 Elevated,
22 Popover,
25 Selected,
28 Glass,
31}
32
33impl SurfaceKind {
34 #[must_use]
36 pub fn css(self) -> &'static str {
37 match self {
38 SurfaceKind::Base => "surface-base",
39 SurfaceKind::Elevated => "surface-elevated",
40 SurfaceKind::Popover => "surface-popover",
41 SurfaceKind::Selected => "surface-selected",
42 SurfaceKind::Glass => "surface-glass",
43 }
44 }
45}
46
47#[component]
48pub fn Surface(
49 #[prop(optional)] kind: SurfaceKind,
50 #[prop(optional, into)] extra_class: String,
51 children: Children,
52) -> impl IntoView {
53 let class = format!(
54 "surface {}{}{}",
55 kind.css(),
56 if extra_class.is_empty() { "" } else { " " },
57 extra_class,
58 );
59 view! { <div class=class>{children()}</div> }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn each_kind_has_a_unique_class() {
68 let classes = [
69 SurfaceKind::Base.css(),
70 SurfaceKind::Elevated.css(),
71 SurfaceKind::Popover.css(),
72 SurfaceKind::Selected.css(),
73 SurfaceKind::Glass.css(),
74 ];
75 let mut sorted = classes.to_vec();
76 sorted.sort_unstable();
77 sorted.dedup();
78 assert_eq!(sorted.len(), classes.len(), "duplicate Surface CSS class");
79 }
80
81 #[test]
82 fn each_class_starts_with_surface_prefix() {
83 for k in [
84 SurfaceKind::Base,
85 SurfaceKind::Elevated,
86 SurfaceKind::Popover,
87 SurfaceKind::Selected,
88 SurfaceKind::Glass,
89 ] {
90 assert!(
91 k.css().starts_with("surface-"),
92 "missing prefix: {}",
93 k.css()
94 );
95 }
96 }
97}