Skip to main content

ui_storybook/components/recorder/
capture_mode_tabs.rs

1//! `CaptureModeTabs` — Screen / Window / Area tabs at the top of the
2//! tray record popover (M-UI.6 / AUT-126). Wraps `SegmentedControl`.
3
4use leptos::prelude::*;
5
6use crate::components::primitives::{Segment, SegmentedControl};
7use crate::fixtures::recorder::CaptureMode;
8
9impl CaptureMode {
10    /// Stable slug used both for the underlying `SegmentedControl`
11    /// segment id and as a kebab-case data attribute.
12    #[must_use]
13    pub fn slug(self) -> &'static str {
14        match self {
15            CaptureMode::Screen => "screen",
16            CaptureMode::Window => "window",
17            CaptureMode::Area => "area",
18        }
19    }
20}
21
22#[component]
23pub fn CaptureModeTabs(
24    /// Currently-selected capture mode. Passed in from above; the
25    /// component never owns this state.
26    selected: CaptureMode,
27    /// Modes to render disabled (e.g. `Area` while permissions are
28    /// pending).
29    #[prop(optional)]
30    disabled_modes: Vec<CaptureMode>,
31) -> impl IntoView {
32    let segments = vec![
33        Segment {
34            id: CaptureMode::Screen.slug(),
35            label: "Screen",
36            icon: Some("▢"),
37            disabled: disabled_modes.contains(&CaptureMode::Screen),
38        },
39        Segment {
40            id: CaptureMode::Window.slug(),
41            label: "Window",
42            icon: Some("◫"),
43            disabled: disabled_modes.contains(&CaptureMode::Window),
44        },
45        Segment {
46            id: CaptureMode::Area.slug(),
47            label: "Area",
48            icon: Some("⊞"),
49            disabled: disabled_modes.contains(&CaptureMode::Area),
50        },
51    ];
52    let active = selected.slug();
53    view! {
54        <SegmentedControl
55            segments=segments
56            active=active.to_string()
57            label="Capture mode".to_string()
58        />
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn each_mode_has_unique_slug() {
68        let slugs = [
69            CaptureMode::Screen.slug(),
70            CaptureMode::Window.slug(),
71            CaptureMode::Area.slug(),
72        ];
73        let mut sorted = slugs.to_vec();
74        sorted.sort_unstable();
75        sorted.dedup();
76        assert_eq!(sorted.len(), slugs.len());
77    }
78
79    #[test]
80    fn slugs_are_lowercase_ascii() {
81        for s in [CaptureMode::Screen, CaptureMode::Window, CaptureMode::Area] {
82            assert!(s.slug().chars().all(|c| c.is_ascii_lowercase()));
83        }
84    }
85}