Skip to main content

kozan_core/html/
html_button_element.rs

1//! `HTMLButtonElement` — a clickable button element.
2//!
3//! Chrome equivalent: `HTMLButtonElement` (inherits from `HTMLFormControlElement`).
4//! Adds `label`, `type`, `value`, `form` association.
5//!
6//! `#[derive(Element)]` generates the full trait chain including `HtmlElement`.
7//! `#[derive(Props)]` generates `label()` / `set_label()` etc.
8
9use kozan_macros::{Element, Props};
10
11use super::form_control::FormControlElement;
12use crate::Handle;
13
14/// A clickable button element (`<button>`).
15///
16/// Chrome hierarchy: `HTMLElement → HTMLFormControlElement → HTMLButtonElement`.
17#[derive(Copy, Clone, Element)]
18#[element(tag = "button", focusable, data = ButtonData)]
19pub struct HtmlButtonElement(Handle);
20
21/// Element-specific data for `<button>`.
22#[derive(Default, Clone, Props)]
23#[props(element = HtmlButtonElement)]
24pub struct ButtonData {
25    /// The button's text label.
26    #[prop]
27    pub label: String,
28}
29
30impl FormControlElement for HtmlButtonElement {}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35    use crate::dom::document::Document;
36    use crate::dom::traits::Element;
37
38    #[test]
39    fn button_tag_name() {
40        let doc = Document::new();
41        let btn = doc.create::<HtmlButtonElement>();
42        assert_eq!(btn.tag_name(), "button");
43    }
44
45    #[test]
46    fn button_label_prop() {
47        let doc = Document::new();
48        let btn = doc.create::<HtmlButtonElement>();
49
50        assert_eq!(btn.label(), "");
51        btn.set_label("Click me".to_string());
52        assert_eq!(btn.label(), "Click me");
53    }
54
55    #[test]
56    fn button_disabled_via_form_control() {
57        let doc = Document::new();
58        let btn = doc.create::<HtmlButtonElement>();
59
60        // FormControlElement trait: disabled via attributes.
61        assert!(!btn.disabled());
62
63        btn.set_disabled(true);
64        assert!(btn.disabled());
65        // The disabled attribute should be present.
66        assert!(btn.attribute("disabled").is_some());
67
68        btn.set_disabled(false);
69        assert!(!btn.disabled());
70        assert!(btn.attribute("disabled").is_none());
71    }
72
73    #[test]
74    fn button_name_via_form_control() {
75        let doc = Document::new();
76        let btn = doc.create::<HtmlButtonElement>();
77
78        assert_eq!(btn.name(), "");
79        btn.set_name("my-button");
80        assert_eq!(btn.name(), "my-button");
81    }
82
83    #[test]
84    fn button_form_id() {
85        let doc = Document::new();
86        let btn = doc.create::<HtmlButtonElement>();
87
88        assert!(btn.form_id().is_none());
89        btn.set_form_id("my-form");
90        assert_eq!(btn.form_id(), Some("my-form".to_string()));
91    }
92
93    #[test]
94    fn button_required_via_form_control() {
95        let doc = Document::new();
96        let btn = doc.create::<HtmlButtonElement>();
97
98        assert!(!btn.required());
99        btn.set_required(true);
100        assert!(btn.required());
101    }
102
103    #[test]
104    fn button_check_validity_default() {
105        let doc = Document::new();
106        let btn = doc.create::<HtmlButtonElement>();
107        // Default: always valid.
108        assert!(btn.check_validity());
109    }
110}