Skip to main content

mittens_engine/engine/ecs/component/
html_element.rs

1use crate::engine::ecs::ComponentId;
2use crate::engine::ecs::component::Component;
3
4/// The structural/semantic role of a layout node, analogous to the HTML element type.
5///
6/// Determines the UA-stylesheet default for `display` when `StyleComponent.display` is `None`.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8pub enum ElementType {
9    // Block-level (default display: block)
10    Div,
11    P,
12    H1,
13    H2,
14    H3,
15    H4,
16    H5,
17    H6,
18    Article,
19    Section,
20    Header,
21    Footer,
22    Main,
23    Nav,
24    Aside,
25
26    // Inline (default display: inline)
27    Span,
28    A,
29    Strong,
30    Em,
31    Code,
32
33    // Special
34    /// Block + also acts as a LayoutComponent root content node.
35    Body,
36    /// Replaced element; intrinsic size from asset.
37    Img,
38
39    // Table (phase 2)
40    Table,
41    Thead,
42    Tbody,
43    Tr,
44    Th,
45    Td,
46
47    // Form (phase 3)
48    Input,
49    Button,
50    Textarea,
51    Select,
52
53    /// Generic — no implied display; `StyleComponent` must set `display` explicitly.
54    #[default]
55    Element,
56}
57
58impl ElementType {
59    /// The UA-stylesheet default `display` for this element type.
60    ///
61    /// Returns `None` for `Element` (no default — caller must set `StyleComponent.display`).
62    pub fn default_display(&self) -> Option<crate::engine::ecs::component::style::Display> {
63        use crate::engine::ecs::component::style::Display;
64        match self {
65            ElementType::Div
66            | ElementType::P
67            | ElementType::H1
68            | ElementType::H2
69            | ElementType::H3
70            | ElementType::H4
71            | ElementType::H5
72            | ElementType::H6
73            | ElementType::Article
74            | ElementType::Section
75            | ElementType::Header
76            | ElementType::Footer
77            | ElementType::Main
78            | ElementType::Nav
79            | ElementType::Aside
80            | ElementType::Body => Some(Display::Block),
81
82            ElementType::Span
83            | ElementType::A
84            | ElementType::Strong
85            | ElementType::Em
86            | ElementType::Code => Some(Display::Inline),
87
88            ElementType::Table => Some(Display::Block),
89            ElementType::Thead | ElementType::Tbody | ElementType::Tr => Some(Display::Block),
90            ElementType::Th | ElementType::Td => Some(Display::Block),
91
92            ElementType::Input | ElementType::Button | ElementType::Select => {
93                Some(Display::InlineBlock)
94            }
95            ElementType::Textarea => Some(Display::Block),
96
97            ElementType::Img => Some(Display::InlineBlock),
98
99            ElementType::Element => None,
100        }
101    }
102}
103
104/// Structural/semantic type of a layout node — the HTML-element half of the layout pair.
105///
106/// Always combined with [`StyleComponent`](crate::engine::ecs::component::StyleComponent)
107/// for visual/layout properties and
108/// [`LayoutComponent`](crate::engine::ecs::component::LayoutComponent) at the root.
109///
110/// `element_type` determines the UA-stylesheet default for any CSS property not explicitly
111/// set in `StyleComponent` — just like browsers: `div` → block, `span` → inline, etc.
112#[derive(Debug, Clone)]
113pub struct HtmlElementComponent {
114    pub element_type: ElementType,
115    component: Option<ComponentId>,
116}
117
118impl HtmlElementComponent {
119    pub fn new(element_type: ElementType) -> Self {
120        Self {
121            element_type,
122            component: None,
123        }
124    }
125
126    pub fn div() -> Self {
127        Self::new(ElementType::Div)
128    }
129    pub fn span() -> Self {
130        Self::new(ElementType::Span)
131    }
132    pub fn body() -> Self {
133        Self::new(ElementType::Body)
134    }
135    pub fn header() -> Self {
136        Self::new(ElementType::Header)
137    }
138    pub fn p() -> Self {
139        Self::new(ElementType::P)
140    }
141}
142
143impl Component for HtmlElementComponent {
144    fn name(&self) -> &'static str {
145        "html_element"
146    }
147
148    fn set_id(&mut self, id: ComponentId) {
149        self.component = Some(id);
150    }
151
152    fn as_any(&self) -> &dyn std::any::Any {
153        self
154    }
155    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
156        self
157    }
158
159    fn to_mms_ast(
160        &self,
161        _world: &crate::engine::ecs::World,
162    ) -> crate::scripting::ast::ComponentExpression {
163        use crate::engine::ecs::component::ce_helpers::*;
164        let ctor = match self.element_type {
165            ElementType::Div => "div",
166            ElementType::Span => "span",
167            ElementType::Body => "body",
168            ElementType::Header => "header",
169            ElementType::Footer => "footer",
170            ElementType::Main => "main",
171            ElementType::Nav => "nav",
172            ElementType::Aside => "aside",
173            ElementType::Section => "section",
174            ElementType::Article => "article",
175            ElementType::P => "p",
176            ElementType::H1 => "h1",
177            ElementType::H2 => "h2",
178            ElementType::H3 => "h3",
179            ElementType::H4 => "h4",
180            ElementType::H5 => "h5",
181            ElementType::H6 => "h6",
182            // Element types without dedicated ctors fall back to bare `HtmlElement {}`,
183            // which `create_component` resolves to `ElementType::Element`. Most authored
184            // scenes use the named ctors above; the rest of the enum is reachable via
185            // future `apply_call` builders or named assignment.
186            _ => return ce("HtmlElement"),
187        };
188        ce_call("HtmlElement", ctor, vec![])
189    }
190}