Skip to main content

stratum_components/overlay/
alert_dialog.rs

1//! Styled AlertDialog component.
2
3use crate::common::merge_classes;
4use stratum_core::aria::{AriaAttributes, AriaRole};
5use stratum_core::render::RenderOutput;
6
7/// Properties for the AlertDialog content.
8#[derive(Debug, Clone, PartialEq, Default)]
9pub struct AlertDialogProps {
10    pub open: bool,
11    pub class: Option<String>,
12    pub aria_label: Option<String>,
13    pub aria_describedby: Option<String>,
14}
15
16pub struct AlertDialog;
17
18impl AlertDialog {
19    const BASE: &'static str = "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 sm:rounded-lg";
20
21    pub fn classes(props: &AlertDialogProps) -> String {
22        merge_classes(Self::BASE, &props.class)
23    }
24
25    pub fn render(props: &AlertDialogProps) -> RenderOutput {
26        let classes = Self::classes(props);
27        let mut aria = AriaAttributes::new()
28            .with_role(AriaRole::AlertDialog)
29            .with_modal(true);
30
31        if let Some(ref label) = props.aria_label {
32            aria = aria.with_label(label.clone());
33        }
34        if let Some(ref desc) = props.aria_describedby {
35            aria = aria.with_describedby(desc.clone());
36        }
37
38        RenderOutput::new()
39            .with_tag("div")
40            .with_class(classes)
41            .with_aria(aria)
42            .with_data("state", if props.open { "open" } else { "closed" })
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn alert_dialog_role() {
52        let props = AlertDialogProps::default();
53        let output = AlertDialog::render(&props);
54        assert_eq!(output.aria.role, Some(AriaRole::AlertDialog));
55        assert_eq!(output.aria.modal, Some(true));
56    }
57
58    #[test]
59    fn alert_dialog_open_state() {
60        let props = AlertDialogProps {
61            open: true,
62            ..Default::default()
63        };
64        let output = AlertDialog::render(&props);
65        assert!(
66            output
67                .data_attrs
68                .iter()
69                .any(|(k, v)| k == "state" && v == "open")
70        );
71    }
72}