Skip to main content

azul_core/
dom.rs

1//! Defines the core Document Object Model (DOM) structures.
2//!
3//! This module is responsible for representing the UI as a tree of nodes,
4//! similar to the HTML DOM. It includes definitions for node types, event handling,
5//! accessibility, and the main `Dom` and `CompactDom` structures.
6
7#[cfg(not(feature = "std"))]
8use alloc::string::ToString;
9use alloc::{boxed::Box, collections::btree_map::BTreeMap, string::String, vec::Vec};
10use core::{
11    fmt,
12    hash::{Hash, Hasher},
13    iter::FromIterator,
14    mem,
15    sync::atomic::{AtomicUsize, Ordering},
16};
17
18use azul_css::{
19    css::{Css, NodeTypeTag},
20    format_rust_code::GetHash,
21    props::{
22        basic::{FloatValue, FontRef},
23        layout::{LayoutDisplay, LayoutFloat, LayoutPosition},
24        property::CssProperty,
25    },
26    AzString, OptionString,
27};
28
29// Re-export event filters from events module (moved in Phase 3.5)
30pub use crate::events::{
31    ApplicationEventFilter, ComponentEventFilter, EventFilter, FocusEventFilter, HoverEventFilter,
32    NotEventFilter, WindowEventFilter,
33};
34pub use crate::id::{Node, NodeHierarchy, NodeId};
35use crate::{
36    callbacks::{
37        CoreCallback, CoreCallbackData, CoreCallbackDataVec, CoreCallbackType, IFrameCallback,
38        IFrameCallbackType,
39    },
40    geom::LogicalPosition,
41    id::{NodeDataContainer, NodeDataContainerRef, NodeDataContainerRefMut},
42    menu::Menu,
43    prop_cache::{CssPropertyCache, CssPropertyCachePtr},
44    refany::{OptionRefAny, RefAny},
45    resources::{
46        image_ref_get_hash, CoreImageCallback, ImageMask, ImageRef, ImageRefHash, RendererResources,
47    },
48    styled_dom::{
49        CompactDom, NodeHierarchyItemId, StyleFontFamilyHash, StyledDom, StyledNode,
50        StyledNodeState,
51    },
52    window::OptionVirtualKeyCodeCombo,
53};
54pub use azul_css::dynamic_selector::{CssPropertyWithConditions, CssPropertyWithConditionsVec};
55
56static TAG_ID: AtomicUsize = AtomicUsize::new(1);
57
58/// Strongly-typed input element types for HTML `<input>` elements.
59#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
60#[repr(C)]
61pub enum InputType {
62    /// Text input (default)
63    Text,
64    /// Button
65    Button,
66    /// Checkbox
67    Checkbox,
68    /// Color picker
69    Color,
70    /// Date picker
71    Date,
72    /// Date and time picker
73    Datetime,
74    /// Date and time picker (local)
75    DatetimeLocal,
76    /// Email address input
77    Email,
78    /// File upload
79    File,
80    /// Hidden input
81    Hidden,
82    /// Image button
83    Image,
84    /// Month picker
85    Month,
86    /// Number input
87    Number,
88    /// Password input
89    Password,
90    /// Radio button
91    Radio,
92    /// Range slider
93    Range,
94    /// Reset button
95    Reset,
96    /// Search input
97    Search,
98    /// Submit button
99    Submit,
100    /// Telephone number input
101    Tel,
102    /// Time picker
103    Time,
104    /// URL input
105    Url,
106    /// Week picker
107    Week,
108}
109
110impl InputType {
111    /// Returns the HTML attribute value for this input type
112    pub const fn as_str(&self) -> &'static str {
113        match self {
114            InputType::Text => "text",
115            InputType::Button => "button",
116            InputType::Checkbox => "checkbox",
117            InputType::Color => "color",
118            InputType::Date => "date",
119            InputType::Datetime => "datetime",
120            InputType::DatetimeLocal => "datetime-local",
121            InputType::Email => "email",
122            InputType::File => "file",
123            InputType::Hidden => "hidden",
124            InputType::Image => "image",
125            InputType::Month => "month",
126            InputType::Number => "number",
127            InputType::Password => "password",
128            InputType::Radio => "radio",
129            InputType::Range => "range",
130            InputType::Reset => "reset",
131            InputType::Search => "search",
132            InputType::Submit => "submit",
133            InputType::Tel => "tel",
134            InputType::Time => "time",
135            InputType::Url => "url",
136            InputType::Week => "week",
137        }
138    }
139}
140
141#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
142#[repr(C)]
143pub struct TagId {
144    pub inner: u64,
145}
146
147impl ::core::fmt::Display for TagId {
148    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
149        f.debug_struct("TagId").field("inner", &self.inner).finish()
150    }
151}
152
153impl_option!(
154    TagId,
155    OptionTagId,
156    [Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash]
157);
158
159impl TagId {
160    pub const fn into_crate_internal(&self) -> TagId {
161        TagId { inner: self.inner }
162    }
163    pub const fn from_crate_internal(t: TagId) -> Self {
164        TagId { inner: t.inner }
165    }
166
167    /// Creates a new, unique hit-testing tag ID.
168    pub fn unique() -> Self {
169        TagId {
170            inner: TAG_ID.fetch_add(1, Ordering::SeqCst) as u64,
171        }
172    }
173
174    /// Resets the counter (usually done after each frame) so that we can
175    /// track hit-testing Tag IDs of subsequent frames.
176    pub fn reset() {
177        TAG_ID.swap(1, Ordering::SeqCst);
178    }
179}
180
181/// Same as the `TagId`, but only for scrollable nodes.
182/// This provides a typed distinction for tags associated with scrolling containers.
183#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
184#[repr(C)]
185pub struct ScrollTagId {
186    pub inner: TagId,
187}
188
189impl ::core::fmt::Display for ScrollTagId {
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        f.debug_struct("ScrollTagId")
192            .field("inner", &self.inner)
193            .finish()
194    }
195}
196
197impl ::core::fmt::Debug for ScrollTagId {
198    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199        write!(f, "{}", self)
200    }
201}
202
203impl ScrollTagId {
204    /// Creates a new, unique scroll tag ID. Note that this should not
205    /// be used for identifying nodes, use the `DomNodeHash` instead.
206    pub fn unique() -> ScrollTagId {
207        ScrollTagId {
208            inner: TagId::unique(),
209        }
210    }
211}
212
213/// Orientation of a scrollbar.
214#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
215#[repr(C)]
216pub enum ScrollbarOrientation {
217    Horizontal,
218    Vertical,
219}
220
221/// Calculated hash of a DOM node, used for identifying identical DOM
222/// nodes across frames for efficient diffing and state preservation.
223#[derive(Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
224#[repr(C)]
225pub struct DomNodeHash {
226    pub inner: u64,
227}
228
229impl ::core::fmt::Debug for DomNodeHash {
230    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
231        write!(f, "DomNodeHash({})", self.inner)
232    }
233}
234
235/// List of core DOM node types built into `azul`.
236/// This enum defines the building blocks of the UI, similar to HTML tags.
237#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
238#[repr(C, u8)]
239pub enum NodeType {
240    // Root and container elements
241    /// Root HTML element.
242    Html,
243    /// Document head (metadata container).
244    Head,
245    /// Root element of the document body.
246    Body,
247    /// Generic block-level container.
248    Div,
249    /// Paragraph.
250    P,
251    /// Article content.
252    Article,
253    /// Section of a document.
254    Section,
255    /// Navigation links.
256    Nav,
257    /// Sidebar/tangential content.
258    Aside,
259    /// Header section.
260    Header,
261    /// Footer section.
262    Footer,
263    /// Main content.
264    Main,
265    /// Figure with optional caption.
266    Figure,
267    /// Caption for figure element.
268    FigCaption,
269    /// Headings.
270    H1,
271    H2,
272    H3,
273    H4,
274    H5,
275    H6,
276    /// Line break.
277    Br,
278    /// Horizontal rule.
279    Hr,
280    /// Preformatted text.
281    Pre,
282    /// Block quote.
283    BlockQuote,
284    /// Address.
285    Address,
286    /// Details disclosure widget.
287    Details,
288    /// Summary for details element.
289    Summary,
290    /// Dialog box or window.
291    Dialog,
292
293    // List elements
294    /// Unordered list.
295    Ul,
296    /// Ordered list.
297    Ol,
298    /// List item.
299    Li,
300    /// Definition list.
301    Dl,
302    /// Definition term.
303    Dt,
304    /// Definition description.
305    Dd,
306    /// Menu list.
307    Menu,
308    /// Menu item.
309    MenuItem,
310    /// Directory list (deprecated).
311    Dir,
312
313    // Table elements
314    /// Table container.
315    Table,
316    /// Table caption.
317    Caption,
318    /// Table header.
319    THead,
320    /// Table body.
321    TBody,
322    /// Table footer.
323    TFoot,
324    /// Table row.
325    Tr,
326    /// Table header cell.
327    Th,
328    /// Table data cell.
329    Td,
330    /// Table column group.
331    ColGroup,
332    /// Table column.
333    Col,
334
335    // Form elements
336    /// Form container.
337    Form,
338    /// Form fieldset.
339    FieldSet,
340    /// Fieldset legend.
341    Legend,
342    /// Label for form controls.
343    Label,
344    /// Input control.
345    Input,
346    /// Button control.
347    Button,
348    /// Select dropdown.
349    Select,
350    /// Option group.
351    OptGroup,
352    /// Select option.
353    SelectOption,
354    /// Multiline text input.
355    TextArea,
356    /// Form output element.
357    Output,
358    /// Progress indicator.
359    Progress,
360    /// Scalar measurement within a known range.
361    Meter,
362    /// List of predefined options for input.
363    DataList,
364
365    // Inline elements
366    /// Generic inline container.
367    Span,
368    /// Anchor/hyperlink.
369    A,
370    /// Emphasized text.
371    Em,
372    /// Strongly emphasized text.
373    Strong,
374    /// Bold text (deprecated - use `Dom::create_strong()` for semantic importance).
375    B,
376    /// Italic text (deprecated - use `Dom::create_em()` for emphasis or `Dom::create_cite()` for citations).
377    I,
378    /// Underline text.
379    U,
380    /// Strikethrough text.
381    S,
382    /// Marked/highlighted text.
383    Mark,
384    /// Deleted text.
385    Del,
386    /// Inserted text.
387    Ins,
388    /// Code.
389    Code,
390    /// Sample output.
391    Samp,
392    /// Keyboard input.
393    Kbd,
394    /// Variable.
395    Var,
396    /// Citation.
397    Cite,
398    /// Defining instance of a term.
399    Dfn,
400    /// Abbreviation.
401    Abbr,
402    /// Acronym.
403    Acronym,
404    /// Inline quotation.
405    Q,
406    /// Date/time.
407    Time,
408    /// Subscript.
409    Sub,
410    /// Superscript.
411    Sup,
412    /// Small text (deprecated - use CSS `font-size` instead).
413    Small,
414    /// Big text (deprecated - use CSS `font-size` instead).
415    Big,
416    /// Bi-directional override.
417    Bdo,
418    /// Bi-directional isolate.
419    Bdi,
420    /// Word break opportunity.
421    Wbr,
422    /// Ruby annotation.
423    Ruby,
424    /// Ruby text.
425    Rt,
426    /// Ruby text container.
427    Rtc,
428    /// Ruby parenthesis.
429    Rp,
430    /// Machine-readable data.
431    Data,
432
433    // Embedded content
434    /// Canvas for graphics.
435    Canvas,
436    /// Embedded object.
437    Object,
438    /// Embedded object parameter.
439    Param,
440    /// External resource embed.
441    Embed,
442    /// Audio content.
443    Audio,
444    /// Video content.
445    Video,
446    /// Media source.
447    Source,
448    /// Text track for media.
449    Track,
450    /// Image map.
451    Map,
452    /// Image map area.
453    Area,
454    /// SVG graphics.
455    Svg,
456
457    // Metadata elements
458    /// Document title.
459    Title,
460    /// Metadata.
461    Meta,
462    /// External resource link.
463    Link,
464    /// Embedded or referenced script.
465    Script,
466    /// Style information.
467    Style,
468    /// Base URL for relative URLs.
469    Base,
470
471    // Pseudo-elements (transformed into real elements)
472    /// ::before pseudo-element.
473    Before,
474    /// ::after pseudo-element.
475    After,
476    /// ::marker pseudo-element.
477    Marker,
478    /// ::placeholder pseudo-element.
479    Placeholder,
480
481    // Special content types
482    /// Text content, ::text
483    Text(AzString),
484    /// Image element, ::image
485    Image(ImageRef),
486    /// IFrame (embedded content)
487    IFrame(IFrameNode),
488    /// Icon element - resolved to actual content by IconProvider
489    /// The string is the icon name (e.g., "home", "settings", "search")
490    Icon(AzString),
491}
492
493impl NodeType {
494    fn into_library_owned_nodetype(&self) -> Self {
495        use self::NodeType::*;
496        match self {
497            Html => Html,
498            Head => Head,
499            Body => Body,
500            Div => Div,
501            P => P,
502            Article => Article,
503            Section => Section,
504            Nav => Nav,
505            Aside => Aside,
506            Header => Header,
507            Footer => Footer,
508            Main => Main,
509            Figure => Figure,
510            FigCaption => FigCaption,
511            H1 => H1,
512            H2 => H2,
513            H3 => H3,
514            H4 => H4,
515            H5 => H5,
516            H6 => H6,
517            Br => Br,
518            Hr => Hr,
519            Pre => Pre,
520            BlockQuote => BlockQuote,
521            Address => Address,
522            Details => Details,
523            Summary => Summary,
524            Dialog => Dialog,
525            Ul => Ul,
526            Ol => Ol,
527            Li => Li,
528            Dl => Dl,
529            Dt => Dt,
530            Dd => Dd,
531            Menu => Menu,
532            MenuItem => MenuItem,
533            Dir => Dir,
534            Table => Table,
535            Caption => Caption,
536            THead => THead,
537            TBody => TBody,
538            TFoot => TFoot,
539            Tr => Tr,
540            Th => Th,
541            Td => Td,
542            ColGroup => ColGroup,
543            Col => Col,
544            Form => Form,
545            FieldSet => FieldSet,
546            Legend => Legend,
547            Label => Label,
548            Input => Input,
549            Button => Button,
550            Select => Select,
551            OptGroup => OptGroup,
552            SelectOption => SelectOption,
553            TextArea => TextArea,
554            Output => Output,
555            Progress => Progress,
556            Meter => Meter,
557            DataList => DataList,
558            Span => Span,
559            A => A,
560            Em => Em,
561            Strong => Strong,
562            B => B,
563            I => I,
564            U => U,
565            S => S,
566            Mark => Mark,
567            Del => Del,
568            Ins => Ins,
569            Code => Code,
570            Samp => Samp,
571            Kbd => Kbd,
572            Var => Var,
573            Cite => Cite,
574            Dfn => Dfn,
575            Abbr => Abbr,
576            Acronym => Acronym,
577            Q => Q,
578            Time => Time,
579            Sub => Sub,
580            Sup => Sup,
581            Small => Small,
582            Big => Big,
583            Bdo => Bdo,
584            Bdi => Bdi,
585            Wbr => Wbr,
586            Ruby => Ruby,
587            Rt => Rt,
588            Rtc => Rtc,
589            Rp => Rp,
590            Data => Data,
591            Canvas => Canvas,
592            Object => Object,
593            Param => Param,
594            Embed => Embed,
595            Audio => Audio,
596            Video => Video,
597            Source => Source,
598            Track => Track,
599            Map => Map,
600            Area => Area,
601            Svg => Svg,
602            Title => Title,
603            Meta => Meta,
604            Link => Link,
605            Script => Script,
606            Style => Style,
607            Base => Base,
608            Before => Before,
609            After => After,
610            Marker => Marker,
611            Placeholder => Placeholder,
612
613            Text(s) => Text(s.clone_self()),
614            Image(i) => Image(i.clone()), // note: shallow clone
615            IFrame(i) => IFrame(IFrameNode {
616                callback: i.callback.clone(),
617                refany: i.refany.clone(),
618            }),
619            Icon(s) => Icon(s.clone_self()),
620        }
621    }
622
623    pub fn format(&self) -> Option<String> {
624        use self::NodeType::*;
625        match self {
626            Text(s) => Some(format!("{}", s)),
627            Image(id) => Some(format!("image({:?})", id)),
628            IFrame(i) => Some(format!("iframe({:?})", i)),
629            Icon(s) => Some(format!("icon({})", s)),
630            _ => None,
631        }
632    }
633
634    /// Returns the NodeTypeTag for CSS selector matching.
635    pub fn get_path(&self) -> NodeTypeTag {
636        match self {
637            Self::Html => NodeTypeTag::Html,
638            Self::Head => NodeTypeTag::Head,
639            Self::Body => NodeTypeTag::Body,
640            Self::Div => NodeTypeTag::Div,
641            Self::P => NodeTypeTag::P,
642            Self::Article => NodeTypeTag::Article,
643            Self::Section => NodeTypeTag::Section,
644            Self::Nav => NodeTypeTag::Nav,
645            Self::Aside => NodeTypeTag::Aside,
646            Self::Header => NodeTypeTag::Header,
647            Self::Footer => NodeTypeTag::Footer,
648            Self::Main => NodeTypeTag::Main,
649            Self::Figure => NodeTypeTag::Figure,
650            Self::FigCaption => NodeTypeTag::FigCaption,
651            Self::H1 => NodeTypeTag::H1,
652            Self::H2 => NodeTypeTag::H2,
653            Self::H3 => NodeTypeTag::H3,
654            Self::H4 => NodeTypeTag::H4,
655            Self::H5 => NodeTypeTag::H5,
656            Self::H6 => NodeTypeTag::H6,
657            Self::Br => NodeTypeTag::Br,
658            Self::Hr => NodeTypeTag::Hr,
659            Self::Pre => NodeTypeTag::Pre,
660            Self::BlockQuote => NodeTypeTag::BlockQuote,
661            Self::Address => NodeTypeTag::Address,
662            Self::Details => NodeTypeTag::Details,
663            Self::Summary => NodeTypeTag::Summary,
664            Self::Dialog => NodeTypeTag::Dialog,
665            Self::Ul => NodeTypeTag::Ul,
666            Self::Ol => NodeTypeTag::Ol,
667            Self::Li => NodeTypeTag::Li,
668            Self::Dl => NodeTypeTag::Dl,
669            Self::Dt => NodeTypeTag::Dt,
670            Self::Dd => NodeTypeTag::Dd,
671            Self::Menu => NodeTypeTag::Menu,
672            Self::MenuItem => NodeTypeTag::MenuItem,
673            Self::Dir => NodeTypeTag::Dir,
674            Self::Table => NodeTypeTag::Table,
675            Self::Caption => NodeTypeTag::Caption,
676            Self::THead => NodeTypeTag::THead,
677            Self::TBody => NodeTypeTag::TBody,
678            Self::TFoot => NodeTypeTag::TFoot,
679            Self::Tr => NodeTypeTag::Tr,
680            Self::Th => NodeTypeTag::Th,
681            Self::Td => NodeTypeTag::Td,
682            Self::ColGroup => NodeTypeTag::ColGroup,
683            Self::Col => NodeTypeTag::Col,
684            Self::Form => NodeTypeTag::Form,
685            Self::FieldSet => NodeTypeTag::FieldSet,
686            Self::Legend => NodeTypeTag::Legend,
687            Self::Label => NodeTypeTag::Label,
688            Self::Input => NodeTypeTag::Input,
689            Self::Button => NodeTypeTag::Button,
690            Self::Select => NodeTypeTag::Select,
691            Self::OptGroup => NodeTypeTag::OptGroup,
692            Self::SelectOption => NodeTypeTag::SelectOption,
693            Self::TextArea => NodeTypeTag::TextArea,
694            Self::Output => NodeTypeTag::Output,
695            Self::Progress => NodeTypeTag::Progress,
696            Self::Meter => NodeTypeTag::Meter,
697            Self::DataList => NodeTypeTag::DataList,
698            Self::Span => NodeTypeTag::Span,
699            Self::A => NodeTypeTag::A,
700            Self::Em => NodeTypeTag::Em,
701            Self::Strong => NodeTypeTag::Strong,
702            Self::B => NodeTypeTag::B,
703            Self::I => NodeTypeTag::I,
704            Self::U => NodeTypeTag::U,
705            Self::S => NodeTypeTag::S,
706            Self::Mark => NodeTypeTag::Mark,
707            Self::Del => NodeTypeTag::Del,
708            Self::Ins => NodeTypeTag::Ins,
709            Self::Code => NodeTypeTag::Code,
710            Self::Samp => NodeTypeTag::Samp,
711            Self::Kbd => NodeTypeTag::Kbd,
712            Self::Var => NodeTypeTag::Var,
713            Self::Cite => NodeTypeTag::Cite,
714            Self::Dfn => NodeTypeTag::Dfn,
715            Self::Abbr => NodeTypeTag::Abbr,
716            Self::Acronym => NodeTypeTag::Acronym,
717            Self::Q => NodeTypeTag::Q,
718            Self::Time => NodeTypeTag::Time,
719            Self::Sub => NodeTypeTag::Sub,
720            Self::Sup => NodeTypeTag::Sup,
721            Self::Small => NodeTypeTag::Small,
722            Self::Big => NodeTypeTag::Big,
723            Self::Bdo => NodeTypeTag::Bdo,
724            Self::Bdi => NodeTypeTag::Bdi,
725            Self::Wbr => NodeTypeTag::Wbr,
726            Self::Ruby => NodeTypeTag::Ruby,
727            Self::Rt => NodeTypeTag::Rt,
728            Self::Rtc => NodeTypeTag::Rtc,
729            Self::Rp => NodeTypeTag::Rp,
730            Self::Data => NodeTypeTag::Data,
731            Self::Canvas => NodeTypeTag::Canvas,
732            Self::Object => NodeTypeTag::Object,
733            Self::Param => NodeTypeTag::Param,
734            Self::Embed => NodeTypeTag::Embed,
735            Self::Audio => NodeTypeTag::Audio,
736            Self::Video => NodeTypeTag::Video,
737            Self::Source => NodeTypeTag::Source,
738            Self::Track => NodeTypeTag::Track,
739            Self::Map => NodeTypeTag::Map,
740            Self::Area => NodeTypeTag::Area,
741            Self::Svg => NodeTypeTag::Svg,
742            Self::Title => NodeTypeTag::Title,
743            Self::Meta => NodeTypeTag::Meta,
744            Self::Link => NodeTypeTag::Link,
745            Self::Script => NodeTypeTag::Script,
746            Self::Style => NodeTypeTag::Style,
747            Self::Base => NodeTypeTag::Base,
748            Self::Text(_) => NodeTypeTag::Text,
749            Self::Image(_) => NodeTypeTag::Img,
750            Self::IFrame(_) => NodeTypeTag::IFrame,
751            Self::Icon(_) => NodeTypeTag::Icon,
752            Self::Before => NodeTypeTag::Before,
753            Self::After => NodeTypeTag::After,
754            Self::Marker => NodeTypeTag::Marker,
755            Self::Placeholder => NodeTypeTag::Placeholder,
756        }
757    }
758
759    /// Returns whether this node type is a semantic HTML element that should
760    /// automatically generate an accessibility tree node.
761    ///
762    /// These are elements with inherent semantic meaning that assistive
763    /// technologies should be aware of, even without explicit ARIA attributes.
764    pub const fn is_semantic_for_accessibility(&self) -> bool {
765        matches!(
766            self,
767            Self::Button
768                | Self::Input
769                | Self::TextArea
770                | Self::Select
771                | Self::A
772                | Self::H1
773                | Self::H2
774                | Self::H3
775                | Self::H4
776                | Self::H5
777                | Self::H6
778                | Self::Article
779                | Self::Section
780                | Self::Nav
781                | Self::Main
782                | Self::Header
783                | Self::Footer
784                | Self::Aside
785        )
786    }
787}
788
789/// Represents the CSS formatting context for an element
790#[derive(Clone, PartialEq)]
791pub enum FormattingContext {
792    /// Block-level formatting context
793    Block {
794        /// Whether this element establishes a new block formatting context
795        establishes_new_context: bool,
796    },
797    /// Inline-level formatting context
798    Inline,
799    /// Inline-block (participates in an IFC but creates a BFC)
800    InlineBlock,
801    /// Flex formatting context
802    Flex,
803    /// Float (left or right)
804    Float(LayoutFloat),
805    /// Absolutely positioned (out of flow)
806    OutOfFlow(LayoutPosition),
807    /// Table formatting context (container)
808    Table,
809    /// Table row group formatting context (thead, tbody, tfoot)
810    TableRowGroup,
811    /// Table row formatting context
812    TableRow,
813    /// Table cell formatting context (td, th)
814    TableCell,
815    /// Table column group formatting context
816    TableColumnGroup,
817    /// Table caption formatting context
818    TableCaption,
819    /// Grid formatting context
820    Grid,
821    /// No formatting context (display: none)
822    None,
823}
824
825impl fmt::Debug for FormattingContext {
826    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
827        match self {
828            FormattingContext::Block {
829                establishes_new_context,
830            } => write!(
831                f,
832                "Block {{ establishes_new_context: {establishes_new_context:?} }}"
833            ),
834            FormattingContext::Inline => write!(f, "Inline"),
835            FormattingContext::InlineBlock => write!(f, "InlineBlock"),
836            FormattingContext::Flex => write!(f, "Flex"),
837            FormattingContext::Float(layout_float) => write!(f, "Float({layout_float:?})"),
838            FormattingContext::OutOfFlow(layout_position) => {
839                write!(f, "OutOfFlow({layout_position:?})")
840            }
841            FormattingContext::Grid => write!(f, "Grid"),
842            FormattingContext::None => write!(f, "None"),
843            FormattingContext::Table => write!(f, "Table"),
844            FormattingContext::TableRowGroup => write!(f, "TableRowGroup"),
845            FormattingContext::TableRow => write!(f, "TableRow"),
846            FormattingContext::TableCell => write!(f, "TableCell"),
847            FormattingContext::TableColumnGroup => write!(f, "TableColumnGroup"),
848            FormattingContext::TableCaption => write!(f, "TableCaption"),
849        }
850    }
851}
852
853impl Default for FormattingContext {
854    fn default() -> Self {
855        FormattingContext::Block {
856            establishes_new_context: false,
857        }
858    }
859}
860
861/// Defines the type of event that can trigger a callback action.
862#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
863#[repr(C)]
864pub enum On {
865    /// Mouse cursor is hovering over the element.
866    MouseOver,
867    /// Mouse cursor has is over element and is pressed
868    /// (not good for "click" events - use `MouseUp` instead).
869    MouseDown,
870    /// (Specialization of `MouseDown`). Fires only if the left mouse button
871    /// has been pressed while cursor was over the element.
872    LeftMouseDown,
873    /// (Specialization of `MouseDown`). Fires only if the middle mouse button
874    /// has been pressed while cursor was over the element.
875    MiddleMouseDown,
876    /// (Specialization of `MouseDown`). Fires only if the right mouse button
877    /// has been pressed while cursor was over the element.
878    RightMouseDown,
879    /// Mouse button has been released while cursor was over the element.
880    MouseUp,
881    /// (Specialization of `MouseUp`). Fires only if the left mouse button has
882    /// been released while cursor was over the element.
883    LeftMouseUp,
884    /// (Specialization of `MouseUp`). Fires only if the middle mouse button has
885    /// been released while cursor was over the element.
886    MiddleMouseUp,
887    /// (Specialization of `MouseUp`). Fires only if the right mouse button has
888    /// been released while cursor was over the element.
889    RightMouseUp,
890    /// Mouse cursor has entered the element.
891    MouseEnter,
892    /// Mouse cursor has left the element.
893    MouseLeave,
894    /// Mousewheel / touchpad scrolling.
895    Scroll,
896    /// The window received a unicode character (also respects the system locale).
897    /// Check `keyboard_state.current_char` to get the current pressed character.
898    TextInput,
899    /// A **virtual keycode** was pressed. Note: This is only the virtual keycode,
900    /// not the actual char. If you want to get the character, use `TextInput` instead.
901    /// A virtual key does not have to map to a printable character.
902    ///
903    /// You can get all currently pressed virtual keycodes in the
904    /// `keyboard_state.current_virtual_keycodes` and / or just the last keycode in the
905    /// `keyboard_state.latest_virtual_keycode`.
906    VirtualKeyDown,
907    /// A **virtual keycode** was release. See `VirtualKeyDown` for more info.
908    VirtualKeyUp,
909    /// A file has been dropped on the element.
910    HoveredFile,
911    /// A file is being hovered on the element.
912    DroppedFile,
913    /// A file was hovered, but has exited the window.
914    HoveredFileCancelled,
915    /// Equivalent to `onfocus`.
916    FocusReceived,
917    /// Equivalent to `onblur`.
918    FocusLost,
919
920    // Accessibility-specific events
921    /// Default action triggered by screen reader (usually same as click/activate)
922    Default,
923    /// Element should collapse (e.g., accordion panel, tree node)
924    Collapse,
925    /// Element should expand (e.g., accordion panel, tree node)
926    Expand,
927    /// Increment value (e.g., number input, slider)
928    Increment,
929    /// Decrement value (e.g., number input, slider)
930    Decrement,
931}
932
933// NOTE: EventFilter types moved to core/src/events.rs (Phase 3.5)
934//
935// The following types are now defined in events.rs and re-exported above:
936// - EventFilter
937// - HoverEventFilter
938// - FocusEventFilter
939// - WindowEventFilter
940// - NotEventFilter
941// - ComponentEventFilter
942// - ApplicationEventFilter
943//
944// This consolidates all event-related logic in one place.
945
946/// Contains the necessary information to render an embedded `IFrame` node.
947#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
948#[repr(C)]
949pub struct IFrameNode {
950    /// The callback function that returns the DOM for the iframe's content.
951    pub callback: IFrameCallback,
952    /// The application data passed to the iframe's layout callback.
953    pub refany: RefAny,
954}
955
956/// An enum that holds either a CSS ID or a class name as a string.
957#[repr(C, u8)]
958#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
959pub enum IdOrClass {
960    Id(AzString),
961    Class(AzString),
962}
963
964impl_vec!(
965    IdOrClass,
966    IdOrClassVec,
967    IdOrClassVecDestructor,
968    IdOrClassVecDestructorType
969);
970impl_vec_debug!(IdOrClass, IdOrClassVec);
971impl_vec_partialord!(IdOrClass, IdOrClassVec);
972impl_vec_ord!(IdOrClass, IdOrClassVec);
973impl_vec_clone!(IdOrClass, IdOrClassVec, IdOrClassVecDestructor);
974impl_vec_partialeq!(IdOrClass, IdOrClassVec);
975impl_vec_eq!(IdOrClass, IdOrClassVec);
976impl_vec_hash!(IdOrClass, IdOrClassVec);
977
978impl IdOrClass {
979    pub fn as_id(&self) -> Option<&str> {
980        match self {
981            IdOrClass::Id(s) => Some(s.as_str()),
982            IdOrClass::Class(_) => None,
983        }
984    }
985    pub fn as_class(&self) -> Option<&str> {
986        match self {
987            IdOrClass::Class(s) => Some(s.as_str()),
988            IdOrClass::Id(_) => None,
989        }
990    }
991}
992
993/// Name-value pair for custom attributes (data-*, aria-*, etc.)
994#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
995#[repr(C)]
996pub struct AttributeNameValue {
997    pub attr_name: AzString,
998    pub value: AzString,
999}
1000
1001/// Strongly-typed HTML attribute with type-safe values.
1002///
1003/// This enum provides a type-safe way to represent HTML attributes, ensuring that
1004/// values are validated at compile-time and properly converted to their string
1005/// representations at runtime.
1006#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1007#[repr(C, u8)]
1008pub enum AttributeType {
1009    /// Element ID attribute (`id="..."`)
1010    Id(AzString),
1011    /// CSS class attribute (`class="..."`)
1012    Class(AzString),
1013    /// Accessible name/label (`aria-label="..."`)
1014    AriaLabel(AzString),
1015    /// Element that labels this one (`aria-labelledby="..."`)
1016    AriaLabelledBy(AzString),
1017    /// Element that describes this one (`aria-describedby="..."`)
1018    AriaDescribedBy(AzString),
1019    /// Role for accessibility (`role="..."`)
1020    AriaRole(AzString),
1021    /// Current state of an element (`aria-checked`, `aria-selected`, etc.)
1022    AriaState(AttributeNameValue),
1023    /// ARIA property (`aria-*`)
1024    AriaProperty(AttributeNameValue),
1025
1026    /// Hyperlink target URL (`href="..."`)
1027    Href(AzString),
1028    /// Link relationship (`rel="..."`)
1029    Rel(AzString),
1030    /// Link target frame (`target="..."`)
1031    Target(AzString),
1032
1033    /// Image source URL (`src="..."`)
1034    Src(AzString),
1035    /// Alternative text for images (`alt="..."`)
1036    Alt(AzString),
1037    /// Image title (tooltip) (`title="..."`)
1038    Title(AzString),
1039
1040    /// Form input name (`name="..."`)
1041    Name(AzString),
1042    /// Form input value (`value="..."`)
1043    Value(AzString),
1044    /// Input type (`type="text|password|email|..."`)
1045    InputType(AzString),
1046    /// Placeholder text (`placeholder="..."`)
1047    Placeholder(AzString),
1048    /// Input is required (`required`)
1049    Required,
1050    /// Input is disabled (`disabled`)
1051    Disabled,
1052    /// Input is readonly (`readonly`)
1053    Readonly,
1054    /// Input is checked (checkbox/radio) (`checked`)
1055    Checked,
1056    /// Input is selected (option) (`selected`)
1057    Selected,
1058    /// Maximum value for number inputs (`max="..."`)
1059    Max(AzString),
1060    /// Minimum value for number inputs (`min="..."`)
1061    Min(AzString),
1062    /// Step value for number inputs (`step="..."`)
1063    Step(AzString),
1064    /// Input pattern for validation (`pattern="..."`)
1065    Pattern(AzString),
1066    /// Minimum length (`minlength="..."`)
1067    MinLength(i32),
1068    /// Maximum length (`maxlength="..."`)
1069    MaxLength(i32),
1070    /// Autocomplete behavior (`autocomplete="on|off|..."`)
1071    Autocomplete(AzString),
1072
1073    /// Table header scope (`scope="row|col|rowgroup|colgroup"`)
1074    Scope(AzString),
1075    /// Number of columns to span (`colspan="..."`)
1076    ColSpan(i32),
1077    /// Number of rows to span (`rowspan="..."`)
1078    RowSpan(i32),
1079
1080    /// Tab index for keyboard navigation (`tabindex="..."`)
1081    TabIndex(i32),
1082    /// Element can receive focus (`tabindex="0"` equivalent)
1083    Focusable,
1084
1085    /// Language code (`lang="..."`)
1086    Lang(AzString),
1087    /// Text direction (`dir="ltr|rtl|auto"`)
1088    Dir(AzString),
1089
1090    /// Content is editable (`contenteditable="true|false"`)
1091    ContentEditable(bool),
1092    /// Element is draggable (`draggable="true|false"`)
1093    Draggable(bool),
1094    /// Element is hidden (`hidden`)
1095    Hidden,
1096
1097    /// Generic data attribute (`data-*="..."`)
1098    Data(AttributeNameValue),
1099    /// Generic custom attribute (for future extensibility)
1100    Custom(AttributeNameValue),
1101}
1102
1103impl_vec!(
1104    AttributeType,
1105    AttributeVec,
1106    AttributeVecDestructor,
1107    AttributeVecDestructorType
1108);
1109impl_vec_debug!(AttributeType, AttributeVec);
1110impl_vec_partialord!(AttributeType, AttributeVec);
1111impl_vec_ord!(AttributeType, AttributeVec);
1112impl_vec_clone!(AttributeType, AttributeVec, AttributeVecDestructor);
1113impl_vec_partialeq!(AttributeType, AttributeVec);
1114impl_vec_eq!(AttributeType, AttributeVec);
1115impl_vec_hash!(AttributeType, AttributeVec);
1116
1117impl AttributeType {
1118    /// Get the attribute name (e.g., "href", "aria-label", "data-foo")
1119    pub fn name(&self) -> &str {
1120        match self {
1121            AttributeType::Id(_) => "id",
1122            AttributeType::Class(_) => "class",
1123            AttributeType::AriaLabel(_) => "aria-label",
1124            AttributeType::AriaLabelledBy(_) => "aria-labelledby",
1125            AttributeType::AriaDescribedBy(_) => "aria-describedby",
1126            AttributeType::AriaRole(_) => "role",
1127            AttributeType::AriaState(nv) => nv.attr_name.as_str(),
1128            AttributeType::AriaProperty(nv) => nv.attr_name.as_str(),
1129            AttributeType::Href(_) => "href",
1130            AttributeType::Rel(_) => "rel",
1131            AttributeType::Target(_) => "target",
1132            AttributeType::Src(_) => "src",
1133            AttributeType::Alt(_) => "alt",
1134            AttributeType::Title(_) => "title",
1135            AttributeType::Name(_) => "name",
1136            AttributeType::Value(_) => "value",
1137            AttributeType::InputType(_) => "type",
1138            AttributeType::Placeholder(_) => "placeholder",
1139            AttributeType::Required => "required",
1140            AttributeType::Disabled => "disabled",
1141            AttributeType::Readonly => "readonly",
1142            AttributeType::Checked => "checked",
1143            AttributeType::Selected => "selected",
1144            AttributeType::Max(_) => "max",
1145            AttributeType::Min(_) => "min",
1146            AttributeType::Step(_) => "step",
1147            AttributeType::Pattern(_) => "pattern",
1148            AttributeType::MinLength(_) => "minlength",
1149            AttributeType::MaxLength(_) => "maxlength",
1150            AttributeType::Autocomplete(_) => "autocomplete",
1151            AttributeType::Scope(_) => "scope",
1152            AttributeType::ColSpan(_) => "colspan",
1153            AttributeType::RowSpan(_) => "rowspan",
1154            AttributeType::TabIndex(_) => "tabindex",
1155            AttributeType::Focusable => "tabindex",
1156            AttributeType::Lang(_) => "lang",
1157            AttributeType::Dir(_) => "dir",
1158            AttributeType::ContentEditable(_) => "contenteditable",
1159            AttributeType::Draggable(_) => "draggable",
1160            AttributeType::Hidden => "hidden",
1161            AttributeType::Data(nv) => nv.attr_name.as_str(),
1162            AttributeType::Custom(nv) => nv.attr_name.as_str(),
1163        }
1164    }
1165
1166    /// Get the attribute value as a string
1167    pub fn value(&self) -> AzString {
1168        match self {
1169            AttributeType::Id(v)
1170            | AttributeType::Class(v)
1171            | AttributeType::AriaLabel(v)
1172            | AttributeType::AriaLabelledBy(v)
1173            | AttributeType::AriaDescribedBy(v)
1174            | AttributeType::AriaRole(v)
1175            | AttributeType::Href(v)
1176            | AttributeType::Rel(v)
1177            | AttributeType::Target(v)
1178            | AttributeType::Src(v)
1179            | AttributeType::Alt(v)
1180            | AttributeType::Title(v)
1181            | AttributeType::Name(v)
1182            | AttributeType::Value(v)
1183            | AttributeType::InputType(v)
1184            | AttributeType::Placeholder(v)
1185            | AttributeType::Max(v)
1186            | AttributeType::Min(v)
1187            | AttributeType::Step(v)
1188            | AttributeType::Pattern(v)
1189            | AttributeType::Autocomplete(v)
1190            | AttributeType::Scope(v)
1191            | AttributeType::Lang(v)
1192            | AttributeType::Dir(v) => v.clone(),
1193
1194            AttributeType::AriaState(nv)
1195            | AttributeType::AriaProperty(nv)
1196            | AttributeType::Data(nv)
1197            | AttributeType::Custom(nv) => nv.value.clone(),
1198
1199            AttributeType::MinLength(n)
1200            | AttributeType::MaxLength(n)
1201            | AttributeType::ColSpan(n)
1202            | AttributeType::RowSpan(n)
1203            | AttributeType::TabIndex(n) => n.to_string().into(),
1204
1205            AttributeType::Focusable => "0".into(),
1206            AttributeType::ContentEditable(b) | AttributeType::Draggable(b) => {
1207                if *b {
1208                    "true".into()
1209                } else {
1210                    "false".into()
1211                }
1212            }
1213
1214            AttributeType::Required
1215            | AttributeType::Disabled
1216            | AttributeType::Readonly
1217            | AttributeType::Checked
1218            | AttributeType::Selected
1219            | AttributeType::Hidden => "".into(), // Boolean attributes
1220        }
1221    }
1222
1223    /// Check if this is a boolean attribute (present = true, absent = false)
1224    pub fn is_boolean(&self) -> bool {
1225        matches!(
1226            self,
1227            AttributeType::Required
1228                | AttributeType::Disabled
1229                | AttributeType::Readonly
1230                | AttributeType::Checked
1231                | AttributeType::Selected
1232                | AttributeType::Hidden
1233        )
1234    }
1235}
1236
1237/// Compact accessibility information for common use cases.
1238///
1239/// This is a lighter-weight alternative to `AccessibilityInfo` for cases where
1240/// only basic accessibility properties are needed. Developers must explicitly
1241/// pass `None` if they choose not to provide accessibility information.
1242#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1243#[repr(C)]
1244pub struct SmallAriaInfo {
1245    /// Accessible label/name
1246    pub label: OptionString,
1247    /// Element's role (button, link, etc.)
1248    pub role: OptionAccessibilityRole,
1249    /// Additional description
1250    pub description: OptionString,
1251}
1252
1253impl_option!(
1254    SmallAriaInfo,
1255    OptionSmallAriaInfo,
1256    copy = false,
1257    [Debug, Clone, PartialEq, Eq, Hash]
1258);
1259
1260impl SmallAriaInfo {
1261    pub fn label<S: Into<AzString>>(text: S) -> Self {
1262        Self {
1263            label: OptionString::Some(text.into()),
1264            role: OptionAccessibilityRole::None,
1265            description: OptionString::None,
1266        }
1267    }
1268
1269    pub fn with_role(mut self, role: AccessibilityRole) -> Self {
1270        self.role = OptionAccessibilityRole::Some(role);
1271        self
1272    }
1273
1274    pub fn with_description<S: Into<AzString>>(mut self, desc: S) -> Self {
1275        self.description = OptionString::Some(desc.into());
1276        self
1277    }
1278
1279    /// Convert to full `AccessibilityInfo`
1280    pub fn to_full_info(&self) -> AccessibilityInfo {
1281        AccessibilityInfo {
1282            accessibility_name: self.label.clone(),
1283            accessibility_value: OptionString::None,
1284            role: match self.role {
1285                OptionAccessibilityRole::Some(r) => r,
1286                OptionAccessibilityRole::None => AccessibilityRole::Unknown,
1287            },
1288            states: Vec::new().into(),
1289            accelerator: OptionVirtualKeyCodeCombo::None,
1290            default_action: OptionString::None,
1291            supported_actions: Vec::new().into(),
1292            is_live_region: false,
1293            labelled_by: OptionDomNodeId::None,
1294            described_by: OptionDomNodeId::None,
1295        }
1296    }
1297}
1298
1299/// Represents all data associated with a single DOM node, such as its type,
1300/// classes, IDs, callbacks, and inline styles.
1301#[repr(C)]
1302#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
1303pub struct NodeData {
1304    /// `div`, `p`, `img`, etc.
1305    pub node_type: NodeType,
1306    /// `data-*` attributes for this node, useful to store UI-related data on the node itself.
1307    pub dataset: OptionRefAny,
1308    /// Stores all ids and classes as one vec - size optimization since
1309    /// most nodes don't have any classes or IDs.
1310    pub ids_and_classes: IdOrClassVec,
1311    /// Strongly-typed HTML attributes (aria-*, href, alt, etc.)
1312    pub attributes: AttributeVec,
1313    /// Callbacks attached to this node:
1314    ///
1315    /// `On::MouseUp` -> `Callback(my_button_click_handler)`
1316    pub callbacks: CoreCallbackDataVec,
1317    /// Conditional CSS properties with dynamic selectors.
1318    /// These are evaluated at runtime based on OS, viewport, container, theme, and pseudo-state.
1319    /// Uses "last wins" semantics - properties are evaluated in order, last match wins.
1320    pub css_props: CssPropertyWithConditionsVec,
1321    /// Tab index (commonly used property).
1322    pub tab_index: OptionTabIndex,
1323    /// Whether this node is contenteditable (accepts text input).
1324    /// Equivalent to HTML `contenteditable="true"` attribute.
1325    pub contenteditable: bool,
1326    /// Stores "extra", not commonly used data of the node: accessibility, clip-mask, tab-index,
1327    /// etc.
1328    ///
1329    /// SHOULD NOT EXPOSED IN THE API - necessary to retroactively add functionality
1330    /// to the node without breaking the ABI.
1331    extra: Option<Box<NodeDataExt>>,
1332}
1333
1334impl Hash for NodeData {
1335    fn hash<H: Hasher>(&self, state: &mut H) {
1336        self.node_type.hash(state);
1337        self.dataset.hash(state);
1338        self.ids_and_classes.as_ref().hash(state);
1339        self.attributes.as_ref().hash(state);
1340        self.contenteditable.hash(state);
1341
1342        // NOTE: callbacks are NOT hashed regularly, otherwise
1343        // they'd cause inconsistencies because of the scroll callback
1344        for callback in self.callbacks.as_ref().iter() {
1345            callback.event.hash(state);
1346            callback.callback.hash(state);
1347            callback.refany.get_type_id().hash(state);
1348        }
1349
1350        // Hash CSS props (conditional CSS with dynamic selectors)
1351        for prop in self.css_props.as_ref().iter() {
1352            // Hash property type as a simple discriminant
1353            core::mem::discriminant(&prop.property).hash(state);
1354        }
1355        if let Some(ext) = self.extra.as_ref() {
1356            if let Some(c) = ext.clip_mask.as_ref() {
1357                c.hash(state);
1358            }
1359            // Note: AccessibilityInfo doesn't implement Hash (has non-hashable fields)
1360            // Skipping accessibility field in hash
1361            if let Some(c) = ext.menu_bar.as_ref() {
1362                c.hash(state);
1363            }
1364            if let Some(c) = ext.context_menu.as_ref() {
1365                c.hash(state);
1366            }
1367        }
1368    }
1369}
1370
1371/// NOTE: NOT EXPOSED IN THE API! Stores extra,
1372/// not commonly used information for the NodeData.
1373/// This helps keep the primary `NodeData` struct smaller for common cases.
1374#[repr(C)]
1375#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1376pub struct NodeDataExt {
1377    /// Optional clip mask for this DOM node.
1378    pub clip_mask: Option<ImageMask>,
1379    /// Optional extra accessibility information about this DOM node (MSAA, AT-SPI, UA).
1380    pub accessibility: Option<Box<AccessibilityInfo>>,
1381    /// Menu bar that should be displayed at the top of this nodes rect.
1382    pub menu_bar: Option<Box<Menu>>,
1383    /// Context menu that should be opened when the item is left-clicked.
1384    pub context_menu: Option<Box<Menu>>,
1385    /// Whether this node is an anonymous box (generated for table layout).
1386    /// Anonymous boxes are not part of the original DOM tree and are created
1387    /// by the layout engine to satisfy table layout requirements (e.g., wrapping
1388    /// non-table children of table elements in anonymous table-row/table-cell boxes).
1389    pub is_anonymous: bool,
1390    /// Stable key for reconciliation. If provided, allows the framework to track
1391    /// this node across frames even if its position in the array changes.
1392    /// This is crucial for correct lifecycle events when lists are reordered.
1393    pub key: Option<u64>,
1394    /// Callback to merge dataset state from a previous frame's node into the current node.
1395    /// This enables heavy resource preservation (video decoders, GL textures) across frames.
1396    pub dataset_merge_callback: Option<DatasetMergeCallback>,
1397    // ... insert further API extensions here...
1398}
1399
1400/// A callback function used to merge the state of an old dataset into a new one.
1401///
1402/// This enables components with heavy internal state (video players, WebGL contexts)
1403/// to preserve their resources across frames, while the DOM tree is recreated.
1404///
1405/// The callback receives both the old and new datasets as `RefAny` (cheap shallow clones)
1406/// and returns the dataset that should be used for the new node.
1407///
1408/// # Example
1409///
1410/// ```rust,ignore
1411/// fn merge_video_state(new_data: RefAny, old_data: RefAny) -> RefAny {
1412///     // Transfer heavy resources from old to new
1413///     if let (Some(mut new), Some(old)) = (
1414///         new_data.downcast_mut::<VideoState>(),
1415///         old_data.downcast_ref::<VideoState>()
1416///     ) {
1417///         new.decoder = old.decoder.take();
1418///         new.gl_texture = old.gl_texture.take();
1419///     }
1420///     new_data // Return the merged state
1421/// }
1422/// ```
1423#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
1424#[repr(C)]
1425pub struct DatasetMergeCallback {
1426    /// The function pointer that performs the merge.
1427    /// Signature: `fn(new_data: RefAny, old_data: RefAny) -> RefAny`
1428    pub cb: DatasetMergeCallbackType,
1429    /// Optional callable for FFI language bindings (Python, etc.)
1430    /// When set, the FFI layer can invoke this instead of `cb`.
1431    pub callable: OptionRefAny,
1432}
1433
1434impl core::fmt::Debug for DatasetMergeCallback {
1435    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1436        f.debug_struct("DatasetMergeCallback")
1437            .field("cb", &(self.cb as usize))
1438            .field("callable", &self.callable)
1439            .finish()
1440    }
1441}
1442
1443/// Allow creating DatasetMergeCallback from a raw function pointer.
1444/// This enables the `Into<DatasetMergeCallback>` pattern for Python bindings.
1445impl From<DatasetMergeCallbackType> for DatasetMergeCallback {
1446    fn from(cb: DatasetMergeCallbackType) -> Self {
1447        DatasetMergeCallback { 
1448            cb,
1449            callable: OptionRefAny::None,
1450        }
1451    }
1452}
1453
1454impl_option!(
1455    DatasetMergeCallback,
1456    OptionDatasetMergeCallback,
1457    copy = false,
1458    [Debug, Clone]
1459);
1460
1461/// Function pointer type for dataset merge callbacks.
1462/// 
1463/// Arguments:
1464/// - `new_data`: The new node's dataset (shallow clone, cheap)
1465/// - `old_data`: The old node's dataset (shallow clone, cheap)
1466/// 
1467/// Returns:
1468/// - The `RefAny` that should be used as the dataset for the new node
1469pub type DatasetMergeCallbackType = extern "C" fn(RefAny, RefAny) -> RefAny;
1470
1471/// Holds information about a UI element for accessibility purposes (e.g., screen readers).
1472/// This is a wrapper for platform-specific accessibility APIs like MSAA.
1473#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
1474#[repr(C)]
1475pub struct AccessibilityInfo {
1476    /// Get the "name" of the `IAccessible`, for example the
1477    /// name of a button, checkbox or menu item. Try to use unique names
1478    /// for each item in a dialog so that voice dictation software doesn't
1479    /// have to deal with extra ambiguity.
1480    pub accessibility_name: OptionString,
1481    /// Get the "value" of the `IAccessible`, for example a number in a slider,
1482    /// a URL for a link, the text a user entered in a field.
1483    pub accessibility_value: OptionString,
1484    /// Get an enumerated value representing what this IAccessible is used for,
1485    /// for example is it a link, static text, editable text, a checkbox, or a table cell, etc.
1486    pub role: AccessibilityRole,
1487    /// Possible on/off states, such as focused, focusable, selected, selectable,
1488    /// visible, protected (for passwords), checked, etc.
1489    pub states: AccessibilityStateVec,
1490    /// Optional keyboard accelerator.
1491    pub accelerator: OptionVirtualKeyCodeCombo,
1492    /// Optional "default action" description. Only used when there is at least
1493    /// one `ComponentEventFilter::DefaultAction` callback present on this node.
1494    pub default_action: OptionString,
1495    /// A list of actions the user can perform on this element.
1496    /// Maps to accesskit's Action enum.
1497    pub supported_actions: AccessibilityActionVec,
1498    /// For live regions that update automatically (e.g., chat messages, timers).
1499    /// Maps to accesskit's `Live` property.
1500    pub is_live_region: bool,
1501    /// ID of another node that labels this one (for `aria-labelledby`).
1502    pub labelled_by: OptionDomNodeId,
1503    /// ID of another node that describes this one (for `aria-describedby`).
1504    pub described_by: OptionDomNodeId,
1505}
1506
1507/// Actions that can be performed on an accessible element.
1508/// This is a simplified version of accesskit::Action to avoid direct dependency in core.
1509#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1510#[repr(C, u8)]
1511pub enum AccessibilityAction {
1512    /// The default action for the element (usually a click).
1513    Default,
1514    /// Set focus to this element.
1515    Focus,
1516    /// Remove focus from this element.
1517    Blur,
1518    /// Collapse an expandable element (e.g., tree node, accordion).
1519    Collapse,
1520    /// Expand a collapsible element (e.g., tree node, accordion).
1521    Expand,
1522    /// Scroll this element into view.
1523    ScrollIntoView,
1524    /// Increment a numeric value (e.g., slider, spinner).
1525    Increment,
1526    /// Decrement a numeric value (e.g., slider, spinner).
1527    Decrement,
1528    /// Show a context menu.
1529    ShowContextMenu,
1530    /// Hide a tooltip.
1531    HideTooltip,
1532    /// Show a tooltip.
1533    ShowTooltip,
1534    /// Scroll up.
1535    ScrollUp,
1536    /// Scroll down.
1537    ScrollDown,
1538    /// Scroll left.
1539    ScrollLeft,
1540    /// Scroll right.
1541    ScrollRight,
1542    /// Replace selected text with new text.
1543    ReplaceSelectedText(AzString),
1544    /// Scroll to a specific point.
1545    ScrollToPoint(LogicalPosition),
1546    /// Set scroll offset.
1547    SetScrollOffset(LogicalPosition),
1548    /// Set text selection.
1549    SetTextSelection(TextSelectionStartEnd),
1550    /// Set sequential focus navigation starting point.
1551    SetSequentialFocusNavigationStartingPoint,
1552    /// Set the value of a control.
1553    SetValue(AzString),
1554    /// Set numeric value of a control.
1555    SetNumericValue(FloatValue),
1556    /// Custom action with ID.
1557    CustomAction(i32),
1558}
1559
1560#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1561#[repr(C)]
1562pub struct TextSelectionStartEnd {
1563    pub selection_start: usize,
1564    pub selection_end: usize,
1565}
1566
1567impl_vec![
1568    AccessibilityAction,
1569    AccessibilityActionVec,
1570    AccessibilityActionVecDestructor,
1571    AccessibilityActionVecDestructorType
1572];
1573impl_vec_debug!(AccessibilityAction, AccessibilityActionVec);
1574impl_vec_clone!(
1575    AccessibilityAction,
1576    AccessibilityActionVec,
1577    AccessibilityActionVecDestructor
1578);
1579impl_vec_partialeq!(AccessibilityAction, AccessibilityActionVec);
1580impl_vec_eq!(AccessibilityAction, AccessibilityActionVec);
1581impl_vec_partialord!(AccessibilityAction, AccessibilityActionVec);
1582impl_vec_ord!(AccessibilityAction, AccessibilityActionVec);
1583impl_vec_hash!(AccessibilityAction, AccessibilityActionVec);
1584
1585impl_option![
1586    AccessibilityAction,
1587    OptionAccessibilityAction,
1588    copy = false,
1589    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
1590];
1591
1592impl_option!(
1593    AccessibilityInfo,
1594    OptionAccessibilityInfo,
1595    copy = false,
1596    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
1597);
1598
1599/// Defines the element's purpose for accessibility APIs, informing assistive technologies
1600/// like screen readers about the function of a UI element. Each variant corresponds to a
1601/// standard control type or UI structure.
1602///
1603/// For more details, see the [MSDN Role Constants page](https://docs.microsoft.com/en-us/windows/winauto/object-roles).
1604#[repr(C)]
1605#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
1606pub enum AccessibilityRole {
1607    /// Represents the title or caption bar of a window.
1608    /// - **Purpose**: To identify the title bar containing the window title and system commands.
1609    /// - **When to use**: This role is typically inserted by the operating system for standard
1610    ///   windows.
1611    /// - **Example**: The bar at the top of an application window displaying its name and the
1612    ///   minimize, maximize, and close buttons.
1613    TitleBar,
1614
1615    /// Represents a menu bar at the top of a window.
1616    /// - **Purpose**: To contain a set of top-level menus for an application.
1617    /// - **When to use**: For the main menu bar of an application, such as one containing "File,"
1618    ///   "Edit," and "View."
1619    /// - **Example**: The "File", "Edit", "View" menu bar at the top of a text editor.
1620    MenuBar,
1621
1622    /// Represents a vertical or horizontal scroll bar.
1623    /// - **Purpose**: To enable scrolling through content that is larger than the visible area.
1624    /// - **When to use**: For any scrollable region of content.
1625    /// - **Example**: The bar on the side of a web page that allows the user to scroll up and
1626    ///   down.
1627    ScrollBar,
1628
1629    /// Represents a handle or grip used for moving or resizing.
1630    /// - **Purpose**: To provide a user interface element for manipulating another element's size
1631    ///   or position.
1632    /// - **When to use**: For handles that allow resizing of windows, panes, or other objects.
1633    /// - **Example**: The small textured area in the bottom-right corner of a window that can be
1634    ///   dragged to resize it.
1635    Grip,
1636
1637    /// Represents a system sound indicating an event.
1638    /// - **Purpose**: To associate a sound with a UI event, providing an auditory cue.
1639    /// - **When to use**: When a sound is the primary representation of an event.
1640    /// - **Example**: A system notification sound that plays when a new message arrives.
1641    Sound,
1642
1643    /// Represents the system's mouse pointer or other pointing device.
1644    /// - **Purpose**: To indicate the screen position of the user's pointing device.
1645    /// - **When to use**: This role is managed by the operating system.
1646    /// - **Example**: The arrow that moves on the screen as you move the mouse.
1647    Cursor,
1648
1649    /// Represents the text insertion point indicator.
1650    /// - **Purpose**: To show the current text entry or editing position.
1651    /// - **When to use**: This role is typically managed by the operating system for text input
1652    ///   fields.
1653    /// - **Example**: The blinking vertical line in a text box that shows where the next character
1654    ///   will be typed.
1655    Caret,
1656
1657    /// Represents an alert or notification.
1658    /// - **Purpose**: To convey an important, non-modal message to the user.
1659    /// - **When to use**: For non-intrusive notifications that do not require immediate user
1660    ///   interaction.
1661    /// - **Example**: A small, temporary "toast" notification that appears to confirm an action,
1662    ///   like "Email sent."
1663    Alert,
1664
1665    /// Represents a window frame.
1666    /// - **Purpose**: To serve as the container for other objects like a title bar and client
1667    ///   area.
1668    /// - **When to use**: This is a fundamental role, typically managed by the windowing system.
1669    /// - **Example**: The main window of any application, which contains all other UI elements.
1670    Window,
1671
1672    /// Represents a window's client area, where the main content is displayed.
1673    /// - **Purpose**: To define the primary content area of a window.
1674    /// - **When to use**: For the main content region of a window. It's often the default role for
1675    ///   a custom control container.
1676    /// - **Example**: The area of a web browser where the web page content is rendered.
1677    Client,
1678
1679    /// Represents a pop-up menu.
1680    /// - **Purpose**: To display a list of `MenuItem` objects that appears when a user performs an
1681    ///   action.
1682    /// - **When to use**: For context menus (right-click menus) or drop-down menus.
1683    /// - **Example**: The menu that appears when you right-click on a file in a file explorer.
1684    MenuPopup,
1685
1686    /// Represents an individual item within a menu.
1687    /// - **Purpose**: To represent a single command, option, or separator within a menu.
1688    /// - **When to use**: For individual options inside a `MenuBar` or `MenuPopup`.
1689    /// - **Example**: The "Save" option within the "File" menu.
1690    MenuItem,
1691
1692    /// Represents a small pop-up window that provides information.
1693    /// - **Purpose**: To offer brief, contextual help or information about a UI element.
1694    /// - **When to use**: For informational pop-ups that appear on mouse hover.
1695    /// - **Example**: The small box of text that appears when you hover over a button in a
1696    ///   toolbar.
1697    Tooltip,
1698
1699    /// Represents the main window of an application.
1700    /// - **Purpose**: To identify the top-level window of an application.
1701    /// - **When to use**: For the primary window that represents the application itself.
1702    /// - **Example**: The main window of a calculator or notepad application.
1703    Application,
1704
1705    /// Represents a document window within an application.
1706    /// - **Purpose**: To represent a contained document, typically in a Multiple Document
1707    ///   Interface (MDI) application.
1708    /// - **When to use**: For individual document windows inside a larger application shell.
1709    /// - **Example**: In a photo editor that allows multiple images to be open in separate
1710    ///   windows, each image window would be a `Document`.
1711    Document,
1712
1713    /// Represents a pane or a distinct section of a window.
1714    /// - **Purpose**: To divide a window into visually and functionally distinct areas.
1715    /// - **When to use**: For sub-regions of a window, like a navigation pane, preview pane, or
1716    ///   sidebar.
1717    /// - **Example**: The preview pane in an email client that shows the content of the selected
1718    ///   email.
1719    Pane,
1720
1721    /// Represents a graphical chart or graph.
1722    /// - **Purpose**: To display data visually in a chart format.
1723    /// - **When to use**: For any type of chart, such as a bar chart, line chart, or pie chart.
1724    /// - **Example**: A bar chart displaying monthly sales figures.
1725    Chart,
1726
1727    /// Represents a dialog box or message box.
1728    /// - **Purpose**: To create a secondary window that requires user interaction before returning
1729    ///   to the main application.
1730    /// - **When to use**: For modal or non-modal windows that prompt the user for information or a
1731    ///   response.
1732    /// - **Example**: The "Open File" or "Print" dialog in most applications.
1733    Dialog,
1734
1735    /// Represents a window's border.
1736    /// - **Purpose**: To identify the border of a window, which is often used for resizing.
1737    /// - **When to use**: This role is typically managed by the windowing system.
1738    /// - **Example**: The decorative and functional frame around a window.
1739    Border,
1740
1741    /// Represents a group of related controls.
1742    /// - **Purpose**: To logically group other objects that share a common purpose.
1743    /// - **When to use**: For grouping controls like a set of radio buttons or a fieldset with a
1744    ///   legend.
1745    /// - **Example**: A "Settings" group box in a dialog that contains several related checkboxes.
1746    Grouping,
1747
1748    /// Represents a visual separator.
1749    /// - **Purpose**: To visually divide a space or a group of controls.
1750    /// - **When to use**: For visual separators in menus, toolbars, or between panes.
1751    /// - **Example**: The horizontal line in a menu that separates groups of related menu items.
1752    Separator,
1753
1754    /// Represents a toolbar containing a group of controls.
1755    /// - **Purpose**: To group controls, typically buttons, for quick access to frequently used
1756    ///   functions.
1757    /// - **When to use**: For a bar of buttons or other controls, usually at the top of a window
1758    ///   or pane.
1759    /// - **Example**: The toolbar at the top of a word processor with buttons for "Bold,"
1760    ///   "Italic," and "Underline."
1761    Toolbar,
1762
1763    /// Represents a status bar for displaying information.
1764    /// - **Purpose**: To display status information about the current state of the application.
1765    /// - **When to use**: For a bar, typically at the bottom of a window, that displays messages.
1766    /// - **Example**: The bar at the bottom of a web browser that shows the loading status of a
1767    ///   page.
1768    StatusBar,
1769
1770    /// Represents a data table.
1771    /// - **Purpose**: To present data in a two-dimensional grid of rows and columns.
1772    /// - **When to use**: For grid-like data presentation.
1773    /// - **Example**: A spreadsheet or a table of data in a database application.
1774    Table,
1775
1776    /// Represents a column header in a table.
1777    /// - **Purpose**: To provide a label for a column of data.
1778    /// - **When to use**: For the headers of columns in a `Table`.
1779    /// - **Example**: The header row in a spreadsheet with labels like "Name," "Date," and
1780    ///   "Amount."
1781    ColumnHeader,
1782
1783    /// Represents a row header in a table.
1784    /// - **Purpose**: To provide a label for a row of data.
1785    /// - **When to use**: For the headers of rows in a `Table`.
1786    /// - **Example**: The numbered rows on the left side of a spreadsheet.
1787    RowHeader,
1788
1789    /// Represents a full column of cells in a table.
1790    /// - **Purpose**: To represent an entire column as a single accessible object.
1791    /// - **When to use**: When it is useful to interact with a column as a whole.
1792    /// - **Example**: The "Amount" column in a financial data table.
1793    Column,
1794
1795    /// Represents a full row of cells in a table.
1796    /// - **Purpose**: To represent an entire row as a single accessible object.
1797    /// - **When to use**: When it is useful to interact with a row as a whole.
1798    /// - **Example**: A row representing a single customer's information in a customer list.
1799    Row,
1800
1801    /// Represents a single cell within a table.
1802    /// - **Purpose**: To represent a single data point or control within a `Table`.
1803    /// - **When to use**: For individual cells in a grid or table.
1804    /// - **Example**: A single cell in a spreadsheet containing a specific value.
1805    Cell,
1806
1807    /// Represents a hyperlink to a resource.
1808    /// - **Purpose**: To provide a navigational link to another document or location.
1809    /// - **When to use**: For text or images that, when clicked, navigate to another resource.
1810    /// - **Example**: A clickable link on a web page.
1811    Link,
1812
1813    /// Represents a help balloon or pop-up.
1814    /// - **Purpose**: To provide more detailed help information than a standard tooltip.
1815    /// - **When to use**: For a pop-up that offers extended help text, often initiated by a help
1816    ///   button.
1817    /// - **Example**: A pop-up balloon with a paragraph of help text that appears when a user
1818    ///   clicks a help icon.
1819    HelpBalloon,
1820
1821    /// Represents an animated, character-like graphic object.
1822    /// - **Purpose**: To provide an animated agent for user assistance or entertainment.
1823    /// - **When to use**: For animated characters or avatars that provide help or guidance.
1824    /// - **Example**: An animated paperclip that offers tips in a word processor (e.g.,
1825    ///   Microsoft's Clippy).
1826    Character,
1827
1828    /// Represents a list of items.
1829    /// - **Purpose**: To contain a set of `ListItem` objects.
1830    /// - **When to use**: For list boxes or similar controls that present a list of selectable
1831    ///   items.
1832    /// - **Example**: The list of files in a file selection dialog.
1833    List,
1834
1835    /// Represents an individual item within a list.
1836    /// - **Purpose**: To represent a single, selectable item within a `List`.
1837    /// - **When to use**: For each individual item in a list box or combo box.
1838    /// - **Example**: A single file name in a list of files.
1839    ListItem,
1840
1841    /// Represents an outline or tree structure.
1842    /// - **Purpose**: To display a hierarchical view of data.
1843    /// - **When to use**: For tree-view controls that show nested items.
1844    /// - **Example**: A file explorer's folder tree view.
1845    Outline,
1846
1847    /// Represents an individual item within an outline or tree.
1848    /// - **Purpose**: To represent a single node (which can be a leaf or a branch) in an
1849    ///   `Outline`.
1850    /// - **When to use**: For each node in a tree view.
1851    /// - **Example**: A single folder in a file explorer's tree view.
1852    OutlineItem,
1853
1854    /// Represents a single tab in a tabbed interface.
1855    /// - **Purpose**: To provide a control for switching between different `PropertyPage` views.
1856    /// - **When to use**: For the individual tabs that the user can click to switch pages.
1857    /// - **Example**: The "General" and "Security" tabs in a file properties dialog.
1858    PageTab,
1859
1860    /// Represents the content of a page in a property sheet.
1861    /// - **Purpose**: To serve as a container for the controls displayed when a `PageTab` is
1862    ///   selected.
1863    /// - **When to use**: For the content area associated with a specific tab.
1864    /// - **Example**: The set of options displayed when the "Security" tab is active.
1865    PropertyPage,
1866
1867    /// Represents a visual indicator, like a slider thumb.
1868    /// - **Purpose**: To visually indicate the current value or position of another control.
1869    /// - **When to use**: For a sub-element that indicates status, like the thumb of a scrollbar.
1870    /// - **Example**: The draggable thumb of a scrollbar that indicates the current scroll
1871    ///   position.
1872    Indicator,
1873
1874    /// Represents a picture or graphical image.
1875    /// - **Purpose**: To display a non-interactive image.
1876    /// - **When to use**: For images and icons that are purely decorative or informational.
1877    /// - **Example**: A company logo displayed in an application's "About" dialog.
1878    Graphic,
1879
1880    /// Represents read-only text.
1881    /// - **Purpose**: To provide a non-editable text label for another control or for displaying
1882    ///   information.
1883    /// - **When to use**: For text that the user cannot edit.
1884    /// - **Example**: The label "Username:" next to a text input field.
1885    StaticText,
1886
1887    /// Represents editable text or a text area.
1888    /// - **Purpose**: To allow for user text input or selection.
1889    /// - **When to use**: For text input fields where the user can type.
1890    /// - **Example**: A text box for entering a username or password.
1891    Text,
1892
1893    /// Represents a standard push button.
1894    /// - **Purpose**: To initiate an immediate action.
1895    /// - **When to use**: For standard buttons that perform an action when clicked.
1896    /// - **Example**: An "OK" or "Cancel" button in a dialog.
1897    PushButton,
1898
1899    /// Represents a check box control.
1900    /// - **Purpose**: To allow the user to make a binary choice (checked or unchecked).
1901    /// - **When to use**: For options that can be toggled on or off independently.
1902    /// - **Example**: A "Remember me" checkbox on a login form.
1903    CheckButton,
1904
1905    /// Represents a radio button.
1906    /// - **Purpose**: To allow the user to select one option from a mutually exclusive group.
1907    /// - **When to use**: For a choice where only one option from a `Grouping` can be selected.
1908    /// - **Example**: "Male" and "Female" radio buttons for selecting gender.
1909    RadioButton,
1910
1911    /// Represents a combination of a text field and a drop-down list.
1912    /// - **Purpose**: To allow the user to either type a value or select one from a list.
1913    /// - **When to use**: For controls that offer a list of suggestions but also allow custom
1914    ///   input.
1915    /// - **Example**: A font selector that allows you to type a font name or choose one from a
1916    ///   list.
1917    ComboBox,
1918
1919    /// Represents a drop-down list box.
1920    /// - **Purpose**: To allow the user to select an item from a non-editable list that drops
1921    ///   down.
1922    /// - **When to use**: For selecting a single item from a predefined list of options.
1923    /// - **Example**: A country selection drop-down menu.
1924    DropList,
1925
1926    /// Represents a progress bar.
1927    /// - **Purpose**: To indicate the progress of a lengthy operation.
1928    /// - **When to use**: To provide feedback for tasks like file downloads or installations.
1929    /// - **Example**: The bar that fills up to show the progress of a file copy operation.
1930    ProgressBar,
1931
1932    /// Represents a dial or knob.
1933    /// - **Purpose**: To allow selecting a value from a continuous or discrete range, often
1934    ///   circularly.
1935    /// - **When to use**: For controls that resemble real-world dials, like a volume knob.
1936    /// - **Example**: A volume control knob in a media player application.
1937    Dial,
1938
1939    /// Represents a control for entering a keyboard shortcut.
1940    /// - **Purpose**: To capture a key combination from the user.
1941    /// - **When to use**: In settings where users can define their own keyboard shortcuts.
1942    /// - **Example**: A text field in a settings dialog where a user can press a key combination
1943    ///   to assign it to a command.
1944    HotkeyField,
1945
1946    /// Represents a slider for selecting a value within a range.
1947    /// - **Purpose**: To allow the user to adjust a setting along a continuous or discrete range.
1948    /// - **When to use**: For adjusting values like volume, brightness, or zoom level.
1949    /// - **Example**: A slider to control the volume of a video.
1950    Slider,
1951
1952    /// Represents a spin button (up/down arrows) for incrementing or decrementing a value.
1953    /// - **Purpose**: To provide fine-tuned adjustment of a value, typically numeric.
1954    /// - **When to use**: For controls that allow stepping through a range of values.
1955    /// - **Example**: The up and down arrows next to a number input for setting the font size.
1956    SpinButton,
1957
1958    /// Represents a diagram or flowchart.
1959    /// - **Purpose**: To represent data or relationships in a schematic form.
1960    /// - **When to use**: For visual representations of structures that are not charts, like a
1961    ///   database schema diagram.
1962    /// - **Example**: A flowchart illustrating a business process.
1963    Diagram,
1964
1965    /// Represents an animation control.
1966    /// - **Purpose**: To display a sequence of images or indicate an ongoing process.
1967    /// - **When to use**: For animations that show that an operation is in progress.
1968    /// - **Example**: The animation that plays while files are being copied.
1969    Animation,
1970
1971    /// Represents a mathematical equation.
1972    /// - **Purpose**: To display a mathematical formula in the correct format.
1973    /// - **When to use**: For displaying mathematical equations.
1974    /// - **Example**: A rendered mathematical equation in a scientific document editor.
1975    Equation,
1976
1977    /// Represents a button that drops down a list of items.
1978    /// - **Purpose**: To combine a default action button with a list of alternative actions.
1979    /// - **When to use**: For buttons that have a primary action and a secondary list of options.
1980    /// - **Example**: A "Send" button with a dropdown arrow that reveals "Send and Archive."
1981    ButtonDropdown,
1982
1983    /// Represents a button that drops down a full menu.
1984    /// - **Purpose**: To provide a button that opens a menu of choices rather than performing a
1985    ///   single action.
1986    /// - **When to use**: When a button's primary purpose is to reveal a menu.
1987    /// - **Example**: A "Tools" button that opens a menu with various tool options.
1988    ButtonMenu,
1989
1990    /// Represents a button that drops down a grid for selection.
1991    /// - **Purpose**: To allow selection from a two-dimensional grid of options.
1992    /// - **When to use**: For buttons that open a grid-based selection UI.
1993    /// - **Example**: A color picker button that opens a grid of color swatches.
1994    ButtonDropdownGrid,
1995
1996    /// Represents blank space between other objects.
1997    /// - **Purpose**: To represent significant empty areas in a UI that are part of the layout.
1998    /// - **When to use**: Sparingly, to signify that a large area is intentionally blank.
1999    /// - **Example**: A large empty panel in a complex layout might use this role.
2000    Whitespace,
2001
2002    /// Represents the container for a set of tabs.
2003    /// - **Purpose**: To group a set of `PageTab` elements.
2004    /// - **When to use**: To act as the parent container for a row or column of tabs.
2005    /// - **Example**: The entire row of tabs at the top of a properties dialog.
2006    PageTabList,
2007
2008    /// Represents a clock control.
2009    /// - **Purpose**: To display the current time.
2010    /// - **When to use**: For any UI element that displays time.
2011    /// - **Example**: The clock in the system tray of the operating system.
2012    Clock,
2013
2014    /// Represents a button with two parts: a default action and a dropdown.
2015    /// - **Purpose**: To combine a frequently used action with a set of related, less-used
2016    ///   actions.
2017    /// - **When to use**: When a button has a default action and other related actions available
2018    ///   in a dropdown.
2019    /// - **Example**: A "Save" split button where the primary part saves, and the dropdown offers
2020    ///   "Save As."
2021    SplitButton,
2022
2023    /// Represents a control for entering an IP address.
2024    /// - **Purpose**: To provide a specialized input field for IP addresses, often with formatting
2025    ///   and validation.
2026    /// - **When to use**: For dedicated IP address input fields.
2027    /// - **Example**: A network configuration dialog with a field for entering a static IP
2028    ///   address.
2029    IpAddress,
2030
2031    /// Represents an element with no specific role.
2032    /// - **Purpose**: To indicate an element that has no semantic meaning for accessibility.
2033    /// - **When to use**: Should be used sparingly for purely decorative elements that should be
2034    ///   ignored by assistive technologies.
2035    /// - **Example**: A decorative graphical flourish that has no function or information to
2036    ///   convey.
2037    Nothing,
2038
2039    /// Unknown or unspecified role.
2040    /// - **Purpose**: Default fallback when no specific role is assigned.
2041    /// - **When to use**: As a default value or when role information is unavailable.
2042    Unknown,
2043}
2044
2045impl_option!(
2046    AccessibilityRole,
2047    OptionAccessibilityRole,
2048    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
2049);
2050
2051/// Defines the current state of an element for accessibility APIs (e.g., focused, checked).
2052/// These states provide dynamic information to assistive technologies about the element's
2053/// condition.
2054///
2055/// See the [MSDN State Constants page](https://docs.microsoft.com/en-us/windows/win32/winauto/object-state-constants) for more details.
2056#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2057#[repr(C)]
2058pub enum AccessibilityState {
2059    /// The element is unavailable and cannot be interacted with.
2060    /// - **Purpose**: To indicate that a control is disabled or grayed out.
2061    /// - **When to use**: For disabled buttons, non-interactive menu items, or any control that is
2062    ///   temporarily non-functional.
2063    /// - **Example**: A "Save" button that is disabled until the user makes changes to a document.
2064    Unavailable,
2065
2066    /// The element is selected.
2067    /// - **Purpose**: To indicate that an item is currently chosen or highlighted. This is
2068    ///   distinct from having focus.
2069    /// - **When to use**: For selected items in a list, highlighted text, or the currently active
2070    ///   tab in a tab list.
2071    /// - **Example**: A file highlighted in a file explorer, or multiple selected emails in an
2072    ///   inbox.
2073    Selected,
2074
2075    /// The element has the keyboard focus.
2076    /// - **Purpose**: To identify the single element that will receive keyboard input.
2077    /// - **When to use**: For the control that is currently active and ready to be manipulated by
2078    ///   the keyboard.
2079    /// - **Example**: A text box with a blinking cursor, or a button with a dotted outline around
2080    ///   it.
2081    Focused,
2082
2083    /// The element is checked, toggled, or in a mixed state.
2084    /// - **Purpose**: To represent the state of controls like checkboxes, radio buttons, and
2085    ///   toggle buttons.
2086    /// - **When to use**: For checkboxes that are ticked, selected radio buttons, or toggle
2087    ///   buttons that are "on."
2088    /// - **Example**: A checked "I agree" checkbox, a selected "Yes" radio button, or an active
2089    ///   "Bold" button in a toolbar.
2090    Checked,
2091
2092    /// The element's content cannot be edited by the user.
2093    /// - **Purpose**: To indicate that the element's value can be viewed and copied, but not
2094    ///   modified.
2095    /// - **When to use**: For display-only text fields or documents.
2096    /// - **Example**: A text box displaying a license agreement that the user can scroll through
2097    ///   but cannot edit.
2098    Readonly,
2099
2100    /// The element is the default action in a dialog or form.
2101    /// - **Purpose**: To identify the button that will be activated if the user presses the Enter
2102    ///   key.
2103    /// - **When to use**: For the primary confirmation button in a dialog.
2104    /// - **Example**: The "OK" button in a dialog box, which often has a thicker or colored
2105    ///   border.
2106    Default,
2107
2108    /// The element is expanded, showing its child items.
2109    /// - **Purpose**: To indicate that a collapsible element is currently open and its contents
2110    ///   are visible.
2111    /// - **When to use**: For tree view nodes, combo boxes with their lists open, or expanded
2112    ///   accordion panels.
2113    /// - **Example**: A folder in a file explorer's tree view that has been clicked to show its
2114    ///   subfolders.
2115    Expanded,
2116
2117    /// The element is collapsed, hiding its child items.
2118    /// - **Purpose**: To indicate that a collapsible element is closed and its contents are
2119    ///   hidden.
2120    /// - **When to use**: The counterpart to `Expanded` for any collapsible UI element.
2121    /// - **Example**: A closed folder in a file explorer's tree view, hiding its contents.
2122    Collapsed,
2123
2124    /// The element is busy and cannot respond to user interaction.
2125    /// - **Purpose**: To indicate that the element or application is performing an operation and
2126    ///   is temporarily unresponsive.
2127    /// - **When to use**: When an application is loading, processing refany, or otherwise occupied.
2128    /// - **Example**: A window that is grayed out and shows a spinning cursor while saving a large
2129    ///   file.
2130    Busy,
2131
2132    /// The element is not currently visible on the screen.
2133    /// - **Purpose**: To indicate that an element exists but is currently scrolled out of the
2134    ///   visible area.
2135    /// - **When to use**: For items in a long list or a large document that are not within the
2136    ///   current viewport.
2137    /// - **Example**: A list item in a long dropdown that you would have to scroll down to see.
2138    Offscreen,
2139
2140    /// The element can accept keyboard focus.
2141    /// - **Purpose**: To indicate that the user can navigate to this element using the keyboard
2142    ///   (e.g., with the Tab key).
2143    /// - **When to use**: On all interactive elements like buttons, links, and input fields,
2144    ///   whether they currently have focus or not.
2145    /// - **Example**: A button that can receive focus, even if it is not the currently focused
2146    ///   element.
2147    Focusable,
2148
2149    /// The element is a container whose children can be selected.
2150    /// - **Purpose**: To indicate that the element contains items that can be chosen.
2151    /// - **When to use**: On container controls like list boxes, tree views, or text spans where
2152    ///   text can be highlighted.
2153    /// - **Example**: A list box control is `Selectable`, while its individual list items have the
2154    ///   `Selected` state when chosen.
2155    Selectable,
2156
2157    /// The element is a hyperlink.
2158    /// - **Purpose**: To identify an object that navigates to another resource or location when
2159    ///   activated.
2160    /// - **When to use**: On any object that functions as a hyperlink.
2161    /// - **Example**: Text or an image that, when clicked, opens a web page.
2162    Linked,
2163
2164    /// The element is a hyperlink that has been visited.
2165    /// - **Purpose**: To indicate that a hyperlink has already been followed by the user.
2166    /// - **When to use**: On a `Linked` object that the user has previously activated.
2167    /// - **Example**: A hyperlink on a web page that has changed color to show it has been
2168    ///   visited.
2169    Traversed,
2170
2171    /// The element allows multiple of its children to be selected at once.
2172    /// - **Purpose**: To indicate that a container control supports multi-selection.
2173    /// - **When to use**: On container controls like list boxes or file explorers that support
2174    ///   multiple selections (e.g., with Ctrl-click).
2175    /// - **Example**: A file list that allows the user to select several files at once for a copy
2176    ///   operation.
2177    Multiselectable,
2178
2179    /// The element contains protected content that should not be read aloud.
2180    /// - **Purpose**: To prevent assistive technologies from speaking the content of a sensitive
2181    ///   field.
2182    /// - **When to use**: Primarily for password input fields.
2183    /// - **Example**: A password text box where typed characters are masked with asterisks or
2184    ///   dots.
2185    Protected,
2186}
2187
2188impl_vec!(
2189    AccessibilityState,
2190    AccessibilityStateVec,
2191    AccessibilityStateVecDestructor,
2192    AccessibilityStateVecDestructorType
2193);
2194impl_vec_clone!(
2195    AccessibilityState,
2196    AccessibilityStateVec,
2197    AccessibilityStateVecDestructor
2198);
2199impl_vec_debug!(AccessibilityState, AccessibilityStateVec);
2200impl_vec_partialeq!(AccessibilityState, AccessibilityStateVec);
2201impl_vec_partialord!(AccessibilityState, AccessibilityStateVec);
2202impl_vec_eq!(AccessibilityState, AccessibilityStateVec);
2203impl_vec_ord!(AccessibilityState, AccessibilityStateVec);
2204impl_vec_hash!(AccessibilityState, AccessibilityStateVec);
2205
2206impl Clone for NodeData {
2207    #[inline]
2208    fn clone(&self) -> Self {
2209        Self {
2210            node_type: self.node_type.into_library_owned_nodetype(),
2211            dataset: match &self.dataset {
2212                OptionRefAny::None => OptionRefAny::None,
2213                OptionRefAny::Some(s) => OptionRefAny::Some(s.clone()),
2214            },
2215            ids_and_classes: self.ids_and_classes.clone(), /* do not clone the IDs and classes if
2216                                                            * they are &'static */
2217            attributes: self.attributes.clone(),
2218            css_props: self.css_props.clone(),
2219            callbacks: self.callbacks.clone(),
2220            tab_index: self.tab_index,
2221            contenteditable: self.contenteditable,
2222            extra: self.extra.clone(),
2223        }
2224    }
2225}
2226
2227// Clone, PartialEq, Eq, Hash, PartialOrd, Ord
2228impl_vec!(
2229    NodeData,
2230    NodeDataVec,
2231    NodeDataVecDestructor,
2232    NodeDataVecDestructorType
2233);
2234impl_vec_clone!(NodeData, NodeDataVec, NodeDataVecDestructor);
2235impl_vec_mut!(NodeData, NodeDataVec);
2236impl_vec_debug!(NodeData, NodeDataVec);
2237impl_vec_partialord!(NodeData, NodeDataVec);
2238impl_vec_ord!(NodeData, NodeDataVec);
2239impl_vec_partialeq!(NodeData, NodeDataVec);
2240impl_vec_eq!(NodeData, NodeDataVec);
2241impl_vec_hash!(NodeData, NodeDataVec);
2242
2243impl NodeDataVec {
2244    #[inline]
2245    pub fn as_container<'a>(&'a self) -> NodeDataContainerRef<'a, NodeData> {
2246        NodeDataContainerRef {
2247            internal: self.as_ref(),
2248        }
2249    }
2250    #[inline]
2251    pub fn as_container_mut<'a>(&'a mut self) -> NodeDataContainerRefMut<'a, NodeData> {
2252        NodeDataContainerRefMut {
2253            internal: self.as_mut(),
2254        }
2255    }
2256}
2257
2258unsafe impl Send for NodeData {}
2259
2260/// Determines the behavior of an element in sequential focus navigation
2261// (e.g., using the Tab key).
2262#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
2263#[repr(C, u8)]
2264pub enum TabIndex {
2265    /// Automatic tab index, similar to simply setting `focusable = "true"` or `tabindex = 0`
2266    /// (both have the effect of making the element focusable).
2267    ///
2268    /// Sidenote: See https://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute
2269    /// for interesting notes on tabindex and accessibility
2270    Auto,
2271    /// Set the tab index in relation to its parent element. I.e. if you have a list of elements,
2272    /// the focusing order is restricted to the current parent.
2273    ///
2274    /// When pressing tab repeatedly, the focusing order will be
2275    /// determined by OverrideInParent elements taking precedence among global order.
2276    OverrideInParent(u32),
2277    /// Elements can be focused in callbacks, but are not accessible via
2278    /// keyboard / tab navigation (-1).
2279    NoKeyboardFocus,
2280}
2281
2282impl_option!(
2283    TabIndex,
2284    OptionTabIndex,
2285    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
2286);
2287
2288impl TabIndex {
2289    /// Returns the HTML-compatible number of the `tabindex` element.
2290    pub fn get_index(&self) -> isize {
2291        use self::TabIndex::*;
2292        match self {
2293            Auto => 0,
2294            OverrideInParent(x) => *x as isize,
2295            NoKeyboardFocus => -1,
2296        }
2297    }
2298}
2299
2300impl Default for TabIndex {
2301    fn default() -> Self {
2302        TabIndex::Auto
2303    }
2304}
2305
2306impl Default for NodeData {
2307    fn default() -> Self {
2308        NodeData::create_node(NodeType::Div)
2309    }
2310}
2311
2312impl fmt::Display for NodeData {
2313    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2314        let html_type = self.node_type.get_path();
2315        let attributes_string = node_data_to_string(&self);
2316
2317        match self.node_type.format() {
2318            Some(content) => write!(
2319                f,
2320                "<{}{}>{}</{}>",
2321                html_type, attributes_string, content, html_type
2322            ),
2323            None => write!(f, "<{}{}/>", html_type, attributes_string),
2324        }
2325    }
2326}
2327
2328fn node_data_to_string(node_data: &NodeData) -> String {
2329    let mut id_string = String::new();
2330    let ids = node_data
2331        .ids_and_classes
2332        .as_ref()
2333        .iter()
2334        .filter_map(|s| s.as_id())
2335        .collect::<Vec<_>>()
2336        .join(" ");
2337
2338    if !ids.is_empty() {
2339        id_string = format!(" id=\"{}\" ", ids);
2340    }
2341
2342    let mut class_string = String::new();
2343    let classes = node_data
2344        .ids_and_classes
2345        .as_ref()
2346        .iter()
2347        .filter_map(|s| s.as_class())
2348        .collect::<Vec<_>>()
2349        .join(" ");
2350
2351    if !classes.is_empty() {
2352        class_string = format!(" class=\"{}\" ", classes);
2353    }
2354
2355    let mut tabindex_string = String::new();
2356    if let Some(tab_index) = node_data.get_tab_index() {
2357        tabindex_string = format!(" tabindex=\"{}\" ", tab_index.get_index());
2358    };
2359
2360    format!("{}{}{}", id_string, class_string, tabindex_string)
2361}
2362
2363impl NodeData {
2364    /// Creates a new `NodeData` instance from a given `NodeType`.
2365    #[inline]
2366    pub const fn create_node(node_type: NodeType) -> Self {
2367        Self {
2368            node_type,
2369            dataset: OptionRefAny::None,
2370            ids_and_classes: IdOrClassVec::from_const_slice(&[]),
2371            attributes: AttributeVec::from_const_slice(&[]),
2372            callbacks: CoreCallbackDataVec::from_const_slice(&[]),
2373            css_props: CssPropertyWithConditionsVec::from_const_slice(&[]),
2374            tab_index: OptionTabIndex::None,
2375            contenteditable: false,
2376            extra: None,
2377        }
2378    }
2379
2380    /// Shorthand for `NodeData::create_node(NodeType::Body)`.
2381    #[inline(always)]
2382    pub const fn create_body() -> Self {
2383        Self::create_node(NodeType::Body)
2384    }
2385
2386    /// Shorthand for `NodeData::create_node(NodeType::Div)`.
2387    #[inline(always)]
2388    pub const fn create_div() -> Self {
2389        Self::create_node(NodeType::Div)
2390    }
2391
2392    /// Shorthand for `NodeData::create_node(NodeType::Br)`.
2393    #[inline(always)]
2394    pub const fn create_br() -> Self {
2395        Self::create_node(NodeType::Br)
2396    }
2397
2398    /// Shorthand for `NodeData::create_node(NodeType::Text(value.into()))`.
2399    #[inline(always)]
2400    pub fn create_text<S: Into<AzString>>(value: S) -> Self {
2401        Self::create_node(NodeType::Text(value.into()))
2402    }
2403
2404    /// Shorthand for `NodeData::create_node(NodeType::Image(image_id))`.
2405    #[inline(always)]
2406    pub fn create_image(image: ImageRef) -> Self {
2407        Self::create_node(NodeType::Image(image))
2408    }
2409
2410    #[inline(always)]
2411    pub fn create_iframe(data: RefAny, callback: impl Into<IFrameCallback>) -> Self {
2412        Self::create_node(NodeType::IFrame(IFrameNode {
2413            callback: callback.into(),
2414            refany: data,
2415        }))
2416    }
2417
2418    /// Checks whether this node is of the given node type (div, image, text).
2419    #[inline]
2420    pub fn is_node_type(&self, searched_type: NodeType) -> bool {
2421        self.node_type == searched_type
2422    }
2423
2424    /// Checks whether this node has the searched ID attached.
2425    pub fn has_id(&self, id: &str) -> bool {
2426        self.ids_and_classes
2427            .iter()
2428            .any(|id_or_class| id_or_class.as_id() == Some(id))
2429    }
2430
2431    /// Checks whether this node has the searched class attached.
2432    pub fn has_class(&self, class: &str) -> bool {
2433        self.ids_and_classes
2434            .iter()
2435            .any(|id_or_class| id_or_class.as_class() == Some(class))
2436    }
2437
2438    pub fn has_context_menu(&self) -> bool {
2439        self.extra
2440            .as_ref()
2441            .map(|m| m.context_menu.is_some())
2442            .unwrap_or(false)
2443    }
2444
2445    pub fn is_text_node(&self) -> bool {
2446        match self.node_type {
2447            NodeType::Text(_) => true,
2448            _ => false,
2449        }
2450    }
2451
2452    pub fn is_iframe_node(&self) -> bool {
2453        match self.node_type {
2454            NodeType::IFrame(_) => true,
2455            _ => false,
2456        }
2457    }
2458
2459    // NOTE: Getters are used here in order to allow changing the memory allocator for the NodeData
2460    // in the future (which is why the fields are all private).
2461
2462    #[inline(always)]
2463    pub const fn get_node_type(&self) -> &NodeType {
2464        &self.node_type
2465    }
2466    #[inline(always)]
2467    pub fn get_dataset_mut(&mut self) -> &mut OptionRefAny {
2468        &mut self.dataset
2469    }
2470    #[inline(always)]
2471    pub const fn get_dataset(&self) -> &OptionRefAny {
2472        &self.dataset
2473    }
2474    #[inline(always)]
2475    pub const fn get_ids_and_classes(&self) -> &IdOrClassVec {
2476        &self.ids_and_classes
2477    }
2478    #[inline(always)]
2479    pub const fn get_callbacks(&self) -> &CoreCallbackDataVec {
2480        &self.callbacks
2481    }
2482    #[inline(always)]
2483    pub const fn get_css_props(&self) -> &CssPropertyWithConditionsVec {
2484        &self.css_props
2485    }
2486
2487    #[inline]
2488    pub fn get_clip_mask(&self) -> Option<&ImageMask> {
2489        self.extra.as_ref().and_then(|e| e.clip_mask.as_ref())
2490    }
2491    #[inline]
2492    pub fn get_tab_index(&self) -> Option<&TabIndex> {
2493        self.tab_index.as_ref()
2494    }
2495    #[inline]
2496    pub fn get_accessibility_info(&self) -> Option<&Box<AccessibilityInfo>> {
2497        self.extra.as_ref().and_then(|e| e.accessibility.as_ref())
2498    }
2499    #[inline]
2500    pub fn get_menu_bar(&self) -> Option<&Box<Menu>> {
2501        self.extra.as_ref().and_then(|e| e.menu_bar.as_ref())
2502    }
2503    #[inline]
2504    pub fn get_context_menu(&self) -> Option<&Box<Menu>> {
2505        self.extra.as_ref().and_then(|e| e.context_menu.as_ref())
2506    }
2507
2508    /// Returns whether this node is an anonymous box generated for table layout.
2509    #[inline]
2510    pub fn is_anonymous(&self) -> bool {
2511        self.extra.as_ref().map(|e| e.is_anonymous).unwrap_or(false)
2512    }
2513
2514    #[inline(always)]
2515    pub fn set_node_type(&mut self, node_type: NodeType) {
2516        self.node_type = node_type;
2517    }
2518    #[inline(always)]
2519    pub fn set_dataset(&mut self, data: OptionRefAny) {
2520        self.dataset = data;
2521    }
2522    #[inline(always)]
2523    pub fn set_ids_and_classes(&mut self, ids_and_classes: IdOrClassVec) {
2524        self.ids_and_classes = ids_and_classes;
2525    }
2526    #[inline(always)]
2527    pub fn set_callbacks(&mut self, callbacks: CoreCallbackDataVec) {
2528        self.callbacks = callbacks;
2529    }
2530    #[inline(always)]
2531    pub fn set_css_props(&mut self, css_props: CssPropertyWithConditionsVec) {
2532        self.css_props = css_props;
2533    }
2534    #[inline]
2535    pub fn set_clip_mask(&mut self, clip_mask: ImageMask) {
2536        self.extra
2537            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
2538            .clip_mask = Some(clip_mask);
2539    }
2540    #[inline]
2541    pub fn set_tab_index(&mut self, tab_index: TabIndex) {
2542        self.tab_index = Some(tab_index).into();
2543    }
2544    #[inline]
2545    pub fn set_contenteditable(&mut self, contenteditable: bool) {
2546        self.contenteditable = contenteditable;
2547    }
2548    #[inline]
2549    pub fn is_contenteditable(&self) -> bool {
2550        self.contenteditable
2551    }
2552    #[inline]
2553    pub fn set_accessibility_info(&mut self, accessibility_info: AccessibilityInfo) {
2554        self.extra
2555            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
2556            .accessibility = Some(Box::new(accessibility_info));
2557    }
2558
2559    /// Marks this node as an anonymous box (generated for table layout).
2560    #[inline]
2561    pub fn set_anonymous(&mut self, is_anonymous: bool) {
2562        self.extra
2563            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
2564            .is_anonymous = is_anonymous;
2565    }
2566    #[inline]
2567    pub fn set_menu_bar(&mut self, menu_bar: Menu) {
2568        self.extra
2569            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
2570            .menu_bar = Some(Box::new(menu_bar));
2571    }
2572    #[inline]
2573    pub fn set_context_menu(&mut self, context_menu: Menu) {
2574        self.extra
2575            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
2576            .context_menu = Some(Box::new(context_menu));
2577    }
2578
2579    /// Sets a stable key for this node used in reconciliation.
2580    ///
2581    /// This key is used to track node identity across DOM updates, enabling
2582    /// the framework to distinguish between "moving" a node and "destroying/creating" one.
2583    /// This is crucial for correct lifecycle events when lists are reordered.
2584    ///
2585    /// # Example
2586    /// ```rust
2587    /// node_data.set_key("user-123");
2588    /// ```
2589    #[inline]
2590    pub fn set_key<K: core::hash::Hash>(&mut self, key: K) {
2591        use highway::{HighwayHash, HighwayHasher, Key};
2592        let mut hasher = HighwayHasher::new(Key([0; 4]));
2593        key.hash(&mut hasher);
2594        self.extra
2595            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
2596            .key = Some(hasher.finalize64());
2597    }
2598
2599    /// Gets the key for this node, if set.
2600    #[inline]
2601    pub fn get_key(&self) -> Option<u64> {
2602        self.extra.as_ref().and_then(|ext| ext.key)
2603    }
2604
2605    /// Sets a dataset merge callback for this node.
2606    ///
2607    /// The merge callback is invoked during reconciliation when a node from the
2608    /// previous frame is matched with a node in the new frame. It allows heavy
2609    /// resources (video decoders, GL textures, network connections) to be
2610    /// transferred from the old node to the new node instead of being destroyed.
2611    ///
2612    /// # Type Safety
2613    ///
2614    /// The callback stores the `TypeId` of `T`. During execution, both the old
2615    /// and new datasets must match this type, otherwise the merge is skipped.
2616    ///
2617    /// # Example
2618    /// ```rust
2619    /// struct VideoPlayer {
2620    ///     url: String,
2621    ///     decoder: Option<DecoderHandle>,
2622    /// }
2623    /// 
2624    /// extern "C" fn merge_video(new_data: RefAny, old_data: RefAny) -> RefAny {
2625    ///     // Transfer the heavy decoder handle from old to new
2626    ///     if let (Some(mut new), Some(old)) = (
2627    ///         new_data.downcast_mut::<VideoPlayer>(),
2628    ///         old_data.downcast_ref::<VideoPlayer>()
2629    ///     ) {
2630    ///         new.decoder = old.decoder.take();
2631    ///     }
2632    ///     new_data
2633    /// }
2634    /// 
2635    /// node_data.set_merge_callback(merge_video);
2636    /// ```
2637    #[inline]
2638    pub fn set_merge_callback<C: Into<DatasetMergeCallback>>(&mut self, callback: C) {
2639        self.extra
2640            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
2641            .dataset_merge_callback = Some(callback.into());
2642    }
2643
2644    /// Gets the merge callback for this node, if set.
2645    #[inline]
2646    pub fn get_merge_callback(&self) -> Option<DatasetMergeCallback> {
2647        self.extra.as_ref().and_then(|ext| ext.dataset_merge_callback.clone())
2648    }
2649
2650    #[inline]
2651    pub fn with_menu_bar(mut self, menu_bar: Menu) -> Self {
2652        self.set_menu_bar(menu_bar);
2653        self
2654    }
2655
2656    #[inline]
2657    pub fn with_context_menu(mut self, context_menu: Menu) -> Self {
2658        self.set_context_menu(context_menu);
2659        self
2660    }
2661
2662    #[inline]
2663    pub fn add_callback<C: Into<CoreCallback>>(
2664        &mut self,
2665        event: EventFilter,
2666        data: RefAny,
2667        callback: C,
2668    ) {
2669        let callback = callback.into();
2670        let mut v: CoreCallbackDataVec = Vec::new().into();
2671        mem::swap(&mut v, &mut self.callbacks);
2672        let mut v = v.into_library_owned_vec();
2673        v.push(CoreCallbackData {
2674            event,
2675            refany: data,
2676            callback,
2677        });
2678        self.callbacks = v.into();
2679    }
2680
2681    #[inline]
2682    pub fn add_id(&mut self, s: AzString) {
2683        let mut v: IdOrClassVec = Vec::new().into();
2684        mem::swap(&mut v, &mut self.ids_and_classes);
2685        let mut v = v.into_library_owned_vec();
2686        v.push(IdOrClass::Id(s));
2687        self.ids_and_classes = v.into();
2688    }
2689    #[inline]
2690    pub fn add_class(&mut self, s: AzString) {
2691        let mut v: IdOrClassVec = Vec::new().into();
2692        mem::swap(&mut v, &mut self.ids_and_classes);
2693        let mut v = v.into_library_owned_vec();
2694        v.push(IdOrClass::Class(s));
2695        self.ids_and_classes = v.into();
2696    }
2697
2698    /// Add an unconditional CSS property (always applies)
2699    #[inline]
2700    pub fn add_css_property(&mut self, p: CssProperty) {
2701        use azul_css::dynamic_selector::CssPropertyWithConditions;
2702        let mut v: CssPropertyWithConditionsVec = Vec::new().into();
2703        mem::swap(&mut v, &mut self.css_props);
2704        let mut v = v.into_library_owned_vec();
2705        v.push(CssPropertyWithConditions::simple(p));
2706        self.css_props = v.into();
2707    }
2708
2709    /// Add a CSS property that applies only on hover
2710    #[inline]
2711    pub fn add_hover_css_property(&mut self, p: CssProperty) {
2712        use azul_css::dynamic_selector::{
2713            CssPropertyWithConditions, DynamicSelector, PseudoStateType,
2714        };
2715        let mut v: CssPropertyWithConditionsVec = Vec::new().into();
2716        mem::swap(&mut v, &mut self.css_props);
2717        let mut v = v.into_library_owned_vec();
2718        v.push(CssPropertyWithConditions::with_condition(
2719            p,
2720            DynamicSelector::PseudoState(PseudoStateType::Hover),
2721        ));
2722        self.css_props = v.into();
2723    }
2724
2725    /// Add a CSS property that applies only when active (clicked)
2726    #[inline]
2727    pub fn add_active_css_property(&mut self, p: CssProperty) {
2728        use azul_css::dynamic_selector::{
2729            CssPropertyWithConditions, DynamicSelector, PseudoStateType,
2730        };
2731        let mut v: CssPropertyWithConditionsVec = Vec::new().into();
2732        mem::swap(&mut v, &mut self.css_props);
2733        let mut v = v.into_library_owned_vec();
2734        v.push(CssPropertyWithConditions::with_condition(
2735            p,
2736            DynamicSelector::PseudoState(PseudoStateType::Active),
2737        ));
2738        self.css_props = v.into();
2739    }
2740
2741    /// Add a CSS property that applies only when focused
2742    #[inline]
2743    pub fn add_focus_css_property(&mut self, p: CssProperty) {
2744        use azul_css::dynamic_selector::{
2745            CssPropertyWithConditions, DynamicSelector, PseudoStateType,
2746        };
2747        let mut v: CssPropertyWithConditionsVec = Vec::new().into();
2748        mem::swap(&mut v, &mut self.css_props);
2749        let mut v = v.into_library_owned_vec();
2750        v.push(CssPropertyWithConditions::with_condition(
2751            p,
2752            DynamicSelector::PseudoState(PseudoStateType::Focus),
2753        ));
2754        self.css_props = v.into();
2755    }
2756
2757    /// Calculates a deterministic node hash for this node.
2758    pub fn calculate_node_data_hash(&self) -> DomNodeHash {
2759        use highway::{HighwayHash, HighwayHasher, Key};
2760        let mut hasher = HighwayHasher::new(Key([0; 4]));
2761        self.hash(&mut hasher);
2762        let h = hasher.finalize64();
2763        DomNodeHash { inner: h }
2764    }
2765
2766    /// Calculates a structural hash for DOM reconciliation that ignores text content.
2767    /// 
2768    /// This hash is used for matching nodes across DOM frames where the text content
2769    /// may have changed (e.g., contenteditable text being edited). It hashes:
2770    /// - Node type discriminant (but NOT the text content for Text nodes)
2771    /// - IDs and classes
2772    /// - Attributes (but NOT contenteditable state which may change with focus)
2773    /// - Callback events and types
2774    /// 
2775    /// This allows a Text("Hello") node to match Text("Hello World") during reconciliation,
2776    /// preserving cursor position and selection state.
2777    pub fn calculate_structural_hash(&self) -> DomNodeHash {
2778        use highway::{HighwayHash, HighwayHasher, Key};
2779        use core::hash::Hasher as StdHasher;
2780        
2781        let mut hasher = HighwayHasher::new(Key([0; 4]));
2782        
2783        // Hash node type discriminant only, not content
2784        // This means Text("A") and Text("B") have the same structural hash
2785        core::mem::discriminant(&self.node_type).hash(&mut hasher);
2786        
2787        // For IFrame nodes, hash the callback to distinguish different iframes
2788        if let NodeType::IFrame(ref iframe) = self.node_type {
2789            // Hash iframe callback (it implements Hash)
2790            iframe.hash(&mut hasher);
2791        }
2792        
2793        // For Image nodes, hash the image reference to distinguish different images
2794        if let NodeType::Image(ref img_ref) = self.node_type {
2795            img_ref.hash(&mut hasher);
2796        }
2797        
2798        // Hash IDs and classes - these are structural and shouldn't change
2799        self.ids_and_classes.as_ref().hash(&mut hasher);
2800        
2801        // Hash attributes - but skip contenteditable since that might change
2802        for attr in self.attributes.as_ref().iter() {
2803            // Skip ContentEditable attribute - it's state, not structure
2804            if !matches!(attr, AttributeType::ContentEditable(_)) {
2805                attr.hash(&mut hasher);
2806            }
2807        }
2808        
2809        // Hash callback events (not the actual callback function pointers)
2810        for callback in self.callbacks.as_ref().iter() {
2811            callback.event.hash(&mut hasher);
2812        }
2813        
2814        let h = hasher.finalize64();
2815        DomNodeHash { inner: h }
2816    }
2817
2818    #[inline(always)]
2819    pub fn with_tab_index(mut self, tab_index: TabIndex) -> Self {
2820        self.set_tab_index(tab_index);
2821        self
2822    }
2823    #[inline(always)]
2824    pub fn with_contenteditable(mut self, contenteditable: bool) -> Self {
2825        self.set_contenteditable(contenteditable);
2826        self
2827    }
2828    #[inline(always)]
2829    pub fn with_node_type(mut self, node_type: NodeType) -> Self {
2830        self.set_node_type(node_type);
2831        self
2832    }
2833    #[inline(always)]
2834    pub fn with_callback<C: Into<CoreCallback>>(
2835        mut self,
2836        event: EventFilter,
2837        data: RefAny,
2838        callback: C,
2839    ) -> Self {
2840        self.add_callback(event, data, callback);
2841        self
2842    }
2843    #[inline(always)]
2844    pub fn with_dataset(mut self, data: OptionRefAny) -> Self {
2845        self.dataset = data;
2846        self
2847    }
2848    #[inline(always)]
2849    pub fn with_ids_and_classes(mut self, ids_and_classes: IdOrClassVec) -> Self {
2850        self.ids_and_classes = ids_and_classes;
2851        self
2852    }
2853    #[inline(always)]
2854    pub fn with_callbacks(mut self, callbacks: CoreCallbackDataVec) -> Self {
2855        self.callbacks = callbacks;
2856        self
2857    }
2858    #[inline(always)]
2859    pub fn with_css_props(mut self, css_props: CssPropertyWithConditionsVec) -> Self {
2860        self.css_props = css_props;
2861        self
2862    }
2863
2864    /// Assigns a stable key to this node for reconciliation.
2865    ///
2866    /// This is crucial for performance and correct state preservation when
2867    /// lists of items change order or items are inserted/removed. Without keys,
2868    /// the reconciliation algorithm falls back to hash-based matching.
2869    ///
2870    /// # Example
2871    /// ```rust
2872    /// NodeData::create_div()
2873    ///     .with_key("user-avatar-123")
2874    /// ```
2875    #[inline]
2876    pub fn with_key<K: core::hash::Hash>(mut self, key: K) -> Self {
2877        self.set_key(key);
2878        self
2879    }
2880
2881    /// Registers a callback to merge dataset state from the previous frame.
2882    ///
2883    /// This is used for components that maintain heavy internal state (video players,
2884    /// WebGL contexts, network connections) that should not be destroyed and recreated
2885    /// on every render frame.
2886    ///
2887    /// The callback receives both datasets as `RefAny` (cheap shallow clones) and
2888    /// returns the `RefAny` that should be used for the new node.
2889    ///
2890    /// # Example
2891    /// ```rust
2892    /// struct VideoPlayer {
2893    ///     url: String,
2894    ///     decoder_handle: Option<DecoderHandle>,
2895    /// }
2896    ///
2897    /// extern "C" fn merge_video(new_data: RefAny, old_data: RefAny) -> RefAny {
2898    ///     if let (Some(mut new), Some(old)) = (
2899    ///         new_data.downcast_mut::<VideoPlayer>(),
2900    ///         old_data.downcast_ref::<VideoPlayer>()
2901    ///     ) {
2902    ///         new.decoder_handle = old.decoder_handle.take();
2903    ///     }
2904    ///     new_data
2905    /// }
2906    ///
2907    /// NodeData::create_div()
2908    ///     .with_dataset(RefAny::new(VideoPlayer::new("movie.mp4")).into())
2909    ///     .with_merge_callback(merge_video)
2910    /// ```
2911    #[inline]
2912    pub fn with_merge_callback<C: Into<DatasetMergeCallback>>(mut self, callback: C) -> Self {
2913        self.set_merge_callback(callback);
2914        self
2915    }
2916
2917    /// Parse CSS from a string and add as unconditional properties
2918    pub fn set_inline_style(&mut self, style: &str) {
2919        use azul_css::dynamic_selector::CssPropertyWithConditions;
2920        let parsed = CssPropertyWithConditionsVec::parse_normal(style);
2921        let mut current = Vec::new().into();
2922        mem::swap(&mut current, &mut self.css_props);
2923        let mut v = current.into_library_owned_vec();
2924        v.extend(parsed.into_library_owned_vec());
2925        self.css_props = v.into();
2926    }
2927
2928    /// Builder method for setting inline CSS styles for the normal state
2929    pub fn with_inline_style(mut self, style: &str) -> Self {
2930        self.set_inline_style(style);
2931        self
2932    }
2933
2934    /// Sets inline CSS styles for the hover state, parsing from a CSS string
2935    pub fn set_inline_hover_style(&mut self, style: &str) {
2936        let parsed = CssPropertyWithConditionsVec::parse_hover(style);
2937        let mut current = Vec::new().into();
2938        mem::swap(&mut current, &mut self.css_props);
2939        let mut v = current.into_library_owned_vec();
2940        v.extend(parsed.into_library_owned_vec());
2941        self.css_props = v.into();
2942    }
2943
2944    /// Builder method for setting inline CSS styles for the hover state
2945    pub fn with_inline_hover_style(mut self, style: &str) -> Self {
2946        self.set_inline_hover_style(style);
2947        self
2948    }
2949
2950    /// Sets inline CSS styles for the active state, parsing from a CSS string
2951    pub fn set_inline_active_style(&mut self, style: &str) {
2952        let parsed = CssPropertyWithConditionsVec::parse_active(style);
2953        let mut current = Vec::new().into();
2954        mem::swap(&mut current, &mut self.css_props);
2955        let mut v = current.into_library_owned_vec();
2956        v.extend(parsed.into_library_owned_vec());
2957        self.css_props = v.into();
2958    }
2959
2960    /// Builder method for setting inline CSS styles for the active state
2961    pub fn with_inline_active_style(mut self, style: &str) -> Self {
2962        self.set_inline_active_style(style);
2963        self
2964    }
2965
2966    /// Sets inline CSS styles for the focus state, parsing from a CSS string
2967    pub fn set_inline_focus_style(&mut self, style: &str) {
2968        let parsed = CssPropertyWithConditionsVec::parse_focus(style);
2969        let mut current = Vec::new().into();
2970        mem::swap(&mut current, &mut self.css_props);
2971        let mut v = current.into_library_owned_vec();
2972        v.extend(parsed.into_library_owned_vec());
2973        self.css_props = v.into();
2974    }
2975
2976    /// Builder method for setting inline CSS styles for the focus state
2977    pub fn with_inline_focus_style(mut self, style: &str) -> Self {
2978        self.set_inline_focus_style(style);
2979        self
2980    }
2981
2982    #[inline(always)]
2983    pub fn swap_with_default(&mut self) -> Self {
2984        let mut s = NodeData::create_div();
2985        mem::swap(&mut s, self);
2986        s
2987    }
2988
2989    #[inline]
2990    pub fn copy_special(&self) -> Self {
2991        Self {
2992            node_type: self.node_type.into_library_owned_nodetype(),
2993            dataset: match &self.dataset {
2994                OptionRefAny::None => OptionRefAny::None,
2995                OptionRefAny::Some(s) => OptionRefAny::Some(s.clone()),
2996            },
2997            ids_and_classes: self.ids_and_classes.clone(), /* do not clone the IDs and classes if
2998                                                            * they are &'static */
2999            attributes: self.attributes.clone(),
3000            css_props: self.css_props.clone(),
3001            callbacks: self.callbacks.clone(),
3002            tab_index: self.tab_index,
3003            contenteditable: self.contenteditable,
3004            extra: self.extra.clone(),
3005        }
3006    }
3007
3008    pub fn is_focusable(&self) -> bool {
3009        // TODO: do some better analysis of next / first / item
3010        self.get_tab_index().is_some()
3011            || self
3012                .get_callbacks()
3013                .iter()
3014                .any(|cb| cb.event.is_focus_callback())
3015    }
3016
3017    /// Returns true if this element has "activation behavior" per HTML5 spec.
3018    ///
3019    /// Elements with activation behavior can be activated via Enter or Space key
3020    /// when focused, which generates a synthetic click event.
3021    ///
3022    /// Per HTML5 spec, elements with activation behavior include:
3023    /// - Button elements
3024    /// - Input elements (submit, button, reset, checkbox, radio)
3025    /// - Anchor elements with href
3026    /// - Any element with a click callback (implicit activation)
3027    ///
3028    /// See: https://html.spec.whatwg.org/multipage/interaction.html#activation-behavior
3029    pub fn has_activation_behavior(&self) -> bool {
3030        use crate::events::{EventFilter, HoverEventFilter};
3031        
3032        // Check for click callback (most common case for Azul)
3033        // In Azul, "click" is typically LeftMouseUp
3034        let has_click_callback = self
3035            .get_callbacks()
3036            .iter()
3037            .any(|cb| matches!(
3038                cb.event, 
3039                EventFilter::Hover(HoverEventFilter::MouseUp) 
3040                | EventFilter::Hover(HoverEventFilter::LeftMouseUp)
3041            ));
3042
3043        if has_click_callback {
3044            return true;
3045        }
3046
3047        // Check accessibility role for button-like elements
3048        if let Some(ref ext) = self.extra {
3049            if let Some(ref accessibility) = ext.accessibility {
3050                use crate::dom::AccessibilityRole;
3051                match accessibility.role {
3052                    AccessibilityRole::PushButton  // Button
3053                    | AccessibilityRole::Link
3054                    | AccessibilityRole::CheckButton  // Checkbox
3055                    | AccessibilityRole::RadioButton  // Radio
3056                    | AccessibilityRole::MenuItem
3057                    | AccessibilityRole::PageTab  // Tab
3058                    => return true,
3059                    _ => {}
3060                }
3061            }
3062        }
3063
3064        false
3065    }
3066
3067    /// Returns true if this element is currently activatable.
3068    ///
3069    /// An element is activatable if it has activation behavior AND is not disabled.
3070    /// This checks for common disability patterns (aria-disabled, disabled attribute).
3071    pub fn is_activatable(&self) -> bool {
3072        if !self.has_activation_behavior() {
3073            return false;
3074        }
3075
3076        // Check for disabled state in accessibility info
3077        if let Some(ref ext) = self.extra {
3078            if let Some(ref accessibility) = ext.accessibility {
3079                // Check if explicitly marked as unavailable
3080                if accessibility
3081                    .states
3082                    .as_ref()
3083                    .iter()
3084                    .any(|s| matches!(s, AccessibilityState::Unavailable))
3085                {
3086                    return false;
3087                }
3088            }
3089        }
3090
3091        // Not disabled, so activatable
3092        true
3093    }
3094
3095    /// Returns the tab index for this element.
3096    ///
3097    /// Tab index determines keyboard navigation order:
3098    /// - `None`: Not in tab order (unless naturally focusable)
3099    /// - `Some(-1)`: Focusable programmatically but not via Tab
3100    /// - `Some(0)`: In natural tab order
3101    /// - `Some(n > 0)`: In tab order with priority n (higher = later)
3102    pub fn get_effective_tabindex(&self) -> Option<i32> {
3103        match self.tab_index {
3104            OptionTabIndex::None => {
3105                // Check if naturally focusable (has focus callback)
3106                if self.get_callbacks().iter().any(|cb| cb.event.is_focus_callback()) {
3107                    Some(0)
3108                } else {
3109                    None
3110                }
3111            }
3112            OptionTabIndex::Some(tab_idx) => {
3113                match tab_idx {
3114                    TabIndex::Auto => Some(0),
3115                    TabIndex::OverrideInParent(n) => Some(n as i32),
3116                    TabIndex::NoKeyboardFocus => Some(-1),
3117                }
3118            }
3119        }
3120    }
3121
3122    pub fn get_iframe_node(&mut self) -> Option<&mut IFrameNode> {
3123        match &mut self.node_type {
3124            NodeType::IFrame(i) => Some(i),
3125            _ => None,
3126        }
3127    }
3128
3129    pub fn get_render_image_callback_node<'a>(
3130        &'a mut self,
3131    ) -> Option<(&'a mut CoreImageCallback, ImageRefHash)> {
3132        match &mut self.node_type {
3133            NodeType::Image(img) => {
3134                let hash = image_ref_get_hash(&img);
3135                img.get_image_callback_mut().map(|r| (r, hash))
3136            }
3137            _ => None,
3138        }
3139    }
3140
3141    pub fn debug_print_start(
3142        &self,
3143        css_cache: &CssPropertyCache,
3144        node_id: &NodeId,
3145        node_state: &StyledNodeState,
3146    ) -> String {
3147        let html_type = self.node_type.get_path();
3148        let attributes_string = node_data_to_string(&self);
3149        let style = css_cache.get_computed_css_style_string(&self, node_id, node_state);
3150        format!(
3151            "<{} data-az-node-id=\"{}\" {} {style}>",
3152            html_type,
3153            node_id.index(),
3154            attributes_string,
3155            style = if style.trim().is_empty() {
3156                String::new()
3157            } else {
3158                format!("style=\"{style}\"")
3159            }
3160        )
3161    }
3162
3163    pub fn debug_print_end(&self) -> String {
3164        let html_type = self.node_type.get_path();
3165        format!("</{}>", html_type)
3166    }
3167}
3168
3169/// A unique, runtime-generated identifier for a single `Dom` instance.
3170#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
3171#[repr(C)]
3172pub struct DomId {
3173    pub inner: usize,
3174}
3175
3176impl fmt::Display for DomId {
3177    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3178        write!(f, "{}", self.inner)
3179    }
3180}
3181
3182impl DomId {
3183    pub const ROOT_ID: DomId = DomId { inner: 0 };
3184}
3185
3186impl Default for DomId {
3187    fn default() -> DomId {
3188        DomId::ROOT_ID
3189    }
3190}
3191
3192impl_option!(
3193    DomId,
3194    OptionDomId,
3195    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
3196);
3197
3198impl_vec!(DomId, DomIdVec, DomIdVecDestructor, DomIdVecDestructorType);
3199impl_vec_debug!(DomId, DomIdVec);
3200impl_vec_clone!(DomId, DomIdVec, DomIdVecDestructor);
3201impl_vec_partialeq!(DomId, DomIdVec);
3202impl_vec_partialord!(DomId, DomIdVec);
3203
3204/// A UUID for a DOM node within a `LayoutWindow`.
3205#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3206#[repr(C)]
3207pub struct DomNodeId {
3208    /// The ID of the `Dom` this node belongs to.
3209    pub dom: DomId,
3210    /// The hierarchical ID of the node within its `Dom`.
3211    pub node: NodeHierarchyItemId,
3212}
3213
3214impl_option!(
3215    DomNodeId,
3216    OptionDomNodeId,
3217    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
3218);
3219
3220impl DomNodeId {
3221    pub const ROOT: DomNodeId = DomNodeId {
3222        dom: DomId::ROOT_ID,
3223        node: NodeHierarchyItemId::NONE,
3224    };
3225}
3226
3227/// The document model, similar to HTML. This is a create-only structure, you don't actually read
3228/// anything back from it. It's designed for ease of construction.
3229#[repr(C)]
3230#[derive(PartialEq, Clone, Eq, Hash, PartialOrd, Ord)]
3231pub struct Dom {
3232    /// The data for the root node of this DOM (or sub-DOM).
3233    pub root: NodeData,
3234    /// The children of this DOM node.
3235    pub children: DomVec,
3236    // Tracks the number of sub-children of the current children, so that
3237    // the `Dom` can be converted into a `CompactDom`.
3238    pub estimated_total_children: usize,
3239}
3240
3241impl_option!(
3242    Dom,
3243    OptionDom,
3244    copy = false,
3245    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
3246);
3247
3248impl_vec!(Dom, DomVec, DomVecDestructor, DomVecDestructorType);
3249impl_vec_clone!(Dom, DomVec, DomVecDestructor);
3250impl_vec_mut!(Dom, DomVec);
3251impl_vec_debug!(Dom, DomVec);
3252impl_vec_partialord!(Dom, DomVec);
3253impl_vec_ord!(Dom, DomVec);
3254impl_vec_partialeq!(Dom, DomVec);
3255impl_vec_eq!(Dom, DomVec);
3256impl_vec_hash!(Dom, DomVec);
3257
3258impl Dom {
3259    // ----- DOM CONSTRUCTORS
3260
3261    /// Creates an empty DOM with a give `NodeType`. Note: This is a `const fn` and
3262    /// doesn't allocate, it only allocates once you add at least one child node.
3263    #[inline(always)]
3264    pub fn create_node(node_type: NodeType) -> Self {
3265        Self {
3266            root: NodeData::create_node(node_type),
3267            children: Vec::new().into(),
3268            estimated_total_children: 0,
3269        }
3270    }
3271    #[inline(always)]
3272    pub fn from_data(node_data: NodeData) -> Self {
3273        Self {
3274            root: node_data,
3275            children: Vec::new().into(),
3276            estimated_total_children: 0,
3277        }
3278    }
3279
3280    // Document Structure Elements
3281
3282    /// Creates the root HTML element.
3283    ///
3284    /// **Accessibility**: The `<html>` element is the root of an HTML document and should have a
3285    /// `lang` attribute.
3286    #[inline(always)]
3287    pub const fn create_html() -> Self {
3288        Self {
3289            root: NodeData::create_node(NodeType::Html),
3290            children: DomVec::from_const_slice(&[]),
3291            estimated_total_children: 0,
3292        }
3293    }
3294
3295    /// Creates the document head element.
3296    ///
3297    /// **Accessibility**: The `<head>` contains metadata. Use `<title>` for page titles.
3298    #[inline(always)]
3299    pub const fn create_head() -> Self {
3300        Self {
3301            root: NodeData::create_node(NodeType::Head),
3302            children: DomVec::from_const_slice(&[]),
3303            estimated_total_children: 0,
3304        }
3305    }
3306
3307    #[inline(always)]
3308    pub const fn create_body() -> Self {
3309        Self {
3310            root: NodeData::create_node(NodeType::Body),
3311            children: DomVec::from_const_slice(&[]),
3312            estimated_total_children: 0,
3313        }
3314    }
3315
3316    /// Creates a generic block-level container.
3317    ///
3318    /// **Accessibility**: Prefer semantic elements like `<article>`, `<section>`, `<nav>` when
3319    /// applicable.
3320    #[inline(always)]
3321    pub const fn create_div() -> Self {
3322        Self {
3323            root: NodeData::create_node(NodeType::Div),
3324            children: DomVec::from_const_slice(&[]),
3325            estimated_total_children: 0,
3326        }
3327    }
3328
3329    // Semantic Structure Elements
3330
3331    /// Creates an article element.
3332    ///
3333    /// **Accessibility**: Represents self-contained content that could be distributed
3334    /// independently. Screen readers can navigate by articles. Consider adding aria-label for
3335    /// multiple articles.
3336    #[inline(always)]
3337    pub const fn create_article() -> Self {
3338        Self {
3339            root: NodeData::create_node(NodeType::Article),
3340            children: DomVec::from_const_slice(&[]),
3341            estimated_total_children: 0,
3342        }
3343    }
3344
3345    /// Creates a section element.
3346    ///
3347    /// **Accessibility**: Represents a thematic grouping of content with a heading.
3348    /// Should typically have a heading (h1-h6) as a child. Consider aria-labelledby.
3349    #[inline(always)]
3350    pub const fn create_section() -> Self {
3351        Self {
3352            root: NodeData::create_node(NodeType::Section),
3353            children: DomVec::from_const_slice(&[]),
3354            estimated_total_children: 0,
3355        }
3356    }
3357
3358    /// Creates a navigation element.
3359    ///
3360    /// **Accessibility**: Represents navigation links. Screen readers can jump to navigation.
3361    /// Use aria-label to distinguish multiple nav elements (e.g., "Main navigation", "Footer
3362    /// links").
3363    #[inline(always)]
3364    pub const fn create_nav() -> Self {
3365        Self {
3366            root: NodeData::create_node(NodeType::Nav),
3367            children: DomVec::from_const_slice(&[]),
3368            estimated_total_children: 0,
3369        }
3370    }
3371
3372    /// Creates an aside element.
3373    ///
3374    /// **Accessibility**: Represents content tangentially related to main content (sidebars,
3375    /// callouts). Screen readers announce this as complementary content.
3376    #[inline(always)]
3377    pub const fn create_aside() -> Self {
3378        Self {
3379            root: NodeData::create_node(NodeType::Aside),
3380            children: DomVec::from_const_slice(&[]),
3381            estimated_total_children: 0,
3382        }
3383    }
3384
3385    /// Creates a header element.
3386    ///
3387    /// **Accessibility**: Represents introductory content or navigational aids.
3388    /// Can be used for page headers or section headers.
3389    #[inline(always)]
3390    pub const fn create_header() -> Self {
3391        Self {
3392            root: NodeData::create_node(NodeType::Header),
3393            children: DomVec::from_const_slice(&[]),
3394            estimated_total_children: 0,
3395        }
3396    }
3397
3398    /// Creates a footer element.
3399    ///
3400    /// **Accessibility**: Represents footer for nearest section or page.
3401    /// Typically contains copyright, author info, or related links.
3402    #[inline(always)]
3403    pub const fn create_footer() -> Self {
3404        Self {
3405            root: NodeData::create_node(NodeType::Footer),
3406            children: DomVec::from_const_slice(&[]),
3407            estimated_total_children: 0,
3408        }
3409    }
3410
3411    /// Creates a main content element.
3412    ///
3413    /// **Accessibility**: Represents the dominant content. There should be only ONE main per page.
3414    /// Screen readers can jump directly to main content. Do not nest inside
3415    /// article/aside/footer/header/nav.
3416    #[inline(always)]
3417    pub const fn create_main() -> Self {
3418        Self {
3419            root: NodeData::create_node(NodeType::Main),
3420            children: DomVec::from_const_slice(&[]),
3421            estimated_total_children: 0,
3422        }
3423    }
3424
3425    /// Creates a figure element.
3426    ///
3427    /// **Accessibility**: Represents self-contained content like diagrams, photos, code listings.
3428    /// Use with `<figcaption>` to provide a caption. Screen readers associate caption with figure.
3429    #[inline(always)]
3430    pub const fn create_figure() -> Self {
3431        Self {
3432            root: NodeData::create_node(NodeType::Figure),
3433            children: DomVec::from_const_slice(&[]),
3434            estimated_total_children: 0,
3435        }
3436    }
3437
3438    /// Creates a figure caption element.
3439    ///
3440    /// **Accessibility**: Provides a caption for `<figure>`. Screen readers announce this as the
3441    /// figure description.
3442    #[inline(always)]
3443    pub const fn create_figcaption() -> Self {
3444        Self {
3445            root: NodeData::create_node(NodeType::FigCaption),
3446            children: DomVec::from_const_slice(&[]),
3447            estimated_total_children: 0,
3448        }
3449    }
3450
3451    // Interactive Elements
3452
3453    /// Creates a details disclosure element.
3454    ///
3455    /// **Accessibility**: Creates a disclosure widget. Screen readers announce expanded/collapsed
3456    /// state. Must contain a `<summary>` element. Keyboard accessible by default.
3457    #[inline(always)]
3458    pub const fn create_details() -> Self {
3459        Self {
3460            root: NodeData::create_node(NodeType::Details),
3461            children: DomVec::from_const_slice(&[]),
3462            estimated_total_children: 0,
3463        }
3464    }
3465
3466    /// Creates a summary element for details.
3467    ///
3468    /// **Accessibility**: The visible heading/label for `<details>`.
3469    /// Must be the first child of details. Keyboard accessible (Enter/Space to toggle).
3470    #[inline]
3471    pub fn summary<S: Into<AzString>>(text: S) -> Self {
3472        Self {
3473            root: NodeData::create_node(NodeType::Summary),
3474            children: DomVec::from_const_slice(&[]),
3475            estimated_total_children: 0,
3476        }
3477        .with_child(Self::create_text(text))
3478    }
3479
3480    /// Creates a dialog element.
3481    ///
3482    /// **Accessibility**: Represents a modal or non-modal dialog.
3483    /// When opened as modal, focus is trapped. Use aria-label or aria-labelledby.
3484    /// Escape key should close modal dialogs.
3485    #[inline(always)]
3486    pub const fn create_dialog() -> Self {
3487        Self {
3488            root: NodeData::create_node(NodeType::Dialog),
3489            children: DomVec::from_const_slice(&[]),
3490            estimated_total_children: 0,
3491        }
3492    }
3493
3494    // Basic Structural Elements
3495
3496    #[inline(always)]
3497    pub const fn create_br() -> Self {
3498        Self {
3499            root: NodeData::create_node(NodeType::Br),
3500            children: DomVec::from_const_slice(&[]),
3501            estimated_total_children: 0,
3502        }
3503    }
3504    #[inline(always)]
3505    pub fn create_text<S: Into<AzString>>(value: S) -> Self {
3506        Self::create_node(NodeType::Text(value.into()))
3507    }
3508    #[inline(always)]
3509    pub fn create_image(image: ImageRef) -> Self {
3510        Self::create_node(NodeType::Image(image))
3511    }
3512    /// Creates an icon node with the given icon name.
3513    ///
3514    /// The icon name should match names from the icon provider (e.g., "home", "settings", "search").
3515    /// Icons are resolved to actual content (font glyph, image, etc.) during StyledDom creation
3516    /// based on the configured IconProvider.
3517    ///
3518    /// # Example
3519    /// ```rust,ignore
3520    /// Dom::create_icon("home")
3521    ///     .with_class("nav-icon")
3522    /// ```
3523    #[inline(always)]
3524    pub fn create_icon<S: Into<AzString>>(icon_name: S) -> Self {
3525        Self::create_node(NodeType::Icon(icon_name.into()))
3526    }
3527
3528    #[inline(always)]
3529    pub fn create_iframe(data: RefAny, callback: impl Into<IFrameCallback>) -> Self {
3530        Self::create_node(NodeType::IFrame(IFrameNode {
3531            callback: callback.into(),
3532            refany: data,
3533        }))
3534    }
3535
3536    // Semantic HTML Elements with Accessibility Guidance
3537
3538    /// Creates a paragraph element.
3539    ///
3540    /// **Accessibility**: Paragraphs provide semantic structure for screen readers.
3541    #[inline(always)]
3542    pub const fn create_p() -> Self {
3543        Self {
3544            root: NodeData::create_node(NodeType::P),
3545            children: DomVec::from_const_slice(&[]),
3546            estimated_total_children: 0,
3547        }
3548    }
3549
3550    /// Creates a heading level 1 element.
3551    ///
3552    /// **Accessibility**: Use `h1` for the main page title. There should typically be only one `h1`
3553    /// per page.
3554    ///
3555    /// **Parameters:**
3556    /// - `text`: Heading text
3557    #[inline]
3558    pub fn h1<S: Into<AzString>>(text: S) -> Self {
3559        Self {
3560            root: NodeData::create_node(NodeType::H1),
3561            children: DomVec::from_const_slice(&[]),
3562            estimated_total_children: 0,
3563        }
3564        .with_child(Self::create_text(text))
3565    }
3566
3567    /// Creates a heading level 2 element.
3568    ///
3569    /// **Accessibility**: Use `h2` for major section headings under `h1`.
3570    ///
3571    /// **Parameters:**
3572    /// - `text`: Heading text
3573    #[inline]
3574    pub fn h2<S: Into<AzString>>(text: S) -> Self {
3575        Self {
3576            root: NodeData::create_node(NodeType::H2),
3577            children: DomVec::from_const_slice(&[]),
3578            estimated_total_children: 0,
3579        }
3580        .with_child(Self::create_text(text))
3581    }
3582
3583    /// Creates a heading level 3 element.
3584    ///
3585    /// **Accessibility**: Use `h3` for subsections under `h2`.
3586    ///
3587    /// **Parameters:**
3588    /// - `text`: Heading text
3589    #[inline]
3590    pub fn h3<S: Into<AzString>>(text: S) -> Self {
3591        Self {
3592            root: NodeData::create_node(NodeType::H3),
3593            children: DomVec::from_const_slice(&[]),
3594            estimated_total_children: 0,
3595        }
3596        .with_child(Self::create_text(text))
3597    }
3598
3599    /// Creates a heading level 4 element.
3600    ///
3601    /// **Parameters:**
3602    /// - `text`: Heading text
3603    #[inline]
3604    pub fn h4<S: Into<AzString>>(text: S) -> Self {
3605        Self {
3606            root: NodeData::create_node(NodeType::H4),
3607            children: DomVec::from_const_slice(&[]),
3608            estimated_total_children: 0,
3609        }
3610        .with_child(Self::create_text(text))
3611    }
3612
3613    /// Creates a heading level 5 element.
3614    ///
3615    /// **Parameters:**
3616    /// - `text`: Heading text
3617    #[inline]
3618    pub fn h5<S: Into<AzString>>(text: S) -> Self {
3619        Self {
3620            root: NodeData::create_node(NodeType::H5),
3621            children: DomVec::from_const_slice(&[]),
3622            estimated_total_children: 0,
3623        }
3624        .with_child(Self::create_text(text))
3625    }
3626
3627    /// Creates a heading level 6 element.
3628    ///
3629    /// **Parameters:**
3630    /// - `text`: Heading text
3631    #[inline]
3632    pub fn h6<S: Into<AzString>>(text: S) -> Self {
3633        Self {
3634            root: NodeData::create_node(NodeType::H6),
3635            children: DomVec::from_const_slice(&[]),
3636            estimated_total_children: 0,
3637        }
3638        .with_child(Self::create_text(text))
3639    }
3640
3641    /// Creates a generic inline container (span).
3642    ///
3643    /// **Accessibility**: Prefer semantic elements like `strong`, `em`, `code`, etc. when
3644    /// applicable.
3645    ///
3646    /// **Parameters:**
3647    /// - `text`: Span content
3648    #[inline]
3649    pub fn span<S: Into<AzString>>(text: S) -> Self {
3650        Self {
3651            root: NodeData::create_node(NodeType::Span),
3652            children: DomVec::from_const_slice(&[]),
3653            estimated_total_children: 0,
3654        }
3655        .with_child(Self::create_text(text))
3656    }
3657
3658    /// Creates a strongly emphasized text element (strong importance).
3659    ///
3660    /// **Accessibility**: Use `strong` instead of `b` for semantic meaning. Screen readers can
3661    /// convey the importance. Use for text that has strong importance, seriousness, or urgency.
3662    ///
3663    /// **Parameters:**
3664    /// - `text`: Text to emphasize
3665    #[inline]
3666    pub fn strong<S: Into<AzString>>(text: S) -> Self {
3667        Self {
3668            root: NodeData::create_node(NodeType::Strong),
3669            children: DomVec::from_const_slice(&[]),
3670            estimated_total_children: 0,
3671        }
3672        .with_child(Self::create_text(text))
3673    }
3674
3675    /// Creates an emphasized text element (stress emphasis).
3676    ///
3677    /// **Accessibility**: Use `em` instead of `i` for semantic meaning. Screen readers can
3678    /// convey the emphasis. Use for text that has stress emphasis.
3679    ///
3680    /// **Parameters:**
3681    /// - `text`: Text to emphasize
3682    #[inline]
3683    pub fn em<S: Into<AzString>>(text: S) -> Self {
3684        Self {
3685            root: NodeData::create_node(NodeType::Em),
3686            children: DomVec::from_const_slice(&[]),
3687            estimated_total_children: 0,
3688        }
3689        .with_child(Self::create_text(text))
3690    }
3691
3692    /// Creates a code/computer code element.
3693    ///
3694    /// **Accessibility**: Represents a fragment of computer code. Screen readers can identify
3695    /// this as code content.
3696    ///
3697    /// **Parameters:**
3698    /// - `code`: Code content
3699    #[inline]
3700    pub fn code<S: Into<AzString>>(code: S) -> Self {
3701        Self::create_node(NodeType::Code).with_child(Self::create_text(code))
3702    }
3703
3704    /// Creates a preformatted text element.
3705    ///
3706    /// **Accessibility**: Preserves whitespace and line breaks. Useful for code blocks or
3707    /// ASCII art. Screen readers will read the content as-is.
3708    ///
3709    /// **Parameters:**
3710    /// - `text`: Preformatted content
3711    #[inline]
3712    pub fn pre<S: Into<AzString>>(text: S) -> Self {
3713        Self::create_node(NodeType::Pre).with_child(Self::create_text(text))
3714    }
3715
3716    /// Creates a blockquote element.
3717    ///
3718    /// **Accessibility**: Represents a section quoted from another source. Screen readers
3719    /// can identify quoted content. Consider adding a `cite` attribute.
3720    ///
3721    /// **Parameters:**
3722    /// - `text`: Quote content
3723    #[inline]
3724    pub fn blockquote<S: Into<AzString>>(text: S) -> Self {
3725        Self::create_node(NodeType::BlockQuote).with_child(Self::create_text(text))
3726    }
3727
3728    /// Creates a citation element.
3729    ///
3730    /// **Accessibility**: Represents a reference to a creative work. Screen readers can
3731    /// identify citations.
3732    ///
3733    /// **Parameters:**
3734    /// - `text`: Citation text
3735    #[inline]
3736    pub fn cite<S: Into<AzString>>(text: S) -> Self {
3737        Self::create_node(NodeType::Cite).with_child(Self::create_text(text))
3738    }
3739
3740    /// Creates an abbreviation element.
3741    ///
3742    /// **Accessibility**: Represents an abbreviation or acronym. Use with a `title` attribute
3743    /// to provide the full expansion for screen readers.
3744    ///
3745    /// **Parameters:**
3746    /// - `abbr_text`: Abbreviated text
3747    /// - `title`: Full expansion
3748    #[inline]
3749    pub fn create_abbr(abbr_text: AzString, title: AzString) -> Self {
3750        Self::create_node(NodeType::Abbr)
3751            .with_attribute(AttributeType::Title(title))
3752            .with_child(Self::create_text(abbr_text))
3753    }
3754
3755    /// Creates a keyboard input element.
3756    ///
3757    /// **Accessibility**: Represents keyboard input or key combinations. Screen readers can
3758    /// identify keyboard instructions.
3759    ///
3760    /// **Parameters:**
3761    /// - `text`: Keyboard instruction
3762    #[inline]
3763    pub fn kbd<S: Into<AzString>>(text: S) -> Self {
3764        Self::create_node(NodeType::Kbd).with_child(Self::create_text(text))
3765    }
3766
3767    /// Creates a sample output element.
3768    ///
3769    /// **Accessibility**: Represents sample output from a program or computing system.
3770    ///
3771    /// **Parameters:**
3772    /// - `text`: Sample text
3773    #[inline]
3774    pub fn samp<S: Into<AzString>>(text: S) -> Self {
3775        Self::create_node(NodeType::Samp).with_child(Self::create_text(text))
3776    }
3777
3778    /// Creates a variable element.
3779    ///
3780    /// **Accessibility**: Represents a variable in mathematical expressions or programming.
3781    ///
3782    /// **Parameters:**
3783    /// - `text`: Variable name
3784    #[inline]
3785    pub fn var<S: Into<AzString>>(text: S) -> Self {
3786        Self::create_node(NodeType::Var).with_child(Self::create_text(text))
3787    }
3788
3789    /// Creates a subscript element.
3790    ///
3791    /// **Accessibility**: Screen readers may announce subscript formatting.
3792    ///
3793    /// **Parameters:**
3794    /// - `text`: Subscript content
3795    #[inline]
3796    pub fn sub<S: Into<AzString>>(text: S) -> Self {
3797        Self::create_node(NodeType::Sub).with_child(Self::create_text(text))
3798    }
3799
3800    /// Creates a superscript element.
3801    ///
3802    /// **Accessibility**: Screen readers may announce superscript formatting.
3803    ///
3804    /// **Parameters:**
3805    /// - `text`: Superscript content
3806    #[inline]
3807    pub fn sup<S: Into<AzString>>(text: S) -> Self {
3808        Self::create_node(NodeType::Sup).with_child(Self::create_text(text))
3809    }
3810
3811    /// Creates an underline text element.
3812    ///
3813    /// **Accessibility**: Screen readers typically don't announce underline formatting.
3814    /// Use semantic elements when possible (e.g., `<em>` for emphasis).
3815    #[inline]
3816    pub fn u<S: Into<AzString>>(text: S) -> Self {
3817        Self::create_node(NodeType::U).with_child(Self::create_text(text))
3818    }
3819
3820    /// Creates a strikethrough text element.
3821    ///
3822    /// **Accessibility**: Represents text that is no longer accurate or relevant.
3823    /// Consider using `<del>` for deleted content with datetime attribute.
3824    #[inline]
3825    pub fn s<S: Into<AzString>>(text: S) -> Self {
3826        Self::create_node(NodeType::S).with_child(Self::create_text(text))
3827    }
3828
3829    /// Creates a marked/highlighted text element.
3830    ///
3831    /// **Accessibility**: Represents text marked for reference or notation purposes.
3832    /// Screen readers may announce this as "highlighted".
3833    #[inline]
3834    pub fn mark<S: Into<AzString>>(text: S) -> Self {
3835        Self::create_node(NodeType::Mark).with_child(Self::create_text(text))
3836    }
3837
3838    /// Creates a deleted text element.
3839    ///
3840    /// **Accessibility**: Represents deleted content in document edits.
3841    /// Use with `datetime` and `cite` attributes for edit tracking.
3842    #[inline]
3843    pub fn del<S: Into<AzString>>(text: S) -> Self {
3844        Self::create_node(NodeType::Del).with_child(Self::create_text(text))
3845    }
3846
3847    /// Creates an inserted text element.
3848    ///
3849    /// **Accessibility**: Represents inserted content in document edits.
3850    /// Use with `datetime` and `cite` attributes for edit tracking.
3851    #[inline]
3852    pub fn ins<S: Into<AzString>>(text: S) -> Self {
3853        Self::create_node(NodeType::Ins).with_child(Self::create_text(text))
3854    }
3855
3856    /// Creates a definition element.
3857    ///
3858    /// **Accessibility**: Represents the defining instance of a term.
3859    /// Often used within a definition list or with `<abbr>`.
3860    #[inline]
3861    pub fn dfn<S: Into<AzString>>(text: S) -> Self {
3862        Self::create_node(NodeType::Dfn).with_child(Self::create_text(text))
3863    }
3864
3865    /// Creates a time element.
3866    ///
3867    /// **Accessibility**: Represents a specific time or date.
3868    /// Use `datetime` attribute for machine-readable format.
3869    ///
3870    /// **Parameters:**
3871    /// - `text`: Human-readable time/date
3872    /// - `datetime`: Optional machine-readable datetime
3873    #[inline]
3874    pub fn create_time(text: AzString, datetime: OptionString) -> Self {
3875        let mut element = Self::create_node(NodeType::Time).with_child(Self::create_text(text));
3876        if let OptionString::Some(dt) = datetime {
3877            element = element.with_attribute(AttributeType::Custom(AttributeNameValue {
3878                attr_name: "datetime".into(),
3879                value: dt,
3880            }));
3881        }
3882        element
3883    }
3884
3885    /// Creates a bi-directional override element.
3886    ///
3887    /// **Accessibility**: Overrides text direction. Use `dir` attribute (ltr/rtl).
3888    #[inline]
3889    pub fn bdo<S: Into<AzString>>(text: S) -> Self {
3890        Self::create_node(NodeType::Bdo).with_child(Self::create_text(text))
3891    }
3892
3893    /// Creates an anchor/hyperlink element.
3894    ///
3895    /// **Accessibility**: Always provide meaningful link text. Avoid "click here" or "read more".
3896    /// Screen readers often navigate by links, so descriptive text is crucial.
3897    ///
3898    /// **Parameters:**
3899    /// - `href`: Link destination URL
3900    /// - `label`: Link text (pass `None` for image-only links with alt text)
3901    #[inline]
3902    pub fn create_a(href: AzString, label: OptionString) -> Self {
3903        let mut link = Self::create_node(NodeType::A).with_attribute(AttributeType::Href(href));
3904        if let OptionString::Some(text) = label {
3905            link = link.with_child(Self::create_text(text));
3906        }
3907        link
3908    }
3909
3910    /// Creates a button element.
3911    ///
3912    /// **Accessibility**: Buttons are keyboard accessible by default. Always provide clear
3913    /// button text or an `aria-label` for icon-only buttons.
3914    ///
3915    /// **Parameters:**
3916    /// - `text`: Button label text
3917    #[inline]
3918    pub fn create_button(text: AzString) -> Self {
3919        Self::create_node(NodeType::Button).with_child(Self::create_text(text))
3920    }
3921
3922    /// Creates a label element for form controls.
3923    ///
3924    /// **Accessibility**: Always associate labels with form controls using `for` attribute
3925    /// or by wrapping the control. This is critical for screen reader users.
3926    ///
3927    /// **Parameters:**
3928    /// - `for_id`: ID of the associated form control
3929    /// - `text`: Label text
3930    #[inline]
3931    pub fn create_label(for_id: AzString, text: AzString) -> Self {
3932        Self::create_node(NodeType::Label)
3933            .with_attribute(AttributeType::Custom(AttributeNameValue {
3934                attr_name: "for".into(),
3935                value: for_id,
3936            }))
3937            .with_child(Self::create_text(text))
3938    }
3939
3940    /// Creates an input element.
3941    ///
3942    /// **Accessibility**: Always provide a label or `aria-label`. Set appropriate `type`
3943    /// and `aria-` attributes for the input's purpose.
3944    ///
3945    /// **Parameters:**
3946    /// - `input_type`: Input type (text, password, email, etc.)
3947    /// - `name`: Form field name
3948    /// - `label`: Accessibility label (required)
3949    #[inline]
3950    pub fn create_input(input_type: AzString, name: AzString, label: AzString) -> Self {
3951        Self::create_node(NodeType::Input)
3952            .with_attribute(AttributeType::InputType(input_type))
3953            .with_attribute(AttributeType::Name(name))
3954            .with_attribute(AttributeType::AriaLabel(label))
3955    }
3956
3957    /// Creates a textarea element.
3958    ///
3959    /// **Accessibility**: Always provide a label or `aria-label`. Consider `aria-describedby`
3960    /// for additional instructions.
3961    ///
3962    /// **Parameters:**
3963    /// - `name`: Form field name
3964    /// - `label`: Accessibility label (required)
3965    #[inline]
3966    pub fn create_textarea(name: AzString, label: AzString) -> Self {
3967        Self::create_node(NodeType::TextArea)
3968            .with_attribute(AttributeType::Name(name))
3969            .with_attribute(AttributeType::AriaLabel(label))
3970    }
3971
3972    /// Creates a select dropdown element.
3973    ///
3974    /// **Accessibility**: Always provide a label. Group related options with `optgroup`.
3975    ///
3976    /// **Parameters:**
3977    /// - `name`: Form field name
3978    /// - `label`: Accessibility label (required)
3979    #[inline]
3980    pub fn create_select(name: AzString, label: AzString) -> Self {
3981        Self::create_node(NodeType::Select)
3982            .with_attribute(AttributeType::Name(name))
3983            .with_attribute(AttributeType::AriaLabel(label))
3984    }
3985
3986    /// Creates an option element for select dropdowns.
3987    ///
3988    /// **Parameters:**
3989    /// - `value`: Option value
3990    /// - `text`: Display text
3991    #[inline]
3992    pub fn create_option(value: AzString, text: AzString) -> Self {
3993        Self::create_node(NodeType::SelectOption)
3994            .with_attribute(AttributeType::Value(value))
3995            .with_child(Self::create_text(text))
3996    }
3997
3998    /// Creates an unordered list element.
3999    ///
4000    /// **Accessibility**: Screen readers announce lists and item counts, helping users
4001    /// understand content structure.
4002    #[inline(always)]
4003    pub fn create_ul() -> Self {
4004        Self::create_node(NodeType::Ul)
4005    }
4006
4007    /// Creates an ordered list element.
4008    ///
4009    /// **Accessibility**: Screen readers announce lists and item counts, helping users
4010    /// understand content structure and numbering.
4011    #[inline(always)]
4012    pub fn create_ol() -> Self {
4013        Self::create_node(NodeType::Ol)
4014    }
4015
4016    /// Creates a list item element.
4017    ///
4018    /// **Accessibility**: Must be a child of `ul`, `ol`, or `menu`. Screen readers announce
4019    /// list item position (e.g., "2 of 5").
4020    #[inline(always)]
4021    pub fn create_li() -> Self {
4022        Self::create_node(NodeType::Li)
4023    }
4024
4025    /// Creates a table element.
4026    ///
4027    /// **Accessibility**: Use proper table structure with `thead`, `tbody`, `th`, and `td`.
4028    /// Provide a `caption` for table purpose. Use `scope` attribute on header cells.
4029    #[inline(always)]
4030    pub fn create_table() -> Self {
4031        Self::create_node(NodeType::Table)
4032    }
4033
4034    /// Creates a table caption element.
4035    ///
4036    /// **Accessibility**: Describes the purpose of the table. Screen readers announce this first.
4037    #[inline(always)]
4038    pub fn create_caption() -> Self {
4039        Self::create_node(NodeType::Caption)
4040    }
4041
4042    /// Creates a table header element.
4043    ///
4044    /// **Accessibility**: Groups header rows. Screen readers can navigate table structure.
4045    #[inline(always)]
4046    pub fn create_thead() -> Self {
4047        Self::create_node(NodeType::THead)
4048    }
4049
4050    /// Creates a table body element.
4051    ///
4052    /// **Accessibility**: Groups body rows. Screen readers can navigate table structure.
4053    #[inline(always)]
4054    pub fn create_tbody() -> Self {
4055        Self::create_node(NodeType::TBody)
4056    }
4057
4058    /// Creates a table footer element.
4059    ///
4060    /// **Accessibility**: Groups footer rows. Screen readers can navigate table structure.
4061    #[inline(always)]
4062    pub fn create_tfoot() -> Self {
4063        Self::create_node(NodeType::TFoot)
4064    }
4065
4066    /// Creates a table row element.
4067    #[inline(always)]
4068    pub fn create_tr() -> Self {
4069        Self::create_node(NodeType::Tr)
4070    }
4071
4072    /// Creates a table header cell element.
4073    ///
4074    /// **Accessibility**: Use `scope` attribute ("col" or "row") to associate headers with
4075    /// data cells. Screen readers use this to announce cell context.
4076    #[inline(always)]
4077    pub fn create_th() -> Self {
4078        Self::create_node(NodeType::Th)
4079    }
4080
4081    /// Creates a table data cell element.
4082    #[inline(always)]
4083    pub fn create_td() -> Self {
4084        Self::create_node(NodeType::Td)
4085    }
4086
4087    /// Creates a form element.
4088    ///
4089    /// **Accessibility**: Group related form controls with `fieldset` and `legend`.
4090    /// Provide clear labels for all inputs. Consider `aria-describedby` for instructions.
4091    #[inline(always)]
4092    pub fn create_form() -> Self {
4093        Self::create_node(NodeType::Form)
4094    }
4095
4096    /// Creates a fieldset element for grouping form controls.
4097    ///
4098    /// **Accessibility**: Groups related form controls. Always include a `legend` as the
4099    /// first child to describe the group. Screen readers announce the legend when entering
4100    /// the fieldset.
4101    #[inline(always)]
4102    pub fn create_fieldset() -> Self {
4103        Self::create_node(NodeType::FieldSet)
4104    }
4105
4106    /// Creates a legend element for fieldsets.
4107    ///
4108    /// **Accessibility**: Describes the purpose of a fieldset. Must be the first child of
4109    /// a fieldset. Screen readers announce this when entering the fieldset.
4110    #[inline(always)]
4111    pub fn create_legend() -> Self {
4112        Self::create_node(NodeType::Legend)
4113    }
4114
4115    /// Creates a horizontal rule element.
4116    ///
4117    /// **Accessibility**: Represents a thematic break. Screen readers may announce this as
4118    /// a separator. Consider using CSS borders for purely decorative lines.
4119    #[inline(always)]
4120    pub fn create_hr() -> Self {
4121        Self::create_node(NodeType::Hr)
4122    }
4123
4124    // Additional Element Constructors
4125
4126    /// Creates an address element.
4127    ///
4128    /// **Accessibility**: Represents contact information. Screen readers identify this
4129    /// as address content.
4130    #[inline(always)]
4131    pub const fn create_address() -> Self {
4132        Self {
4133            root: NodeData::create_node(NodeType::Address),
4134            children: DomVec::from_const_slice(&[]),
4135            estimated_total_children: 0,
4136        }
4137    }
4138
4139    /// Creates a definition list element.
4140    ///
4141    /// **Accessibility**: Screen readers announce definition lists and their structure.
4142    #[inline(always)]
4143    pub const fn create_dl() -> Self {
4144        Self {
4145            root: NodeData::create_node(NodeType::Dl),
4146            children: DomVec::from_const_slice(&[]),
4147            estimated_total_children: 0,
4148        }
4149    }
4150
4151    /// Creates a definition term element.
4152    ///
4153    /// **Accessibility**: Must be a child of `dl`. Represents the term being defined.
4154    #[inline(always)]
4155    pub const fn create_dt() -> Self {
4156        Self {
4157            root: NodeData::create_node(NodeType::Dt),
4158            children: DomVec::from_const_slice(&[]),
4159            estimated_total_children: 0,
4160        }
4161    }
4162
4163    /// Creates a definition description element.
4164    ///
4165    /// **Accessibility**: Must be a child of `dl`. Provides the definition for the term.
4166    #[inline(always)]
4167    pub const fn create_dd() -> Self {
4168        Self {
4169            root: NodeData::create_node(NodeType::Dd),
4170            children: DomVec::from_const_slice(&[]),
4171            estimated_total_children: 0,
4172        }
4173    }
4174
4175    /// Creates a table column group element.
4176    #[inline(always)]
4177    pub const fn create_colgroup() -> Self {
4178        Self {
4179            root: NodeData::create_node(NodeType::ColGroup),
4180            children: DomVec::from_const_slice(&[]),
4181            estimated_total_children: 0,
4182        }
4183    }
4184
4185    /// Creates a table column element.
4186    #[inline]
4187    pub fn create_col(span: i32) -> Self {
4188        Self::create_node(NodeType::Col).with_attribute(AttributeType::ColSpan(span))
4189    }
4190
4191    /// Creates an optgroup element for grouping select options.
4192    ///
4193    /// **Parameters:**
4194    /// - `label`: Label for the option group
4195    #[inline]
4196    pub fn create_optgroup(label: AzString) -> Self {
4197        Self::create_node(NodeType::OptGroup).with_attribute(AttributeType::AriaLabel(label))
4198    }
4199
4200    /// Creates a quotation element.
4201    ///
4202    /// **Accessibility**: Represents an inline quotation.
4203    #[inline(always)]
4204    pub const fn create_q() -> Self {
4205        Self {
4206            root: NodeData::create_node(NodeType::Q),
4207            children: DomVec::from_const_slice(&[]),
4208            estimated_total_children: 0,
4209        }
4210    }
4211
4212    /// Creates an acronym element.
4213    ///
4214    /// **Note**: Deprecated in HTML5. Consider using `abbr()` instead.
4215    #[inline(always)]
4216    pub const fn acronym() -> Self {
4217        Self {
4218            root: NodeData::create_node(NodeType::Acronym),
4219            children: DomVec::from_const_slice(&[]),
4220            estimated_total_children: 0,
4221        }
4222    }
4223
4224    /// Creates a menu element.
4225    ///
4226    /// **Accessibility**: Represents a list of commands. Similar to `<ul>` but semantic for
4227    /// toolbars/menus.
4228    #[inline(always)]
4229    pub const fn create_menu() -> Self {
4230        Self {
4231            root: NodeData::create_node(NodeType::Menu),
4232            children: DomVec::from_const_slice(&[]),
4233            estimated_total_children: 0,
4234        }
4235    }
4236
4237    /// Creates a menu item element.
4238    ///
4239    /// **Accessibility**: Represents a command in a menu. Use with appropriate role/aria
4240    /// attributes.
4241    #[inline(always)]
4242    pub const fn menuitem() -> Self {
4243        Self {
4244            root: NodeData::create_node(NodeType::MenuItem),
4245            children: DomVec::from_const_slice(&[]),
4246            estimated_total_children: 0,
4247        }
4248    }
4249
4250    /// Creates an output element.
4251    ///
4252    /// **Accessibility**: Represents the result of a calculation or user action.
4253    /// Use `for` attribute to associate with input elements. Screen readers announce updates.
4254    #[inline(always)]
4255    pub const fn create_output() -> Self {
4256        Self {
4257            root: NodeData::create_node(NodeType::Output),
4258            children: DomVec::from_const_slice(&[]),
4259            estimated_total_children: 0,
4260        }
4261    }
4262
4263    /// Creates a progress indicator element.
4264    ///
4265    /// **Accessibility**: Represents task progress. Use `value` and `max` attributes.
4266    /// Screen readers announce progress percentage. Use aria-label to describe the task.
4267    #[inline]
4268    pub fn create_progress(value: f32, max: f32) -> Self {
4269        Self::create_node(NodeType::Progress)
4270            .with_attribute(AttributeType::Custom(AttributeNameValue {
4271                attr_name: "value".into(),
4272                value: value.to_string().into(),
4273            }))
4274            .with_attribute(AttributeType::Custom(AttributeNameValue {
4275                attr_name: "max".into(),
4276                value: max.to_string().into(),
4277            }))
4278    }
4279
4280    /// Creates a meter gauge element.
4281    ///
4282    /// **Accessibility**: Represents a scalar measurement within a known range.
4283    /// Use `value`, `min`, `max`, `low`, `high`, `optimum` attributes.
4284    /// Screen readers announce the measurement. Provide aria-label for context.
4285    #[inline]
4286    pub fn create_meter(value: f32, min: f32, max: f32) -> Self {
4287        Self::create_node(NodeType::Meter)
4288            .with_attribute(AttributeType::Custom(AttributeNameValue {
4289                attr_name: "value".into(),
4290                value: value.to_string().into(),
4291            }))
4292            .with_attribute(AttributeType::Custom(AttributeNameValue {
4293                attr_name: "min".into(),
4294                value: min.to_string().into(),
4295            }))
4296            .with_attribute(AttributeType::Custom(AttributeNameValue {
4297                attr_name: "max".into(),
4298                value: max.to_string().into(),
4299            }))
4300    }
4301
4302    /// Creates a datalist element for input suggestions.
4303    ///
4304    /// **Accessibility**: Provides autocomplete options for inputs.
4305    /// Associate with input using `list` attribute. Screen readers announce available options.
4306    #[inline(always)]
4307    pub const fn create_datalist() -> Self {
4308        Self {
4309            root: NodeData::create_node(NodeType::DataList),
4310            children: DomVec::from_const_slice(&[]),
4311            estimated_total_children: 0,
4312        }
4313    }
4314
4315    // Embedded Content Elements
4316
4317    /// Creates a canvas element for graphics.
4318    ///
4319    /// **Accessibility**: Canvas content is not accessible by default.
4320    /// Always provide fallback content as children and/or detailed aria-label.
4321    /// Consider using SVG for accessible graphics when possible.
4322    #[inline(always)]
4323    pub const fn create_canvas() -> Self {
4324        Self {
4325            root: NodeData::create_node(NodeType::Canvas),
4326            children: DomVec::from_const_slice(&[]),
4327            estimated_total_children: 0,
4328        }
4329    }
4330
4331    /// Creates an object element for embedded content.
4332    ///
4333    /// **Accessibility**: Provide fallback content as children. Use aria-label to describe content.
4334    #[inline(always)]
4335    pub const fn create_object() -> Self {
4336        Self {
4337            root: NodeData::create_node(NodeType::Object),
4338            children: DomVec::from_const_slice(&[]),
4339            estimated_total_children: 0,
4340        }
4341    }
4342
4343    /// Creates a param element for object parameters.
4344    ///
4345    /// **Parameters:**
4346    /// - `name`: Parameter name
4347    /// - `value`: Parameter value
4348    #[inline]
4349    pub fn create_param(name: AzString, value: AzString) -> Self {
4350        Self::create_node(NodeType::Param)
4351            .with_attribute(AttributeType::Name(name))
4352            .with_attribute(AttributeType::Value(value))
4353    }
4354
4355    /// Creates an embed element.
4356    ///
4357    /// **Accessibility**: Provide alternative content or link. Use aria-label to describe embedded
4358    /// content.
4359    #[inline(always)]
4360    pub const fn create_embed() -> Self {
4361        Self {
4362            root: NodeData::create_node(NodeType::Embed),
4363            children: DomVec::from_const_slice(&[]),
4364            estimated_total_children: 0,
4365        }
4366    }
4367
4368    /// Creates an audio element.
4369    ///
4370    /// **Accessibility**: Always provide controls. Use `<track>` for captions/subtitles.
4371    /// Provide fallback text for unsupported browsers.
4372    #[inline(always)]
4373    pub const fn create_audio() -> Self {
4374        Self {
4375            root: NodeData::create_node(NodeType::Audio),
4376            children: DomVec::from_const_slice(&[]),
4377            estimated_total_children: 0,
4378        }
4379    }
4380
4381    /// Creates a video element.
4382    ///
4383    /// **Accessibility**: Always provide controls. Use `<track>` for
4384    /// captions/subtitles/descriptions. Provide fallback text. Consider providing transcript.
4385    #[inline(always)]
4386    pub const fn create_video() -> Self {
4387        Self {
4388            root: NodeData::create_node(NodeType::Video),
4389            children: DomVec::from_const_slice(&[]),
4390            estimated_total_children: 0,
4391        }
4392    }
4393
4394    /// Creates a source element for media.
4395    ///
4396    /// **Parameters:**
4397    /// - `src`: Media source URL
4398    /// - `media_type`: MIME type (e.g., "video/mp4", "audio/ogg")
4399    #[inline]
4400    pub fn create_source(src: AzString, media_type: AzString) -> Self {
4401        Self::create_node(NodeType::Source)
4402            .with_attribute(AttributeType::Src(src))
4403            .with_attribute(AttributeType::Custom(AttributeNameValue {
4404                attr_name: "type".into(),
4405                value: media_type,
4406            }))
4407    }
4408
4409    /// Creates a track element for media captions/subtitles.
4410    ///
4411    /// **Accessibility**: Essential for deaf/hard-of-hearing users and non-native speakers.
4412    /// Use `kind` (subtitles/captions/descriptions), `srclang`, and `label` attributes.
4413    ///
4414    /// **Parameters:**
4415    /// - `src`: Track file URL (WebVTT format)
4416    /// - `kind`: Track kind ("subtitles", "captions", "descriptions", "chapters", "metadata")
4417    #[inline]
4418    pub fn create_track(src: AzString, kind: AzString) -> Self {
4419        Self::create_node(NodeType::Track)
4420            .with_attribute(AttributeType::Src(src))
4421            .with_attribute(AttributeType::Custom(AttributeNameValue {
4422                attr_name: "kind".into(),
4423                value: kind,
4424            }))
4425    }
4426
4427    /// Creates a map element for image maps.
4428    ///
4429    /// **Accessibility**: Provide text alternatives. Ensure all areas have alt text.
4430    #[inline(always)]
4431    pub const fn create_map() -> Self {
4432        Self {
4433            root: NodeData::create_node(NodeType::Map),
4434            children: DomVec::from_const_slice(&[]),
4435            estimated_total_children: 0,
4436        }
4437    }
4438
4439    /// Creates an area element for image map regions.
4440    ///
4441    /// **Accessibility**: Always provide `alt` text describing the region/link purpose.
4442    /// Keyboard users should be able to navigate areas.
4443    #[inline(always)]
4444    pub const fn create_area() -> Self {
4445        Self {
4446            root: NodeData::create_node(NodeType::Area),
4447            children: DomVec::from_const_slice(&[]),
4448            estimated_total_children: 0,
4449        }
4450    }
4451
4452    // Metadata Elements
4453
4454    /// Creates a title element for document title.
4455    ///
4456    /// **Accessibility**: Required for all pages. Screen readers announce this first.
4457    /// Should be unique and descriptive. Keep under 60 characters.
4458    #[inline]
4459    pub fn title<S: Into<AzString>>(text: S) -> Self {
4460        Self::create_node(NodeType::Title).with_child(Self::create_text(text))
4461    }
4462
4463    /// Creates a meta element.
4464    ///
4465    /// **Accessibility**: Use for charset, viewport, description. Crucial for proper text display.
4466    #[inline(always)]
4467    pub const fn meta() -> Self {
4468        Self {
4469            root: NodeData::create_node(NodeType::Meta),
4470            children: DomVec::from_const_slice(&[]),
4471            estimated_total_children: 0,
4472        }
4473    }
4474
4475    /// Creates a link element for external resources.
4476    ///
4477    /// **Accessibility**: Use for stylesheets, icons, alternate versions.
4478    /// Provide meaningful `title` attribute for alternate stylesheets.
4479    #[inline(always)]
4480    pub const fn create_link() -> Self {
4481        Self {
4482            root: NodeData::create_node(NodeType::Link),
4483            children: DomVec::from_const_slice(&[]),
4484            estimated_total_children: 0,
4485        }
4486    }
4487
4488    /// Creates a script element.
4489    ///
4490    /// **Accessibility**: Ensure scripted content is accessible.
4491    /// Provide noscript fallbacks for critical functionality.
4492    #[inline(always)]
4493    pub const fn create_script() -> Self {
4494        Self {
4495            root: NodeData::create_node(NodeType::Script),
4496            children: DomVec::from_const_slice(&[]),
4497            estimated_total_children: 0,
4498        }
4499    }
4500
4501    /// Creates a style element for embedded CSS.
4502    ///
4503    /// **Note**: In Azul, use the `.style()` method instead for styling.
4504    /// This creates a `<style>` HTML element for embedded stylesheets.
4505    #[inline(always)]
4506    pub const fn style_element() -> Self {
4507        Self {
4508            root: NodeData::create_node(NodeType::Style),
4509            children: DomVec::from_const_slice(&[]),
4510            estimated_total_children: 0,
4511        }
4512    }
4513
4514    /// Creates a base element for document base URL.
4515    ///
4516    /// **Parameters:**
4517    /// - `href`: Base URL for relative URLs in the document
4518    #[inline]
4519    pub fn base(href: AzString) -> Self {
4520        Self::create_node(NodeType::Base).with_attribute(AttributeType::Href(href))
4521    }
4522
4523    // Advanced Constructors with Parameters
4524
4525    /// Creates a table header cell with scope.
4526    ///
4527    /// **Parameters:**
4528    /// - `scope`: "col", "row", "colgroup", or "rowgroup"
4529    /// - `text`: Header text
4530    ///
4531    /// **Accessibility**: The scope attribute is crucial for associating headers with data cells.
4532    #[inline]
4533    pub fn th_with_scope(scope: AzString, text: AzString) -> Self {
4534        Self::create_node(NodeType::Th)
4535            .with_attribute(AttributeType::Scope(scope))
4536            .with_child(Self::create_text(text))
4537    }
4538
4539    /// Creates a table data cell with text.
4540    ///
4541    /// **Parameters:**
4542    /// - `text`: Cell content
4543    #[inline]
4544    pub fn td_with_text<S: Into<AzString>>(text: S) -> Self {
4545        Self::create_td().with_child(Self::create_text(text))
4546    }
4547
4548    /// Creates a table header cell with text.
4549    ///
4550    /// **Parameters:**
4551    /// - `text`: Header text
4552    #[inline]
4553    pub fn th_with_text<S: Into<AzString>>(text: S) -> Self {
4554        Self::create_th().with_child(Self::create_text(text))
4555    }
4556
4557    /// Creates a list item with text.
4558    ///
4559    /// **Parameters:**
4560    /// - `text`: List item content
4561    #[inline]
4562    pub fn li_with_text<S: Into<AzString>>(text: S) -> Self {
4563        Self::create_li().with_child(Self::create_text(text))
4564    }
4565
4566    /// Creates a paragraph with text.
4567    ///
4568    /// **Parameters:**
4569    /// - `text`: Paragraph content
4570    #[inline]
4571    pub fn p_with_text<S: Into<AzString>>(text: S) -> Self {
4572        Self::create_p().with_child(Self::create_text(text))
4573    }
4574
4575    // Accessibility-Aware Constructors
4576    // These constructors require explicit accessibility information.
4577
4578    /// Creates a button with text content and accessibility information.
4579    ///
4580    /// **Parameters:**
4581    /// - `text`: The visible button text
4582    /// - `aria`: Accessibility information (role, description, etc.)
4583    #[inline]
4584    pub fn button_with_aria<S: Into<AzString>>(text: S, aria: SmallAriaInfo) -> Self {
4585        let mut btn = Self::create_button(text.into());
4586        btn.root.set_accessibility_info(aria.to_full_info());
4587        btn
4588    }
4589
4590    /// Creates a link (anchor) with href, text, and accessibility information.
4591    ///
4592    /// **Parameters:**
4593    /// - `href`: The link destination
4594    /// - `text`: The visible link text
4595    /// - `aria`: Accessibility information (expanded description, etc.)
4596    #[inline]
4597    pub fn link_with_aria<S1: Into<AzString>, S2: Into<AzString>>(
4598        href: S1,
4599        text: S2,
4600        aria: SmallAriaInfo,
4601    ) -> Self {
4602        let mut link = Self::create_a(href.into(), OptionString::Some(text.into()));
4603        link.root.set_accessibility_info(aria.to_full_info());
4604        link
4605    }
4606
4607    /// Creates an input element with type, name, and accessibility information.
4608    ///
4609    /// **Parameters:**
4610    /// - `input_type`: The input type (text, password, email, etc.)
4611    /// - `name`: The form field name
4612    /// - `label`: Base accessibility label
4613    /// - `aria`: Additional accessibility information (description, etc.)
4614    #[inline]
4615    pub fn input_with_aria<S1: Into<AzString>, S2: Into<AzString>, S3: Into<AzString>>(
4616        input_type: S1,
4617        name: S2,
4618        label: S3,
4619        aria: SmallAriaInfo,
4620    ) -> Self {
4621        let mut input = Self::create_input(input_type.into(), name.into(), label.into());
4622        input.root.set_accessibility_info(aria.to_full_info());
4623        input
4624    }
4625
4626    /// Creates a textarea with name and accessibility information.
4627    ///
4628    /// **Parameters:**
4629    /// - `name`: The form field name
4630    /// - `label`: Base accessibility label
4631    /// - `aria`: Additional accessibility information (description, etc.)
4632    #[inline]
4633    pub fn textarea_with_aria<S1: Into<AzString>, S2: Into<AzString>>(
4634        name: S1,
4635        label: S2,
4636        aria: SmallAriaInfo,
4637    ) -> Self {
4638        let mut textarea = Self::create_textarea(name.into(), label.into());
4639        textarea.root.set_accessibility_info(aria.to_full_info());
4640        textarea
4641    }
4642
4643    /// Creates a select dropdown with name and accessibility information.
4644    ///
4645    /// **Parameters:**
4646    /// - `name`: The form field name
4647    /// - `label`: Base accessibility label
4648    /// - `aria`: Additional accessibility information (description, etc.)
4649    #[inline]
4650    pub fn select_with_aria<S1: Into<AzString>, S2: Into<AzString>>(
4651        name: S1,
4652        label: S2,
4653        aria: SmallAriaInfo,
4654    ) -> Self {
4655        let mut select = Self::create_select(name.into(), label.into());
4656        select.root.set_accessibility_info(aria.to_full_info());
4657        select
4658    }
4659
4660    /// Creates a table with caption and accessibility information.
4661    ///
4662    /// **Parameters:**
4663    /// - `caption`: Table caption (visible title)
4664    /// - `aria`: Accessibility information describing table purpose
4665    #[inline]
4666    pub fn table_with_aria<S: Into<AzString>>(caption: S, aria: SmallAriaInfo) -> Self {
4667        let mut table = Self::create_table()
4668            .with_child(Self::create_caption().with_child(Self::create_text(caption)));
4669        table.root.set_accessibility_info(aria.to_full_info());
4670        table
4671    }
4672
4673    /// Creates a label for a form control with additional accessibility information.
4674    ///
4675    /// **Parameters:**
4676    /// - `for_id`: The ID of the associated form control
4677    /// - `text`: The visible label text
4678    /// - `aria`: Additional accessibility information (description, etc.)
4679    #[inline]
4680    pub fn label_with_aria<S1: Into<AzString>, S2: Into<AzString>>(
4681        for_id: S1,
4682        text: S2,
4683        aria: SmallAriaInfo,
4684    ) -> Self {
4685        let mut label = Self::create_label(for_id.into(), text.into());
4686        label.root.set_accessibility_info(aria.to_full_info());
4687        label
4688    }
4689
4690    /// Parse XML/XHTML string into a DOM
4691    ///
4692    /// This is a simple wrapper that parses XML and converts it to a DOM.
4693    /// For now, it just creates a text node with the content since full XML parsing
4694    /// requires the xml feature and more complex parsing logic.
4695    #[cfg(feature = "xml")]
4696    pub fn from_xml<S: AsRef<str>>(xml_str: S) -> Self {
4697        // TODO: Implement full XML parsing
4698        // For now, just create a text node showing that XML was loaded
4699        Self::create_text(format!(
4700            "XML content loaded ({} bytes)",
4701            xml_str.as_ref().len()
4702        ))
4703    }
4704
4705    /// Parse XML/XHTML string into a DOM (fallback without xml feature)
4706    #[cfg(not(feature = "xml"))]
4707    pub fn from_xml<S: AsRef<str>>(xml_str: S) -> Self {
4708        Self::create_text(format!(
4709            "XML parsing requires 'xml' feature ({} bytes)",
4710            xml_str.as_ref().len()
4711        ))
4712    }
4713
4714    // Swaps `self` with a default DOM, necessary for builder methods
4715    #[inline(always)]
4716    pub fn swap_with_default(&mut self) -> Self {
4717        let mut s = Self {
4718            root: NodeData::create_div(),
4719            children: DomVec::from_const_slice(&[]),
4720            estimated_total_children: 0,
4721        };
4722        mem::swap(&mut s, self);
4723        s
4724    }
4725
4726    #[inline]
4727    pub fn add_child(&mut self, child: Dom) {
4728        let estimated = child.estimated_total_children;
4729        let mut v: DomVec = Vec::new().into();
4730        mem::swap(&mut v, &mut self.children);
4731        let mut v = v.into_library_owned_vec();
4732        v.push(child);
4733        self.children = v.into();
4734        self.estimated_total_children += estimated + 1;
4735    }
4736
4737    #[inline(always)]
4738    pub fn set_children(&mut self, children: DomVec) {
4739        let children_estimated = children
4740            .iter()
4741            .map(|s| s.estimated_total_children + 1)
4742            .sum();
4743        self.children = children;
4744        self.estimated_total_children = children_estimated;
4745    }
4746
4747    pub fn copy_except_for_root(&mut self) -> Self {
4748        Self {
4749            root: self.root.copy_special(),
4750            children: self.children.clone(),
4751            estimated_total_children: self.estimated_total_children,
4752        }
4753    }
4754    pub fn node_count(&self) -> usize {
4755        self.estimated_total_children + 1
4756    }
4757
4758    pub fn style(&mut self, css: azul_css::css::Css) -> StyledDom {
4759        StyledDom::create(self, css)
4760    }
4761    #[inline(always)]
4762    pub fn with_children(mut self, children: DomVec) -> Self {
4763        self.set_children(children);
4764        self
4765    }
4766    #[inline(always)]
4767    pub fn with_child(mut self, child: Self) -> Self {
4768        self.add_child(child);
4769        self
4770    }
4771    #[inline(always)]
4772    pub fn with_node_type(mut self, node_type: NodeType) -> Self {
4773        self.root.set_node_type(node_type);
4774        self
4775    }
4776    #[inline(always)]
4777    pub fn with_id(mut self, id: AzString) -> Self {
4778        self.root.add_id(id);
4779        self
4780    }
4781    #[inline(always)]
4782    pub fn with_class(mut self, class: AzString) -> Self {
4783        self.root.add_class(class);
4784        self
4785    }
4786    #[inline(always)]
4787    pub fn with_callback<C: Into<CoreCallback>>(
4788        mut self,
4789        event: EventFilter,
4790        data: RefAny,
4791        callback: C,
4792    ) -> Self {
4793        self.root.add_callback(event, data, callback);
4794        self
4795    }
4796    #[inline(always)]
4797    pub fn with_css_property(mut self, prop: CssProperty) -> Self {
4798        self.root.add_css_property(prop);
4799        self
4800    }
4801    #[inline(always)]
4802    pub fn with_hover_css_property(mut self, prop: CssProperty) -> Self {
4803        self.root.add_hover_css_property(prop);
4804        self
4805    }
4806    #[inline(always)]
4807    pub fn with_active_css_property(mut self, prop: CssProperty) -> Self {
4808        self.root.add_active_css_property(prop);
4809        self
4810    }
4811    #[inline(always)]
4812    pub fn with_focus_css_property(mut self, prop: CssProperty) -> Self {
4813        self.root.add_focus_css_property(prop);
4814        self
4815    }
4816    #[inline(always)]
4817    pub fn with_tab_index(mut self, tab_index: TabIndex) -> Self {
4818        self.root.set_tab_index(tab_index);
4819        self
4820    }
4821    #[inline(always)]
4822    pub fn with_contenteditable(mut self, contenteditable: bool) -> Self {
4823        self.root.set_contenteditable(contenteditable);
4824        self
4825    }
4826    #[inline(always)]
4827    pub fn with_dataset(mut self, data: OptionRefAny) -> Self {
4828        self.root.dataset = data;
4829        self
4830    }
4831    #[inline(always)]
4832    pub fn with_ids_and_classes(mut self, ids_and_classes: IdOrClassVec) -> Self {
4833        self.root.ids_and_classes = ids_and_classes;
4834        self
4835    }
4836
4837    /// Adds an attribute to this DOM element.
4838    #[inline(always)]
4839    pub fn with_attribute(mut self, attr: AttributeType) -> Self {
4840        let mut attrs = self.root.attributes.clone();
4841        let mut v = attrs.into_library_owned_vec();
4842        v.push(attr);
4843        self.root.attributes = v.into();
4844        self
4845    }
4846
4847    /// Adds multiple attributes to this DOM element.
4848    #[inline(always)]
4849    pub fn with_attributes(mut self, attributes: AttributeVec) -> Self {
4850        self.root.attributes = attributes;
4851        self
4852    }
4853
4854    #[inline(always)]
4855    pub fn with_callbacks(mut self, callbacks: CoreCallbackDataVec) -> Self {
4856        self.root.callbacks = callbacks;
4857        self
4858    }
4859    #[inline(always)]
4860    pub fn with_css_props(mut self, css_props: CssPropertyWithConditionsVec) -> Self {
4861        self.root.css_props = css_props;
4862        self
4863    }
4864
4865    /// Assigns a stable key to the root node of this DOM for reconciliation.
4866    ///
4867    /// This is crucial for performance and correct state preservation when
4868    /// lists of items change order or items are inserted/removed.
4869    ///
4870    /// # Example
4871    /// ```rust
4872    /// Dom::create_div()
4873    ///     .with_key("user-avatar-123")
4874    /// ```
4875    #[inline]
4876    pub fn with_key<K: core::hash::Hash>(mut self, key: K) -> Self {
4877        self.root.set_key(key);
4878        self
4879    }
4880
4881    /// Registers a callback to merge dataset state from the previous frame.
4882    ///
4883    /// This is used for components that maintain heavy internal state (video players,
4884    /// WebGL contexts, network connections) that should not be destroyed and recreated
4885    /// on every render frame.
4886    ///
4887    /// The callback receives both datasets as `RefAny` (cheap shallow clones) and
4888    /// returns the `RefAny` that should be used for the new node.
4889    #[inline]
4890    pub fn with_merge_callback<C: Into<DatasetMergeCallback>>(mut self, callback: C) -> Self {
4891        self.root.set_merge_callback(callback);
4892        self
4893    }
4894
4895    pub fn set_inline_style(&mut self, style: &str) {
4896        self.root.set_inline_style(style);
4897    }
4898
4899    pub fn with_inline_style(mut self, style: &str) -> Self {
4900        self.set_inline_style(style);
4901        self
4902    }
4903
4904    /// Sets inline CSS styles for the hover state on the root node
4905    pub fn set_inline_hover_style(&mut self, style: &str) {
4906        self.root.set_inline_hover_style(style);
4907    }
4908
4909    /// Builder method for setting inline CSS styles for the hover state
4910    pub fn with_inline_hover_style(mut self, style: &str) -> Self {
4911        self.set_inline_hover_style(style);
4912        self
4913    }
4914
4915    /// Sets inline CSS styles for the active state on the root node
4916    pub fn set_inline_active_style(&mut self, style: &str) {
4917        self.root.set_inline_active_style(style);
4918    }
4919
4920    /// Builder method for setting inline CSS styles for the active state
4921    pub fn with_inline_active_style(mut self, style: &str) -> Self {
4922        self.set_inline_active_style(style);
4923        self
4924    }
4925
4926    /// Sets inline CSS styles for the focus state on the root node
4927    pub fn set_inline_focus_style(&mut self, style: &str) {
4928        self.root.set_inline_focus_style(style);
4929    }
4930
4931    /// Builder method for setting inline CSS styles for the focus state
4932    pub fn with_inline_focus_style(mut self, style: &str) -> Self {
4933        self.set_inline_focus_style(style);
4934        self
4935    }
4936
4937    /// Sets the context menu for the root node
4938    #[inline]
4939    pub fn set_context_menu(&mut self, context_menu: Menu) {
4940        self.root.set_context_menu(context_menu);
4941    }
4942
4943    #[inline]
4944    pub fn with_context_menu(mut self, context_menu: Menu) -> Self {
4945        self.set_context_menu(context_menu);
4946        self
4947    }
4948
4949    /// Sets the menu bar for the root node
4950    #[inline]
4951    pub fn set_menu_bar(&mut self, menu_bar: Menu) {
4952        self.root.set_menu_bar(menu_bar);
4953    }
4954
4955    #[inline]
4956    pub fn with_menu_bar(mut self, menu_bar: Menu) -> Self {
4957        self.set_menu_bar(menu_bar);
4958        self
4959    }
4960
4961    #[inline]
4962    pub fn with_clip_mask(mut self, clip_mask: ImageMask) -> Self {
4963        self.root.set_clip_mask(clip_mask);
4964        self
4965    }
4966
4967    #[inline]
4968    pub fn with_accessibility_info(mut self, accessibility_info: AccessibilityInfo) -> Self {
4969        self.root.set_accessibility_info(accessibility_info);
4970        self
4971    }
4972
4973    pub fn fixup_children_estimated(&mut self) -> usize {
4974        if self.children.is_empty() {
4975            self.estimated_total_children = 0;
4976        } else {
4977            self.estimated_total_children = self
4978                .children
4979                .iter_mut()
4980                .map(|s| s.fixup_children_estimated() + 1)
4981                .sum();
4982        }
4983        return self.estimated_total_children;
4984    }
4985}
4986
4987impl core::iter::FromIterator<Dom> for Dom {
4988    fn from_iter<I: IntoIterator<Item = Dom>>(iter: I) -> Self {
4989        let mut estimated_total_children = 0;
4990        let children = iter
4991            .into_iter()
4992            .map(|c| {
4993                estimated_total_children += c.estimated_total_children + 1;
4994                c
4995            })
4996            .collect::<Vec<Dom>>();
4997
4998        Dom {
4999            root: NodeData::create_div(),
5000            children: children.into(),
5001            estimated_total_children,
5002        }
5003    }
5004}
5005
5006impl fmt::Debug for Dom {
5007    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
5008        fn print_dom(d: &Dom, f: &mut fmt::Formatter) -> fmt::Result {
5009            write!(f, "Dom {{\r\n")?;
5010            write!(f, "\troot: {:#?}\r\n", d.root)?;
5011            write!(
5012                f,
5013                "\testimated_total_children: {:#?}\r\n",
5014                d.estimated_total_children
5015            )?;
5016            write!(f, "\tchildren: [\r\n")?;
5017            for c in d.children.iter() {
5018                print_dom(c, f)?;
5019            }
5020            write!(f, "\t]\r\n")?;
5021            write!(f, "}}\r\n")?;
5022            Ok(())
5023        }
5024
5025        print_dom(self, f)
5026    }
5027}