simple_rsx/lib.rs
1//! Simple RSX - A lightweight JSX-like library for Rust
2//!
3//! This crate provides a simple way to write HTML-like components in Rust using JSX-style syntax.
4//! It's perfect for building user interfaces or generating HTML content with a familiar, component-based approach.
5//!
6//! # Quick Start
7//!
8//! ```rust
9//! use simple_rsx::*;
10//!
11//! // Create a simple component
12//! let greeting = rsx!(
13//! <div class="greeting">
14//! <h1>Hello, World!</h1>
15//! <p>Welcome to Simple RSX</p>
16//! </div>
17//! );
18//!
19//! // Convert to HTML string
20//! println!("{}", greeting); // Outputs the HTML
21//! ```
22//!
23//! # Features
24//!
25//! - JSX-like syntax with the `rsx!` macro
26//! - Component-based architecture
27//! - Type-safe attributes and children
28//! - Easy conversion to HTML strings
29//! - Support for custom components
30//!
31//! # Custom Components
32//!
33//! ```rust
34//! use simple_rsx::*;
35//!
36//! #[derive(Default)]
37//! struct ButtonProps {
38//! text: String,
39//! children: Vec<Node>,
40//! }
41//!
42//! #[component]
43//! fn Button(props: ButtonProps) -> Node {
44//! rsx!(
45//! <button class="btn">
46//! {props.text}
47//! {props.children}
48//! </button>
49//! )
50//! }
51//! ```
52
53use indexmap::IndexMap;
54pub use simple_rsx_macros::{component, rsx};
55use std::fmt::Display;
56
57/// A trait for converting values into HTML attribute strings.
58///
59/// This trait is automatically implemented for any type that implements `ToString`,
60/// making it easy to use various types as attribute values.
61///
62/// # Example
63///
64/// ```rust
65/// use simple_rsx::*;
66///
67/// let element = rsx!(<div id="my-id" hidden={true} />);
68/// ```
69pub trait Attribute {
70 fn value(&self) -> String;
71}
72
73/// A trait for handling optional attribute values.
74///
75/// This trait is automatically implemented for `Option<T>` where T implements `ToString`.
76/// It allows for graceful handling of optional attributes, rendering them as empty strings when None.
77///
78/// # Example
79///
80/// ```rust
81/// use simple_rsx::*;
82///
83/// let maybe_title = Some("Hello".to_string());
84/// let element = rsx!(<div title={maybe_title} />);
85/// ```
86pub trait OptionAttribute {
87 fn value(&self) -> String;
88}
89
90impl<T: ToString> Attribute for T {
91 fn value(&self) -> String {
92 self.to_string()
93 }
94}
95
96impl<T: ToString> OptionAttribute for Option<T> {
97 fn value(&self) -> String {
98 match self {
99 Some(t) => t.to_string(),
100 None => String::new(),
101 }
102 }
103}
104
105/// Represents an HTML element with its tag name, attributes, and children.
106///
107/// Elements are the building blocks of the RSX tree structure. Each element
108/// can have attributes (like class, id, etc.) and can contain other elements
109/// or text nodes as children.
110///
111/// You typically won't create Elements directly, but rather use the `rsx!` macro:
112///
113/// ```rust
114/// use simple_rsx::*;
115///
116/// let element = rsx!(
117/// <div class="container">
118/// <p>Hello world!</p>
119/// </div>
120/// );
121/// ```
122#[derive(Clone)]
123pub struct Element {
124 tag: String,
125 attributes: IndexMap<String, String>,
126 children: Vec<Node>,
127}
128
129impl Element {
130 /// Creates a new Element node with the specified tag name.
131 ///
132 /// # Example
133 ///
134 /// ```rust
135 /// use simple_rsx::*;
136 ///
137 /// let element = Element::new("div");
138 /// assert!(matches!(element, Node::Element(_)));
139 /// ```
140 pub fn new(tag: &str) -> Node {
141 Node::Element(Element {
142 tag: tag.to_string(),
143 attributes: IndexMap::new(),
144 children: Vec::new(),
145 })
146 }
147
148 /// Sets an attribute on the element.
149 ///
150 /// # Example
151 ///
152 /// ```rust
153 /// use simple_rsx::*;
154 ///
155 /// let mut node = Element::new("div");
156 /// let mut element = node.as_element_mut().unwrap();
157 /// element.set_attribute("class", "container");
158 /// ```
159 pub fn set_attribute(&mut self, name: &str, value: impl Attribute) {
160 self.attributes.insert(name.to_string(), value.value());
161 }
162
163 /// Adds a child node to this element.
164 ///
165 /// # Example
166 ///
167 /// ```rust
168 /// use simple_rsx::*;
169 ///
170 /// let mut parent_node = Element::new("div");
171 /// let mut parent = parent_node.as_element_mut().unwrap();
172 /// parent.append_child(Element::new("p"));
173 /// ```
174 pub fn append_child(&mut self, node: Node) {
175 self.children.push(node);
176 }
177}
178
179impl Node {
180 /// Attempts to get a mutable reference to the underlying Element if this node is an Element.
181 ///
182 /// Returns None if the node is not an Element (e.g., if it's Text or Fragment).
183 pub fn as_element_mut(&mut self) -> Option<&mut Element> {
184 match self {
185 Node::Element(el) => Some(el),
186 _ => None,
187 }
188 }
189
190 /// Adds a child node if this node is an Element.
191 ///
192 /// This method has no effect if the node is not an Element.
193 pub fn append_child(&mut self, node: Node) {
194 if let Node::Element(el) = self {
195 el.children.push(node);
196 }
197 }
198}
199
200/// A trait for creating reusable components.
201///
202/// Components are the heart of RSX's reusability model. They allow you to create
203/// custom elements with their own logic and state.
204///
205/// # Example
206///
207/// ```rust
208/// use simple_rsx::*;
209///
210/// struct Card;
211/// #[derive(Default)]
212/// struct CardProps {
213/// title: String,
214/// children: Vec<Node>,
215/// }
216///
217/// impl Component for Card {
218/// type Props = CardProps;
219/// fn render(&mut self, props: Self::Props) -> Node {
220/// rsx!(
221/// <div class="card">
222/// <h2>{props.title}</h2>
223/// <div class="card-content">{props.children}</div>
224/// </div>
225/// )
226/// }
227/// }
228/// ```
229pub trait Component {
230 /// The type of props this component accepts
231 type Props;
232
233 /// Renders the component with the given props
234 fn render(&mut self, props: Self::Props) -> Node;
235}
236
237/// Implements Component for functions that take props and return a Node.
238///
239/// This allows you to use simple functions as components.
240///
241/// # Example
242///
243/// ```rust
244/// use simple_rsx::*;
245///
246/// fn Button(text: String) -> Node {
247/// rsx!(<button>{text}</button>)
248/// }
249/// ```
250impl<P> Component for fn(P) -> Node {
251 type Props = P;
252 fn render(&mut self, props: Self::Props) -> Node {
253 self(props.into())
254 }
255}
256
257/// Represents a node in the RSX tree.
258///
259/// Nodes are the fundamental building blocks of RSX. They can be:
260/// - Elements (like `<div>` or `<p>`)
261/// - Text content
262/// - Fragments (groups of nodes)
263/// - Comments
264///
265/// # Example
266///
267/// ```rust
268/// use simple_rsx::*;
269///
270/// let text_node = Node::Text("Hello".to_string());
271/// let element_node = Element::new("div");
272/// let fragment = Node::Fragment(vec![text_node, element_node]);
273/// ```
274#[derive(Clone)]
275pub enum Node {
276 /// An HTML element with a tag name, attributes, and children
277 Element(Element),
278 /// Plain text content
279 Text(String),
280 /// A group of nodes without a wrapper element
281 Fragment(Vec<Node>),
282 /// An HTML comment
283 Comment(String),
284}
285
286impl From<String> for Node {
287 fn from(value: String) -> Self {
288 Node::Text(value)
289 }
290}
291
292impl From<&String> for Node {
293 fn from(value: &String) -> Self {
294 Node::Text(value.to_string())
295 }
296}
297
298impl From<&str> for Node {
299 fn from(value: &str) -> Self {
300 Node::Text(value.to_string())
301 }
302}
303
304impl From<&&str> for Node {
305 fn from(value: &&str) -> Self {
306 Node::Text(value.to_string())
307 }
308}
309
310impl<T: ToString> From<Vec<T>> for Node {
311 fn from(value: Vec<T>) -> Self {
312 Node::Fragment(
313 value
314 .into_iter()
315 .map(|t| Node::Text(t.to_string()))
316 .collect(),
317 )
318 }
319}
320
321impl<T: ToString> From<Option<T>> for Node {
322 fn from(value: Option<T>) -> Self {
323 match value {
324 Some(t) => Node::Text(t.to_string()),
325 None => Node::Text("".to_string()),
326 }
327 }
328}
329
330impl From<&Vec<String>> for Node {
331 fn from(value: &Vec<String>) -> Self {
332 Node::Fragment(value.iter().map(|s| Node::Text(s.to_string())).collect())
333 }
334}
335
336impl From<i32> for Node {
337 fn from(value: i32) -> Self {
338 Node::Text(value.to_string())
339 }
340}
341
342impl From<u32> for Node {
343 fn from(value: u32) -> Self {
344 Node::Text(value.to_string())
345 }
346}
347
348impl From<u64> for Node {
349 fn from(value: u64) -> Self {
350 Node::Text(value.to_string())
351 }
352}
353
354impl FromIterator<u32> for Node {
355 fn from_iter<T: IntoIterator<Item = u32>>(iter: T) -> Self {
356 let mut result = Vec::new();
357 for i in iter {
358 result.push(Node::Text(i.to_string()));
359 }
360 Node::Fragment(result)
361 }
362}
363
364impl FromIterator<u64> for Node {
365 fn from_iter<T: IntoIterator<Item = u64>>(iter: T) -> Self {
366 let mut result = Vec::new();
367 for i in iter {
368 result.push(Node::Text(i.to_string()));
369 }
370 Node::Fragment(result)
371 }
372}
373
374impl FromIterator<i32> for Node {
375 fn from_iter<T: IntoIterator<Item = i32>>(iter: T) -> Self {
376 let mut result = Vec::new();
377 for i in iter {
378 result.push(Node::Text(i.to_string()));
379 }
380 Node::Fragment(result)
381 }
382}
383
384impl From<f32> for Node {
385 fn from(value: f32) -> Self {
386 Node::Text(value.to_string())
387 }
388}
389
390impl From<bool> for Node {
391 fn from(value: bool) -> Self {
392 Node::Text(value.to_string())
393 }
394}
395
396impl<I, F, R> From<std::iter::Map<I, F>> for Node
397where
398 I: Iterator,
399 F: FnMut(I::Item) -> R,
400 R: Into<Node>,
401 Vec<Node>: FromIterator<R>,
402{
403 fn from(iter: std::iter::Map<I, F>) -> Self {
404 let nodes: Vec<Node> = iter.collect();
405 Node::from(nodes)
406 }
407}
408
409impl Display for Node {
410 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
411 match self {
412 Node::Element(el) => {
413 write!(f, "<{}", el.tag)?;
414 for (key, value) in &el.attributes {
415 write!(f, " {}=\"{}\"", key, value)?;
416 }
417 write!(f, ">")?;
418 for child in &el.children {
419 write!(f, "{}", child)?;
420 }
421 write!(f, "</{}>", el.tag)?;
422 Ok(())
423 }
424 Node::Text(text) => {
425 write!(f, "{}", text)?;
426 Ok(())
427 }
428 Node::Fragment(nodes) => {
429 for node in nodes {
430 write!(f, "{}", node)?;
431 }
432 Ok(())
433 }
434 Node::Comment(comment) => {
435 write!(f, "<!--{}-->", comment)?;
436 Ok(())
437 }
438 }
439 }
440}
441
442macro_rules! derive_elements {
443 (
444 $(
445 $(#[$tag_meta:meta])*
446 $tag:ident {
447 $(
448 $(#[$attr_meta:meta])*
449 $attr_name:ident : $attr_value:ty
450 ),* $(,)?
451 }
452 )*
453 ) => {
454 $(
455 #[allow(non_camel_case_types)]
456 $(#[$tag_meta])*
457 pub struct $tag;
458
459 paste::paste! {
460 #[derive(Default)]
461 #[allow(non_snake_case)]
462 pub struct [<HTML $tag:camel Element Props>] {
463 // Global HTML attributes
464
465 /// The child nodes of the element
466 pub children: Vec<Node>,
467
468 /// The id attribute specifies a unique id for an HTML element
469 pub id: String,
470
471 /// A unique key to identify the element
472 pub key: String,
473
474 /// The class attribute specifies one or more class names for an HTML element
475 pub class: String,
476
477 /// The style attribute specifies an inline CSS style for an element
478 pub style: String,
479
480 /// The title attribute specifies extra information about an element (displayed as a tooltip)
481 pub title: Option<String>,
482 /// The width attribute specifies the width of the image
483 pub width: Option<String>,
484 /// The height attribute specifies the height of the image
485 pub height: Option<String>,
486
487 /// Specifies whether an element is draggable or not
488 pub draggable: bool,
489
490 /// Specifies visibility of an element (hidden or visible)
491 pub hidden: bool,
492
493 /// Specifies a shortcut key to activate/focus an element
494 pub accesskey: String,
495
496 /// Specifies whether the content of an element is editable or not
497 pub contenteditable: bool,
498
499 /// Specifies the text direction for the content in an element
500 pub dir: String,
501
502 /// Specifies the tabbing order of an element (when the tab button is used)
503 pub tabindex: Option<i32>,
504
505 /// Specifies whether the element is to have its spelling and grammar checked
506 pub spellcheck: bool,
507
508 /// Specifies the language of the element's content
509 pub lang: String,
510
511 /// Specifies whether an element is translateable or not
512 pub translate: bool,
513
514 /// Controls whether and how text input is automatically capitalized
515 pub autocapitalize: String,
516
517 /// Specifies an inline CSS style for an element
518 pub role: String,
519
520 // ARIA Accessibility attributes
521
522 /// Identifies the current element within a set
523 pub aria_current: String,
524
525 /// Defines a string value that labels the current element
526 pub aria_label: Option<String>,
527
528 /// Identifies the element that labels the current element
529 pub aria_labelledby: Option<String>,
530
531 /// Identifies the element that describes the current element
532 pub aria_describedby: Option<String>,
533
534 /// Indicates whether an element is expanded or collapsed
535 pub aria_expanded: bool,
536
537 /// Indicates the element that represents the current item within a container or set
538 pub aria_selected: bool,
539
540 /// Indicates whether the element is checked, unchecked, or represents mixed mode
541 pub aria_checked: String,
542
543 /// Indicates whether an element and its subtree are hidden
544 pub aria_hidden: bool,
545
546 /// Indicates the availability and type of interactive popup element
547 pub aria_haspopup: String,
548
549 /// Defines an element's role
550 pub aria_role: String,
551
552 // Element specific attributes
553 $(
554 pub $attr_name: $attr_value,
555 )*
556 }
557
558 impl [<HTML $tag:camel Element Props>] {
559 fn to_attributes(&self) -> IndexMap<String, String> {
560 #[allow(unused_mut)]
561 let mut attributes = IndexMap::new();
562 $(
563 if !self.$attr_name.value().is_empty() {
564 let mut key = stringify!($attr_name);
565 if let Some(last_char) = key.chars().last() {
566 if last_char == '_' {
567 key = &key[..key.len() - 1];
568 }
569 }
570 attributes.insert(key.replace('_', "-"), self.$attr_name.value());
571 }
572 )*
573 if !self.id.value().is_empty() {
574 attributes.insert("id".to_string(), self.id.value());
575 }
576 if !self.class.value().is_empty() {
577 attributes.insert("class".to_string(), self.class.value());
578 }
579 if !self.style.value().is_empty() {
580 attributes.insert("style".to_string(), self.style.value());
581 }
582 if !self.title.value().is_empty() {
583 attributes.insert("title".to_string(), self.title.value());
584 }
585 if self.draggable {
586 attributes.insert("draggable".to_string(), "true".to_string());
587 }
588 if self.hidden {
589 attributes.insert("hidden".to_string(), "true".to_string());
590 }
591 if !self.accesskey.value().is_empty() {
592 attributes.insert("accesskey".to_string(), self.accesskey.value());
593 }
594 if self.contenteditable {
595 attributes.insert("contenteditable".to_string(), "true".to_string());
596 }
597 if !self.dir.value().is_empty() {
598 attributes.insert("dir".to_string(), self.dir.value());
599 }
600 if let Some(tabindex) = self.tabindex {
601 attributes.insert("tabindex".to_string(), tabindex.to_string());
602 }
603 if self.spellcheck {
604 attributes.insert("spellcheck".to_string(), "true".to_string());
605 }
606 if !self.lang.value().is_empty() {
607 attributes.insert("lang".to_string(), self.lang.value());
608 }
609 if self.translate {
610 attributes.insert("translate".to_string(), "true".to_string());
611 }
612 if !self.autocapitalize.value().is_empty() {
613 attributes.insert("autocapitalize".to_string(), self.autocapitalize.value());
614 }
615 if !self.role.value().is_empty() {
616 attributes.insert("role".to_string(), self.role.value());
617 }
618 if !self.aria_current.value().is_empty() {
619 attributes.insert("aria-current".to_string(), self.aria_current.value());
620 }
621 if !self.aria_label.value().is_empty() {
622 attributes.insert("aria-label".to_string(), self.aria_label.value());
623 }
624 if !self.aria_labelledby.value().is_empty() {
625 attributes.insert("aria-labelledby".to_string(), self.aria_labelledby.value());
626 }
627 if !self.aria_describedby.value().is_empty() {
628 attributes.insert("aria-describedby".to_string(), self.aria_describedby.value());
629 }
630 if self.aria_expanded {
631 attributes.insert("aria-expanded".to_string(), "true".to_string());
632 }
633 if self.aria_selected {
634 attributes.insert("aria-selected".to_string(), "true".to_string());
635 }
636 if !self.aria_checked.value().is_empty() {
637 attributes.insert("aria-checked".to_string(), self.aria_checked.value());
638 }
639 if self.aria_hidden {
640 attributes.insert("aria-hidden".to_string(), "true".to_string());
641 }
642 if !self.aria_haspopup.value().is_empty() {
643 attributes.insert("aria-haspopup".to_string(), self.aria_haspopup.value());
644 }
645 if !self.aria_role.value().is_empty() {
646 attributes.insert("aria-role".to_string(), self.aria_role.value());
647 }
648
649 attributes
650 }
651 }
652
653 impl Component for $tag {
654 type Props = [<HTML $tag:camel Element Props>];
655
656 fn render(&mut self, props: Self::Props) -> Node {
657 Node::Element(Element {
658 tag: stringify!($tag).to_string(),
659 attributes: props.to_attributes(),
660 children: props.children,
661 })
662 }
663 }
664 }
665 )*
666 };
667}
668
669derive_elements! {
670 /// HTML `<html>` element - Root element of an HTML document
671 html {
672 }
673 /// HTML `<body>` element - Represents the content of an HTML document
674 ///
675 /// Example:
676 ///
677 /// ```<body>Content goes here</body>```
678 body {
679 }
680 /// HTML `<head>` element - Contains metadata about the document
681 ///
682 /// Example:
683 ///
684 /// ```<head><title>Document Title</title></head>```
685 head {
686 }
687 /// HTML `<title>` element - Defines the title of the document
688 ///
689 /// Example:
690 ///
691 /// ```<title>Document Title</title>```
692 title {
693 }
694 /// HTML `<meta` element - Provides metadata about the document
695 ///
696 /// Example:
697 ///
698 /// ```<meta charset="UTF-8">```
699 meta {
700 /// The character encoding of the document
701 charset: Option<String>,
702 /// The HTTP response status code
703 http_equiv: Option<String>,
704 /// The content of the document
705 content: Option<String>,
706 /// The name of the metadata
707 name: String,
708 /// The property of the metadata
709 property: Option<String>,
710 }
711 /// HTML `<style>` element - Defines style information for a document
712 ///
713 /// Example:
714 ///
715 /// ```<style>body { background-color: #f0f0f0; }</style>```
716 style {
717 }
718 /// HTML `<script>` element - Embeds executable code or data
719 ///
720 /// Example:
721 ///
722 /// ```<script src="script.js"></script>```
723 script {
724 }
725 /// HTML `<link>` element - Specifies relationships between the current document and an external resource
726 ///
727 /// Example:
728 ///
729 /// ```<link rel="stylesheet" href="style.css">```
730 link {
731 /// The relationship between the current document and the linked resource
732 rel: String,
733 /// The URL of the linked resource
734 href: String,
735 /// The type of the linked resource
736 type_: String,
737 }
738 /// HTML `<div>` element - Container element for grouping and styling content
739 ///
740 /// Example:
741 ///
742 /// ```<div class="container">Content goes here</div>```
743 div {
744 }
745
746 /// HTML `<p>` element - Represents a paragraph of text
747 ///
748 /// Example:
749 ///
750 /// ```<p>This is a paragraph of text.</p>```
751 p {
752 }
753
754 /// HTML `<span>` element - Inline container for targeting text with styles
755 ///
756 /// Example:
757 ///
758 /// ```<span class="highlight">Highlighted text</span>```
759 span {
760 }
761
762 /// HTML `<a>` element - Creates a hyperlink to other web pages or resources
763 ///
764 /// Example:
765 ///
766 /// ```<a href="https://example.com" target="_blank">Visit Example</a>```
767 a {
768 /// The href attribute specifies the URL of the page the link goes to
769 /// Example: href="https://example.com"
770 href: String,
771 /// The target attribute specifies where to open the linked document
772 /// Example: target="_blank" (opens in new tab)
773 target: String,
774 /// The rel attribute specifies the relationship between the current document and the linked document
775 /// Example: rel="nofollow" (tells search engines not to follow this link)
776 rel: String,
777 /// The download attribute indicates the browser to download the URL instead of navigating
778 /// Example: download="filename.pdf"
779 download: String,
780 /// The hreflang attribute specifies the language of the linked document
781 /// Example: hreflang="en" (English)
782 hreflang: String,
783 /// The type attribute specifies the media type of the linked document
784 /// Example: type="text/html"
785 type_: String,
786 /// The media attribute specifies what media/device the linked document is optimized for
787 /// Example: media="print" (for print stylesheets)
788 media: String,
789 /// The referrerpolicy attribute specifies which referrer information to send
790 /// Example: referrerpolicy="no-referrer"
791 referrerpolicy: String,
792 /// The ping attribute specifies URLs to be notified when the link is followed
793 /// Example: ping="https://example.com/track"
794 ping: String,
795 }
796
797 /// HTML <h1> element - First level heading (most important)
798 ///
799 /// Example:
800 ///
801 /// ```<h1>Main Page Title</h1>```
802 h1 {
803 }
804
805 /// HTML <h2> element - Second level heading
806 ///
807 /// Example:
808 ///
809 /// ```<h2>Section Heading</h2>```
810 h2 {
811 }
812
813 /// HTML <h3> element - Third level heading
814 ///
815 /// Example:
816 ///
817 /// ```<h3>Subsection Heading</h3>```
818 h3 {
819 }
820
821 /// HTML <h4> element - Fourth level heading
822 ///
823 /// Example:
824 ///
825 /// ```<h4>Sub-subsection Heading</h4>```
826 h4 {
827 }
828
829 /// HTML <h5> element - Fifth level heading
830 ///
831 /// Example:
832 ///
833 /// ```<h5>Minor Heading</h5>```
834 h5 {
835 }
836
837 /// HTML <h6> element - Sixth level heading (least important)
838 ///
839 /// Example:
840 ///
841 /// ```<h6>Fine Detail Heading</h6>```
842 h6 {
843 }
844
845 /// HTML `<img>` element - Embeds an image into the document
846 ///
847 /// Example:
848 ///
849 /// ```<img src="image.jpg" alt="Description of image">```
850 img {
851 /// The src attribute specifies the URL/path to the image
852 /// Example: src="images/logo.png"
853 src: String,
854 /// The alt attribute provides alternative text for screen readers and if image fails to load
855 /// Example: alt="Company Logo"
856 alt: String,
857 /// The loading attribute indicates how the browser should load the image
858 /// Example: loading="lazy" (defers loading until it's near viewport)
859 loading: String,
860 }
861
862 /// HTML `<br>` element - Produces a line break in text
863 ///
864 /// Example:
865 ///
866 /// ```<br>```
867 br {}
868
869 /// HTML `<hr>` element - Creates a horizontal rule (divider)
870 ///
871 /// Example:
872 ///
873 /// ```<hr>```
874 hr {
875 }
876
877 /// HTML `<ul>` element - Unordered list with bullet points
878 ///
879 /// Example:
880 ///
881 /// ```<ul><li>Item 1</li><li>Item 2</li></ul>```
882 ul {
883 /// The type attribute specifies the bullet style (disc, circle, square)
884 /// Example: type="square"
885 type_: String,
886 }
887
888 /// HTML `<li>` element - List item within ordered or unordered lists
889 ///
890 /// Example:
891 ///
892 /// ```<li>List item content</li>```
893 li {
894 /// The value attribute specifies the start value of the list item (for ol)
895 /// Example: value="3" (starts this item at number 3)
896 value: Option<i32>,
897 }
898
899 /// HTML `<ol>` element - Ordered (numbered) list
900 ///
901 /// Example:
902 ///
903 /// ```<ol start="5" type="A"><li>Item E</li><li>Item F</li></ol>```
904 ol {
905 /// The type attribute specifies the numbering type (1, A, a, I, i)
906 /// Example: type="A" (uses capital letters)
907 type_: String,
908 /// The start attribute specifies the start value of the list
909 /// Example: start="5" (starts counting from 5)
910 start: i32,
911 /// The reversed attribute specifies that list should be in descending order
912 /// Example: reversed (counts down instead of up)
913 reversed: bool,
914 }
915
916 /// HTML `<table>` element - Creates a data table with rows and columns
917 ///
918 /// Example:
919 ///
920 /// ```<table border="1"><tr><th>Header</th></tr><tr><td>Data</td></tr></table>```
921 table {
922 /// The border attribute specifies the width of the border around the table
923 /// Example: border="1" (1 pixel border)
924 border: i32,
925 /// The cellpadding attribute specifies the space between cell content and borders
926 /// Example: cellpadding="5" (5 pixels of padding)
927 cellpadding: i32,
928 /// The cellspacing attribute specifies the space between cells
929 /// Example: cellspacing="2" (2 pixels between cells)
930 cellspacing: i32,
931 }
932
933 /// HTML `<tr>` element - Table row container
934 ///
935 /// Example:
936 ///
937 /// ```<tr><td>Cell 1</td><td>Cell 2</td></tr>```
938 tr {
939 }
940
941 /// HTML `<td>` element - Table data cell
942 ///
943 /// Example:
944 ///
945 /// ```<td colspan="2">This cell spans two columns</td>```
946 td {
947 /// The colspan attribute specifies how many columns a cell should span
948 /// Example: colspan="3" (cell spans 3 columns)
949 colspan: i32,
950 /// The rowspan attribute specifies how many rows a cell should span
951 /// Example: rowspan="2" (cell spans 2 rows)
952 rowspan: i32,
953 /// The headers attribute associates data cells with header cells
954 /// Example: headers="col1 row1" (associates with those header IDs)
955 headers: String,
956 /// The scope attribute specifies whether header cells are for rows or columns
957 /// Example: scope="col" (header applies to whole column)
958 scope: String,
959 }
960
961 /// HTML `<th>` element - Table header cell
962 ///
963 /// Example:
964 ///
965 /// ```<th scope="col">Column Header</th>```
966 th {
967 /// The colspan attribute specifies how many columns a cell should span
968 /// Example: colspan="3" (header spans 3 columns)
969 colspan: i32,
970 /// The rowspan attribute specifies how many rows a cell should span
971 /// Example: rowspan="2" (header spans 2 rows)
972 rowspan: i32,
973 /// The headers attribute associates data cells with header cells
974 /// Example: headers="col1 row1" (associates with those header IDs)
975 headers: String,
976 /// The scope attribute specifies whether the header cell is for a row, column, etc.
977 /// Example: scope="row" (header applies to whole row)
978 scope: String,
979 }
980
981 /// HTML `<tbody>` element - Groups body content in a table
982 ///
983 /// Example:
984 ///
985 /// ```<table><tbody><tr><td>Data</td></tr></tbody></table>```
986 tbody {
987 }
988
989 /// HTML `<thead>` element - Groups header content in a table
990 ///
991 /// Example:
992 ///
993 /// ```<table><thead><tr><th>Header</th></tr></thead><tbody>...</tbody></table>```
994 thead {
995 }
996
997 /// HTML `<tfoot>` element - Groups footer content in a table
998 ///
999 /// Example:
1000 ///
1001 /// ```<table><thead>...</thead><tbody>...</tbody><tfoot><tr><td>Summary</td></tr></tfoot></table>```
1002 tfoot {
1003 }
1004
1005 /// HTML `<form>` element - Container for interactive inputs to collect user data
1006 ///
1007 /// Example:
1008 ///
1009 /// ```<form action="/submit" method="post"><input type="text"><button type="submit">Submit</button></form>```
1010 form {
1011 /// The action attribute specifies where to send form data when submitted
1012 ///
1013 /// Example: action="/process-form.php"
1014 action: String,
1015 /// The method attribute specifies HTTP method for sending data (GET/POST)
1016 ///
1017 /// Example: method="post" (sends data in request body)
1018 method: String,
1019 /// The target attribute specifies where to display the response
1020 ///
1021 /// Example: target="_blank" (opens response in new tab)
1022 target: String,
1023 /// The enctype attribute specifies how form data should be encoded
1024 ///
1025 /// Example: enctype="multipart/form-data" (needed for file uploads)
1026 enctype: String,
1027 /// The novalidate attribute disables browser's built-in form validation
1028 ///
1029 /// Example: novalidate (skips validation)
1030 novalidate: bool,
1031 /// The autocomplete attribute controls browser autofill behavior
1032 ///
1033 /// Example: autocomplete="off" (disables autofill)
1034 autocomplete: String,
1035 /// The accept attribute specifies file types the server accepts (for file inputs)
1036 ///
1037 /// Example: accept=".jpg,.png" (accepts only those image formats)
1038 accept: String,
1039 /// Example: name="contact-form"
1040 name: String,
1041 }
1042
1043 /// HTML `<input>` element - Creates interactive controls for forms
1044 ///
1045 /// Example:
1046 ///
1047 /// ```<input type="text" placeholder="Enter your name" required>```
1048 input {
1049 /// The type attribute specifies the input type (text, password, email, etc.)
1050 ///
1051 /// Example: type="email" (validates as email address)
1052 type_: String,
1053 /// The placeholder attribute shows hint text when field is empty
1054 ///
1055 /// Example: placeholder="Enter your email"
1056 placeholder: String,
1057 /// The required attribute makes the field mandatory
1058 ///
1059 /// Example: required (field must be filled)
1060 required: bool,
1061 /// The value attribute specifies the default/current value
1062 ///
1063 /// Example: value="Default text"
1064 value: String,
1065 /// The name attribute specifies the name of the input (for form submission)
1066 ///
1067 /// Example: name="email"
1068 name: String,
1069 /// The disabled attribute disables the input
1070 ///
1071 /// Example: disabled (user cannot interact with input)
1072 disabled: bool,
1073 /// The readonly attribute makes the input read-only
1074 ///
1075 /// Example: readonly (user cannot modify but can focus/select)
1076 readonly: bool,
1077 /// The min attribute specifies minimum value for number/date inputs
1078 ///
1079 /// Example: min="1" (number input minimum value)
1080 min: String,
1081 /// The max attribute specifies maximum value for number/date inputs
1082 ///
1083 /// Example: max="100" (number input maximum value)
1084 max: String,
1085 /// The pattern attribute specifies a regex pattern for validation
1086 ///
1087 /// Example: pattern="[0-9]{3}" (requires exactly 3 digits)
1088 pattern: String,
1089 /// The autocomplete attribute controls browser autofill for this field
1090 ///
1091 /// Example: autocomplete="current-password"
1092 autocomplete: String,
1093 }
1094
1095 /// HTML `<textarea>` element - Multi-line text input control
1096 ///
1097 /// Example:
1098 ///
1099 /// ```<textarea rows="4" cols="50" placeholder="Your message here"></textarea>```
1100 textarea {
1101 /// The placeholder attribute shows hint text when field is empty
1102 /// Example: placeholder="Enter your comments"
1103 placeholder: String,
1104 /// The required attribute makes the field mandatory
1105 /// Example: required (must be filled before submission)
1106 required: bool,
1107 /// The value attribute specifies the default/current text content
1108 /// Example: value="Default text in the textarea"
1109 value: String,
1110 /// The rows attribute specifies visible number of text lines
1111 /// Example: rows="10" (shows 10 lines of text)
1112 rows: i32,
1113 /// The cols attribute specifies visible width in average characters
1114 /// Example: cols="40" (about 40 characters wide)
1115 cols: i32,
1116 /// The name attribute specifies the name of the textarea (for form submission)
1117 /// Example: name="comments"
1118 name: String,
1119 /// The disabled attribute disables the textarea
1120 /// Example: disabled (user cannot interact)
1121 disabled: bool,
1122 /// The readonly attribute makes the textarea read-only
1123 /// Example: readonly (user cannot modify but can focus/select)
1124 readonly: bool,
1125 /// The maxlength attribute specifies maximum character count
1126 /// Example: maxlength="500" (limits to 500 characters)
1127 maxlength: i32,
1128 }
1129
1130 /// HTML `<button>` element - Clickable button control
1131 ///
1132 /// Example:
1133 ///
1134 /// ```<button type="submit">Click Me</button>```
1135 button {
1136 /// The type attribute specifies button function (submit, reset, button)
1137 /// Example: type="submit" (submits the form)
1138 type_: String,
1139 /// The value attribute specifies the value associated with the button
1140 /// Example: value="btn1" (for form processing)
1141 value: String,
1142 /// The disabled attribute disables the button
1143 /// Example: disabled (button cannot be clicked)
1144 disabled: bool,
1145 /// The name attribute specifies the name of the button (for form submission)
1146 /// Example: name="submit-button"
1147 name: String,
1148 /// The formaction attribute overrides form's action for this button
1149 /// Example: formaction="/alternative-submit"
1150 formaction: String,
1151 /// The formmethod attribute overrides form's method for this button
1152 /// Example: formmethod="get"
1153 formmethod: String,
1154 }
1155
1156 /// HTML `<select>` element - Dropdown selection list
1157 ///
1158 /// Example:
1159 ///
1160 /// ```<select><option value="1">Option 1</option><option value="2">Option 2</option></select>```
1161 select {
1162 /// The multiple attribute allows selecting multiple options
1163 /// Example: multiple (user can select multiple items)
1164 multiple: bool,
1165 /// The disabled attribute disables the dropdown
1166 /// Example: disabled (user cannot interact)
1167 disabled: bool,
1168 /// The value attribute specifies the selected value
1169 /// Example: value="option2" (preselects this option)
1170 value: String,
1171 /// The name attribute specifies the name of the select (for form submission)
1172 /// Example: name="country"
1173 name: String,
1174 /// The size attribute specifies number of visible options
1175 /// Example: size="5" (shows 5 options at once)
1176 size: i32,
1177 /// The required attribute makes selection mandatory
1178 /// Example: required (user must select an option)
1179 required: bool,
1180 }
1181
1182 /// HTML `<option>` element - Defines option in a select dropdown
1183 ///
1184 /// Example:
1185 ///
1186 /// ```<option value="blue" selected>Blue</option>```
1187 option {
1188 /// The value attribute specifies the value to be sent to server
1189 /// Example: value="NY" (value sent when this option is selected)
1190 value: String,
1191 /// The selected attribute preselects this option when page loads
1192 /// Example: selected (this option is selected by default)
1193 selected: bool,
1194 /// The disabled attribute makes this option unselectable
1195 /// Example: disabled (cannot be chosen)
1196 disabled: bool,
1197 }
1198
1199 /// HTML `<label>` element - Caption for a form control
1200 ///
1201 /// Example:
1202 ///
1203 /// ```<label for="username">Username:</label><input id="username">```
1204 label {
1205 /// The for attribute connects the label to a form control by ID
1206 /// Example: for="email" (associates with input having id="email")
1207 for_: String,
1208 }
1209
1210 /// HTML `<iframe>` element - Embeds another document within the current HTML document
1211 ///
1212 /// Example:
1213 ///
1214 /// ```<iframe src="https://example.com" title="Example Site"></iframe>```
1215 iframe {
1216 /// The src attribute specifies the URL of the embedded document
1217 /// Example: src="https://maps.google.com"
1218 src: String,
1219 /// The frameborder attribute specifies whether to display a border
1220 /// Example: frameborder="0" (no border)
1221 frameborder: String,
1222 /// The allow attribute specifies features allowed in the iframe
1223 /// Example: allow="camera; microphone" (permits access to these devices)
1224 allow: String,
1225 /// The allowfullscreen attribute allows iframe content to go fullscreen
1226 /// Example: allowfullscreen (allows fullscreen mode)
1227 allowfullscreen: bool,
1228 /// The sandbox attribute restricts iframe capabilities for security
1229 /// Example: sandbox="allow-scripts" (only allows scripts to run)
1230 sandbox: String,
1231 }
1232
1233 /// HTML `<video>` element - Embeds video content in the document
1234 ///
1235 /// Example:
1236 ///
1237 /// ```<video src="movie.mp4" controls width="500">Video not supported</video>```
1238 video {
1239 /// The src attribute specifies URL/path of the video
1240 /// Example: src="videos/intro.mp4"
1241 src: String,
1242 /// The controls attribute displays video playback controls
1243 /// Example: controls (shows play/pause/volume controls)
1244 controls: bool,
1245 /// The autoplay attribute starts playing video automatically
1246 /// Example: autoplay (video plays when page loads)
1247 autoplay: bool,
1248 /// The loop attribute makes the video replay when finished
1249 /// Example: loop (continuously replays)
1250 loop_: bool,
1251 /// The poster attribute specifies an image shown before video plays
1252 /// Example: poster="thumbnail.jpg"
1253 poster: String,
1254 /// The muted attribute mutes the audio by default
1255 /// Example: muted (starts with no sound)
1256 muted: bool,
1257 /// The preload attribute hints how to preload the video
1258 /// Example: preload="auto" (preload entire video)
1259 preload: String,
1260 /// The playsinline attribute plays inline on iOS (instead of fullscreen)
1261 /// Example: playsinline (important for iPhone users)
1262 playsinline: bool,
1263 }
1264
1265 /// HTML `<audio>` element - Embeds sound content in the document
1266 ///
1267 /// Example:
1268 ///
1269 /// ```<audio src="song.mp3" controls>Audio not supported</audio>```
1270 audio {
1271 /// The src attribute specifies URL/path of the audio file
1272 /// Example: src="audio/background-music.mp3"
1273 src: String,
1274 /// The controls attribute displays audio playback controls
1275 /// Example: controls (shows play/pause/volume controls)
1276 controls: bool,
1277 /// The autoplay attribute starts playing audio automatically
1278 /// Example: autoplay (audio plays when page loads)
1279 autoplay: bool,
1280 /// The loop attribute makes the audio replay when finished
1281 /// Example: loop (continuously replays)
1282 loop_: bool,
1283 /// The muted attribute mutes the audio by default
1284 /// Example: muted (starts with no sound)
1285 muted: bool,
1286 /// The preload attribute hints how to preload the audio
1287 /// Example: preload="none" (doesn't preload)
1288 preload: String,
1289 }
1290
1291 /// HTML `<source>` element - Defines media resources for video/audio elements
1292 ///
1293 /// Example:
1294 ///
1295 /// ```<video><source src="movie.mp4" type="video/mp4"><source src="movie.webm" type="video/webm"></video>```
1296 source {
1297 /// The src attribute specifies URL/path of the media resource
1298 /// Example: src="audio/song.ogg"
1299 src: String,
1300 /// The type attribute specifies the MIME type of the resource
1301 /// Example: type="video/webm" (defines file format)
1302 type_: String,
1303 /// The media attribute specifies for which media the resource is intended
1304 /// Example: media="(min-width: 600px)" (responsive resources)
1305 media: String,
1306 }
1307
1308 /// HTML `<canvas>` element - Container for graphics rendered with JavaScript
1309 ///
1310 /// Example:
1311 ///
1312 /// ```<canvas id="myCanvas" width="200" height="100">Your browser does not support canvas</canvas>```
1313 canvas {
1314 }
1315
1316 /// HTML `<svg>` element - Container for SVG graphics
1317 ///
1318 /// Example:
1319 ///
1320 /// ```<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="red" /></svg>```
1321 svg {
1322 /// The viewBox attribute defines coordinate system and aspect ratio
1323 /// Example: viewBox="0 0 800 600" (x, y, width, height)
1324 viewBox: String,
1325 /// The preserveAspectRatio attribute controls scaling behavior
1326 /// Example: preserveAspectRatio="xMidYMid meet" (center and scale)
1327 preserve_aspect_ratio: String,
1328 /// The xmlns attribute defines the XML namespace (required for standalone SVG)
1329 /// Example: xmlns="http://www.w3.org/2000/svg"
1330 xmlns: String,
1331 }
1332
1333 /// HTML `<path>` element - Defines a path in SVG graphics
1334 ///
1335 /// Example:
1336 ///
1337 /// ```<path d="M10 10 H 90 V 90 H 10 Z" fill="transparent" stroke="black" />```
1338 path {
1339 /// The d attribute defines the path to be drawn
1340 /// Example: d="M20,20 L80,20 L80,80 L20,80 Z" (square path)
1341 d: String,
1342 /// The fill attribute specifies the fill color
1343 /// Example: fill="#3498db" (blue fill)
1344 fill: String,
1345 /// The stroke attribute specifies the outline color
1346 /// Example: stroke="#e74c3c" (red outline)
1347 stroke: String,
1348 /// The stroke-width attribute specifies the width of the outline
1349 /// Example: stroke-width="3" (3 units thick)
1350 stroke_width: String,
1351 /// The stroke-linecap attribute specifies line end style
1352 /// Example: stroke-linecap="round" (rounded ends)
1353 stroke_linecap: String,
1354 /// The stroke-linejoin attribute specifies how line joins are rendered
1355 /// Example: stroke-linejoin="miter" (pointed corners)
1356 stroke_linejoin: String,
1357 /// The stroke-miterlimit attribute limits the length of miters
1358 /// Example: stroke-miterlimit="4" (limits pointy corners)
1359 stroke_miterlimit: String,
1360 /// The stroke-dasharray attribute creates dashed lines
1361 /// Example: stroke-dasharray="5,5" (5 units on, 5 units off)
1362 stroke_dasharray: String,
1363 /// The stroke-dashoffset attribute adjusts dash pattern start
1364 /// Example: stroke-dashoffset="10" (starts 10 units into pattern)
1365 stroke_dashoffset: String,
1366 /// The stroke-opacity attribute sets stroke transparency
1367 /// Example: stroke-opacity="0.5" (50% transparent)
1368 stroke_opacity: String,
1369 /// The fill-opacity attribute sets fill transparency
1370 /// Example: fill-opacity="0.7" (70% opaque)
1371 fill_opacity: String,
1372 }
1373
1374 /// HTML `<rect>` element - Draws a rectangle in SVG
1375 ///
1376 /// Example:
1377 ///
1378 /// ```<rect x="10" y="10" width="100" height="50" fill="blue" />```
1379 rect {
1380 /// The x attribute specifies the x-coordinate of the rectangle
1381 /// Example: x="25" (25 units from the left)
1382 x: String,
1383 /// The y attribute specifies the y-coordinate of the rectangle
1384 /// Example: y="50" (50 units from the top)
1385 y: String,
1386 /// The rx attribute specifies the horizontal corner radius
1387 /// Example: rx="10" (rounded corners)
1388 rx: String,
1389 /// The ry attribute specifies the vertical corner radius
1390 /// Example: ry="10" (rounded corners)
1391 ry: String,
1392 /// The fill attribute specifies the fill color
1393 /// Example: fill="#2ecc71" (green fill)
1394 fill: String,
1395 /// The stroke attribute specifies the outline color
1396 /// Example: stroke="#27ae60" (darker green outline)
1397 stroke: String,
1398 /// The stroke-width attribute specifies the width of the outline
1399 /// Example: stroke-width="2" (2 units thick)
1400 stroke_width: String,
1401 }
1402
1403 /// HTML `<circle>` element - Draws a circle in SVG
1404 ///
1405 /// Example:
1406 ///
1407 /// ```<circle cx="50" cy="50" r="40" fill="red" />```
1408 circle {
1409 /// The cx attribute specifies the x-coordinate of the center
1410 /// Example: cx="100" (center x at 100 units)
1411 cx: String,
1412 /// The cy attribute specifies the y-coordinate of the center
1413 /// Example: cy="100" (center y at 100 units)
1414 cy: String,
1415 /// The r attribute specifies the radius of the circle
1416 /// Example: r="75" (75 units radius)
1417 r: String,
1418 /// The fill attribute specifies the fill color
1419 /// Example: fill="#9b59b6" (purple fill)
1420 fill: String,
1421 /// The stroke attribute specifies the outline color
1422 /// Example: stroke="#8e44ad" (darker purple outline)
1423 stroke: String,
1424 /// The stroke-width attribute specifies the width of the outline
1425 /// Example: stroke-width="3" (3 units thick)
1426 stroke_width: String,
1427 }
1428
1429 /// HTML `<ellipse>` element - Draws an ellipse in SVG
1430 ///
1431 /// Example:
1432 ///
1433 /// ```<ellipse cx="100" cy="50" rx="100" ry="50" fill="yellow" />```
1434 ellipse {
1435 /// The cx attribute specifies the x-coordinate of the center
1436 /// Example: cx="150" (center x at 150 units)
1437 cx: String,
1438 /// The cy attribute specifies the y-coordinate of the center
1439 /// Example: cy="75" (center y at 75 units)
1440 cy: String,
1441 /// The rx attribute specifies the horizontal radius
1442 /// Example: rx="100" (100 units horizontal radius)
1443 rx: String,
1444 /// The ry attribute specifies the vertical radius
1445 /// Example: ry="50" (50 units vertical radius)
1446 ry: String,
1447 /// The fill attribute specifies the fill color
1448 /// Example: fill="#f1c40f" (yellow fill)
1449 fill: String,
1450 /// The stroke attribute specifies the outline color
1451 /// Example: stroke="#f39c12" (darker yellow outline)
1452 stroke: String,
1453 /// The stroke-width attribute specifies the width of the outline
1454 /// Example: stroke-width="2" (2 units thick)
1455 stroke_width: String,
1456 }
1457
1458 /// HTML `<line>` element - Draws a line in SVG
1459 ///
1460 /// Example:
1461 ///
1462 /// ```<line x1="0" y1="0" x2="100" y2="100" stroke="black" />```
1463 line {
1464 /// The x1 attribute specifies the x-coordinate of the start point
1465 /// Example: x1="10" (starts 10 units from left)
1466 x1: String,
1467 /// The y1 attribute specifies the y-coordinate of the start point
1468 /// Example: y1="10" (starts 10 units from top)
1469 y1: String,
1470 /// The x2 attribute specifies the x-coordinate of the end point
1471 /// Example: x2="200" (ends 200 units from left)
1472 x2: String,
1473 /// The y2 attribute specifies the y-coordinate of the end point
1474 /// Example: y2="200" (ends 200 units from top)
1475 y2: String,
1476 /// The stroke attribute specifies the line color
1477 /// Example: stroke="#34495e" (dark blue line)
1478 stroke: String,
1479 /// The stroke-width attribute specifies the width of the line
1480 /// Example: stroke-width="5" (5 units thick)
1481 stroke_width: String,
1482 /// The stroke-linecap attribute specifies line end style
1483 /// Example: stroke-linecap="round" (rounded ends)
1484 stroke_linecap: String,
1485 /// The stroke-dasharray attribute creates dashed lines
1486 /// Example: stroke-dasharray="10,5" (10 units on, 5 units off)
1487 stroke_dasharray: String,
1488 }
1489
1490 /// HTML `<polyline>` element - Draws connected straight lines in SVG
1491 ///
1492 /// Example:
1493 ///
1494 /// ```<polyline points="20,20 40,25 60,40 80,120 120,140 200,180" stroke="orange" fill="none" />```
1495 polyline {
1496 /// The points attribute specifies coordinates for each point
1497 /// Example: points="0,0 50,50 100,25" (series of x,y pairs)
1498 points: String,
1499 /// The fill attribute specifies the fill color between lines
1500 /// Example: fill="none" (transparent fill)
1501 fill: String,
1502 /// The stroke attribute specifies the line color
1503 /// Example: stroke="#e67e22" (orange line)
1504 stroke: String,
1505 /// The stroke-width attribute specifies the width of the lines
1506 /// Example: stroke-width="3" (3 units thick)
1507 stroke_width: String,
1508 /// The stroke-linejoin attribute specifies how lines are joined
1509 /// Example: stroke-linejoin="round" (rounded corners)
1510 stroke_linejoin: String,
1511 }
1512
1513 /// HTML `<polygon>` element - Draws a closed shape with straight lines in SVG
1514 ///
1515 /// Example:
1516 ///
1517 /// ```<polygon points="200,10 250,190 160,210" fill="green" />```
1518 polygon {
1519 /// The points attribute specifies coordinates for each point
1520 /// Example: points="50,50 150,50 100,150" (triangle coordinates)
1521 points: String,
1522 /// The fill attribute specifies the fill color of the shape
1523 /// Example: fill="#1abc9c" (teal fill)
1524 fill: String,
1525 /// The stroke attribute specifies the outline color
1526 /// Example: stroke="#16a085" (darker teal outline)
1527 stroke: String,
1528 /// The stroke-width attribute specifies the width of the outline
1529 /// Example: stroke-width="2" (2 units thick)
1530 stroke_width: String,
1531 /// The fill-rule attribute specifies how to fill shapes with holes
1532 /// Example: fill-rule="evenodd" (alternates fill for nested shapes)
1533 fill_rule: String,
1534 }
1535
1536 /// HTML `<g>` element - Groups SVG elements together
1537 ///
1538 /// Example:
1539 ///
1540 /// ```<g transform="rotate(45 50 50)"><rect x="20" y="20" width="60" height="60" /></g>```
1541 g {
1542 /// The transform attribute applies transformations to the group
1543 /// Example: transform="translate(100,50) scale(2)" (moves and scales)
1544 transform: String,
1545 /// The fill attribute specifies the fill color for all elements in the group
1546 /// Example: fill="#3498db" (blue fill for all children)
1547 fill: String,
1548 /// The stroke attribute specifies the outline color for all elements in the group
1549 /// Example: stroke="#2980b9" (darker blue outline for all children)
1550 stroke: String,
1551 }
1552
1553 /// HTML `<use>` element - Reuses an SVG element defined elsewhere
1554 ///
1555 /// Example:
1556 ///
1557 /// ```<r#use href="#myCircle" x="10" y="10" fill="blue" />```
1558 r#use {
1559 /// The href attribute specifies which element to reuse
1560 /// Example: href="#icon-star" (references element with id="icon-star")
1561 href: String,
1562 /// The x attribute specifies the x-coordinate where to place the reused element
1563 /// Example: x="100" (100 units from left)
1564 x: String,
1565 /// The y attribute specifies the y-coordinate where to place the reused element
1566 /// Example: y="50" (50 units from top)
1567 y: String,
1568 }
1569
1570 /// HTML <foreignObject> element - Includes non-SVG elements inside SVG
1571 ///
1572 /// Example:
1573 ///
1574 /// ```<foreignObject x="20" y="20" width="160" height="160"><div>HTML content inside SVG</div></foreignObject>```
1575 foreignObject {
1576 /// The x attribute specifies the x-coordinate of the foreign object
1577 /// Example: x="25" (25 units from left)
1578 x: String,
1579 /// The y attribute specifies the y-coordinate of the foreign object
1580 /// Example: y="25" (25 units from top)
1581 y: String,
1582 }
1583
1584 /// HTML `<defs>` element - Container for reusable SVG elements
1585 ///
1586 /// Example:
1587 ///
1588 /// ```<defs><circle id="myCircle" cx="5" cy="5" r="4" /></defs>```
1589 defs {
1590 }
1591
1592 /// HTML <linearGradient> element - Defines a linear gradient for SVG fills
1593 ///
1594 /// Example:
1595 ///
1596 /// ```<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" style="stop-color:rgb(255,255,0)" /></linearGradient>```
1597 linearGradient {
1598 /// The x1 attribute defines the start point of the gradient (x-coordinate)
1599 /// Example: x1="0%" (starts at left edge)
1600 x1: String,
1601 /// The y1 attribute defines the start point of the gradient (y-coordinate)
1602 /// Example: y1="0%" (starts at top edge)
1603 y1: String,
1604 /// The x2 attribute defines the end point of the gradient (x-coordinate)
1605 /// Example: x2="100%" (ends at right edge)
1606 x2: String,
1607 /// The y2 attribute defines the end point of the gradient (y-coordinate)
1608 /// Example: y2="100%" (ends at bottom edge)
1609 y2: String,
1610 /// The gradientUnits attribute defines the coordinate system for the gradient
1611 /// Example: gradientUnits="userSpaceOnUse" (uses absolute coordinates)
1612 gradientUnits: String,
1613 /// The spreadMethod attribute defines how the gradient fills beyond its bounds
1614 /// Example: spreadMethod="reflect" (gradient reflects at boundaries)
1615 spreadMethod: String,
1616 }
1617
1618 /// HTML `<stop>` element - Defines color transitions in gradients
1619 ///
1620 /// Example:
1621 ///
1622 /// ```<stop offset="0%" style="stop-color:rgb(255,0,0);stop-opacity:1" />```
1623 stop {
1624 /// The offset attribute defines where along the gradient this color appears
1625 /// Example: offset="50%" (color positioned halfway through gradient)
1626 offset: String,
1627 /// The stop-color attribute defines the color at this stop
1628 /// Example: stop-color="#3498db" (blue color)
1629 stop_color: String,
1630 /// The stop-opacity attribute defines the opacity at this stop
1631 /// Example: stop-opacity="0.5" (50% transparent)
1632 stop_opacity: String,
1633 }
1634
1635 /// HTML <radialGradient> element - Defines a radial gradient for SVG fills
1636 ///
1637 /// Example:
1638 ///
1639 /// ```<radialGradient id="grad2" cx="50%" cy="50%" r="50%"><stop offset="0%" style="stop-color:red" /></radialGradient>```
1640 radialGradient {
1641 /// The cx attribute defines the x-coordinate of the center point
1642 /// Example: cx="50%" (center of the area horizontally)
1643 cx: String,
1644 /// The cy attribute defines the y-coordinate of the center point
1645 /// Example: cy="50%" (center of the area vertically)
1646 cy: String,
1647 /// The r attribute defines the radius of the gradient
1648 /// Example: r="75%" (extends to 75% of the reference area)
1649 r: String,
1650 /// The fx attribute defines the x-coordinate of the focal point
1651 /// Example: fx="60%" (focal point slightly right of center)
1652 fx: String,
1653 /// The fy attribute defines the y-coordinate of the focal point
1654 /// Example: fy="40%" (focal point slightly above center)
1655 fy: String,
1656 /// The fr attribute defines the radius of the focal point
1657 /// Example: fr="5%" (small focal point)
1658 fr: String,
1659 /// The gradientUnits attribute defines the coordinate system for the gradient
1660 /// Example: gradientUnits="objectBoundingBox" (relative to object)
1661 gradientUnits: String,
1662 /// The spreadMethod attribute defines how the gradient fills beyond its bounds
1663 /// Example: spreadMethod="pad" (uses edge color beyond boundaries)
1664 spreadMethod: String,
1665 }
1666
1667 /// HTML `<mask>` element - Defines an area where SVG elements are partially or fully hidden
1668 ///
1669 /// Example:
1670 ///
1671 /// ```<mask id="myMask"><rect width="100%" height="100%" fill="white" opacity="0.5" /></mask>```
1672 mask {
1673 /// The maskUnits attribute specifies the coordinate system for mask positioning
1674 /// Example: maskUnits="userSpaceOnUse" (absolute coordinates)
1675 mask_units: String,
1676 /// The maskContentUnits attribute specifies the coordinate system for mask content
1677 /// Example: maskContentUnits="objectBoundingBox" (relative to object)
1678 mask_content_units: String,
1679 /// The x attribute specifies the x-coordinate of the mask
1680 /// Example: x="0" (starts at left edge)
1681 x: String,
1682 /// The y attribute specifies the y-coordinate of the mask
1683 /// Example: y="0" (starts at top edge)
1684 y: String,
1685 }
1686}