cotis_web/custom_data.rs
1//! Custom HTML host data for render commands.
2//!
3//! Attach [`ExtraHTMLData`] as the `extra_data` type parameter on
4//! [`ElementConfig`](cotis_defaults::element_configs::ElementConfig) and render commands
5//! ([`Rectangle`](cotis_defaults::render_commands::Rectangle),
6//! [`Text`](cotis_defaults::render_commands::Text), etc.). During drawing,
7//! [`OptionalExtraHTMLData::extra_html_data`] is read and passed to
8//! [`HTMLCanvas::ensure_command_element`](crate::rendering::HTMLCanvas::ensure_command_element),
9//! which sets the DOM tag name and optional inline style on the `cotis-{id}` host element.
10//!
11//! For arbitrary HTML fragments inside a host, use [`HTMLElement`] with custom draw logic
12//! or [`HTMLRenderer::get_custom_element_html`](crate::renderer::HTMLRenderer::get_custom_element_html).
13
14#[allow(dead_code)]
15pub(crate) trait IntoHTMLElement {
16 fn html_element(&self) -> Option<HTMLElement>;
17}
18
19impl IntoHTMLElement for () {
20 fn html_element(&self) -> Option<HTMLElement> {
21 None
22 }
23}
24
25impl IntoHTMLElement for HTMLElement {
26 fn html_element(&self) -> Option<HTMLElement> {
27 Some(self.clone())
28 }
29}
30
31/// Raw HTML content for a custom host element's `innerHTML`.
32#[derive(Debug, Clone)]
33pub struct HTMLElement {
34 html: String,
35}
36
37impl HTMLElement {
38 /// Creates a wrapper around an HTML fragment string.
39 ///
40 /// # Examples
41 ///
42 /// ```
43 /// use cotis_web::custom_data::HTMLElement;
44 ///
45 /// let el = HTMLElement::new("<span>Hello</span>");
46 /// assert_eq!(el.html(), "<span>Hello</span>");
47 /// ```
48 pub fn new(html: &str) -> HTMLElement {
49 Self {
50 html: html.to_string(),
51 }
52 }
53
54 /// Returns the stored HTML fragment.
55 pub fn html(&self) -> &str {
56 &self.html
57 }
58}
59
60/// Types that may carry [`ExtraHTMLData`] on a render command's `extra_data` field.
61pub trait OptionalExtraHTMLData {
62 /// Returns host tag/style overrides, or `None` for default `div` styling.
63 fn extra_html_data(&self) -> Option<ExtraHTMLData>;
64}
65
66impl OptionalExtraHTMLData for () {
67 fn extra_html_data(&self) -> Option<ExtraHTMLData> {
68 None
69 }
70}
71
72impl OptionalExtraHTMLData for ExtraHTMLData {
73 fn extra_html_data(&self) -> Option<ExtraHTMLData> {
74 Some(self.clone())
75 }
76}
77
78/// HTML tag name for a render command's DOM host element (`cotis-{id}`).
79///
80/// Used via [`ExtraHTMLData::tag`] on render command
81/// [`RenderCommandInfo::extra_data`](cotis_defaults::render_commands::RenderCommandInfo::extra_data).
82#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
83pub enum CustomHtmlElementTag {
84 /// Standard block container (`<div>`).
85 #[default]
86 Div,
87 /// Clickable button host (`<button>`).
88 Button,
89}
90
91impl CustomHtmlElementTag {
92 /// Returns the lowercase HTML tag name for this variant.
93 ///
94 /// # Examples
95 ///
96 /// ```
97 /// use cotis_web::custom_data::CustomHtmlElementTag;
98 ///
99 /// assert_eq!(CustomHtmlElementTag::Div.as_json_str(), "div");
100 /// assert_eq!(CustomHtmlElementTag::Button.as_json_str(), "button");
101 /// ```
102 pub const fn as_json_str(self) -> &'static str {
103 match self {
104 Self::Div => "div",
105 Self::Button => "button",
106 }
107 }
108}
109
110/// Per-command overrides for the DOM host element tag and inline CSS.
111#[derive(Clone, Debug, Default)]
112pub struct ExtraHTMLData {
113 /// HTML tag for the host element (default [`CustomHtmlElementTag::Div`]).
114 pub tag: CustomHtmlElementTag,
115 /// Optional inline `style` attribute value applied before drawable CSS pushes.
116 pub extra_style: Option<String>,
117}