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
//! and the main `Dom` and `CompactDom` structures.
6

            
7
#[cfg(not(feature = "std"))]
8
use alloc::string::ToString;
9
use alloc::{boxed::Box, collections::btree_map::BTreeMap, string::String, vec::Vec};
10
use core::{
11
    fmt,
12
    hash::{Hash, Hasher},
13
    iter::FromIterator,
14
    mem,
15
    sync::atomic::{AtomicUsize, Ordering},
16
};
17

            
18
use azul_css::{
19
    css::{BoxOrStatic, 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-exported from a11y.rs and events.rs
30
pub use crate::a11y::*;
31
pub use crate::events::{
32
    ApplicationEventFilter, ComponentEventFilter, EventFilter, FocusEventFilter, HoverEventFilter,
33
    WindowEventFilter,
34
};
35
pub use crate::id::{Node, NodeHierarchy, NodeId};
36
use crate::{
37
    callbacks::{
38
        CoreCallback, CoreCallbackData, CoreCallbackDataVec, CoreCallbackType, VirtualViewCallback,
39
        VirtualViewCallbackType,
40
    },
41
    geom::LogicalPosition,
42
    id::{NodeDataContainer, NodeDataContainerRef, NodeDataContainerRefMut},
43
    menu::Menu,
44
    prop_cache::{CssPropertyCache, CssPropertyCachePtr},
45
    refany::{OptionRefAny, RefAny},
46
    resources::{
47
        image_ref_get_hash, CoreImageCallback, ImageMask, ImageRef, ImageRefHash, RendererResources,
48
    },
49
    styled_dom::{
50
        CompactDom, NodeHierarchyItemId, StyleFontFamilyHash, StyledDom, StyledNode,
51
        StyledNodeState,
52
    },
53
    window::OptionVirtualKeyCodeCombo,
54
};
55
pub use azul_css::dynamic_selector::{CssPropertyWithConditions, CssPropertyWithConditionsVec};
56

            
57
static TAG_ID: AtomicUsize = AtomicUsize::new(1);
58

            
59
/// Strongly-typed input element types for HTML `<input>` elements.
60
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
61
#[repr(C)]
62
pub enum InputType {
63
    /// Text input (default)
64
    Text,
65
    /// Button
66
    Button,
67
    /// Checkbox
68
    Checkbox,
69
    /// Color picker
70
    Color,
71
    /// Date picker
72
    Date,
73
    /// Date and time picker
74
    Datetime,
75
    /// Date and time picker (local)
76
    DatetimeLocal,
77
    /// Email address input
78
    Email,
79
    /// File upload
80
    File,
81
    /// Hidden input
82
    Hidden,
83
    /// Image button
84
    Image,
85
    /// Month picker
86
    Month,
87
    /// Number input
88
    Number,
89
    /// Password input
90
    Password,
91
    /// Radio button
92
    Radio,
93
    /// Range slider
94
    Range,
95
    /// Reset button
96
    Reset,
97
    /// Search input
98
    Search,
99
    /// Submit button
100
    Submit,
101
    /// Telephone number input
102
    Tel,
103
    /// Time picker
104
    Time,
105
    /// URL input
106
    Url,
107
    /// Week picker
108
    Week,
109
}
110

            
111
impl InputType {
112
    /// Returns the HTML attribute value for this input type
113
    pub const fn as_str(&self) -> &'static str {
114
        match self {
115
            InputType::Text => "text",
116
            InputType::Button => "button",
117
            InputType::Checkbox => "checkbox",
118
            InputType::Color => "color",
119
            InputType::Date => "date",
120
            InputType::Datetime => "datetime",
121
            InputType::DatetimeLocal => "datetime-local",
122
            InputType::Email => "email",
123
            InputType::File => "file",
124
            InputType::Hidden => "hidden",
125
            InputType::Image => "image",
126
            InputType::Month => "month",
127
            InputType::Number => "number",
128
            InputType::Password => "password",
129
            InputType::Radio => "radio",
130
            InputType::Range => "range",
131
            InputType::Reset => "reset",
132
            InputType::Search => "search",
133
            InputType::Submit => "submit",
134
            InputType::Tel => "tel",
135
            InputType::Time => "time",
136
            InputType::Url => "url",
137
            InputType::Week => "week",
138
        }
139
    }
140
}
141

            
142
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
143
#[repr(C)]
144
pub struct TagId {
145
    pub inner: u64,
146
}
147

            
148
impl ::core::fmt::Display for TagId {
149
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150
        f.debug_struct("TagId").field("inner", &self.inner).finish()
151
    }
152
}
153

            
154
impl_option!(
155
    TagId,
156
    OptionTagId,
157
    [Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash]
158
);
159

            
160
impl TagId {
161
    pub const fn into_crate_internal(&self) -> TagId {
162
        TagId { inner: self.inner }
163
    }
164
19140
    pub const fn from_crate_internal(t: TagId) -> Self {
165
19140
        TagId { inner: t.inner }
166
19140
    }
167

            
168
    /// Creates a new, unique hit-testing tag ID.
169
    /// Wraps around to 1 on overflow (0 is reserved for "no tag").
170
19140
    pub fn unique() -> Self {
171
        loop {
172
19350
            let current = TAG_ID.load(Ordering::SeqCst);
173
19350
            let next = if current == usize::MAX { 1 } else { current + 1 };
174
19350
            if TAG_ID.compare_exchange(current, next, Ordering::SeqCst, Ordering::SeqCst).is_ok() {
175
19140
                return TagId { inner: current as u64 };
176
210
            }
177
        }
178
19140
    }
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)]
185
pub struct ScrollTagId {
186
    pub inner: TagId,
187
}
188

            
189
impl ::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

            
197
impl ::core::fmt::Debug for ScrollTagId {
198
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
199
        write!(f, "{}", self)
200
    }
201
}
202

            
203
impl 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)]
216
pub 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)]
225
pub struct DomNodeHash {
226
    pub inner: u64,
227
}
228

            
229
impl ::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)]
239
pub 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 elements — container
455
    /// SVG `<svg>` root graphics container.
456
    Svg,
457
    /// SVG `<g>` group element.
458
    SvgG,
459
    /// SVG `<defs>` — reusable definitions (not rendered directly).
460
    SvgDefs,
461
    /// SVG `<symbol>` — like defs but with its own viewBox.
462
    SvgSymbol,
463
    /// SVG `<use>` — references and instantiates a defs element.
464
    SvgUse,
465
    /// SVG `<switch>` — conditional processing.
466
    SvgSwitch,
467

            
468
    // SVG elements — shape
469
    /// SVG `<path>` element.
470
    SvgPath,
471
    /// SVG `<circle>` element.
472
    SvgCircle,
473
    /// SVG `<rect>` element.
474
    SvgRect,
475
    /// SVG `<ellipse>` element.
476
    SvgEllipse,
477
    /// SVG `<line>` element.
478
    SvgLine,
479
    /// SVG `<polygon>` element.
480
    SvgPolygon,
481
    /// SVG `<polyline>` element.
482
    SvgPolyline,
483

            
484
    // SVG elements — text
485
    /// SVG `<text>` element.
486
    SvgText(AzString),
487
    /// SVG `<tspan>` element.
488
    SvgTspan,
489
    /// SVG `<textPath>` element.
490
    SvgTextPath,
491

            
492
    // SVG elements — paint servers
493
    /// SVG `<linearGradient>` element.
494
    SvgLinearGradient,
495
    /// SVG `<radialGradient>` element.
496
    SvgRadialGradient,
497
    /// SVG `<stop>` gradient stop element.
498
    SvgStop,
499
    /// SVG `<pattern>` element.
500
    SvgPattern,
501

            
502
    // SVG elements — clipping / masking
503
    /// SVG `<clipPath>` element.
504
    SvgClipPathElement,
505
    /// SVG `<mask>` element.
506
    SvgMask,
507

            
508
    // SVG elements — filter
509
    /// SVG `<filter>` container element.
510
    SvgFilter,
511
    /// SVG `<feBlend>`.
512
    SvgFeBlend,
513
    /// SVG `<feColorMatrix>`.
514
    SvgFeColorMatrix,
515
    /// SVG `<feComponentTransfer>`.
516
    SvgFeComponentTransfer,
517
    /// SVG `<feComposite>`.
518
    SvgFeComposite,
519
    /// SVG `<feConvolveMatrix>`.
520
    SvgFeConvolveMatrix,
521
    /// SVG `<feDiffuseLighting>`.
522
    SvgFeDiffuseLighting,
523
    /// SVG `<feDisplacementMap>`.
524
    SvgFeDisplacementMap,
525
    /// SVG `<feDistantLight>`.
526
    SvgFeDistantLight,
527
    /// SVG `<feDropShadow>`.
528
    SvgFeDropShadow,
529
    /// SVG `<feFlood>`.
530
    SvgFeFlood,
531
    /// SVG `<feFuncR>`.
532
    SvgFeFuncR,
533
    /// SVG `<feFuncG>`.
534
    SvgFeFuncG,
535
    /// SVG `<feFuncB>`.
536
    SvgFeFuncB,
537
    /// SVG `<feFuncA>`.
538
    SvgFeFuncA,
539
    /// SVG `<feGaussianBlur>`.
540
    SvgFeGaussianBlur,
541
    /// SVG `<feImage>`.
542
    SvgFeImage,
543
    /// SVG `<feMerge>`.
544
    SvgFeMerge,
545
    /// SVG `<feMergeNode>`.
546
    SvgFeMergeNode,
547
    /// SVG `<feMorphology>`.
548
    SvgFeMorphology,
549
    /// SVG `<feOffset>`.
550
    SvgFeOffset,
551
    /// SVG `<fePointLight>`.
552
    SvgFePointLight,
553
    /// SVG `<feSpecularLighting>`.
554
    SvgFeSpecularLighting,
555
    /// SVG `<feSpotLight>`.
556
    SvgFeSpotLight,
557
    /// SVG `<feTile>`.
558
    SvgFeTile,
559
    /// SVG `<feTurbulence>`.
560
    SvgFeTurbulence,
561

            
562
    // SVG elements — marker / image / foreign
563
    /// SVG `<marker>` element (not the CSS ::marker pseudo-element).
564
    SvgMarker,
565
    /// SVG `<image>` element (embedded raster image in SVG).
566
    SvgImage(ImageRef),
567
    /// SVG `<foreignObject>` element.
568
    SvgForeignObject,
569

            
570
    // SVG elements — descriptive / structural
571
    /// SVG `<title>` element (distinct from HTML `<title>`).
572
    SvgTitle,
573
    /// SVG `<desc>` element.
574
    SvgDesc,
575
    /// SVG `<metadata>` element.
576
    SvgMetadata,
577
    /// SVG `<a>` hyperlink element (distinct from HTML `<a>`).
578
    SvgA,
579
    /// SVG `<view>` element.
580
    SvgView,
581
    /// SVG `<style>` element (distinct from HTML `<style>`).
582
    SvgStyle,
583
    /// SVG `<script>` element (distinct from HTML `<script>`).
584
    SvgScript,
585

            
586
    // SVG elements — animation
587
    /// SVG `<animate>` element.
588
    SvgAnimate,
589
    /// SVG `<animateMotion>` element.
590
    SvgAnimateMotion,
591
    /// SVG `<animateTransform>` element.
592
    SvgAnimateTransform,
593
    /// SVG `<set>` element.
594
    SvgSet,
595
    /// SVG `<mpath>` element.
596
    SvgMpath,
597

            
598
    // Metadata elements
599
    /// Document title.
600
    Title,
601
    /// Metadata.
602
    Meta,
603
    /// External resource link.
604
    Link,
605
    /// Embedded or referenced script.
606
    Script,
607
    /// Style information.
608
    Style,
609
    /// Base URL for relative URLs.
610
    Base,
611

            
612
    // Pseudo-elements (transformed into real elements)
613
    /// ::before pseudo-element.
614
    Before,
615
    /// ::after pseudo-element.
616
    After,
617
    /// ::marker pseudo-element.
618
    Marker,
619
    /// ::placeholder pseudo-element.
620
    Placeholder,
621

            
622
    // Special content types
623
    /// Text content, ::text.
624
    /// Uses BoxOrStatic to keep NodeType small (~16B vs ~72B with inline AzString)
625
    /// and to allow static text references in the future.
626
    Text(BoxOrStatic<AzString>),
627
    /// Image element, ::image.
628
    /// Uses BoxOrStatic to keep NodeType small.
629
    Image(BoxOrStatic<ImageRef>),
630
    /// VirtualView (embedded content) - payload stored in NodeDataExt.virtual_view
631
    VirtualView,
632
    /// Icon element - resolved to actual content by IconProvider.
633
    /// The string is the icon name (e.g., "home", "settings", "search").
634
    /// Uses BoxOrStatic to keep NodeType small.
635
    Icon(BoxOrStatic<AzString>),
636
    /// Invisible probe node that signals "this subtree needs the user's
637
    /// GPS / network location". Zero-size in layout, skipped in the
638
    /// display list. The `GeolocationManager` walks the styled DOM for
639
    /// these at end-of-layout and starts / stops the matching native
640
    /// subscription. See `SUPER_PLAN_2.md` §1.5 + research/08.
641
    GeolocationProbe(crate::geolocation::GeolocationProbeConfig),
642
}
643

            
644
/// Type alias: `BoxOrStatic<ImageRef>` — used by NodeType::Image for FFI monomorphization.
645
pub type BoxOrStaticImageRef = BoxOrStatic<ImageRef>;
646

            
647
impl_option!(NodeType, OptionNodeType, copy = false, [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]);
648

            
649
impl NodeType {
650
65971
    fn into_library_owned_nodetype(&self) -> Self {
651
        use self::NodeType::*;
652
65971
        match self {
653
612
            Html => Html,
654
            Head => Head,
655
2058
            Body => Body,
656
45897
            Div => Div,
657
500
            P => P,
658
17
            Article => Article,
659
17
            Section => Section,
660
            Nav => Nav,
661
            Aside => Aside,
662
            Header => Header,
663
            Footer => Footer,
664
            Main => Main,
665
            Figure => Figure,
666
            FigCaption => FigCaption,
667
127
            H1 => H1,
668
            H2 => H2,
669
            H3 => H3,
670
            H4 => H4,
671
            H5 => H5,
672
            H6 => H6,
673
            Br => Br,
674
            Hr => Hr,
675
            Pre => Pre,
676
            BlockQuote => BlockQuote,
677
            Address => Address,
678
            Details => Details,
679
            Summary => Summary,
680
            Dialog => Dialog,
681
            Ul => Ul,
682
            Ol => Ol,
683
            Li => Li,
684
            Dl => Dl,
685
            Dt => Dt,
686
            Dd => Dd,
687
            Menu => Menu,
688
            MenuItem => MenuItem,
689
            Dir => Dir,
690
1344
            Table => Table,
691
            Caption => Caption,
692
            THead => THead,
693
            TBody => TBody,
694
            TFoot => TFoot,
695
1386
            Tr => Tr,
696
            Th => Th,
697
3486
            Td => Td,
698
            ColGroup => ColGroup,
699
            Col => Col,
700
            Form => Form,
701
            FieldSet => FieldSet,
702
            Legend => Legend,
703
            Label => Label,
704
17
            Input => Input,
705
            Button => Button,
706
            Select => Select,
707
            OptGroup => OptGroup,
708
            SelectOption => SelectOption,
709
            TextArea => TextArea,
710
            Output => Output,
711
            Progress => Progress,
712
            Meter => Meter,
713
            DataList => DataList,
714
2320
            Span => Span,
715
2092
            A => A,
716
            Em => Em,
717
            Strong => Strong,
718
            B => B,
719
            I => I,
720
            U => U,
721
            S => S,
722
            Mark => Mark,
723
            Del => Del,
724
            Ins => Ins,
725
            Code => Code,
726
            Samp => Samp,
727
            Kbd => Kbd,
728
            Var => Var,
729
            Cite => Cite,
730
            Dfn => Dfn,
731
            Abbr => Abbr,
732
            Acronym => Acronym,
733
            Q => Q,
734
            Time => Time,
735
            Sub => Sub,
736
            Sup => Sup,
737
            Small => Small,
738
            Big => Big,
739
            Bdo => Bdo,
740
            Bdi => Bdi,
741
            Wbr => Wbr,
742
            Ruby => Ruby,
743
            Rt => Rt,
744
            Rtc => Rtc,
745
            Rp => Rp,
746
            Data => Data,
747
            Canvas => Canvas,
748
            Object => Object,
749
            Param => Param,
750
            Embed => Embed,
751
            Audio => Audio,
752
            Video => Video,
753
            Source => Source,
754
            Track => Track,
755
            Map => Map,
756
            Area => Area,
757
            // SVG container
758
            Svg => Svg, SvgG => SvgG, SvgDefs => SvgDefs, SvgSymbol => SvgSymbol,
759
            SvgUse => SvgUse, SvgSwitch => SvgSwitch,
760
            // SVG shape
761
            SvgPath => SvgPath, SvgCircle => SvgCircle, SvgRect => SvgRect,
762
            SvgEllipse => SvgEllipse, SvgLine => SvgLine,
763
            SvgPolygon => SvgPolygon, SvgPolyline => SvgPolyline,
764
            // SVG text
765
            SvgText(s) => SvgText(s.clone_self()),
766
            SvgTspan => SvgTspan, SvgTextPath => SvgTextPath,
767
            // SVG paint
768
            SvgLinearGradient => SvgLinearGradient, SvgRadialGradient => SvgRadialGradient,
769
            SvgStop => SvgStop, SvgPattern => SvgPattern,
770
            // SVG clip/mask
771
            SvgClipPathElement => SvgClipPathElement, SvgMask => SvgMask,
772
            // SVG filter
773
            SvgFilter => SvgFilter, SvgFeBlend => SvgFeBlend,
774
            SvgFeColorMatrix => SvgFeColorMatrix,
775
            SvgFeComponentTransfer => SvgFeComponentTransfer,
776
            SvgFeComposite => SvgFeComposite, SvgFeConvolveMatrix => SvgFeConvolveMatrix,
777
            SvgFeDiffuseLighting => SvgFeDiffuseLighting,
778
            SvgFeDisplacementMap => SvgFeDisplacementMap,
779
            SvgFeDistantLight => SvgFeDistantLight, SvgFeDropShadow => SvgFeDropShadow,
780
            SvgFeFlood => SvgFeFlood,
781
            SvgFeFuncR => SvgFeFuncR, SvgFeFuncG => SvgFeFuncG,
782
            SvgFeFuncB => SvgFeFuncB, SvgFeFuncA => SvgFeFuncA,
783
            SvgFeGaussianBlur => SvgFeGaussianBlur, SvgFeImage => SvgFeImage,
784
            SvgFeMerge => SvgFeMerge, SvgFeMergeNode => SvgFeMergeNode,
785
            SvgFeMorphology => SvgFeMorphology, SvgFeOffset => SvgFeOffset,
786
            SvgFePointLight => SvgFePointLight,
787
            SvgFeSpecularLighting => SvgFeSpecularLighting,
788
            SvgFeSpotLight => SvgFeSpotLight,
789
            SvgFeTile => SvgFeTile, SvgFeTurbulence => SvgFeTurbulence,
790
            // SVG marker/image/foreign
791
            SvgMarker => SvgMarker,
792
            SvgImage(i) => SvgImage(i.clone()),
793
            SvgForeignObject => SvgForeignObject,
794
            // SVG descriptive/structural
795
            SvgTitle => SvgTitle, SvgDesc => SvgDesc, SvgMetadata => SvgMetadata,
796
            SvgA => SvgA, SvgView => SvgView,
797
            SvgStyle => SvgStyle, SvgScript => SvgScript,
798
            // SVG animation
799
            SvgAnimate => SvgAnimate, SvgAnimateMotion => SvgAnimateMotion,
800
            SvgAnimateTransform => SvgAnimateTransform,
801
            SvgSet => SvgSet, SvgMpath => SvgMpath,
802
            // HTML metadata
803
            Title => Title,
804
            Meta => Meta,
805
            Link => Link,
806
            Script => Script,
807
            Style => Style,
808
            Base => Base,
809
            Before => Before,
810
            After => After,
811
            Marker => Marker,
812
            Placeholder => Placeholder,
813

            
814
6098
            Text(s) => Text(BoxOrStatic::heap(s.clone_self())),
815
            Image(i) => Image(i.clone()),
816
            VirtualView => VirtualView,
817
            Icon(s) => Icon(BoxOrStatic::heap(s.clone_self())),
818
            GeolocationProbe(cfg) => GeolocationProbe(*cfg),
819
        }
820
65971
    }
821

            
822
    pub fn format(&self) -> Option<String> {
823
        use self::NodeType::*;
824
        match self {
825
            Text(s) => Some(format!("{}", s)),
826
            Image(id) => Some(format!("image({:?})", id)),
827
            VirtualView => Some("virtualized-view".to_string()),
828
            Icon(s) => Some(format!("icon({})", s)),
829
            GeolocationProbe(cfg) => Some(format!(
830
                "geolocation-probe(hi={}, bg={}, max={}m, every={}ms)",
831
                cfg.high_accuracy, cfg.background, cfg.max_accuracy_m, cfg.min_interval_ms
832
            )),
833
            _ => None,
834
        }
835
    }
836

            
837
    /// Returns the NodeTypeTag for CSS selector matching.
838
34700
    pub fn get_path(&self) -> NodeTypeTag {
839
34700
        match self {
840
1740
            Self::Html => NodeTypeTag::Html,
841
            Self::Head => NodeTypeTag::Head,
842
4345
            Self::Body => NodeTypeTag::Body,
843
5782
            Self::Div => NodeTypeTag::Div,
844
874
            Self::P => NodeTypeTag::P,
845
            Self::Article => NodeTypeTag::Article,
846
            Self::Section => NodeTypeTag::Section,
847
            Self::Nav => NodeTypeTag::Nav,
848
            Self::Aside => NodeTypeTag::Aside,
849
            Self::Header => NodeTypeTag::Header,
850
            Self::Footer => NodeTypeTag::Footer,
851
            Self::Main => NodeTypeTag::Main,
852
            Self::Figure => NodeTypeTag::Figure,
853
            Self::FigCaption => NodeTypeTag::FigCaption,
854
42
            Self::H1 => NodeTypeTag::H1,
855
            Self::H2 => NodeTypeTag::H2,
856
            Self::H3 => NodeTypeTag::H3,
857
            Self::H4 => NodeTypeTag::H4,
858
            Self::H5 => NodeTypeTag::H5,
859
            Self::H6 => NodeTypeTag::H6,
860
42
            Self::Br => NodeTypeTag::Br,
861
            Self::Hr => NodeTypeTag::Hr,
862
126
            Self::Pre => NodeTypeTag::Pre,
863
            Self::BlockQuote => NodeTypeTag::BlockQuote,
864
            Self::Address => NodeTypeTag::Address,
865
            Self::Details => NodeTypeTag::Details,
866
            Self::Summary => NodeTypeTag::Summary,
867
            Self::Dialog => NodeTypeTag::Dialog,
868
            Self::Ul => NodeTypeTag::Ul,
869
            Self::Ol => NodeTypeTag::Ol,
870
            Self::Li => NodeTypeTag::Li,
871
            Self::Dl => NodeTypeTag::Dl,
872
            Self::Dt => NodeTypeTag::Dt,
873
            Self::Dd => NodeTypeTag::Dd,
874
            Self::Menu => NodeTypeTag::Menu,
875
            Self::MenuItem => NodeTypeTag::MenuItem,
876
            Self::Dir => NodeTypeTag::Dir,
877
1512
            Self::Table => NodeTypeTag::Table,
878
            Self::Caption => NodeTypeTag::Caption,
879
            Self::THead => NodeTypeTag::THead,
880
            Self::TBody => NodeTypeTag::TBody,
881
            Self::TFoot => NodeTypeTag::TFoot,
882
1596
            Self::Tr => NodeTypeTag::Tr,
883
            Self::Th => NodeTypeTag::Th,
884
3780
            Self::Td => NodeTypeTag::Td,
885
            Self::ColGroup => NodeTypeTag::ColGroup,
886
            Self::Col => NodeTypeTag::Col,
887
            Self::Form => NodeTypeTag::Form,
888
            Self::FieldSet => NodeTypeTag::FieldSet,
889
            Self::Legend => NodeTypeTag::Legend,
890
            Self::Label => NodeTypeTag::Label,
891
            Self::Input => NodeTypeTag::Input,
892
            Self::Button => NodeTypeTag::Button,
893
            Self::Select => NodeTypeTag::Select,
894
            Self::OptGroup => NodeTypeTag::OptGroup,
895
            Self::SelectOption => NodeTypeTag::SelectOption,
896
            Self::TextArea => NodeTypeTag::TextArea,
897
            Self::Output => NodeTypeTag::Output,
898
            Self::Progress => NodeTypeTag::Progress,
899
            Self::Meter => NodeTypeTag::Meter,
900
            Self::DataList => NodeTypeTag::DataList,
901
2478
            Self::Span => NodeTypeTag::Span,
902
2058
            Self::A => NodeTypeTag::A,
903
            Self::Em => NodeTypeTag::Em,
904
            Self::Strong => NodeTypeTag::Strong,
905
            Self::B => NodeTypeTag::B,
906
            Self::I => NodeTypeTag::I,
907
            Self::U => NodeTypeTag::U,
908
            Self::S => NodeTypeTag::S,
909
            Self::Mark => NodeTypeTag::Mark,
910
            Self::Del => NodeTypeTag::Del,
911
            Self::Ins => NodeTypeTag::Ins,
912
            Self::Code => NodeTypeTag::Code,
913
            Self::Samp => NodeTypeTag::Samp,
914
            Self::Kbd => NodeTypeTag::Kbd,
915
            Self::Var => NodeTypeTag::Var,
916
            Self::Cite => NodeTypeTag::Cite,
917
            Self::Dfn => NodeTypeTag::Dfn,
918
            Self::Abbr => NodeTypeTag::Abbr,
919
            Self::Acronym => NodeTypeTag::Acronym,
920
            Self::Q => NodeTypeTag::Q,
921
            Self::Time => NodeTypeTag::Time,
922
            Self::Sub => NodeTypeTag::Sub,
923
            Self::Sup => NodeTypeTag::Sup,
924
            Self::Small => NodeTypeTag::Small,
925
            Self::Big => NodeTypeTag::Big,
926
            Self::Bdo => NodeTypeTag::Bdo,
927
            Self::Bdi => NodeTypeTag::Bdi,
928
            Self::Wbr => NodeTypeTag::Wbr,
929
            Self::Ruby => NodeTypeTag::Ruby,
930
            Self::Rt => NodeTypeTag::Rt,
931
            Self::Rtc => NodeTypeTag::Rtc,
932
            Self::Rp => NodeTypeTag::Rp,
933
            Self::Data => NodeTypeTag::Data,
934
            Self::Canvas => NodeTypeTag::Canvas,
935
            Self::Object => NodeTypeTag::Object,
936
            Self::Param => NodeTypeTag::Param,
937
            Self::Embed => NodeTypeTag::Embed,
938
            Self::Audio => NodeTypeTag::Audio,
939
            Self::Video => NodeTypeTag::Video,
940
            Self::Source => NodeTypeTag::Source,
941
            Self::Track => NodeTypeTag::Track,
942
            Self::Map => NodeTypeTag::Map,
943
            Self::Area => NodeTypeTag::Area,
944
            // SVG — all variants map 1:1 to NodeTypeTag
945
            Self::Svg => NodeTypeTag::Svg,
946
            Self::SvgG => NodeTypeTag::SvgG,
947
            Self::SvgDefs => NodeTypeTag::SvgDefs,
948
            Self::SvgSymbol => NodeTypeTag::SvgSymbol,
949
            Self::SvgUse => NodeTypeTag::SvgUse,
950
            Self::SvgSwitch => NodeTypeTag::SvgSwitch,
951
            Self::SvgPath => NodeTypeTag::SvgPath,
952
            Self::SvgCircle => NodeTypeTag::SvgCircle,
953
            Self::SvgRect => NodeTypeTag::SvgRect,
954
            Self::SvgEllipse => NodeTypeTag::SvgEllipse,
955
            Self::SvgLine => NodeTypeTag::SvgLine,
956
            Self::SvgPolygon => NodeTypeTag::SvgPolygon,
957
            Self::SvgPolyline => NodeTypeTag::SvgPolyline,
958
            Self::SvgText(_) => NodeTypeTag::SvgText,
959
            Self::SvgTspan => NodeTypeTag::SvgTspan,
960
            Self::SvgTextPath => NodeTypeTag::SvgTextPath,
961
            Self::SvgLinearGradient => NodeTypeTag::SvgLinearGradient,
962
            Self::SvgRadialGradient => NodeTypeTag::SvgRadialGradient,
963
            Self::SvgStop => NodeTypeTag::SvgStop,
964
            Self::SvgPattern => NodeTypeTag::SvgPattern,
965
            Self::SvgClipPathElement => NodeTypeTag::SvgClipPathElement,
966
            Self::SvgMask => NodeTypeTag::SvgMask,
967
            Self::SvgFilter => NodeTypeTag::SvgFilter,
968
            Self::SvgFeBlend => NodeTypeTag::SvgFeBlend,
969
            Self::SvgFeColorMatrix => NodeTypeTag::SvgFeColorMatrix,
970
            Self::SvgFeComponentTransfer => NodeTypeTag::SvgFeComponentTransfer,
971
            Self::SvgFeComposite => NodeTypeTag::SvgFeComposite,
972
            Self::SvgFeConvolveMatrix => NodeTypeTag::SvgFeConvolveMatrix,
973
            Self::SvgFeDiffuseLighting => NodeTypeTag::SvgFeDiffuseLighting,
974
            Self::SvgFeDisplacementMap => NodeTypeTag::SvgFeDisplacementMap,
975
            Self::SvgFeDistantLight => NodeTypeTag::SvgFeDistantLight,
976
            Self::SvgFeDropShadow => NodeTypeTag::SvgFeDropShadow,
977
            Self::SvgFeFlood => NodeTypeTag::SvgFeFlood,
978
            Self::SvgFeFuncR => NodeTypeTag::SvgFeFuncR,
979
            Self::SvgFeFuncG => NodeTypeTag::SvgFeFuncG,
980
            Self::SvgFeFuncB => NodeTypeTag::SvgFeFuncB,
981
            Self::SvgFeFuncA => NodeTypeTag::SvgFeFuncA,
982
            Self::SvgFeGaussianBlur => NodeTypeTag::SvgFeGaussianBlur,
983
            Self::SvgFeImage => NodeTypeTag::SvgFeImage,
984
            Self::SvgFeMerge => NodeTypeTag::SvgFeMerge,
985
            Self::SvgFeMergeNode => NodeTypeTag::SvgFeMergeNode,
986
            Self::SvgFeMorphology => NodeTypeTag::SvgFeMorphology,
987
            Self::SvgFeOffset => NodeTypeTag::SvgFeOffset,
988
            Self::SvgFePointLight => NodeTypeTag::SvgFePointLight,
989
            Self::SvgFeSpecularLighting => NodeTypeTag::SvgFeSpecularLighting,
990
            Self::SvgFeSpotLight => NodeTypeTag::SvgFeSpotLight,
991
            Self::SvgFeTile => NodeTypeTag::SvgFeTile,
992
            Self::SvgFeTurbulence => NodeTypeTag::SvgFeTurbulence,
993
            Self::SvgMarker => NodeTypeTag::SvgMarker,
994
            Self::SvgImage(_) => NodeTypeTag::SvgImage,
995
            Self::SvgForeignObject => NodeTypeTag::SvgForeignObject,
996
            Self::SvgTitle => NodeTypeTag::SvgTitle,
997
            Self::SvgDesc => NodeTypeTag::SvgDesc,
998
            Self::SvgMetadata => NodeTypeTag::SvgMetadata,
999
            Self::SvgA => NodeTypeTag::SvgA,
            Self::SvgView => NodeTypeTag::SvgView,
            Self::SvgStyle => NodeTypeTag::SvgStyle,
            Self::SvgScript => NodeTypeTag::SvgScript,
            Self::SvgAnimate => NodeTypeTag::SvgAnimate,
            Self::SvgAnimateMotion => NodeTypeTag::SvgAnimateMotion,
            Self::SvgAnimateTransform => NodeTypeTag::SvgAnimateTransform,
            Self::SvgSet => NodeTypeTag::SvgSet,
            Self::SvgMpath => NodeTypeTag::SvgMpath,
            // HTML metadata
            Self::Title => NodeTypeTag::Title,
            Self::Meta => NodeTypeTag::Meta,
            Self::Link => NodeTypeTag::Link,
            Self::Script => NodeTypeTag::Script,
            Self::Style => NodeTypeTag::Style,
            Self::Base => NodeTypeTag::Base,
10325
            Self::Text(_) => NodeTypeTag::Text,
            Self::Image(_) => NodeTypeTag::Img,
            Self::VirtualView => NodeTypeTag::VirtualView,
            Self::Icon(_) => NodeTypeTag::Icon,
            Self::GeolocationProbe(_) => NodeTypeTag::GeolocationProbe,
            Self::Before => NodeTypeTag::Before,
            Self::After => NodeTypeTag::After,
            Self::Marker => NodeTypeTag::Marker,
            Self::Placeholder => NodeTypeTag::Placeholder,
        }
34700
    }
    /// Returns whether this node type is a semantic HTML element that should
    /// automatically generate an accessibility tree node.
    ///
    /// These are elements with inherent semantic meaning that assistive
    /// technologies should be aware of, even without explicit ARIA attributes.
    pub const fn is_semantic_for_accessibility(&self) -> bool {
        matches!(
            self,
            Self::Button
                | Self::Input
                | Self::TextArea
                | Self::Select
                | Self::A
                | Self::H1
                | Self::H2
                | Self::H3
                | Self::H4
                | Self::H5
                | Self::H6
                | Self::Article
                | Self::Section
                | Self::Nav
                | Self::Main
                | Self::Header
                | Self::Footer
                | Self::Aside
        )
    }
}
/// Represents the CSS formatting context for an element
#[derive(Clone, PartialEq)]
// +spec:display-property:844893 - block-level box establishing a new formatting context (BFC) modeled here
pub enum FormattingContext {
    /// Block-level formatting context
    Block {
        /// Whether this element establishes a new block formatting context
        establishes_new_context: bool,
    },
    /// Inline-level formatting context
    Inline,
    /// Inline-block (participates in an IFC but creates a BFC)
    InlineBlock,
    /// Flex formatting context
    Flex,
    /// Float (left or right)
    Float(LayoutFloat),
    /// Absolutely positioned (out of flow)
    OutOfFlow(LayoutPosition),
    /// Table formatting context (container)
    Table,
    /// Table row group formatting context (thead, tbody, tfoot)
    TableRowGroup,
    /// Table row formatting context
    TableRow,
    /// Table cell formatting context (td, th)
    TableCell,
    /// Table column group formatting context
    TableColumnGroup,
    /// Table caption formatting context
    TableCaption,
    /// Grid formatting context
    Grid,
    /// display:contents - element generates no box, children promoted to parent
    Contents,
    /// No formatting context (display: none)
    None,
}
impl fmt::Debug for FormattingContext {
61194
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61194
        match self {
            FormattingContext::Block {
11592
                establishes_new_context,
11592
            } => write!(
11592
                f,
11592
                "Block {{ establishes_new_context: {establishes_new_context:?} }}"
            ),
33474
            FormattingContext::Inline => write!(f, "Inline"),
252
            FormattingContext::InlineBlock => write!(f, "InlineBlock"),
294
            FormattingContext::Flex => write!(f, "Flex"),
            FormattingContext::Float(layout_float) => write!(f, "Float({layout_float:?})"),
            FormattingContext::OutOfFlow(layout_position) => {
                write!(f, "OutOfFlow({layout_position:?})")
            }
            FormattingContext::Grid => write!(f, "Grid"),
            FormattingContext::None => write!(f, "None"),
1596
            FormattingContext::Table => write!(f, "Table"),
            FormattingContext::TableRowGroup => write!(f, "TableRowGroup"),
210
            FormattingContext::TableRow => write!(f, "TableRow"),
13776
            FormattingContext::TableCell => write!(f, "TableCell"),
            FormattingContext::TableColumnGroup => write!(f, "TableColumnGroup"),
            FormattingContext::TableCaption => write!(f, "TableCaption"),
            FormattingContext::Contents => write!(f, "Contents"),
        }
61194
    }
}
impl Default for FormattingContext {
    fn default() -> Self {
        FormattingContext::Block {
            establishes_new_context: false,
        }
    }
}
/// Defines the type of event that can trigger a callback action.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C)]
pub enum On {
    /// Mouse cursor is hovering over the element.
    MouseOver,
    /// Mouse cursor has is over element and is pressed
    /// (not good for "click" events - use `MouseUp` instead).
    MouseDown,
    /// (Specialization of `MouseDown`). Fires only if the left mouse button
    /// has been pressed while cursor was over the element.
    LeftMouseDown,
    /// (Specialization of `MouseDown`). Fires only if the middle mouse button
    /// has been pressed while cursor was over the element.
    MiddleMouseDown,
    /// (Specialization of `MouseDown`). Fires only if the right mouse button
    /// has been pressed while cursor was over the element.
    RightMouseDown,
    /// Mouse button has been released while cursor was over the element.
    MouseUp,
    /// (Specialization of `MouseUp`). Fires only if the left mouse button has
    /// been released while cursor was over the element.
    LeftMouseUp,
    /// (Specialization of `MouseUp`). Fires only if the middle mouse button has
    /// been released while cursor was over the element.
    MiddleMouseUp,
    /// (Specialization of `MouseUp`). Fires only if the right mouse button has
    /// been released while cursor was over the element.
    RightMouseUp,
    /// Mouse cursor has entered the element.
    MouseEnter,
    /// Mouse cursor has left the element.
    MouseLeave,
    /// Mousewheel / touchpad scrolling.
    Scroll,
    /// The window received a unicode character (also respects the system locale).
    /// Check `keyboard_state.current_char` to get the current pressed character.
    TextInput,
    /// A **virtual keycode** was pressed. Note: This is only the virtual keycode,
    /// not the actual char. If you want to get the character, use `TextInput` instead.
    /// A virtual key does not have to map to a printable character.
    ///
    /// You can get all currently pressed virtual keycodes in the
    /// `keyboard_state.current_virtual_keycodes` and / or just the last keycode in the
    /// `keyboard_state.latest_virtual_keycode`.
    VirtualKeyDown,
    /// A **virtual keycode** was release. See `VirtualKeyDown` for more info.
    VirtualKeyUp,
    /// A file has been dropped on the element.
    HoveredFile,
    /// A file is being hovered on the element.
    DroppedFile,
    /// A file was hovered, but has exited the window.
    HoveredFileCancelled,
    /// Equivalent to `onfocus`.
    FocusReceived,
    /// Equivalent to `onblur`.
    FocusLost,
    // Accessibility-specific events
    /// Default action triggered by screen reader (usually same as click/activate)
    Default,
    /// Element should collapse (e.g., accordion panel, tree node)
    Collapse,
    /// Element should expand (e.g., accordion panel, tree node)
    Expand,
    /// Increment value (e.g., number input, slider)
    Increment,
    /// Decrement value (e.g., number input, slider)
    Decrement,
}
/// Contains the necessary information to render an embedded `VirtualView` node.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct VirtualViewNode {
    /// The callback function that returns the DOM for the virtualized view's content.
    pub callback: VirtualViewCallback,
    /// The application data passed to the virtualized view's layout callback.
    pub refany: RefAny,
}
/// An enum that holds either a CSS ID or a class name as a string.
#[repr(C, u8)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum IdOrClass {
    Id(AzString),
    Class(AzString),
}
impl_option!(
    IdOrClass,
    OptionIdOrClass,
    copy = false,
    [Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord]
);
impl_vec!(IdOrClass, IdOrClassVec, IdOrClassVecDestructor, IdOrClassVecDestructorType, IdOrClassVecSlice, OptionIdOrClass);
impl_vec_debug!(IdOrClass, IdOrClassVec);
impl_vec_partialord!(IdOrClass, IdOrClassVec);
impl_vec_ord!(IdOrClass, IdOrClassVec);
impl_vec_clone!(IdOrClass, IdOrClassVec, IdOrClassVecDestructor);
impl_vec_partialeq!(IdOrClass, IdOrClassVec);
impl_vec_eq!(IdOrClass, IdOrClassVec);
impl_vec_hash!(IdOrClass, IdOrClassVec);
impl IdOrClass {
    pub fn as_id(&self) -> Option<&str> {
        match self {
            IdOrClass::Id(s) => Some(s.as_str()),
            IdOrClass::Class(_) => None,
        }
    }
    pub fn as_class(&self) -> Option<&str> {
        match self {
            IdOrClass::Class(s) => Some(s.as_str()),
            IdOrClass::Id(_) => None,
        }
    }
}
/// Name-value pair for custom attributes (data-*, aria-*, etc.)
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct AttributeNameValue {
    pub attr_name: AzString,
    pub value: AzString,
}
/// Strongly-typed HTML attribute with type-safe values.
///
/// This enum provides a type-safe way to represent HTML attributes, ensuring that
/// values are validated at compile-time and properly converted to their string
/// representations at runtime.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C, u8)]
pub enum AttributeType {
    /// Element ID attribute (`id="..."`)
    Id(AzString),
    /// CSS class attribute (`class="..."`)
    Class(AzString),
    /// Accessible name/label (`aria-label="..."`)
    AriaLabel(AzString),
    /// Element that labels this one (`aria-labelledby="..."`)
    AriaLabelledBy(AzString),
    /// Element that describes this one (`aria-describedby="..."`)
    AriaDescribedBy(AzString),
    /// Role for accessibility (`role="..."`)
    AriaRole(AzString),
    /// Current state of an element (`aria-checked`, `aria-selected`, etc.)
    AriaState(AttributeNameValue),
    /// ARIA property (`aria-*`)
    AriaProperty(AttributeNameValue),
    /// Hyperlink target URL (`href="..."`)
    Href(AzString),
    /// Link relationship (`rel="..."`)
    Rel(AzString),
    /// Link target frame (`target="..."`)
    Target(AzString),
    /// Image source URL (`src="..."`)
    Src(AzString),
    /// Alternative text for images (`alt="..."`)
    Alt(AzString),
    /// Image title (tooltip) (`title="..."`)
    Title(AzString),
    /// Form input name (`name="..."`)
    Name(AzString),
    /// Form input value (`value="..."`)
    Value(AzString),
    /// Input type (`type="text|password|email|..."`)
    InputType(AzString),
    /// Placeholder text (`placeholder="..."`)
    Placeholder(AzString),
    /// Input is required (`required`)
    Required,
    /// Input is disabled (`disabled`)
    Disabled,
    /// Input is readonly (`readonly`)
    Readonly,
    /// Input is checked (checkbox/radio) (`checked`)
    CheckedTrue,
    /// Input is unchecked (checkbox/radio)
    CheckedFalse,
    /// Input is selected (option) (`selected`)
    Selected,
    /// Maximum value for number inputs (`max="..."`)
    Max(AzString),
    /// Minimum value for number inputs (`min="..."`)
    Min(AzString),
    /// Step value for number inputs (`step="..."`)
    Step(AzString),
    /// Input pattern for validation (`pattern="..."`)
    Pattern(AzString),
    /// Minimum length (`minlength="..."`)
    MinLength(i32),
    /// Maximum length (`maxlength="..."`)
    MaxLength(i32),
    /// Autocomplete behavior (`autocomplete="on|off|..."`)
    Autocomplete(AzString),
    /// Table header scope (`scope="row|col|rowgroup|colgroup"`)
    Scope(AzString),
    /// Number of columns to span (`colspan="..."`)
    ColSpan(i32),
    /// Number of rows to span (`rowspan="..."`)
    RowSpan(i32),
    /// Tab index for keyboard navigation (`tabindex="..."`)
    TabIndex(i32),
    /// Element can receive focus (`tabindex="0"` equivalent)
    Focusable,
    /// Language code (`lang="..."`)
    Lang(AzString),
    /// Text direction (`dir="ltr|rtl|auto"`)
    Dir(AzString),
    /// Content is editable (`contenteditable="true|false"`)
    ContentEditable(bool),
    /// Element is draggable (`draggable="true|false"`)
    Draggable(bool),
    /// Element is hidden (`hidden`)
    Hidden,
    /// Generic data attribute (`data-*="..."`)
    Data(AttributeNameValue),
    /// Generic custom attribute (for future extensibility)
    Custom(AttributeNameValue),
}
impl_option!(
    AttributeType,
    OptionAttributeType,
    copy = false,
    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl_vec!(AttributeType, AttributeTypeVec, AttributeTypeVecDestructor, AttributeTypeVecDestructorType, AttributeTypeVecSlice, OptionAttributeType);
impl_vec_debug!(AttributeType, AttributeTypeVec);
impl_vec_partialord!(AttributeType, AttributeTypeVec);
impl_vec_ord!(AttributeType, AttributeTypeVec);
impl_vec_clone!(AttributeType, AttributeTypeVec, AttributeTypeVecDestructor);
impl_vec_partialeq!(AttributeType, AttributeTypeVec);
impl_vec_eq!(AttributeType, AttributeTypeVec);
impl_vec_hash!(AttributeType, AttributeTypeVec);
impl AttributeType {
    /// Returns the id string if this is an `Id` attribute, `None` otherwise.
38428
    pub fn as_id(&self) -> Option<&str> {
38428
        match self {
34314
            AttributeType::Id(s) => Some(s.as_str()),
4114
            _ => None,
        }
38428
    }
    /// Returns the class string if this is a `Class` attribute, `None` otherwise.
22962
    pub fn as_class(&self) -> Option<&str> {
22962
        match self {
22962
            AttributeType::Class(s) => Some(s.as_str()),
            _ => None,
        }
22962
    }
    /// Get the attribute name (e.g., "href", "aria-label", "data-foo")
289
    pub fn name(&self) -> &str {
289
        match self {
17
            AttributeType::Id(_) => "id",
51
            AttributeType::Class(_) => "class",
            AttributeType::AriaLabel(_) => "aria-label",
            AttributeType::AriaLabelledBy(_) => "aria-labelledby",
            AttributeType::AriaDescribedBy(_) => "aria-describedby",
            AttributeType::AriaRole(_) => "role",
            AttributeType::AriaState(nv) => nv.attr_name.as_str(),
            AttributeType::AriaProperty(nv) => nv.attr_name.as_str(),
119
            AttributeType::Href(_) => "href",
            AttributeType::Rel(_) => "rel",
            AttributeType::Target(_) => "target",
            AttributeType::Src(_) => "src",
            AttributeType::Alt(_) => "alt",
            AttributeType::Title(_) => "title",
            AttributeType::Name(_) => "name",
            AttributeType::Value(_) => "value",
34
            AttributeType::InputType(_) => "type",
            AttributeType::Placeholder(_) => "placeholder",
            AttributeType::Required => "required",
            AttributeType::Disabled => "disabled",
            AttributeType::Readonly => "readonly",
            AttributeType::CheckedTrue => "checked",
            AttributeType::CheckedFalse => "checked",
            AttributeType::Selected => "selected",
            AttributeType::Max(_) => "max",
            AttributeType::Min(_) => "min",
            AttributeType::Step(_) => "step",
            AttributeType::Pattern(_) => "pattern",
            AttributeType::MinLength(_) => "minlength",
            AttributeType::MaxLength(_) => "maxlength",
            AttributeType::Autocomplete(_) => "autocomplete",
            AttributeType::Scope(_) => "scope",
            AttributeType::ColSpan(_) => "colspan",
            AttributeType::RowSpan(_) => "rowspan",
            AttributeType::TabIndex(_) => "tabindex",
            AttributeType::Focusable => "tabindex",
51
            AttributeType::Lang(_) => "lang",
            AttributeType::Dir(_) => "dir",
            AttributeType::ContentEditable(_) => "contenteditable",
            AttributeType::Draggable(_) => "draggable",
            AttributeType::Hidden => "hidden",
17
            AttributeType::Data(nv) => nv.attr_name.as_str(),
            AttributeType::Custom(nv) => nv.attr_name.as_str(),
        }
289
    }
    /// Get the attribute value as a string
289
    pub fn value(&self) -> AzString {
289
        match self {
17
            AttributeType::Id(v)
51
            | AttributeType::Class(v)
            | AttributeType::AriaLabel(v)
            | AttributeType::AriaLabelledBy(v)
            | AttributeType::AriaDescribedBy(v)
            | AttributeType::AriaRole(v)
119
            | AttributeType::Href(v)
            | AttributeType::Rel(v)
            | AttributeType::Target(v)
            | AttributeType::Src(v)
            | AttributeType::Alt(v)
            | AttributeType::Title(v)
            | AttributeType::Name(v)
            | AttributeType::Value(v)
34
            | AttributeType::InputType(v)
            | AttributeType::Placeholder(v)
            | AttributeType::Max(v)
            | AttributeType::Min(v)
            | AttributeType::Step(v)
            | AttributeType::Pattern(v)
            | AttributeType::Autocomplete(v)
            | AttributeType::Scope(v)
51
            | AttributeType::Lang(v)
272
            | AttributeType::Dir(v) => v.clone(),
            AttributeType::AriaState(nv)
            | AttributeType::AriaProperty(nv)
17
            | AttributeType::Data(nv)
17
            | AttributeType::Custom(nv) => nv.value.clone(),
            AttributeType::MinLength(n)
            | AttributeType::MaxLength(n)
            | AttributeType::ColSpan(n)
            | AttributeType::RowSpan(n)
            | AttributeType::TabIndex(n) => n.to_string().into(),
            AttributeType::Focusable => "0".into(),
            AttributeType::ContentEditable(b) | AttributeType::Draggable(b) => {
                if *b {
                    "true".into()
                } else {
                    "false".into()
                }
            }
            AttributeType::Required
            | AttributeType::Disabled
            | AttributeType::Readonly
            | AttributeType::CheckedTrue
                | AttributeType::CheckedFalse
            | AttributeType::Selected
            | AttributeType::Hidden => "".into(), // Boolean attributes
        }
289
    }
    /// Check if this is a boolean attribute (present = true, absent = false)
    pub fn is_boolean(&self) -> bool {
        matches!(
            self,
            AttributeType::Required
                | AttributeType::Disabled
                | AttributeType::Readonly
                | AttributeType::CheckedTrue
                | AttributeType::CheckedFalse
                | AttributeType::Selected
                | AttributeType::Hidden
        )
    }
}
/// Represents all data associated with a single DOM node, such as its type,
/// classes, IDs, callbacks, and inline styles.
#[repr(C)]
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct NodeData {
    /// `div`, `p`, `img`, etc.
    pub node_type: NodeType,
    /// Callbacks attached to this node:
    ///
    /// `On::MouseUp` -> `Callback(my_button_click_handler)`
    pub callbacks: CoreCallbackDataVec,
    /// Inline style: a `Css` value that applies only to this node (implicit `:scope`).
    /// Each rule carries conditions (@media/@os/:hover/...) and declarations; rules
    /// produced by parsing inline strings are tagged `rule_priority::INLINE`, while
    /// widget defaults pushed via `with_css_props` keep the same INLINE priority so
    /// they override author CSS — preserving the cascade priority that the previous
    /// per-property `css_props` field had.
    pub style: azul_css::css::Css,
    /// Packed flags: tab_index + contenteditable + is_anonymous.
    pub flags: NodeFlags,
    /// Optional extra accessibility information about this DOM node (MSAA, AT-SPI, UA).
    /// 8 bytes (Option<Box<T>> is pointer-sized).
    pub accessibility: Option<Box<AccessibilityInfo>>,
    /// Stores "extra", not commonly used data of the node: clip-mask, menus, etc.
    ///
    /// SHOULD NOT EXPOSED IN THE API - necessary to retroactively add functionality
    /// to the node without breaking the ABI.
    extra: Option<Box<NodeDataExt>>,
}
impl_option!(
    NodeData,
    OptionNodeData,
    copy = false,
    [Debug, PartialEq, Eq, PartialOrd, Ord]
);
impl Hash for NodeData {
64430
    fn hash<H: Hasher>(&self, state: &mut H) {
64430
        self.node_type.hash(state);
64430
        self.attributes().as_ref().hash(state);
64430
        self.flags.hash(state);
        // NOTE: callbacks are NOT hashed regularly, otherwise
        // they'd cause inconsistencies because of the scroll callback
64430
        for callback in self.callbacks.as_ref().iter() {
323
            callback.event.hash(state);
323
            callback.callback.hash(state);
323
            callback.refany.get_type_id().hash(state);
323
        }
        // Hash inline CSS properties (Static declarations only — same set the
        // legacy `css_props` field hashed). Conditions are intentionally
        // skipped to match the previous behaviour.
64430
        for (prop, _conds) in self.style.iter_inline_properties() {
102
            core::mem::discriminant(prop).hash(state);
102
        }
64430
        if let Some(ext) = self.extra.as_ref() {
57817
            if let Some(ds) = ext.dataset.as_ref() {
51
                ds.hash(state);
57766
            }
57817
            if let Some(c) = ext.svg_data.as_ref() {
                c.hash(state);
57817
            }
57817
            if let Some(c) = ext.menu_bar.as_ref() {
                c.hash(state);
57817
            }
57817
            if let Some(c) = ext.context_menu.as_ref() {
                c.hash(state);
57817
            }
57817
            if let Some(vv) = ext.virtual_view.as_ref() {
                vv.hash(state);
57817
            }
6613
        }
64430
    }
}
/// Tracks which component rendered a DOM subtree.
///
/// When a component's `render_fn` returns a `StyledDom`, the framework stamps the
/// root node(s) of the output with a `ComponentOrigin`. This enables:
/// - The debugger to show a "Component Tree" alongside the DOM tree
/// - Code generation roundtrips (rendered DOM → component invocations → code)
/// - Clicking a DOM node to navigate to the component that produced it
#[derive(Debug, Clone, PartialEq)]
pub struct ComponentOrigin {
    /// Qualified component name, e.g. "shadcn:card", "builtin:div"
    pub component_id: AzString,
    /// Snapshot of the data model at render time, stored as a JSON value.
    /// The debug server can inspect typed values; the frontend serializes
    /// them back to JSON for display and editing.
    pub data_model_json: crate::json::Json,
}
// Manual impls because Json contains f64 (no Eq/Ord/Hash derive),
// but we need them for NodeDataExt. We compare on the Display string.
impl Eq for ComponentOrigin {}
impl PartialOrd for ComponentOrigin {
    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
        Some(self.cmp(other))
    }
}
impl Ord for ComponentOrigin {
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
        self.component_id.cmp(&other.component_id)
            .then_with(|| {
                let a = alloc::format!("{}", self.data_model_json);
                let b = alloc::format!("{}", other.data_model_json);
                a.cmp(&b)
            })
    }
}
impl core::hash::Hash for ComponentOrigin {
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
        self.component_id.hash(state);
        let s = alloc::format!("{}", self.data_model_json);
        s.hash(state);
    }
}
impl Default for ComponentOrigin {
    fn default() -> Self {
        Self {
            component_id: AzString::from_const_str(""),
            data_model_json: crate::json::Json::null(),
        }
    }
}
/// SVG-specific data stored on a DOM node.
///
/// Each SVG element type stores its parsed attribute data here.
/// Also used for raster image clip masks (legacy C API).
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum SvgNodeData {
    /// Raster R8 image clip mask (legacy C API for chart.c style manual masks).
    ImageClipMask(ImageMask),
    /// `<path d="...">` — resolved path geometry.
    Path(crate::svg::SvgMultiPolygon),
    /// `<circle cx="" cy="" r="">`.
    Circle { cx: f32, cy: f32, r: f32 },
    /// `<rect x="" y="" width="" height="" rx="" ry="">`.
    Rect { x: f32, y: f32, width: f32, height: f32, rx: f32, ry: f32 },
    /// `<ellipse cx="" cy="" rx="" ry="">`.
    Ellipse { cx: f32, cy: f32, rx: f32, ry: f32 },
    /// `<line x1="" y1="" x2="" y2="">`.
    Line { x1: f32, y1: f32, x2: f32, y2: f32 },
    /// `<polygon points="">` / `<polyline points="">` — parsed point list.
    PointsList { points: alloc::vec::Vec<azul_css::props::basic::SvgPoint>, closed: bool },
    /// `<svg viewBox="" width="" height="">` — viewport attributes.
    ViewBox { min_x: f32, min_y: f32, width: f32, height: f32 },
    /// `<linearGradient>` attributes.
    LinearGradient { x1: f32, y1: f32, x2: f32, y2: f32 },
    /// `<radialGradient>` attributes.
    RadialGradient { cx: f32, cy: f32, r: f32, fx: f32, fy: f32 },
    /// `<stop offset="" stop-color="" stop-opacity="">`.
    GradientStop { offset: f32 },
    /// `<use href="" x="" y="">`.
    Use { href: AzString, x: f32, y: f32 },
    /// `<image href="" x="" y="" width="" height="">`.
    SvgImageData { href: AzString, x: f32, y: f32, width: f32, height: f32 },
}
impl Eq for SvgNodeData {}
impl Ord for SvgNodeData {
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
        self.partial_cmp(other).unwrap_or(core::cmp::Ordering::Equal)
    }
}
impl Hash for SvgNodeData {
    fn hash<H: Hasher>(&self, state: &mut H) {
        core::mem::discriminant(self).hash(state);
        match self {
            SvgNodeData::ImageClipMask(m) => m.hash(state),
            SvgNodeData::Path(mp) => {
                for ring in mp.rings.as_ref().iter() {
                    for item in ring.items.as_ref().iter() {
                        match item {
                            crate::svg::SvgPathElement::Line(l) => {
                                0u8.hash(state);
                                l.start.x.to_bits().hash(state);
                                l.start.y.to_bits().hash(state);
                                l.end.x.to_bits().hash(state);
                                l.end.y.to_bits().hash(state);
                            }
                            crate::svg::SvgPathElement::QuadraticCurve(q) => {
                                1u8.hash(state);
                                q.start.x.to_bits().hash(state);
                                q.start.y.to_bits().hash(state);
                                q.ctrl.x.to_bits().hash(state);
                                q.ctrl.y.to_bits().hash(state);
                                q.end.x.to_bits().hash(state);
                                q.end.y.to_bits().hash(state);
                            }
                            crate::svg::SvgPathElement::CubicCurve(c) => {
                                2u8.hash(state);
                                c.start.x.to_bits().hash(state);
                                c.start.y.to_bits().hash(state);
                                c.ctrl_1.x.to_bits().hash(state);
                                c.ctrl_1.y.to_bits().hash(state);
                                c.ctrl_2.x.to_bits().hash(state);
                                c.ctrl_2.y.to_bits().hash(state);
                                c.end.x.to_bits().hash(state);
                                c.end.y.to_bits().hash(state);
                            }
                        }
                    }
                }
            }
            SvgNodeData::Circle { cx, cy, r } => {
                cx.to_bits().hash(state); cy.to_bits().hash(state); r.to_bits().hash(state);
            }
            SvgNodeData::Rect { x, y, width, height, rx, ry } => {
                x.to_bits().hash(state); y.to_bits().hash(state);
                width.to_bits().hash(state); height.to_bits().hash(state);
                rx.to_bits().hash(state); ry.to_bits().hash(state);
            }
            SvgNodeData::Ellipse { cx, cy, rx, ry } => {
                cx.to_bits().hash(state); cy.to_bits().hash(state);
                rx.to_bits().hash(state); ry.to_bits().hash(state);
            }
            SvgNodeData::Line { x1, y1, x2, y2 } => {
                x1.to_bits().hash(state); y1.to_bits().hash(state);
                x2.to_bits().hash(state); y2.to_bits().hash(state);
            }
            SvgNodeData::PointsList { points, closed } => {
                for p in points.iter() {
                    p.x.to_bits().hash(state); p.y.to_bits().hash(state);
                }
                closed.hash(state);
            }
            SvgNodeData::ViewBox { min_x, min_y, width, height } => {
                min_x.to_bits().hash(state); min_y.to_bits().hash(state);
                width.to_bits().hash(state); height.to_bits().hash(state);
            }
            SvgNodeData::LinearGradient { x1, y1, x2, y2 } => {
                x1.to_bits().hash(state); y1.to_bits().hash(state);
                x2.to_bits().hash(state); y2.to_bits().hash(state);
            }
            SvgNodeData::RadialGradient { cx, cy, r, fx, fy } => {
                cx.to_bits().hash(state); cy.to_bits().hash(state);
                r.to_bits().hash(state); fx.to_bits().hash(state);
                fy.to_bits().hash(state);
            }
            SvgNodeData::GradientStop { offset } => {
                offset.to_bits().hash(state);
            }
            SvgNodeData::Use { href, x, y } => {
                href.hash(state);
                x.to_bits().hash(state); y.to_bits().hash(state);
            }
            SvgNodeData::SvgImageData { href, x, y, width, height } => {
                href.hash(state);
                x.to_bits().hash(state); y.to_bits().hash(state);
                width.to_bits().hash(state); height.to_bits().hash(state);
            }
        }
    }
}
/// NOTE: NOT EXPOSED IN THE API! Stores extra,
/// not commonly used information for the NodeData.
/// This helps keep the primary `NodeData` struct smaller for common cases.
#[repr(C)]
#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct NodeDataExt {
    /// Strongly-typed HTML attributes (aria-*, href, alt, etc.)
    /// IDs and classes are stored as `AttributeType::Id` and `AttributeType::Class` entries.
    /// Moved from NodeData to save 48B for the ~95% of nodes with no attributes.
    pub attributes: AttributeTypeVec,
    /// VirtualView callback data, only set when node_type == NodeType::VirtualView.
    pub virtual_view: Option<VirtualViewNode>,
    /// `data-*` attributes for this node, useful to store UI-related data on the node itself.
    pub dataset: Option<RefAny>,
    /// SVG-specific data or raster clip mask for this DOM node.
    pub svg_data: Option<SvgNodeData>,
    /// Menu bar that should be displayed at the top of this nodes rect.
    pub menu_bar: Option<Box<Menu>>,
    /// Context menu that should be opened when the item is left-clicked.
    pub context_menu: Option<Box<Menu>>,
    /// Stable key for reconciliation. If provided, allows the framework to track
    /// this node across frames even if its position in the array changes.
    /// This is crucial for correct lifecycle events when lists are reordered.
    pub key: Option<u64>,
    /// Callback to merge dataset state from a previous frame's node into the current node.
    /// This enables heavy resource preservation (video decoders, GL textures) across frames.
    pub dataset_merge_callback: Option<DatasetMergeCallback>,
    /// Tracks which component rendered this DOM subtree.
    /// Set by the framework during component rendering — the root node(s) of a
    /// component's output DOM get stamped with the component's qualified name.
    /// Enables the debugger to reconstruct the component invocation tree from the
    /// flat rendered DOM, and enables code generation roundtrips.
    pub component_origin: Option<ComponentOrigin>,
}
/// A callback function used to merge the state of an old dataset into a new one.
///
/// This enables components with heavy internal state (video players, WebGL contexts)
/// to preserve their resources across frames, while the DOM tree is recreated.
///
/// The callback receives both the old and new datasets as `RefAny` (cheap shallow clones)
/// and returns the dataset that should be used for the new node.
///
/// # Example
///
/// ```rust,ignore
/// fn merge_video_state(new_data: RefAny, old_data: RefAny) -> RefAny {
///     // Transfer heavy resources from old to new
///     if let (Some(mut new), Some(old)) = (
///         new_data.downcast_mut::<VideoState>(),
///         old_data.downcast_ref::<VideoState>()
///     ) {
///         new.decoder = old.decoder.take();
///         new.gl_texture = old.gl_texture.take();
///     }
///     new_data // Return the merged state
/// }
/// ```
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(C)]
pub struct DatasetMergeCallback {
    /// The function pointer that performs the merge.
    /// Signature: `fn(new_data: RefAny, old_data: RefAny) -> RefAny`
    pub cb: DatasetMergeCallbackType,
    /// Optional callable for FFI language bindings (Python, etc.)
    /// When set, the FFI layer can invoke this instead of `cb`.
    pub callable: OptionRefAny,
}
impl core::fmt::Debug for DatasetMergeCallback {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("DatasetMergeCallback")
            .field("cb", &(self.cb as usize))
            .field("callable", &self.callable)
            .finish()
    }
}
/// Allow creating DatasetMergeCallback from a raw function pointer.
/// This enables the `Into<DatasetMergeCallback>` pattern for Python bindings.
impl From<DatasetMergeCallbackType> for DatasetMergeCallback {
9
    fn from(cb: DatasetMergeCallbackType) -> Self {
9
        DatasetMergeCallback {
9
            cb,
9
            callable: OptionRefAny::None,
9
        }
9
    }
}
impl_option!(
    DatasetMergeCallback,
    OptionDatasetMergeCallback,
    copy = false,
    [Debug, Clone]
);
/// Function pointer type for dataset merge callbacks.
///
/// Arguments:
/// - `new_data`: The new node's dataset (shallow clone, cheap)
/// - `old_data`: The old node's dataset (shallow clone, cheap)
///
/// Returns:
/// - The `RefAny` that should be used as the dataset for the new node
pub type DatasetMergeCallbackType = extern "C" fn(RefAny, RefAny) -> RefAny;
impl Clone for NodeData {
    #[inline]
39978
    fn clone(&self) -> Self {
39978
        Self {
39978
            node_type: self.node_type.into_library_owned_nodetype(),
39978
            style: self.style.clone(),
39978
            callbacks: self.callbacks.clone(),
39978
            flags: self.flags,
39978
            accessibility: self.accessibility.clone(),
39978
            extra: self.extra.clone(),
39978
        }
39978
    }
}
// Clone, PartialEq, Eq, Hash, PartialOrd, Ord
impl_vec!(NodeData, NodeDataVec, NodeDataVecDestructor, NodeDataVecDestructorType, NodeDataVecSlice, OptionNodeData);
impl_vec_clone!(NodeData, NodeDataVec, NodeDataVecDestructor);
impl_vec_mut!(NodeData, NodeDataVec);
impl_vec_debug!(NodeData, NodeDataVec);
impl_vec_partialord!(NodeData, NodeDataVec);
impl_vec_ord!(NodeData, NodeDataVec);
impl_vec_partialeq!(NodeData, NodeDataVec);
impl_vec_eq!(NodeData, NodeDataVec);
impl_vec_hash!(NodeData, NodeDataVec);
impl NodeDataVec {
    #[inline]
1687817
    pub fn as_container<'a>(&'a self) -> NodeDataContainerRef<'a, NodeData> {
1687817
        NodeDataContainerRef {
1687817
            internal: self.as_ref(),
1687817
        }
1687817
    }
    #[inline]
    pub fn as_container_mut<'a>(&'a mut self) -> NodeDataContainerRefMut<'a, NodeData> {
        NodeDataContainerRefMut {
            internal: self.as_mut(),
        }
    }
}
// SAFETY: All fields in NodeData are either Send (NodeType, NodeFlags, CssPropertyWithConditionsVec),
// Arc-wrapped (RefAny), or plain data (Box<AccessibilityInfo>, Box<NodeDataExt>).
// Function pointers (callbacks) are inherently Send. The RefAny uses atomic reference counting.
unsafe impl Send for NodeData {}
/// Determines the behavior of an element in sequential focus navigation
// (e.g., using the Tab key).
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[repr(C, u8)]
pub enum TabIndex {
    /// Automatic tab index, similar to simply setting `focusable = "true"` or `tabindex = 0`
    /// (both have the effect of making the element focusable).
    ///
    /// Sidenote: See https://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute
    /// for interesting notes on tabindex and accessibility
    Auto,
    /// Set the tab index in relation to its parent element. I.e. if you have a list of elements,
    /// the focusing order is restricted to the current parent.
    ///
    /// When pressing tab repeatedly, the focusing order will be
    /// determined by OverrideInParent elements taking precedence among global order.
    OverrideInParent(u32),
    /// Elements can be focused in callbacks, but are not accessible via
    /// keyboard / tab navigation (-1).
    NoKeyboardFocus,
}
impl_option!(
    TabIndex,
    OptionTabIndex,
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl TabIndex {
    /// Returns the HTML-compatible number of the `tabindex` element.
    pub fn get_index(&self) -> isize {
        use self::TabIndex::*;
        match self {
            Auto => 0,
            OverrideInParent(x) => *x as isize,
            NoKeyboardFocus => -1,
        }
    }
}
impl Default for TabIndex {
    fn default() -> Self {
        TabIndex::Auto
    }
}
/// Packed representation of tab index + contenteditable flag.
///
/// Bit layout (32 bits):
///   [31]     contenteditable flag (1 = true)
///   [30:29]  tab_index variant:
///              00 = None (no tab index set)
///              01 = Auto
///              10 = OverrideInParent (value in bits [28:0])
///              11 = NoKeyboardFocus
///   [28]     is_anonymous (1 = anonymous box for table layout)
///   [27:0]   OverrideInParent value (max ~268 million)
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NodeFlags {
    pub inner: u32,
}
impl Default for NodeFlags {
    fn default() -> Self {
        NodeFlags { inner: 0 }
    }
}
impl NodeFlags {
    const CONTENTEDITABLE_BIT: u32 = 1 << 31;
    const TAB_INDEX_MASK: u32      = 0b11 << 29;
    const ANONYMOUS_BIT: u32       = 1 << 28;
    const TAB_VALUE_MASK: u32      = (1 << 28) - 1;
    const TAB_NONE: u32            = 0b00 << 29;
    const TAB_AUTO: u32            = 0b01 << 29;
    const TAB_OVERRIDE: u32        = 0b10 << 29;
    const TAB_NO_KEYBOARD: u32     = 0b11 << 29;
89370
    pub const fn new() -> Self {
89370
        NodeFlags { inner: 0 }
89370
    }
145838
    pub const fn is_contenteditable(&self) -> bool {
145838
        (self.inner & Self::CONTENTEDITABLE_BIT) != 0
145838
    }
    pub const fn set_contenteditable(mut self, v: bool) -> Self {
        if v {
            self.inner |= Self::CONTENTEDITABLE_BIT;
        } else {
            self.inner &= !Self::CONTENTEDITABLE_BIT;
        }
        self
    }
287
    pub fn set_contenteditable_mut(&mut self, v: bool) {
287
        if v {
286
            self.inner |= Self::CONTENTEDITABLE_BIT;
286
        } else {
1
            self.inner &= !Self::CONTENTEDITABLE_BIT;
1
        }
287
    }
124976
    pub fn get_tab_index(&self) -> Option<TabIndex> {
124976
        match self.inner & Self::TAB_INDEX_MASK {
124976
            x if x == Self::TAB_NONE => None,
689
            x if x == Self::TAB_AUTO => Some(TabIndex::Auto),
            x if x == Self::TAB_OVERRIDE => {
                let val = self.inner & Self::TAB_VALUE_MASK;
                Some(TabIndex::OverrideInParent(val))
            }
            x if x == Self::TAB_NO_KEYBOARD => Some(TabIndex::NoKeyboardFocus),
            _ => None,
        }
124976
    }
    /// Returns whether this node is an anonymous box generated for table layout.
63125
    pub const fn is_anonymous(&self) -> bool {
63125
        (self.inner & Self::ANONYMOUS_BIT) != 0
63125
    }
    pub fn set_anonymous(&mut self, v: bool) {
        if v {
            self.inner |= Self::ANONYMOUS_BIT;
        } else {
            self.inner &= !Self::ANONYMOUS_BIT;
        }
    }
370
    pub fn set_tab_index(&mut self, tab_index: Option<TabIndex>) {
        // Clear tab index bits (bits 29-30) and value bits (bits 0-27)
        // keep contenteditable bit (31) and anonymous bit (28)
370
        self.inner &= Self::CONTENTEDITABLE_BIT | Self::ANONYMOUS_BIT;
370
        match tab_index {
            None => { /* TAB_NONE = 0, already cleared */ }
370
            Some(TabIndex::Auto) => {
370
                self.inner |= Self::TAB_AUTO;
370
            }
            Some(TabIndex::OverrideInParent(val)) => {
                self.inner |= Self::TAB_OVERRIDE | (val & Self::TAB_VALUE_MASK);
            }
            Some(TabIndex::NoKeyboardFocus) => {
                self.inner |= Self::TAB_NO_KEYBOARD;
            }
        }
370
    }
}
impl Default for NodeData {
    fn default() -> Self {
        NodeData::create_node(NodeType::Div)
    }
}
impl fmt::Display for NodeData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let html_type = self.node_type.get_path();
        let attributes_string = node_data_to_string(&self);
        match self.node_type.format() {
            Some(content) => write!(
                f,
                "<{}{}>{}</{}>",
                html_type, attributes_string, content, html_type
            ),
            None => write!(f, "<{}{}/>", html_type, attributes_string),
        }
    }
}
fn node_data_to_string(node_data: &NodeData) -> String {
    let mut id_string = String::new();
    let ids = node_data
        .attributes()
        .as_ref()
        .iter()
        .filter_map(|s| s.as_id())
        .collect::<Vec<_>>()
        .join(" ");
    if !ids.is_empty() {
        id_string = format!(" id=\"{}\" ", ids);
    }
    let mut class_string = String::new();
    let classes = node_data
        .attributes()
        .as_ref()
        .iter()
        .filter_map(|s| s.as_class())
        .collect::<Vec<_>>()
        .join(" ");
    if !classes.is_empty() {
        class_string = format!(" class=\"{}\" ", classes);
    }
    let mut tabindex_string = String::new();
    if let Some(tab_index) = node_data.get_tab_index() {
        tabindex_string = format!(" tabindex=\"{}\" ", tab_index.get_index());
    };
    format!("{}{}{}", id_string, class_string, tabindex_string)
}
impl NodeData {
    /// Creates a new `NodeData` instance from a given `NodeType`.
    #[inline]
89370
    pub const fn create_node(node_type: NodeType) -> Self {
89370
        Self {
89370
            node_type,
89370
            callbacks: CoreCallbackDataVec::from_const_slice(&[]),
89370
            style: azul_css::css::Css {
89370
                rules: azul_css::css::CssRuleBlockVec::from_const_slice(&[]),
89370
            },
89370
            flags: NodeFlags::new(),
89370
            accessibility: None,
89370
            extra: None,
89370
        }
89370
    }
    /// Returns a reference to the node's attributes (from NodeDataExt).
    /// Returns an empty slice if no attributes have been set.
    #[inline]
341555
    pub fn attributes(&self) -> &AttributeTypeVec {
        static EMPTY: AttributeTypeVec = AttributeTypeVec::from_const_slice(&[]);
341555
        match &self.extra {
178070
            Some(ext) => &ext.attributes,
163485
            None => &EMPTY,
        }
341555
    }
    /// Returns a mutable reference to the node's attributes,
    /// lazily allocating NodeDataExt if needed.
    #[inline]
27505
    pub fn attributes_mut(&mut self) -> &mut AttributeTypeVec {
27505
        &mut self.extra.get_or_insert_with(|| Box::new(NodeDataExt::default())).attributes
27505
    }
    /// Sets the node's attributes, replacing any existing ones.
    #[inline]
28236
    pub fn set_attributes(&mut self, attrs: AttributeTypeVec) {
28236
        self.extra.get_or_insert_with(|| Box::new(NodeDataExt::default())).attributes = attrs;
28236
    }
    /// Shorthand for `NodeData::create_node(NodeType::Body)`.
    #[inline(always)]
42
    pub const fn create_body() -> Self {
42
        Self::create_node(NodeType::Body)
42
    }
    /// Shorthand for `NodeData::create_node(NodeType::Div)`.
    #[inline(always)]
31252
    pub const fn create_div() -> Self {
31252
        Self::create_node(NodeType::Div)
31252
    }
    /// Shorthand for `NodeData::create_node(NodeType::Br)`.
    #[inline(always)]
    pub const fn create_br() -> Self {
        Self::create_node(NodeType::Br)
    }
    /// Shorthand for `NodeData::create_node(NodeType::Text(value.into()))`.
    #[inline(always)]
7115
    pub fn create_text<S: Into<AzString>>(value: S) -> Self {
7115
        Self::create_node(NodeType::Text(BoxOrStatic::heap(value.into())))
7115
    }
    /// Shorthand for `NodeData::create_node(NodeType::Image(image_id))`.
    #[inline(always)]
    pub fn create_image(image: ImageRef) -> Self {
        Self::create_node(NodeType::Image(BoxOrStatic::heap(image)))
    }
    #[inline(always)]
    pub fn create_virtual_view(data: RefAny, callback: impl Into<VirtualViewCallback>) -> Self {
        let mut nd = Self::create_node(NodeType::VirtualView);
        let ext = nd.extra.get_or_insert_with(|| Box::new(NodeDataExt::default()));
        ext.virtual_view = Some(VirtualViewNode {
            callback: callback.into(),
            refany: data,
        });
        nd
    }
    // -- Accessibility-aware NodeData constructors --
    // Each a11y-able element has two constructors: the canonical one takes a
    // `SmallAriaInfo` so the caller must opt in to an accessible name, and the
    // `*_no_a11y` variant is a deliberate escape hatch with a longer name.
306
    fn with_attribute(mut self, attr: AttributeType) -> Self {
306
        let mut v = self.attributes().clone().into_library_owned_vec();
306
        v.push(attr);
306
        self.set_attributes(v.into());
306
        self
306
    }
    /// Creates a button `NodeData` with accessibility information.
    #[inline]
1
    pub fn create_button(aria: SmallAriaInfo) -> Self {
1
        let mut nd = Self::create_node(NodeType::Button);
1
        nd.set_accessibility_info(aria.to_full_info());
1
        nd
1
    }
    /// Creates a button `NodeData` without accessibility information.
    #[inline]
1
    pub fn create_button_no_a11y() -> Self {
1
        Self::create_node(NodeType::Button)
1
    }
    /// Creates an anchor `NodeData` with an href and accessibility information.
    #[inline]
1
    pub fn create_a(href: AzString, aria: SmallAriaInfo) -> Self {
1
        let mut nd = Self::create_node(NodeType::A).with_attribute(AttributeType::Href(href));
1
        nd.set_accessibility_info(aria.to_full_info());
1
        nd
1
    }
    /// Creates an anchor `NodeData` with an href but no accessibility information.
    #[inline]
1
    pub fn create_a_no_a11y(href: AzString) -> Self {
1
        Self::create_node(NodeType::A).with_attribute(AttributeType::Href(href))
1
    }
    /// Creates an input `NodeData` with accessibility information.
    #[inline]
1
    pub fn create_input(
1
        input_type: AzString,
1
        name: AzString,
1
        label: AzString,
1
        aria: SmallAriaInfo,
1
    ) -> Self {
1
        let mut nd = Self::create_node(NodeType::Input)
1
            .with_attribute(AttributeType::InputType(input_type))
1
            .with_attribute(AttributeType::Name(name))
1
            .with_attribute(AttributeType::AriaLabel(label));
1
        nd.set_accessibility_info(aria.to_full_info());
1
        nd
1
    }
    /// Creates an input `NodeData` without accessibility information.
    #[inline]
1
    pub fn create_input_no_a11y(input_type: AzString, name: AzString, label: AzString) -> Self {
1
        Self::create_node(NodeType::Input)
1
            .with_attribute(AttributeType::InputType(input_type))
1
            .with_attribute(AttributeType::Name(name))
1
            .with_attribute(AttributeType::AriaLabel(label))
1
    }
    /// Creates a textarea `NodeData` with accessibility information.
    #[inline]
1
    pub fn create_textarea(name: AzString, label: AzString, aria: SmallAriaInfo) -> Self {
1
        let mut nd = Self::create_node(NodeType::TextArea)
1
            .with_attribute(AttributeType::Name(name))
1
            .with_attribute(AttributeType::AriaLabel(label));
1
        nd.set_accessibility_info(aria.to_full_info());
1
        nd
1
    }
    /// Creates a textarea `NodeData` without accessibility information.
    #[inline]
1
    pub fn create_textarea_no_a11y(name: AzString, label: AzString) -> Self {
1
        Self::create_node(NodeType::TextArea)
1
            .with_attribute(AttributeType::Name(name))
1
            .with_attribute(AttributeType::AriaLabel(label))
1
    }
    /// Creates a select `NodeData` with accessibility information.
    #[inline]
1
    pub fn create_select(name: AzString, label: AzString, aria: SmallAriaInfo) -> Self {
1
        let mut nd = Self::create_node(NodeType::Select)
1
            .with_attribute(AttributeType::Name(name))
1
            .with_attribute(AttributeType::AriaLabel(label));
1
        nd.set_accessibility_info(aria.to_full_info());
1
        nd
1
    }
    /// Creates a select `NodeData` without accessibility information.
    #[inline]
1
    pub fn create_select_no_a11y(name: AzString, label: AzString) -> Self {
1
        Self::create_node(NodeType::Select)
1
            .with_attribute(AttributeType::Name(name))
1
            .with_attribute(AttributeType::AriaLabel(label))
1
    }
    /// Creates a table `NodeData` with accessibility information.
    #[inline]
1
    pub fn create_table(aria: SmallAriaInfo) -> Self {
1
        let mut nd = Self::create_node(NodeType::Table);
1
        nd.set_accessibility_info(aria.to_full_info());
1
        nd
1
    }
    /// Creates a table `NodeData` without accessibility information.
    #[inline]
1
    pub fn create_table_no_a11y() -> Self {
1
        Self::create_node(NodeType::Table)
1
    }
    /// Creates a label `NodeData` with an associated control ID and accessibility
    /// information.
    #[inline]
1
    pub fn create_label(for_id: AzString, aria: SmallAriaInfo) -> Self {
1
        let mut nd = Self::create_node(NodeType::Label).with_attribute(AttributeType::Custom(
1
            AttributeNameValue {
1
                attr_name: "for".into(),
1
                value: for_id,
1
            },
1
        ));
1
        nd.set_accessibility_info(aria.to_full_info());
1
        nd
1
    }
    /// Creates a label `NodeData` with an associated control ID but no
    /// accessibility information.
    #[inline]
1
    pub fn create_label_no_a11y(for_id: AzString) -> Self {
1
        Self::create_node(NodeType::Label).with_attribute(AttributeType::Custom(AttributeNameValue {
1
            attr_name: "for".into(),
1
            value: for_id,
1
        }))
1
    }
    /// Checks whether this node is of the given node type (div, image, text).
    #[inline]
    pub fn is_node_type(&self, searched_type: NodeType) -> bool {
        self.node_type == searched_type
    }
    /// Checks whether this node has the searched ID attached.
336
    pub fn has_id(&self, id: &str) -> bool {
336
        self.attributes()
336
            .iter()
336
            .any(|attr| attr.as_id() == Some(id))
336
    }
    /// Checks whether this node has the searched class attached.
46129
    pub fn has_class(&self, class: &str) -> bool {
46129
        self.attributes()
46129
            .iter()
46129
            .any(|attr| attr.as_class() == Some(class))
46129
    }
91424
    pub fn has_context_menu(&self) -> bool {
91424
        self.extra
91424
            .as_ref()
91424
            .map(|m| m.context_menu.is_some())
91424
            .unwrap_or(false)
91424
    }
128340
    pub fn is_text_node(&self) -> bool {
128340
        matches!(self.node_type, NodeType::Text(_))
128340
    }
48720
    pub fn is_virtual_view_node(&self) -> bool {
48720
        matches!(self.node_type, NodeType::VirtualView)
48720
    }
    // NOTE: Getters are used here in order to allow changing the memory allocator for the NodeData
    // in the future (which is why the fields are all private).
    #[inline(always)]
603706
    pub const fn get_node_type(&self) -> &NodeType {
603706
        &self.node_type
603706
    }
    #[inline]
11
    pub fn get_dataset_mut(&mut self) -> Option<&mut RefAny> {
11
        self.extra.as_mut().and_then(|e| e.dataset.as_mut())
11
    }
    #[inline]
97760
    pub fn get_dataset(&self) -> Option<&RefAny> {
97760
        self.extra.as_ref().and_then(|e| e.dataset.as_ref())
97760
    }
    /// Take the dataset out of the node, replacing it with None.
306
    pub fn take_dataset(&mut self) -> Option<RefAny> {
306
        self.extra.as_mut().and_then(|e| e.dataset.take())
306
    }
    /// Returns IDs and classes as a computed `IdOrClassVec`.
    /// Note: this allocates a new vec each time, prefer `has_id()`/`has_class()` for checks.
    #[inline]
    pub fn get_ids_and_classes(&self) -> IdOrClassVec {
        let v: Vec<IdOrClass> = self.attributes().as_ref().iter().filter_map(|attr| {
            match attr {
                AttributeType::Id(s) => Some(IdOrClass::Id(s.clone())),
                AttributeType::Class(s) => Some(IdOrClass::Class(s.clone())),
                _ => None,
            }
        }).collect();
        v.into()
    }
    #[inline(always)]
279127
    pub const fn get_callbacks(&self) -> &CoreCallbackDataVec {
279127
        &self.callbacks
279127
    }
    #[inline(always)]
    pub const fn get_style(&self) -> &azul_css::css::Css {
        &self.style
    }
    #[inline]
28735
    pub fn get_svg_data(&self) -> Option<&SvgNodeData> {
28735
        self.extra.as_ref().and_then(|e| e.svg_data.as_ref())
28735
    }
    /// Legacy accessor for raster clip mask. Returns `Some` only for `SvgNodeData::ImageClipMask`.
    #[inline]
    pub fn get_image_clip_mask(&self) -> Option<&ImageMask> {
        match self.get_svg_data()? {
            SvgNodeData::ImageClipMask(m) => Some(m),
            _ => None,
        }
    }
    #[inline]
124976
    pub fn get_tab_index(&self) -> Option<TabIndex> {
124976
        self.flags.get_tab_index()
124976
    }
    #[inline]
18354
    pub fn get_accessibility_info(&self) -> Option<&Box<AccessibilityInfo>> {
18354
        self.accessibility.as_ref()
18354
    }
    #[inline]
    pub fn get_menu_bar(&self) -> Option<&Box<Menu>> {
        self.extra.as_ref().and_then(|e| e.menu_bar.as_ref())
    }
    #[inline]
91424
    pub fn get_context_menu(&self) -> Option<&Box<Menu>> {
91424
        self.extra.as_ref().and_then(|e| e.context_menu.as_ref())
91424
    }
    /// Returns whether this node is an anonymous box generated for table layout.
    #[inline]
63125
    pub fn is_anonymous(&self) -> bool {
63125
        self.flags.is_anonymous()
63125
    }
    #[inline(always)]
1
    pub fn set_node_type(&mut self, node_type: NodeType) {
1
        self.node_type = node_type;
1
    }
    #[inline]
544
    pub fn set_dataset(&mut self, data: OptionRefAny) {
544
        match data {
            OptionRefAny::None => {
                if let Some(ext) = self.extra.as_mut() {
                    ext.dataset = None;
                }
            }
544
            OptionRefAny::Some(r) => {
544
                self.extra
544
                    .get_or_insert_with(|| Box::new(NodeDataExt::default()))
544
                    .dataset = Some(r);
            }
        }
544
    }
    /// Sets the IDs and classes by converting `IdOrClassVec` entries into
    /// `AttributeType::Id`/`AttributeType::Class` and merging them into `self.attributes`.
    /// Any existing Id/Class attributes are removed first.
    #[inline]
7903
    pub fn set_ids_and_classes(&mut self, ids_and_classes: IdOrClassVec) {
        // Remove existing Id/Class from attributes
7903
        let mut v: AttributeTypeVec = Vec::new().into();
7903
        mem::swap(&mut v, self.attributes_mut());
7903
        let mut v = v.into_library_owned_vec();
7903
        v.retain(|a| !matches!(a, AttributeType::Id(_) | AttributeType::Class(_)));
        // Convert and append
7937
        for ioc in ids_and_classes.as_ref().iter() {
7937
            match ioc {
60
                IdOrClass::Id(s) => v.push(AttributeType::Id(s.clone())),
7877
                IdOrClass::Class(s) => v.push(AttributeType::Class(s.clone())),
            }
        }
7903
        self.set_attributes(v.into());
7903
    }
    #[inline(always)]
    pub fn set_callbacks(&mut self, callbacks: CoreCallbackDataVec) {
        self.callbacks = callbacks;
    }
    /// Legacy: replace this node's inline style with a flat list of property+conditions.
    /// Each entry becomes a single-declaration rule at `rule_priority::INLINE`. Prefer
    /// `set_style` (or `with_style` / `with_css(&str)`) for new code.
    #[inline(always)]
    pub fn set_css_props(&mut self, css_props: CssPropertyWithConditionsVec) {
        self.style = css_props.into();
    }
    /// Replace this node's inline style with a `Css` value. The Css's rules apply only
    /// to this node (implicit `:scope`).
    #[inline(always)]
    pub fn set_style(&mut self, style: azul_css::css::Css) {
        self.style = style;
    }
    #[inline]
    pub fn set_clip_mask(&mut self, clip_mask: ImageMask) {
        self.extra
            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
            .svg_data = Some(SvgNodeData::ImageClipMask(clip_mask));
    }
    #[inline]
1008
    pub fn set_svg_data(&mut self, data: SvgNodeData) {
1008
        self.extra
1008
            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
1008
            .svg_data = Some(data);
1008
    }
    #[inline]
370
    pub fn set_tab_index(&mut self, tab_index: TabIndex) {
370
        self.flags.set_tab_index(Some(tab_index));
370
    }
    #[inline]
287
    pub fn set_contenteditable(&mut self, contenteditable: bool) {
287
        self.flags.set_contenteditable_mut(contenteditable);
287
    }
    #[inline]
145838
    pub fn is_contenteditable(&self) -> bool {
145838
        self.flags.is_contenteditable()
145838
    }
    #[inline]
238
    pub fn set_accessibility_info(&mut self, accessibility_info: AccessibilityInfo) {
238
        self.accessibility = Some(Box::new(accessibility_info));
238
    }
    /// Marks this node as an anonymous box (generated for table layout).
    #[inline]
    pub fn set_anonymous(&mut self, is_anonymous: bool) {
        self.flags.set_anonymous(is_anonymous);
    }
    #[inline]
    pub fn set_menu_bar(&mut self, menu_bar: Menu) {
        self.extra
            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
            .menu_bar = Some(Box::new(menu_bar));
    }
    #[inline]
    pub fn set_context_menu(&mut self, context_menu: Menu) {
        self.extra
            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
            .context_menu = Some(Box::new(context_menu));
    }
    /// Sets a stable key for this node used in reconciliation.
    ///
    /// This key is used to track node identity across DOM updates, enabling
    /// the framework to distinguish between "moving" a node and "destroying/creating" one.
    /// This is crucial for correct lifecycle events when lists are reordered.
    ///
    /// # Example
    /// ```rust
    /// # use azul_core::dom::NodeData;
    /// # let mut node_data = NodeData::create_div();
    /// node_data.set_key("user-123");
    /// ```
    #[inline]
17
    pub fn set_key<K: core::hash::Hash>(&mut self, key: K) {
        use core::hash::Hasher;
17
        let mut hasher = crate::hash::DefaultHasher::new();
17
        key.hash(&mut hasher);
17
        self.extra
17
            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
17
            .key = Some(hasher.finish());
17
    }
    /// Gets the key for this node, if set.
    #[inline]
66861
    pub fn get_key(&self) -> Option<u64> {
66861
        self.extra.as_ref().and_then(|ext| ext.key)
66861
    }
    /// Sets a dataset merge callback for this node.
    ///
    /// The merge callback is invoked during reconciliation when a node from the
    /// previous frame is matched with a node in the new frame. It allows heavy
    /// resources (video decoders, GL textures, network connections) to be
    /// transferred from the old node to the new node instead of being destroyed.
    ///
    /// # Type Safety
    ///
    /// The callback stores the `TypeId` of `T`. During execution, both the old
    /// and new datasets must match this type, otherwise the merge is skipped.
    ///
    /// # Example
    /// ```rust,ignore
    /// struct VideoPlayer {
    ///     url: String,
    ///     decoder: Option<DecoderHandle>,
    /// }
    ///
    /// extern "C" fn merge_video(new_data: RefAny, old_data: RefAny) -> RefAny {
    ///     // Transfer the heavy decoder handle from old to new
    ///     if let (Some(mut new), Some(old)) = (
    ///         new_data.downcast_mut::<VideoPlayer>(),
    ///         old_data.downcast_ref::<VideoPlayer>()
    ///     ) {
    ///         new.decoder = old.decoder.take();
    ///     }
    ///     new_data
    /// }
    ///
    /// node_data.set_merge_callback(merge_video);
    /// ```
    #[inline]
9
    pub fn set_merge_callback<C: Into<DatasetMergeCallback>>(&mut self, callback: C) {
9
        self.extra
9
            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
9
            .dataset_merge_callback = Some(callback.into());
9
    }
    /// Gets the merge callback for this node, if set.
    #[inline]
221
    pub fn get_merge_callback(&self) -> Option<DatasetMergeCallback> {
221
        self.extra.as_ref().and_then(|ext| ext.dataset_merge_callback.clone())
221
    }
    /// Sets the component origin for this node.
    ///
    /// This stamps the node with information about which component rendered it,
    /// enabling the debugger to reconstruct the component invocation tree.
    #[inline]
    pub fn set_component_origin(&mut self, origin: ComponentOrigin) {
        self.extra
            .get_or_insert_with(|| Box::new(NodeDataExt::default()))
            .component_origin = Some(origin);
    }
    /// Gets the component origin for this node, if set.
    #[inline]
    pub fn get_component_origin(&self) -> Option<&ComponentOrigin> {
        self.extra.as_ref().and_then(|ext| ext.component_origin.as_ref())
    }
    #[inline]
    pub fn with_menu_bar(mut self, menu_bar: Menu) -> Self {
        self.set_menu_bar(menu_bar);
        self
    }
    #[inline]
    pub fn with_context_menu(mut self, context_menu: Menu) -> Self {
        self.set_context_menu(context_menu);
        self
    }
    #[inline]
14
    pub fn add_callback<C: Into<CoreCallback>>(
14
        &mut self,
14
        event: EventFilter,
14
        data: RefAny,
14
        callback: C,
14
    ) {
14
        let callback = callback.into();
14
        let mut v: CoreCallbackDataVec = Vec::new().into();
14
        mem::swap(&mut v, &mut self.callbacks);
14
        let mut v = v.into_library_owned_vec();
14
        v.push(CoreCallbackData {
14
            event,
14
            refany: data,
14
            callback,
14
        });
14
        self.callbacks = v.into();
14
    }
    #[inline]
1015
    pub fn add_id(&mut self, s: AzString) {
1015
        let mut v: AttributeTypeVec = Vec::new().into();
1015
        mem::swap(&mut v, self.attributes_mut());
1015
        let mut v = v.into_library_owned_vec();
1015
        v.push(AttributeType::Id(s));
1015
        self.set_attributes(v.into());
1015
    }
    #[inline]
277
    pub fn add_class(&mut self, s: AzString) {
277
        let mut v: AttributeTypeVec = Vec::new().into();
277
        mem::swap(&mut v, self.attributes_mut());
277
        let mut v = v.into_library_owned_vec();
277
        v.push(AttributeType::Class(s));
277
        self.set_attributes(v.into());
277
    }
    /// Add a CSS property with optional conditions (hover, focus, active, etc.).
    ///
    /// Wraps the property in a single-declaration rule at `rule_priority::INLINE`
    /// and appends it to this node's inline style.
    #[inline]
160
    pub fn add_css_property(&mut self, p: CssPropertyWithConditions) {
        use azul_css::css::{rule_priority, CssDeclaration, CssPath, CssRuleBlock};
160
        let rule = CssRuleBlock {
160
            path: CssPath { selectors: Vec::new().into() },
160
            declarations: vec![CssDeclaration::Static(p.property)].into(),
160
            conditions: p.apply_if,
160
            priority: rule_priority::INLINE,
160
        };
160
        let mut v: azul_css::css::CssRuleBlockVec = Vec::new().into();
160
        mem::swap(&mut v, &mut self.style.rules);
160
        let mut v = v.into_library_owned_vec();
160
        v.push(rule);
160
        self.style.rules = v.into();
160
    }
    /// Calculates a deterministic node hash for this node.
64430
    pub fn calculate_node_data_hash(&self) -> DomNodeHash {
        use core::hash::Hasher;
64430
        let mut hasher = crate::hash::DefaultHasher::new();
64430
        self.hash(&mut hasher);
64430
        let h = hasher.finish();
64430
        DomNodeHash { inner: h }
64430
    }
    /// Calculates a structural hash for DOM reconciliation that ignores text content.
    ///
    /// This hash is used for matching nodes across DOM frames where the text content
    /// may have changed (e.g., contenteditable text being edited). It hashes:
    /// - Node type discriminant (but NOT the text content for Text nodes)
    /// - IDs and classes
    /// - Attributes (but NOT contenteditable state which may change with focus)
    /// - Callback events and types
    ///
    /// This allows a Text("Hello") node to match Text("Hello World") during reconciliation,
    /// preserving cursor position and selection state.
24276
    pub fn calculate_structural_hash(&self) -> DomNodeHash {
        use core::hash::Hasher;
        use core::hash::Hasher as StdHasher;
24276
        let mut hasher = crate::hash::DefaultHasher::new();
        // Hash node type discriminant only, not content
        // This means Text("A") and Text("B") have the same structural hash
24276
        core::mem::discriminant(&self.node_type).hash(&mut hasher);
        // For VirtualView nodes, hash the callback to distinguish different virtualized views
24276
        if let NodeType::VirtualView = self.node_type {
            if let Some(ext) = self.extra.as_ref() {
                if let Some(vv) = ext.virtual_view.as_ref() {
                    vv.hash(&mut hasher);
                }
            }
24276
        }
        // For Image nodes, hash the image reference to distinguish different images.
        // For callback images, hash the callback function pointer and RefAny type ID
        // instead of the heap pointer, so that the same callback produces the same
        // structural hash across frames (the heap pointer differs each frame because
        // ImageRef::new() does Box::into_raw(Box::new(...))).
24276
        if let NodeType::Image(ref img_ref) = self.node_type {
            match img_ref.get_data() {
                crate::resources::DecodedImage::Callback(cb) => {
                    // Hash callback function pointer (stable across frames)
                    cb.callback.cb.hash(&mut hasher);
                    // Hash RefAny type ID (not instance pointer)
                    cb.refany.get_type_id().hash(&mut hasher);
                }
                _ => {
                    // Raw images / GL textures: hash normally (pointer identity)
                    img_ref.hash(&mut hasher);
                }
            }
24276
        }
        // Hash IDs and classes - these are structural and shouldn't change
        // (They are now stored as AttributeType::Id / AttributeType::Class in attributes)
24276
        for attr in self.attributes().as_ref().iter() {
19261
            match attr {
17153
                AttributeType::Id(s) => { 0u8.hash(&mut hasher); s.as_str().hash(&mut hasher); }
2108
                AttributeType::Class(s) => { 1u8.hash(&mut hasher); s.as_str().hash(&mut hasher); }
                _ => {}
            }
        }
        // Hash other attributes - but skip contenteditable since that might change
        // Also skip Id/Class since they were already hashed above
24276
        for attr in self.attributes().as_ref().iter() {
19261
            if !matches!(attr, AttributeType::ContentEditable(_) | AttributeType::Id(_) | AttributeType::Class(_)) {
                attr.hash(&mut hasher);
19261
            }
        }
        // Hash callback events (not the actual callback function pointers)
24276
        for callback in self.callbacks.as_ref().iter() {
153
            callback.event.hash(&mut hasher);
153
        }
24276
        let h = hasher.finish();
24276
        DomNodeHash { inner: h }
24276
    }
    #[inline(always)]
    pub fn with_tab_index(mut self, tab_index: TabIndex) -> Self {
        self.set_tab_index(tab_index);
        self
    }
    #[inline(always)]
    pub fn with_contenteditable(mut self, contenteditable: bool) -> Self {
        self.set_contenteditable(contenteditable);
        self
    }
    #[inline(always)]
    pub fn with_node_type(mut self, node_type: NodeType) -> Self {
        self.set_node_type(node_type);
        self
    }
    #[inline(always)]
    pub fn with_callback<C: Into<CoreCallback>>(
        mut self,
        event: EventFilter,
        data: RefAny,
        callback: C,
    ) -> Self {
        self.add_callback(event, data, callback);
        self
    }
    #[inline(always)]
    pub fn with_dataset(mut self, data: OptionRefAny) -> Self {
        self.set_dataset(data);
        self
    }
    #[inline(always)]
    pub fn with_ids_and_classes(mut self, ids_and_classes: IdOrClassVec) -> Self {
        self.set_ids_and_classes(ids_and_classes);
        self
    }
    #[inline(always)]
    pub fn with_callbacks(mut self, callbacks: CoreCallbackDataVec) -> Self {
        self.callbacks = callbacks;
        self
    }
    /// Legacy: builder-form of `set_css_props`. Each `CssPropertyWithConditions`
    /// becomes a single-declaration rule at `rule_priority::INLINE`.
    /// Prefer `with_style(Css)` for new code.
    #[inline(always)]
    pub fn with_css_props(mut self, css_props: CssPropertyWithConditionsVec) -> Self {
        self.style = css_props.into();
        self
    }
    /// Builder-form of `set_style`.
    #[inline(always)]
    pub fn with_style(mut self, style: azul_css::css::Css) -> Self {
        self.style = style;
        self
    }
    /// Assigns a stable key to this node for reconciliation.
    ///
    /// This is crucial for performance and correct state preservation when
    /// lists of items change order or items are inserted/removed. Without keys,
    /// the reconciliation algorithm falls back to hash-based matching.
    ///
    /// # Example
    /// ```rust
    /// # use azul_core::dom::NodeData;
    /// NodeData::create_div()
    ///     .with_key("user-avatar-123");
    /// ```
    #[inline]
2
    pub fn with_key<K: core::hash::Hash>(mut self, key: K) -> Self {
2
        self.set_key(key);
2
        self
2
    }
    /// Registers a callback to merge dataset state from the previous frame.
    ///
    /// This is used for components that maintain heavy internal state (video players,
    /// WebGL contexts, network connections) that should not be destroyed and recreated
    /// on every render frame.
    ///
    /// The callback receives both datasets as `RefAny` (cheap shallow clones) and
    /// returns the `RefAny` that should be used for the new node.
    ///
    /// # Example
    /// ```rust,ignore
    /// struct VideoPlayer {
    ///     url: String,
    ///     decoder_handle: Option<DecoderHandle>,
    /// }
    ///
    /// extern "C" fn merge_video(new_data: RefAny, old_data: RefAny) -> RefAny {
    ///     if let (Some(mut new), Some(old)) = (
    ///         new_data.downcast_mut::<VideoPlayer>(),
    ///         old_data.downcast_ref::<VideoPlayer>()
    ///     ) {
    ///         new.decoder_handle = old.decoder_handle.take();
    ///     }
    ///     new_data
    /// }
    ///
    /// NodeData::create_div()
    ///     .with_dataset(RefAny::new(VideoPlayer::new("movie.mp4")).into())
    ///     .with_merge_callback(merge_video)
    /// ```
    #[inline]
    pub fn with_merge_callback<C: Into<DatasetMergeCallback>>(mut self, callback: C) -> Self {
        self.set_merge_callback(callback);
        self
    }
    /// Parse and set CSS styles with full selector support.
    ///
    /// This is the unified API for setting inline CSS on a node. It supports:
    /// - Simple properties: `color: red; font-size: 14px;`
    /// - Pseudo-selectors: `:hover { background: blue; }`
    /// - @-rules: `@os linux { font-size: 14px; }`
    /// - Nesting: `@os linux { font-size: 14px; :hover { color: red; }}`
    ///
    /// # Examples
    /// ```rust
    /// # use azul_core::dom::NodeData;
    /// NodeData::create_div().with_css("
    ///     color: blue;
    ///     :hover { color: red; }
    ///     @os linux { font-size: 14px; }
    /// ");
    /// ```
221
    pub fn set_css(&mut self, style: &str) {
        // Parse via Css::parse_inline so the inline path goes through the same
        // selector + nesting machinery as author CSS. Rules are tagged
        // `rule_priority::INLINE` and appended to whatever this node already has.
221
        let parsed = azul_css::css::Css::parse_inline(style);
221
        let mut current: azul_css::css::CssRuleBlockVec = Vec::new().into();
221
        mem::swap(&mut current, &mut self.style.rules);
221
        let mut v = current.into_library_owned_vec();
221
        v.extend(parsed.rules.into_library_owned_vec());
221
        self.style.rules = v.into();
221
    }
    /// Builder method for `set_css`
221
    pub fn with_css(mut self, style: &str) -> Self {
221
        self.set_css(style);
221
        self
221
    }
    #[inline(always)]
    pub fn swap_with_default(&mut self) -> Self {
        let mut s = NodeData::create_div();
        mem::swap(&mut s, self);
        s
    }
    #[inline]
25993
    pub fn copy_special(&self) -> Self {
25993
        Self {
25993
            node_type: self.node_type.into_library_owned_nodetype(),
25993
            style: self.style.clone(),
25993
            callbacks: self.callbacks.clone(),
25993
            flags: self.flags,
25993
            accessibility: self.accessibility.clone(),
25993
            extra: self.extra.clone(),
25993
        }
25993
    }
36331
    pub fn is_focusable(&self) -> bool {
        // Inherently focusable elements per HTML spec
36331
        if matches!(self.node_type,
            NodeType::A | NodeType::Button | NodeType::Input
            | NodeType::Select | NodeType::TextArea
        ) {
4117
            return true;
32214
        }
        // Contenteditable elements are implicitly focusable (W3C spec)
32214
        if self.is_contenteditable() {
336
            return true;
31878
        }
        // Element is focusable if it has a tab index or any focus-related callback
31878
        self.get_tab_index().is_some()
31878
            || self
31878
                .get_callbacks()
31878
                .iter()
31878
                .any(|cb| cb.event.is_focus_callback())
36331
    }
    /// Returns true if this element has "activation behavior" per HTML5 spec.
    ///
    /// Elements with activation behavior can be activated via Enter or Space key
    /// when focused, which generates a synthetic click event.
    ///
    /// Per HTML5 spec, elements with activation behavior include:
    /// - Button elements
    /// - Input elements (submit, button, reset, checkbox, radio)
    /// - Anchor elements with href
    /// - Any element with a click callback (implicit activation)
    ///
    /// See: https://html.spec.whatwg.org/multipage/interaction.html#activation-behavior
18315
    pub fn has_activation_behavior(&self) -> bool {
        // Inherently activatable elements per HTML spec
18315
        if matches!(self.node_type, NodeType::A | NodeType::Button) {
2060
            return true;
16255
        }
        use crate::events::{EventFilter, HoverEventFilter};
        // Check for click callback (most common case for Azul)
        // In Azul, "click" is typically LeftMouseUp
16255
        let has_click_callback = self
16255
            .get_callbacks()
16255
            .iter()
16255
            .any(|cb| matches!(
                cb.event,
                EventFilter::Hover(HoverEventFilter::MouseUp)
                | EventFilter::Hover(HoverEventFilter::LeftMouseUp)
            ));
16255
        if has_click_callback {
            return true;
16255
        }
        // Check accessibility role for button-like elements
16255
        if let Some(ref accessibility) = self.accessibility {
            use crate::a11y::AccessibilityRole;
            match accessibility.role {
                AccessibilityRole::PushButton  // Button
                | AccessibilityRole::Link
                | AccessibilityRole::CheckButton  // Checkbox
                | AccessibilityRole::RadioButton  // Radio
                | AccessibilityRole::MenuItem
                | AccessibilityRole::PageTab  // Tab
                => return true,
                _ => {}
            }
16255
        }
16255
        false
18315
    }
    /// Returns true if this element is currently activatable.
    ///
    /// An element is activatable if it has activation behavior AND is not disabled.
    /// This checks for common disability patterns (aria-disabled, disabled attribute).
1
    pub fn is_activatable(&self) -> bool {
1
        if !self.has_activation_behavior() {
            return false;
1
        }
        // Check for disabled state in accessibility info
1
        if let Some(ref accessibility) = self.accessibility {
            // Check if explicitly marked as unavailable
            if accessibility
                .states
                .as_ref()
                .iter()
                .any(|s| matches!(s, AccessibilityState::Unavailable))
            {
                return false;
            }
1
        }
        // Not disabled, so activatable
1
        true
1
    }
    /// Returns the tab index for this element.
    ///
    /// Tab index determines keyboard navigation order:
    /// - `None`: Not in tab order (unless naturally focusable)
    /// - `Some(-1)`: Focusable programmatically but not via Tab
    /// - `Some(0)`: In natural tab order
    /// - `Some(n > 0)`: In tab order with priority n (higher = later)
    pub fn get_effective_tabindex(&self) -> Option<i32> {
        match self.flags.get_tab_index() {
            None => {
                // Check if naturally focusable (has focus callback)
                if self.get_callbacks().iter().any(|cb| cb.event.is_focus_callback()) {
                    Some(0)
                } else {
                    None
                }
            }
            Some(tab_idx) => {
                match tab_idx {
                    TabIndex::Auto => Some(0),
                    TabIndex::OverrideInParent(n) => Some(n as i32),
                    TabIndex::NoKeyboardFocus => Some(-1),
                }
            }
        }
    }
    /// Returns the accessible label for this node.
    ///
    /// Priority: `aria-label` attribute > `alt` attribute > `title` attribute > None.
    /// Does NOT include child text — the caller should collect that separately
    /// using the DOM hierarchy.
18312
    pub fn get_accessible_label(&self) -> Option<&str> {
18312
        for attr in self.attributes().as_ref() {
2268
            match attr {
                AttributeType::AriaLabel(s) => return Some(s.as_str()),
2268
                _ => {}
            }
        }
18312
        for attr in self.attributes().as_ref() {
2268
            match attr {
                AttributeType::Alt(s) | AttributeType::Title(s) => return Some(s.as_str()),
2268
                _ => {}
            }
        }
18312
        None
18312
    }
    /// Returns the accessible value for this node.
    ///
    /// Priority: `value` attribute > None.
    /// For text inputs, this is the input's current value.
18312
    pub fn get_accessible_value(&self) -> Option<&str> {
18312
        for attr in self.attributes().as_ref() {
2268
            if let AttributeType::Value(s) = attr {
                return Some(s.as_str());
2268
            }
        }
18312
        None
18312
    }
    /// Returns the placeholder text for this node.
    pub fn get_placeholder(&self) -> Option<&str> {
        for attr in self.attributes().as_ref() {
            if let AttributeType::Placeholder(s) = attr {
                return Some(s.as_str());
            }
        }
        None
    }
    pub fn get_virtual_view_node(&mut self) -> Option<&mut VirtualViewNode> {
        self.extra.as_mut()?.virtual_view.as_mut()
    }
    pub fn get_virtual_view_node_ref(&self) -> Option<&VirtualViewNode> {
        self.extra.as_ref()?.virtual_view.as_ref()
    }
    pub fn get_render_image_callback_node<'a>(
        &'a mut self,
    ) -> Option<(&'a mut CoreImageCallback, ImageRefHash)> {
        match &mut self.node_type {
            NodeType::Image(ref mut img) => {
                let hash = image_ref_get_hash(img.as_ref());
                img.as_mut().get_image_callback_mut().map(|r| (r, hash))
            }
            _ => None,
        }
    }
    pub fn debug_print_start(
        &self,
        css_cache: &CssPropertyCache,
        node_id: &NodeId,
        node_state: &StyledNodeState,
    ) -> String {
        let html_type = self.node_type.get_path();
        let attributes_string = node_data_to_string(&self);
        let style = css_cache.get_computed_css_style_string(&self, node_id, node_state);
        format!(
            "<{} data-az-node-id=\"{}\" {} {style}>",
            html_type,
            node_id.index(),
            attributes_string,
            style = if style.trim().is_empty() {
                String::new()
            } else {
                format!("style=\"{style}\"")
            }
        )
    }
    pub fn debug_print_end(&self) -> String {
        let html_type = self.node_type.get_path();
        format!("</{}>", html_type)
    }
}
impl crate::events::ActivationBehavior for NodeData {
2
    fn has_activation_behavior(&self) -> bool {
2
        NodeData::has_activation_behavior(self)
2
    }
1
    fn is_activatable(&self) -> bool {
1
        NodeData::is_activatable(self)
1
    }
}
impl crate::events::Focusable for NodeData {
    fn get_tabindex(&self) -> Option<i32> {
        self.get_effective_tabindex()
    }
1
    fn is_focusable(&self) -> bool {
1
        NodeData::is_focusable(self)
1
    }
3
    fn is_naturally_focusable(&self) -> bool {
1
        matches!(
3
            self.node_type,
            NodeType::A
                | NodeType::Button
                | NodeType::Input
                | NodeType::Select
                | NodeType::TextArea
        )
3
    }
}
/// A unique, runtime-generated identifier for a single `Dom` instance.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
#[repr(C)]
pub struct DomId {
    pub inner: usize,
}
impl fmt::Display for DomId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.inner)
    }
}
impl DomId {
    pub const ROOT_ID: DomId = DomId { inner: 0 };
}
impl Default for DomId {
    fn default() -> DomId {
        DomId::ROOT_ID
    }
}
impl_option!(
    DomId,
    OptionDomId,
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl_vec!(DomId, DomIdVec, DomIdVecDestructor, DomIdVecDestructorType, DomIdVecSlice, OptionDomId);
impl_vec_debug!(DomId, DomIdVec);
impl_vec_clone!(DomId, DomIdVec, DomIdVecDestructor);
impl_vec_partialeq!(DomId, DomIdVec);
impl_vec_partialord!(DomId, DomIdVec);
/// A UUID for a DOM node within a `LayoutWindow`.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct DomNodeId {
    /// The ID of the `Dom` this node belongs to.
    pub dom: DomId,
    /// The hierarchical ID of the node within its `Dom`.
    pub node: NodeHierarchyItemId,
}
impl_option!(
    DomNodeId,
    OptionDomNodeId,
    [Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl DomNodeId {
    pub const ROOT: DomNodeId = DomNodeId {
        dom: DomId::ROOT_ID,
        node: NodeHierarchyItemId::NONE,
    };
}
/// The document model, similar to HTML. This is a create-only structure, you don't actually read
/// anything back from it. It's designed for ease of construction.
///
/// This is the "slow" tree-based DOM. For bulk construction (XML parsing),
/// use `FastDom` which builds flat arenas directly and skips the tree→arena conversion.
#[repr(C)]
#[derive(PartialEq, Clone, PartialOrd)]
pub struct Dom {
    /// The data for the root node of this DOM (or sub-DOM).
    pub root: NodeData,
    /// The children of this DOM node.
    pub children: DomVec,
    /// Ordered list of CSS stylesheets to apply to this DOM subtree.
    /// Stylesheets are applied in push order during the single deferred cascade pass.
    /// Later entries override earlier ones (higher cascade priority).
    pub css: azul_css::css::CssVec,
    // Tracks the number of sub-children of the current children, so that
    // the `Dom` can be converted into a `CompactDom`.
    pub estimated_total_children: usize,
}
/// CSS stylesheet associated with a specific node ID in the flat arena.
/// In the tree DOM, each node carries its own `css` field. In the flat arena,
/// we record which node a stylesheet scopes to (e.g. for `<style>` tags
/// in different parts of the document).
#[repr(C)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct CssWithNodeId {
    /// 1-based encoded NodeId (0 = root / global scope).
    pub node_id: usize,
    /// The CSS stylesheet.
    pub css: azul_css::css::Css,
}
impl_vec!(CssWithNodeId, CssWithNodeIdVec, CssWithNodeIdVecDestructor, CssWithNodeIdVecDestructorType, CssWithNodeIdVecSlice, OptionCssWithNodeId);
impl_option!(CssWithNodeId, OptionCssWithNodeId, copy = false, [Debug, Clone, PartialEq, PartialOrd]);
impl_vec_clone!(CssWithNodeId, CssWithNodeIdVec, CssWithNodeIdVecDestructor);
impl_vec_mut!(CssWithNodeId, CssWithNodeIdVec);
impl_vec_debug!(CssWithNodeId, CssWithNodeIdVec);
impl_vec_partialord!(CssWithNodeId, CssWithNodeIdVec);
impl_vec_partialeq!(CssWithNodeId, CssWithNodeIdVec);
/// Arena-based DOM for bulk construction (e.g. XML/XHTML parsing).
/// The hierarchy and node data are stored in two parallel flat vectors,
/// skipping the tree→arena conversion step entirely.
///
/// Use `FastDom::into_dom()` to convert to a tree-based `Dom` if needed.
/// `StyledDom::create_from_fast_dom()` consumes this directly without conversion.
#[repr(C)]
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct FastDom {
    /// Flat arena of parent/child/sibling relationships.
    pub node_hierarchy: crate::styled_dom::NodeHierarchyItemVec,
    /// Flat arena of node data, parallel to `node_hierarchy`.
    pub node_data: NodeDataVec,
    /// CSS stylesheets with the node ID they scope to.
    pub css: CssWithNodeIdVec,
}
// Manual Eq/Hash/Ord impls that skip the transient `css` field,
// since CssVec does not implement Eq/Hash/Ord.
impl Eq for Dom {}
impl core::hash::Hash for Dom {
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
        self.root.hash(state);
        self.children.hash(state);
        self.estimated_total_children.hash(state);
    }
}
impl Ord for Dom {
    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
        self.root.cmp(&other.root)
            .then_with(|| self.children.cmp(&other.children))
            .then_with(|| self.estimated_total_children.cmp(&other.estimated_total_children))
    }
}
impl_option!(
    Dom,
    OptionDom,
    copy = false,
    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
);
impl_vec!(Dom, DomVec, DomVecDestructor, DomVecDestructorType, DomVecSlice, OptionDom);
impl_vec_clone!(Dom, DomVec, DomVecDestructor);
impl_vec_mut!(Dom, DomVec);
impl_vec_debug!(Dom, DomVec);
impl_vec_partialord!(Dom, DomVec);
impl_vec_ord!(Dom, DomVec);
impl_vec_partialeq!(Dom, DomVec);
impl_vec_eq!(Dom, DomVec);
impl_vec_hash!(Dom, DomVec);
/// An empty `<body>` DOM. Used as the safe fallback return value when a layout
/// callback cannot produce a DOM (e.g. a foreign-language binding's trampoline
/// raised, or an app-data downcast failed). `StyledDom` is the post-cascade
/// CSSOM; layout callbacks return an un-cascaded `Dom`, so an empty body is the
/// natural "nothing to show" default.
impl Default for Dom {
    fn default() -> Self {
        Dom::create_body()
    }
}
impl Dom {
    // ----- DOM CONSTRUCTORS
    /// Creates an empty DOM with a give `NodeType`. Note: This is a `const fn` and
    /// doesn't allocate, it only allocates once you add at least one child node.
    #[inline(always)]
20504
    pub fn create_node(node_type: NodeType) -> Self {
20504
        Self {
20504
            root: NodeData::create_node(node_type),
20504
            children: Vec::new().into(),
20504
            css: Vec::new().into(),
20504
            estimated_total_children: 0,
20504
        }
20504
    }
    #[inline(always)]
31
    pub fn create_from_data(node_data: NodeData) -> Self {
31
        Self {
31
            root: node_data,
31
            children: Vec::new().into(),
31
            css: Vec::new().into(),
31
            estimated_total_children: 0,
31
        }
31
    }
    // Document Structure Elements
    /// Creates the root HTML element.
    ///
    /// **Accessibility**: The `<html>` element is the root of an HTML document and should have a
    /// `lang` attribute.
    #[inline(always)]
612
    pub const fn create_html() -> Self {
612
        Self {
612
            root: NodeData::create_node(NodeType::Html),
612
            children: DomVec::from_const_slice(&[]),
612
            css: azul_css::css::CssVec::from_const_slice(&[]),
612
            estimated_total_children: 0,
612
        }
612
    }
    /// Creates the document head element.
    ///
    /// **Accessibility**: The `<head>` contains metadata. Use `<title>` for page titles.
    #[inline(always)]
    pub const fn create_head() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Head),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    #[inline(always)]
7607
    pub const fn create_body() -> Self {
7607
        Self {
7607
            root: NodeData::create_node(NodeType::Body),
7607
            children: DomVec::from_const_slice(&[]),
7607
            css: azul_css::css::CssVec::from_const_slice(&[]),
7607
            estimated_total_children: 0,
7607
        }
7607
    }
    /// Creates a generic block-level container.
    ///
    /// **Accessibility**: Prefer semantic elements like `<article>`, `<section>`, `<nav>` when
    /// applicable.
    #[inline(always)]
4520
    pub const fn create_div() -> Self {
4520
        Self {
4520
            root: NodeData::create_node(NodeType::Div),
4520
            children: DomVec::from_const_slice(&[]),
4520
            css: azul_css::css::CssVec::from_const_slice(&[]),
4520
            estimated_total_children: 0,
4520
        }
4520
    }
    // Semantic Structure Elements
    /// Creates an article element.
    ///
    /// **Accessibility**: Represents self-contained content that could be distributed
    /// independently. Screen readers can navigate by articles. Consider adding aria-label for
    /// multiple articles.
    #[inline(always)]
    pub const fn create_article() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Article),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a section element.
    ///
    /// **Accessibility**: Represents a thematic grouping of content with a heading.
    /// Should typically have a heading (h1-h6) as a child. Consider aria-labelledby.
    #[inline(always)]
    pub const fn create_section() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Section),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a navigation element.
    ///
    /// **Accessibility**: Represents navigation links. Screen readers can jump to navigation.
    /// Use aria-label to distinguish multiple nav elements (e.g., "Main navigation", "Footer
    /// links").
    #[inline(always)]
    pub const fn create_nav() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Nav),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an aside element.
    ///
    /// **Accessibility**: Represents content tangentially related to main content (sidebars,
    /// callouts). Screen readers announce this as complementary content.
    #[inline(always)]
    pub const fn create_aside() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Aside),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a header element.
    ///
    /// **Accessibility**: Represents introductory content or navigational aids.
    /// Can be used for page headers or section headers.
    #[inline(always)]
    pub const fn create_header() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Header),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a footer element.
    ///
    /// **Accessibility**: Represents footer for nearest section or page.
    /// Typically contains copyright, author info, or related links.
    #[inline(always)]
    pub const fn create_footer() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Footer),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a main content element.
    ///
    /// **Accessibility**: Represents the dominant content. There should be only ONE main per page.
    /// Screen readers can jump directly to main content. Do not nest inside
    /// article/aside/footer/header/nav.
    #[inline(always)]
    pub const fn create_main() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Main),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a figure element.
    ///
    /// **Accessibility**: Represents self-contained content like diagrams, photos, code listings.
    /// Use with `<figcaption>` to provide a caption. Screen readers associate caption with figure.
    #[inline(always)]
    pub const fn create_figure() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Figure),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a figure caption element.
    ///
    /// **Accessibility**: Provides a caption for `<figure>`. Screen readers announce this as the
    /// figure description.
    #[inline(always)]
    pub const fn create_figcaption() -> Self {
        Self {
            root: NodeData::create_node(NodeType::FigCaption),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    // Interactive Elements
    /// Creates a details disclosure element without accessibility information.
    ///
    /// Prefer [`Dom::create_details`] so that screen readers announce the
    /// disclosure widget's purpose.
    #[inline(always)]
    pub const fn create_details_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Details),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a details disclosure element with accessibility information.
    ///
    /// **Accessibility**: Creates a disclosure widget. Screen readers announce expanded/collapsed
    /// state. Must contain a `<summary>` element. Keyboard accessible by default.
    ///
    /// Use [`Dom::create_details_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_details(aria: SmallAriaInfo) -> Self {
        Self::create_details_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates an empty summary element for details without accessibility information.
    ///
    /// Prefer [`Dom::create_summary`] so that screen readers can announce the
    /// disclosure heading.
    #[inline(always)]
    pub const fn create_summary_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Summary),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an empty summary element for details with accessibility information.
    ///
    /// **Accessibility**: The visible heading/label for `<details>`.
    /// Must be the first child of details. Keyboard accessible (Enter/Space to toggle).
    ///
    /// Use [`Dom::create_summary_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_summary(aria: SmallAriaInfo) -> Self {
        Self::create_summary_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates a summary element with text without accessibility information.
    ///
    /// Prefer [`Dom::create_summary_with_text`] so that screen readers
    /// announce the disclosure heading.
    #[inline]
    pub fn create_summary_with_text_no_a11y<S: Into<AzString>>(text: S) -> Self {
        Self::create_summary_no_a11y().with_child(Self::create_text(text))
    }
    /// Creates a summary element with text and accessibility information for details.
    ///
    /// **Accessibility**: The visible heading/label for `<details>`.
    /// Must be the first child of details. Keyboard accessible (Enter/Space to toggle).
    ///
    /// Use [`Dom::create_summary_with_text_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_summary_with_text<S: Into<AzString>>(text: S, aria: SmallAriaInfo) -> Self {
        Self::create_summary_with_text_no_a11y(text).with_accessibility_info(aria.to_full_info())
    }
    /// Creates a dialog element without accessibility information.
    ///
    /// Prefer [`Dom::create_dialog`] so that the dialog's purpose, modality,
    /// and described-by relationship are surfaced to assistive technologies.
    #[inline(always)]
    pub const fn create_dialog_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Dialog),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a dialog element with accessibility information.
    ///
    /// **Accessibility**: Represents a modal or non-modal dialog.
    /// When opened as modal, focus is trapped. Use aria-label or aria-labelledby.
    /// Escape key should close modal dialogs.
    ///
    /// Use [`Dom::create_dialog_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_dialog(aria: DialogAriaInfo) -> Self {
        Self::create_dialog_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    // Basic Structural Elements
    #[inline(always)]
    pub const fn create_br() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Br),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    #[inline(always)]
326
    pub fn create_text<S: Into<AzString>>(value: S) -> Self {
326
        Self::create_node(NodeType::Text(BoxOrStatic::heap(value.into())))
326
    }
    #[inline(always)]
    pub fn create_image(image: ImageRef) -> Self {
        Self::create_node(NodeType::Image(BoxOrStatic::heap(image)))
    }
    /// Creates an icon node with the given icon name.
    ///
    /// The icon name should match names from the icon provider (e.g., "home", "settings", "search").
    /// Icons are resolved to actual content (font glyph, image, etc.) during StyledDom creation
    /// based on the configured IconProvider.
    ///
    /// # Example
    /// ```rust,ignore
    /// Dom::create_icon("home")
    ///     .with_class("nav-icon")
    /// ```
    #[inline(always)]
    pub fn create_icon<S: Into<AzString>>(icon_name: S) -> Self {
        Self::create_node(NodeType::Icon(BoxOrStatic::heap(icon_name.into())))
    }
    #[inline(always)]
    pub fn create_virtual_view(data: RefAny, callback: impl Into<VirtualViewCallback>) -> Self {
        Self::create_from_data(NodeData::create_virtual_view(data, callback))
    }
    /// Creates an invisible `NodeType::GeolocationProbe` node that
    /// signals "this subtree needs the user's location". Lays out as
    /// zero-size and is skipped in the display list - the framework
    /// scans for it at end-of-layout and starts / stops the native
    /// `CLLocationManager` / `LocationManager` / `geoclue`
    /// subscription. See `SUPER_PLAN_2.md` section 1.5.
    #[inline(always)]
    pub fn create_geolocation_probe(config: crate::geolocation::GeolocationProbeConfig) -> Self {
        Self::create_node(NodeType::GeolocationProbe(config))
    }
    // Semantic HTML Elements with Accessibility Guidance
    /// Creates a paragraph element.
    ///
    /// **Accessibility**: Paragraphs provide semantic structure for screen readers.
    #[inline(always)]
36
    pub const fn create_p() -> Self {
36
        Self {
36
            root: NodeData::create_node(NodeType::P),
36
            children: DomVec::from_const_slice(&[]),
36
            css: azul_css::css::CssVec::from_const_slice(&[]),
36
            estimated_total_children: 0,
36
        }
36
    }
    /// Creates an empty heading level 1 element.
    ///
    /// **Accessibility**: Use `h1` for the main page title. There should typically be only one `h1`
    /// per page.
    #[inline(always)]
1
    pub const fn create_h1() -> Self {
1
        Self {
1
            root: NodeData::create_node(NodeType::H1),
1
            children: DomVec::from_const_slice(&[]),
1
            css: azul_css::css::CssVec::from_const_slice(&[]),
1
            estimated_total_children: 0,
1
        }
1
    }
    /// Creates a heading level 1 element with text.
    ///
    /// **Accessibility**: Use `h1` for the main page title. There should typically be only one `h1`
    /// per page.
    ///
    /// **Parameters:**
    /// - `text`: Heading text
    #[inline]
1
    pub fn create_h1_with_text<S: Into<AzString>>(text: S) -> Self {
1
        Self::create_h1().with_child(Self::create_text(text))
1
    }
    /// Creates an empty heading level 2 element.
    ///
    /// **Accessibility**: Use `h2` for major section headings under `h1`.
    #[inline(always)]
    pub const fn create_h2() -> Self {
        Self {
            root: NodeData::create_node(NodeType::H2),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a heading level 2 element with text.
    ///
    /// **Accessibility**: Use `h2` for major section headings under `h1`.
    ///
    /// **Parameters:**
    /// - `text`: Heading text
    #[inline]
    pub fn create_h2_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_h2().with_child(Self::create_text(text))
    }
    /// Creates an empty heading level 3 element.
    ///
    /// **Accessibility**: Use `h3` for subsections under `h2`.
    #[inline(always)]
    pub const fn create_h3() -> Self {
        Self {
            root: NodeData::create_node(NodeType::H3),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a heading level 3 element with text.
    ///
    /// **Accessibility**: Use `h3` for subsections under `h2`.
    ///
    /// **Parameters:**
    /// - `text`: Heading text
    #[inline]
    pub fn create_h3_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_h3().with_child(Self::create_text(text))
    }
    /// Creates an empty heading level 4 element.
    #[inline(always)]
    pub const fn create_h4() -> Self {
        Self {
            root: NodeData::create_node(NodeType::H4),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a heading level 4 element with text.
    ///
    /// **Parameters:**
    /// - `text`: Heading text
    #[inline]
    pub fn create_h4_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_h4().with_child(Self::create_text(text))
    }
    /// Creates an empty heading level 5 element.
    #[inline(always)]
    pub const fn create_h5() -> Self {
        Self {
            root: NodeData::create_node(NodeType::H5),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a heading level 5 element with text.
    ///
    /// **Parameters:**
    /// - `text`: Heading text
    #[inline]
    pub fn create_h5_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_h5().with_child(Self::create_text(text))
    }
    /// Creates an empty heading level 6 element.
    #[inline(always)]
    pub const fn create_h6() -> Self {
        Self {
            root: NodeData::create_node(NodeType::H6),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a heading level 6 element with text.
    ///
    /// **Parameters:**
    /// - `text`: Heading text
    #[inline]
    pub fn create_h6_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_h6().with_child(Self::create_text(text))
    }
    /// Creates an empty generic inline container (span).
    ///
    /// **Accessibility**: Prefer semantic elements like `strong`, `em`, `code`, etc. when
    /// applicable.
    #[inline(always)]
    pub const fn create_span() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Span),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a generic inline container (span) with text.
    ///
    /// **Accessibility**: Prefer semantic elements like `strong`, `em`, `code`, etc. when
    /// applicable.
    ///
    /// **Parameters:**
    /// - `text`: Span content
    #[inline]
    pub fn create_span_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_span().with_child(Self::create_text(text))
    }
    /// Creates an empty strong importance element.
    ///
    /// **Accessibility**: Use `strong` instead of `b` for semantic meaning.
    #[inline(always)]
    pub const fn create_strong() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Strong),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a strongly emphasized text element with text (strong importance).
    ///
    /// **Accessibility**: Use `strong` instead of `b` for semantic meaning. Screen readers can
    /// convey the importance. Use for text that has strong importance, seriousness, or urgency.
    ///
    /// **Parameters:**
    /// - `text`: Text to emphasize
    #[inline]
    pub fn create_strong_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_strong().with_child(Self::create_text(text))
    }
    /// Creates an empty emphasis element (stress emphasis).
    ///
    /// **Accessibility**: Use `em` instead of `i` for semantic meaning.
    #[inline(always)]
    pub const fn create_em() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Em),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an emphasized text element with text (stress emphasis).
    ///
    /// **Accessibility**: Use `em` instead of `i` for semantic meaning. Screen readers can
    /// convey the emphasis. Use for text that has stress emphasis.
    ///
    /// **Parameters:**
    /// - `text`: Text to emphasize
    #[inline]
    pub fn create_em_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_em().with_child(Self::create_text(text))
    }
    /// Creates an empty code element.
    ///
    /// **Accessibility**: Represents a fragment of computer code.
    #[inline(always)]
    pub fn create_code() -> Self {
        Self::create_node(NodeType::Code)
    }
    /// Creates a code/computer code element with text.
    ///
    /// **Accessibility**: Represents a fragment of computer code. Screen readers can identify
    /// this as code content.
    ///
    /// **Parameters:**
    /// - `code`: Code content
    #[inline]
    pub fn create_code_with_text<S: Into<AzString>>(code: S) -> Self {
        Self::create_code().with_child(Self::create_text(code))
    }
    /// Creates an empty preformatted text element.
    ///
    /// **Accessibility**: Preserves whitespace and line breaks.
    #[inline(always)]
    pub fn create_pre() -> Self {
        Self::create_node(NodeType::Pre)
    }
    /// Creates a preformatted text element with text.
    ///
    /// **Accessibility**: Preserves whitespace and line breaks. Useful for code blocks or
    /// ASCII art. Screen readers will read the content as-is.
    ///
    /// **Parameters:**
    /// - `text`: Preformatted content
    #[inline]
    pub fn create_pre_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_pre().with_child(Self::create_text(text))
    }
    /// Creates an empty blockquote element.
    ///
    /// **Accessibility**: Represents a section quoted from another source.
    #[inline(always)]
    pub fn create_blockquote() -> Self {
        Self::create_node(NodeType::BlockQuote)
    }
    /// Creates a blockquote element with text.
    ///
    /// **Accessibility**: Represents a section quoted from another source. Screen readers
    /// can identify quoted content. Consider adding a `cite` attribute.
    ///
    /// **Parameters:**
    /// - `text`: Quote content
    #[inline]
    pub fn create_blockquote_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_blockquote().with_child(Self::create_text(text))
    }
    /// Creates an empty citation element.
    ///
    /// **Accessibility**: Represents a reference to a creative work.
    #[inline(always)]
    pub fn create_cite() -> Self {
        Self::create_node(NodeType::Cite)
    }
    /// Creates a citation element with text.
    ///
    /// **Accessibility**: Represents a reference to a creative work. Screen readers can
    /// identify citations.
    ///
    /// **Parameters:**
    /// - `text`: Citation text
    #[inline]
    pub fn create_cite_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_cite().with_child(Self::create_text(text))
    }
    /// Creates an empty abbreviation element.
    ///
    /// **Accessibility**: Represents an abbreviation or acronym. Use with a `title` attribute
    /// to provide the full expansion for screen readers.
    #[inline(always)]
    pub fn create_abbr() -> Self {
        Self::create_node(NodeType::Abbr)
    }
    /// Creates an abbreviation element with abbreviated text and a `title` expansion.
    ///
    /// **Accessibility**: Represents an abbreviation or acronym. The `title` attribute
    /// provides the full expansion for screen readers.
    ///
    /// **Parameters:**
    /// - `abbr_text`: Abbreviated text
    /// - `title`: Full expansion
    #[inline]
    pub fn create_abbr_with_title(abbr_text: AzString, title: AzString) -> Self {
        Self::create_node(NodeType::Abbr)
            .with_attribute(AttributeType::Title(title))
            .with_child(Self::create_text(abbr_text))
    }
    /// Creates an empty keyboard input element.
    ///
    /// **Accessibility**: Represents keyboard input or key combinations.
    #[inline(always)]
    pub fn create_kbd() -> Self {
        Self::create_node(NodeType::Kbd)
    }
    /// Creates a keyboard input element with text.
    ///
    /// **Accessibility**: Represents keyboard input or key combinations. Screen readers can
    /// identify keyboard instructions.
    ///
    /// **Parameters:**
    /// - `text`: Keyboard instruction
    #[inline]
    pub fn create_kbd_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_kbd().with_child(Self::create_text(text))
    }
    /// Creates an empty sample output element.
    ///
    /// **Accessibility**: Represents sample output from a program or computing system.
    #[inline(always)]
    pub fn create_samp() -> Self {
        Self::create_node(NodeType::Samp)
    }
    /// Creates a sample output element with text.
    ///
    /// **Accessibility**: Represents sample output from a program or computing system.
    ///
    /// **Parameters:**
    /// - `text`: Sample text
    #[inline]
    pub fn create_samp_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_samp().with_child(Self::create_text(text))
    }
    /// Creates an empty variable element.
    ///
    /// **Accessibility**: Represents a variable in mathematical expressions or programming.
    #[inline(always)]
    pub fn create_var() -> Self {
        Self::create_node(NodeType::Var)
    }
    /// Creates a variable element with text.
    ///
    /// **Accessibility**: Represents a variable in mathematical expressions or programming.
    ///
    /// **Parameters:**
    /// - `text`: Variable name
    #[inline]
    pub fn create_var_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_var().with_child(Self::create_text(text))
    }
    /// Creates an empty subscript element.
    #[inline(always)]
    pub fn create_sub() -> Self {
        Self::create_node(NodeType::Sub)
    }
    /// Creates a subscript element with text.
    ///
    /// **Accessibility**: Screen readers may announce subscript formatting.
    ///
    /// **Parameters:**
    /// - `text`: Subscript content
    #[inline]
    pub fn create_sub_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_sub().with_child(Self::create_text(text))
    }
    /// Creates an empty superscript element.
    #[inline(always)]
    pub fn create_sup() -> Self {
        Self::create_node(NodeType::Sup)
    }
    /// Creates a superscript element with text.
    ///
    /// **Accessibility**: Screen readers may announce superscript formatting.
    ///
    /// **Parameters:**
    /// - `text`: Superscript content
    #[inline]
    pub fn create_sup_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_sup().with_child(Self::create_text(text))
    }
    /// Creates an empty underline element.
    #[inline(always)]
    pub fn create_u() -> Self {
        Self::create_node(NodeType::U)
    }
    /// Creates an underline text element with text.
    ///
    /// **Accessibility**: Screen readers typically don't announce underline formatting.
    /// Use semantic elements when possible (e.g., `<em>` for emphasis).
    #[inline]
    pub fn create_u_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_u().with_child(Self::create_text(text))
    }
    /// Creates an empty strikethrough element.
    #[inline(always)]
    pub fn create_s() -> Self {
        Self::create_node(NodeType::S)
    }
    /// Creates a strikethrough text element with text.
    ///
    /// **Accessibility**: Represents text that is no longer accurate or relevant.
    /// Consider using `<del>` for deleted content with datetime attribute.
    #[inline]
    pub fn create_s_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_s().with_child(Self::create_text(text))
    }
    /// Creates an empty mark element.
    #[inline(always)]
    pub fn create_mark() -> Self {
        Self::create_node(NodeType::Mark)
    }
    /// Creates a marked/highlighted text element with text.
    ///
    /// **Accessibility**: Represents text marked for reference or notation purposes.
    /// Screen readers may announce this as "highlighted".
    #[inline]
    pub fn create_mark_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_mark().with_child(Self::create_text(text))
    }
    /// Creates an empty deleted text element.
    #[inline(always)]
    pub fn create_del() -> Self {
        Self::create_node(NodeType::Del)
    }
    /// Creates a deleted text element with text.
    ///
    /// **Accessibility**: Represents deleted content in document edits.
    /// Use with `datetime` and `cite` attributes for edit tracking.
    #[inline]
    pub fn create_del_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_del().with_child(Self::create_text(text))
    }
    /// Creates an empty inserted text element.
    #[inline(always)]
    pub fn create_ins() -> Self {
        Self::create_node(NodeType::Ins)
    }
    /// Creates an inserted text element with text.
    ///
    /// **Accessibility**: Represents inserted content in document edits.
    /// Use with `datetime` and `cite` attributes for edit tracking.
    #[inline]
    pub fn create_ins_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_ins().with_child(Self::create_text(text))
    }
    /// Creates an empty definition element.
    #[inline(always)]
    pub fn create_dfn() -> Self {
        Self::create_node(NodeType::Dfn)
    }
    /// Creates a definition element with text.
    ///
    /// **Accessibility**: Represents the defining instance of a term.
    /// Often used within a definition list or with `<abbr>`.
    #[inline]
    pub fn create_dfn_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_dfn().with_child(Self::create_text(text))
    }
    /// Creates a time element.
    ///
    /// **Accessibility**: Represents a specific time or date.
    /// Use `datetime` attribute for machine-readable format.
    ///
    /// **Parameters:**
    /// - `text`: Human-readable time/date
    /// - `datetime`: Optional machine-readable datetime
    #[inline]
    pub fn create_time(text: AzString, datetime: OptionString) -> Self {
        let mut element = Self::create_node(NodeType::Time).with_child(Self::create_text(text));
        if let OptionString::Some(dt) = datetime {
            element = element.with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "datetime".into(),
                value: dt,
            }));
        }
        element
    }
    /// Creates an empty bi-directional override element.
    ///
    /// **Accessibility**: Overrides text direction. Use `dir` attribute (ltr/rtl).
    #[inline(always)]
    pub fn create_bdo() -> Self {
        Self::create_node(NodeType::Bdo)
    }
    /// Creates a bi-directional override element with text.
    ///
    /// **Accessibility**: Overrides text direction. Use `dir` attribute (ltr/rtl).
    #[inline]
    pub fn create_bdo_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_bdo().with_child(Self::create_text(text))
    }
    // Additional inline / text-level elements
    /// Creates an empty bold element.
    ///
    /// **Accessibility**: Prefer `<strong>` for semantic emphasis. `<b>` is purely stylistic.
    #[inline(always)]
    pub fn create_b() -> Self {
        Self::create_node(NodeType::B)
    }
    /// Creates a bold element with text.
    ///
    /// **Accessibility**: Prefer `<strong>` for semantic emphasis. `<b>` is purely stylistic.
    ///
    /// **Parameters:**
    /// - `text`: Bold text content
    #[inline]
    pub fn create_b_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_b().with_child(Self::create_text(text))
    }
    /// Creates an empty italic element.
    ///
    /// **Accessibility**: Prefer `<em>` for stress emphasis. `<i>` is purely stylistic.
    #[inline(always)]
    pub fn create_i() -> Self {
        Self::create_node(NodeType::I)
    }
    /// Creates an italic element with text.
    ///
    /// **Accessibility**: Prefer `<em>` for stress emphasis. `<i>` is purely stylistic.
    ///
    /// **Parameters:**
    /// - `text`: Italic text content
    #[inline]
    pub fn create_i_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_i().with_child(Self::create_text(text))
    }
    /// Creates an empty small text element.
    ///
    /// **Accessibility**: Represents side-comments and small print like copyright/legal text.
    #[inline(always)]
    pub fn create_small() -> Self {
        Self::create_node(NodeType::Small)
    }
    /// Creates a small text element with text.
    ///
    /// **Parameters:**
    /// - `text`: Small text content
    #[inline]
    pub fn create_small_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_small().with_child(Self::create_text(text))
    }
    /// Creates an empty `<big>` element.
    ///
    /// **Note**: Deprecated in HTML5. Prefer CSS `font-size`.
    #[inline(always)]
    pub fn create_big() -> Self {
        Self::create_node(NodeType::Big)
    }
    /// Creates a `<big>` element with text.
    ///
    /// **Note**: Deprecated in HTML5. Prefer CSS `font-size`.
    #[inline]
    pub fn create_big_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_big().with_child(Self::create_text(text))
    }
    /// Creates an empty bi-directional isolate element.
    ///
    /// **Accessibility**: Used to isolate text whose direction is unknown,
    /// keeping it from affecting surrounding bidi layout.
    #[inline(always)]
    pub fn create_bdi() -> Self {
        Self::create_node(NodeType::Bdi)
    }
    /// Creates a bi-directional isolate element with text.
    ///
    /// **Accessibility**: Used to isolate text whose direction is unknown,
    /// keeping it from affecting surrounding bidi layout.
    #[inline]
    pub fn create_bdi_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_bdi().with_child(Self::create_text(text))
    }
    /// Creates an empty word break opportunity element.
    ///
    /// **Note**: `<wbr>` is a self-closing element that suggests a line-break opportunity.
    /// It does not take text content.
    #[inline(always)]
    pub fn create_wbr() -> Self {
        Self::create_node(NodeType::Wbr)
    }
    /// Creates an empty ruby annotation element.
    ///
    /// **Accessibility**: Used for East Asian typography to provide
    /// pronunciation/translation annotations. Wraps `<rt>`/`<rp>` children.
    #[inline(always)]
    pub fn create_ruby() -> Self {
        Self::create_node(NodeType::Ruby)
    }
    /// Creates an empty ruby text element.
    ///
    /// **Accessibility**: Pronunciation/translation annotation inside `<ruby>`.
    #[inline(always)]
    pub fn create_rt() -> Self {
        Self::create_node(NodeType::Rt)
    }
    /// Creates a ruby text element with text.
    ///
    /// **Parameters:**
    /// - `text`: Ruby annotation content
    #[inline]
    pub fn create_rt_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_rt().with_child(Self::create_text(text))
    }
    /// Creates an empty ruby text container element.
    ///
    /// **Accessibility**: Container for ruby text annotations.
    #[inline(always)]
    pub fn create_rtc() -> Self {
        Self::create_node(NodeType::Rtc)
    }
    /// Creates an empty ruby fallback parenthesis element.
    ///
    /// **Accessibility**: Provides parentheses around `<rt>` for browsers without ruby support.
    #[inline(always)]
    pub fn create_rp() -> Self {
        Self::create_node(NodeType::Rp)
    }
    /// Creates a ruby fallback parenthesis element with text.
    ///
    /// **Parameters:**
    /// - `text`: Parenthesis text (typically "(" or ")")
    #[inline]
    pub fn create_rp_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_rp().with_child(Self::create_text(text))
    }
    /// Creates a `<data>` element binding a machine-readable value to its content.
    ///
    /// **Parameters:**
    /// - `value`: Machine-readable value for the `value` attribute.
    #[inline]
    pub fn create_data(value: AzString) -> Self {
        Self::create_node(NodeType::Data).with_attribute(AttributeType::Value(value))
    }
    /// Creates a `<data>` element with both a machine-readable value and visible text.
    ///
    /// **Parameters:**
    /// - `value`: Machine-readable value for the `value` attribute.
    /// - `text`: Human-readable text content.
    #[inline]
    pub fn create_data_with_text(value: AzString, text: AzString) -> Self {
        Self::create_data(value).with_child(Self::create_text(text))
    }
    /// Creates an empty directory list element.
    ///
    /// **Note**: Deprecated in HTML5. Use `<ul>` instead.
    #[inline(always)]
    pub fn create_dir() -> Self {
        Self::create_node(NodeType::Dir)
    }
    /// Creates an empty SVG container element.
    ///
    /// **Accessibility**: Provide `aria-label` or `<title>` child for assistive tech.
    #[inline(always)]
    pub fn create_svg() -> Self {
        Self::create_node(NodeType::Svg)
    }
    /// Creates an anchor/hyperlink element without accessibility information.
    ///
    /// Prefer [`Dom::create_a`] so that screen readers get a meaningful label.
    ///
    /// **Parameters:**
    /// - `href`: Link destination URL
    /// - `label`: Link text (pass `None` for image-only links with alt text)
    #[inline]
2
    pub fn create_a_no_a11y(href: AzString, label: OptionString) -> Self {
2
        let mut link = Self::create_node(NodeType::A).with_attribute(AttributeType::Href(href));
2
        if let OptionString::Some(text) = label {
1
            link = link.with_child(Self::create_text(text));
1
        }
2
        link
2
    }
    /// Creates a button element without accessibility information.
    ///
    /// Prefer [`Dom::create_button`] so that the element has a meaningful accessible
    /// name for screen readers.
    ///
    /// **Parameters:**
    /// - `text`: Button label text
    #[inline]
2
    pub fn create_button_no_a11y(text: AzString) -> Self {
2
        Self::create_node(NodeType::Button).with_child(Self::create_text(text))
2
    }
    /// Creates a label element for form controls without accessibility information.
    ///
    /// Prefer [`Dom::create_label`] so that screen readers get a descriptive label.
    ///
    /// **Parameters:**
    /// - `for_id`: ID of the associated form control
    /// - `text`: Label text
    #[inline]
2
    pub fn create_label_no_a11y(for_id: AzString, text: AzString) -> Self {
2
        Self::create_node(NodeType::Label)
2
            .with_attribute(AttributeType::Custom(AttributeNameValue {
2
                attr_name: "for".into(),
2
                value: for_id,
2
            }))
2
            .with_child(Self::create_text(text))
2
    }
    /// Creates an input element without accessibility information.
    ///
    /// Prefer [`Dom::create_input`] so that screen readers get a descriptive label
    /// beyond the HTML `aria-label` attribute.
    ///
    /// **Parameters:**
    /// - `input_type`: Input type (text, password, email, etc.)
    /// - `name`: Form field name
    /// - `label`: Accessibility label (required)
    #[inline]
2
    pub fn create_input_no_a11y(input_type: AzString, name: AzString, label: AzString) -> Self {
2
        Self::create_node(NodeType::Input)
2
            .with_attribute(AttributeType::InputType(input_type))
2
            .with_attribute(AttributeType::Name(name))
2
            .with_attribute(AttributeType::AriaLabel(label))
2
    }
    /// Creates a textarea element without accessibility information.
    ///
    /// Prefer [`Dom::create_textarea`] so that screen readers get an accurate
    /// description of the control.
    ///
    /// **Parameters:**
    /// - `name`: Form field name
    /// - `label`: Accessibility label (required)
    #[inline]
2
    pub fn create_textarea_no_a11y(name: AzString, label: AzString) -> Self {
2
        Self::create_node(NodeType::TextArea)
2
            .with_attribute(AttributeType::Name(name))
2
            .with_attribute(AttributeType::AriaLabel(label))
2
    }
    /// Creates a select dropdown element without accessibility information.
    ///
    /// Prefer [`Dom::create_select`] so that screen readers announce the control
    /// appropriately.
    ///
    /// **Parameters:**
    /// - `name`: Form field name
    /// - `label`: Accessibility label (required)
    #[inline]
2
    pub fn create_select_no_a11y(name: AzString, label: AzString) -> Self {
2
        Self::create_node(NodeType::Select)
2
            .with_attribute(AttributeType::Name(name))
2
            .with_attribute(AttributeType::AriaLabel(label))
2
    }
    /// Creates an option element for select dropdowns.
    ///
    /// **Parameters:**
    /// - `value`: Option value
    /// - `text`: Display text
    #[inline]
    pub fn create_option_no_a11y(value: AzString, text: AzString) -> Self {
        Self::create_node(NodeType::SelectOption)
            .with_attribute(AttributeType::Value(value))
            .with_child(Self::create_text(text))
    }
    /// Creates an option element for select dropdowns with accessibility information.
    ///
    /// **Parameters:**
    /// - `value`: Option value
    /// - `text`: Display text
    /// - `aria`: Accessibility information (description, etc.)
    ///
    /// Use [`Dom::create_option_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_option(value: AzString, text: AzString, aria: SmallAriaInfo) -> Self {
        Self::create_option_no_a11y(value, text).with_accessibility_info(aria.to_full_info())
    }
    /// Creates an unordered list element.
    ///
    /// **Accessibility**: Screen readers announce lists and item counts, helping users
    /// understand content structure.
    #[inline(always)]
    pub fn create_ul() -> Self {
        Self::create_node(NodeType::Ul)
    }
    /// Creates an ordered list element.
    ///
    /// **Accessibility**: Screen readers announce lists and item counts, helping users
    /// understand content structure and numbering.
    #[inline(always)]
    pub fn create_ol() -> Self {
        Self::create_node(NodeType::Ol)
    }
    /// Creates a list item element.
    ///
    /// **Accessibility**: Must be a child of `ul`, `ol`, or `menu`. Screen readers announce
    /// list item position (e.g., "2 of 5").
    #[inline(always)]
    pub fn create_li() -> Self {
        Self::create_node(NodeType::Li)
    }
    /// Creates a table element without accessibility information.
    ///
    /// Prefer [`Dom::create_table`] so that screen readers can announce the table's
    /// purpose alongside its caption.
    #[inline(always)]
2
    pub fn create_table_no_a11y() -> Self {
2
        Self::create_node(NodeType::Table)
2
    }
    /// Creates a table caption element.
    ///
    /// **Accessibility**: Describes the purpose of the table. Screen readers announce this first.
    #[inline(always)]
1
    pub fn create_caption() -> Self {
1
        Self::create_node(NodeType::Caption)
1
    }
    /// Creates a table header element.
    ///
    /// **Accessibility**: Groups header rows. Screen readers can navigate table structure.
    #[inline(always)]
    pub fn create_thead() -> Self {
        Self::create_node(NodeType::THead)
    }
    /// Creates a table body element.
    ///
    /// **Accessibility**: Groups body rows. Screen readers can navigate table structure.
    #[inline(always)]
    pub fn create_tbody() -> Self {
        Self::create_node(NodeType::TBody)
    }
    /// Creates a table footer element.
    ///
    /// **Accessibility**: Groups footer rows. Screen readers can navigate table structure.
    #[inline(always)]
    pub fn create_tfoot() -> Self {
        Self::create_node(NodeType::TFoot)
    }
    /// Creates a table row element.
    #[inline(always)]
    pub fn create_tr() -> Self {
        Self::create_node(NodeType::Tr)
    }
    /// Creates a table header cell element.
    ///
    /// **Accessibility**: Use `scope` attribute ("col" or "row") to associate headers with
    /// data cells. Screen readers use this to announce cell context.
    #[inline(always)]
    pub fn create_th() -> Self {
        Self::create_node(NodeType::Th)
    }
    /// Creates a table data cell element.
    #[inline(always)]
    pub fn create_td() -> Self {
        Self::create_node(NodeType::Td)
    }
    /// Creates a form element without accessibility information.
    ///
    /// Prefer [`Dom::create_form`] so that screen readers can announce the form's purpose.
    #[inline(always)]
    pub fn create_form_no_a11y() -> Self {
        Self::create_node(NodeType::Form)
    }
    /// Creates a form element with accessibility information.
    ///
    /// **Accessibility**: Group related form controls with `fieldset` and `legend`.
    /// Provide clear labels for all inputs. Consider `aria-describedby` for instructions.
    ///
    /// Use [`Dom::create_form_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_form(aria: SmallAriaInfo) -> Self {
        Self::create_form_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates a fieldset element for grouping form controls without accessibility info.
    ///
    /// Prefer [`Dom::create_fieldset`] so that screen readers can announce the group's purpose.
    #[inline(always)]
    pub fn create_fieldset_no_a11y() -> Self {
        Self::create_node(NodeType::FieldSet)
    }
    /// Creates a fieldset element with accessibility information.
    ///
    /// **Accessibility**: Groups related form controls. Always include a `legend` as the
    /// first child to describe the group. Screen readers announce the legend when entering
    /// the fieldset.
    ///
    /// Use [`Dom::create_fieldset_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_fieldset(aria: SmallAriaInfo) -> Self {
        Self::create_fieldset_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates a legend element without accessibility information.
    ///
    /// Prefer [`Dom::create_legend`] so that the legend's accessible name is explicit.
    #[inline(always)]
    pub fn create_legend_no_a11y() -> Self {
        Self::create_node(NodeType::Legend)
    }
    /// Creates a legend element with accessibility information.
    ///
    /// **Accessibility**: Describes the purpose of a fieldset. Must be the first child of
    /// a fieldset. Screen readers announce this when entering the fieldset.
    ///
    /// Use [`Dom::create_legend_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_legend(aria: SmallAriaInfo) -> Self {
        Self::create_legend_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates a horizontal rule element.
    ///
    /// **Accessibility**: Represents a thematic break. Screen readers may announce this as
    /// a separator. Consider using CSS borders for purely decorative lines.
    #[inline(always)]
    pub fn create_hr() -> Self {
        Self::create_node(NodeType::Hr)
    }
    // Additional Element Constructors
    /// Creates an address element.
    ///
    /// **Accessibility**: Represents contact information. Screen readers identify this
    /// as address content.
    #[inline(always)]
    pub const fn create_address() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Address),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a definition list element.
    ///
    /// **Accessibility**: Screen readers announce definition lists and their structure.
    #[inline(always)]
    pub const fn create_dl() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Dl),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a definition term element.
    ///
    /// **Accessibility**: Must be a child of `dl`. Represents the term being defined.
    #[inline(always)]
    pub const fn create_dt() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Dt),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a definition description element.
    ///
    /// **Accessibility**: Must be a child of `dl`. Provides the definition for the term.
    #[inline(always)]
    pub const fn create_dd() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Dd),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a table column group element.
    #[inline(always)]
    pub const fn create_colgroup() -> Self {
        Self {
            root: NodeData::create_node(NodeType::ColGroup),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a table column element.
    #[inline]
    pub fn create_col(span: i32) -> Self {
        Self::create_node(NodeType::Col).with_attribute(AttributeType::ColSpan(span))
    }
    /// Creates an optgroup element for grouping select options without accessibility info.
    ///
    /// Prefer [`Dom::create_optgroup`] so that screen readers can announce the group's purpose.
    ///
    /// **Parameters:**
    /// - `label`: Label for the option group
    #[inline]
    pub fn create_optgroup_no_a11y(label: AzString) -> Self {
        Self::create_node(NodeType::OptGroup).with_attribute(AttributeType::AriaLabel(label))
    }
    /// Creates an optgroup element for grouping select options with accessibility information.
    ///
    /// **Parameters:**
    /// - `label`: Label for the option group (visible)
    /// - `aria`: Additional accessibility information (description, etc.)
    ///
    /// Use [`Dom::create_optgroup_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_optgroup(label: AzString, aria: SmallAriaInfo) -> Self {
        Self::create_optgroup_no_a11y(label).with_accessibility_info(aria.to_full_info())
    }
    /// Creates a quotation element.
    ///
    /// **Accessibility**: Represents an inline quotation.
    #[inline(always)]
    pub const fn create_q() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Q),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an empty acronym element.
    ///
    /// **Note**: Deprecated in HTML5. Consider using `create_abbr()` instead.
    #[inline(always)]
    pub const fn create_acronym() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Acronym),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an acronym element with text.
    ///
    /// **Note**: Deprecated in HTML5. Consider using `create_abbr_with_title()` instead.
    #[inline]
    pub fn create_acronym_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_acronym().with_child(Self::create_text(text))
    }
    /// Creates a menu element without accessibility information.
    ///
    /// Prefer [`Dom::create_menu`] so that the menu's purpose is announced.
    #[inline(always)]
    pub const fn create_menu_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Menu),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a menu element with accessibility information.
    ///
    /// **Accessibility**: Represents a list of commands. Similar to `<ul>` but semantic for
    /// toolbars/menus.
    ///
    /// Use [`Dom::create_menu_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_menu(aria: SmallAriaInfo) -> Self {
        Self::create_menu_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates an empty menu item element without accessibility information.
    ///
    /// Prefer [`Dom::create_menuitem`] so that the menu item's purpose is announced.
    #[inline(always)]
    pub const fn create_menuitem_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::MenuItem),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an empty menu item element with accessibility information.
    ///
    /// **Accessibility**: Represents a command in a menu. Use with appropriate role/aria
    /// attributes.
    ///
    /// Use [`Dom::create_menuitem_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_menuitem(aria: SmallAriaInfo) -> Self {
        Self::create_menuitem_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates a menu item element with text but without accessibility information.
    ///
    /// Prefer [`Dom::create_menuitem_with_text`] so that screen readers get a
    /// distinct accessible name in addition to the visible text.
    #[inline]
    pub fn create_menuitem_with_text_no_a11y<S: Into<AzString>>(text: S) -> Self {
        Self::create_menuitem_no_a11y().with_child(Self::create_text(text))
    }
    /// Creates a menu item element with text and accessibility information.
    ///
    /// **Accessibility**: Represents a command in a menu. Use with appropriate role/aria
    /// attributes.
    ///
    /// Use [`Dom::create_menuitem_with_text_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_menuitem_with_text<S: Into<AzString>>(text: S, aria: SmallAriaInfo) -> Self {
        Self::create_menuitem_with_text_no_a11y(text).with_accessibility_info(aria.to_full_info())
    }
    /// Creates an output element without accessibility information.
    ///
    /// Prefer [`Dom::create_output`] so that screen readers can announce the
    /// computed value's purpose.
    #[inline(always)]
    pub const fn create_output_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Output),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an output element with accessibility information.
    ///
    /// **Accessibility**: Represents the result of a calculation or user action.
    /// Use `for` attribute to associate with input elements. Screen readers announce updates.
    ///
    /// Use [`Dom::create_output_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_output(aria: SmallAriaInfo) -> Self {
        Self::create_output_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates a progress indicator element without accessibility information.
    ///
    /// Prefer [`Dom::create_progress`] so that the task being measured is announced.
    ///
    /// **Parameters:**
    /// - `value`: Current progress value
    /// - `max`: Maximum value
    #[inline]
    pub fn create_progress_no_a11y(value: f32, max: f32) -> Self {
        Self::create_node(NodeType::Progress)
            .with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "value".into(),
                value: value.to_string().into(),
            }))
            .with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "max".into(),
                value: max.to_string().into(),
            }))
    }
    /// Creates a progress indicator element with accessibility information.
    ///
    /// **Accessibility**: Represents task progress. Screen readers announce progress
    /// percentage. The `aria` value carries the label, current value, max, and an
    /// indeterminate flag for spinners with no known endpoint.
    ///
    /// Use [`Dom::create_progress_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_progress(aria: ProgressAriaInfo) -> Self {
        let mut node = Self::create_node(NodeType::Progress);
        if !aria.indeterminate {
            if let azul_css::OptionF32::Some(v) = aria.current_value {
                node = node.with_attribute(AttributeType::Custom(AttributeNameValue {
                    attr_name: "value".into(),
                    value: v.to_string().into(),
                }));
            }
        }
        if let azul_css::OptionF32::Some(m) = aria.max {
            node = node.with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "max".into(),
                value: m.to_string().into(),
            }));
        }
        node.with_accessibility_info(aria.to_full_info())
    }
    /// Creates a meter gauge element without accessibility information.
    ///
    /// Prefer [`Dom::create_meter`] so that the measurement's purpose is announced.
    ///
    /// **Parameters:**
    /// - `value`: Current meter value
    /// - `min`: Minimum value
    /// - `max`: Maximum value
    #[inline]
    pub fn create_meter_no_a11y(value: f32, min: f32, max: f32) -> Self {
        Self::create_node(NodeType::Meter)
            .with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "value".into(),
                value: value.to_string().into(),
            }))
            .with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "min".into(),
                value: min.to_string().into(),
            }))
            .with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "max".into(),
                value: max.to_string().into(),
            }))
    }
    /// Creates a meter gauge element with accessibility information.
    ///
    /// **Accessibility**: Represents a scalar measurement within a known range.
    /// Screen readers announce the measurement. The `aria` value carries the
    /// label plus value/min/max/low/high/optimum metadata.
    ///
    /// Use [`Dom::create_meter_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_meter(aria: MeterAriaInfo) -> Self {
        let mut node = Self::create_meter_no_a11y(aria.current_value, aria.min, aria.max);
        if let azul_css::OptionF32::Some(v) = aria.low {
            node = node.with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "low".into(),
                value: v.to_string().into(),
            }));
        }
        if let azul_css::OptionF32::Some(v) = aria.high {
            node = node.with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "high".into(),
                value: v.to_string().into(),
            }));
        }
        if let azul_css::OptionF32::Some(v) = aria.optimum {
            node = node.with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "optimum".into(),
                value: v.to_string().into(),
            }));
        }
        node.with_accessibility_info(aria.to_full_info())
    }
    /// Creates a datalist element without accessibility information.
    ///
    /// Prefer [`Dom::create_datalist`] so that the suggestion list's purpose is announced.
    #[inline(always)]
    pub const fn create_datalist_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::DataList),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a datalist element with accessibility information.
    ///
    /// **Accessibility**: Provides autocomplete options for inputs.
    /// Associate with input using `list` attribute. Screen readers announce available options.
    ///
    /// Use [`Dom::create_datalist_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_datalist(aria: SmallAriaInfo) -> Self {
        Self::create_datalist_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    // Embedded Content Elements
    /// Creates a canvas element for graphics without accessibility information.
    ///
    /// Prefer [`Dom::create_canvas`] so that the canvas's purpose is announced; canvas
    /// content is otherwise opaque to assistive technologies.
    #[inline(always)]
    pub const fn create_canvas_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Canvas),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a canvas element for graphics with accessibility information.
    ///
    /// **Accessibility**: Canvas content is not accessible by default.
    /// Always provide fallback content as children and/or detailed aria-label.
    /// Consider using SVG for accessible graphics when possible.
    ///
    /// Use [`Dom::create_canvas_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_canvas(aria: SmallAriaInfo) -> Self {
        Self::create_canvas_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates an object element for embedded content.
    ///
    /// **Accessibility**: Provide fallback content as children. Use aria-label to describe content.
    #[inline(always)]
    pub const fn create_object() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Object),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a param element for object parameters.
    ///
    /// **Parameters:**
    /// - `name`: Parameter name
    /// - `value`: Parameter value
    #[inline]
    pub fn create_param(name: AzString, value: AzString) -> Self {
        Self::create_node(NodeType::Param)
            .with_attribute(AttributeType::Name(name))
            .with_attribute(AttributeType::Value(value))
    }
    /// Creates an embed element.
    ///
    /// **Accessibility**: Provide alternative content or link. Use aria-label to describe embedded
    /// content.
    #[inline(always)]
    pub const fn create_embed() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Embed),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an audio element without accessibility information.
    ///
    /// Prefer [`Dom::create_audio`] so that screen readers announce the audio's purpose.
    #[inline(always)]
    pub const fn create_audio_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Audio),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an audio element with accessibility information.
    ///
    /// **Accessibility**: Always provide controls. Use `<track>` for captions/subtitles.
    /// Provide fallback text for unsupported browsers.
    ///
    /// Use [`Dom::create_audio_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_audio(aria: SmallAriaInfo) -> Self {
        Self::create_audio_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates a video element without accessibility information.
    ///
    /// Prefer [`Dom::create_video`] so that screen readers announce the video's purpose.
    #[inline(always)]
    pub const fn create_video_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Video),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a video element with accessibility information.
    ///
    /// **Accessibility**: Always provide controls. Use `<track>` for
    /// captions/subtitles/descriptions. Provide fallback text. Consider providing transcript.
    ///
    /// Use [`Dom::create_video_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_video(aria: SmallAriaInfo) -> Self {
        Self::create_video_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    /// Creates a source element for media.
    ///
    /// **Parameters:**
    /// - `src`: Media source URL
    /// - `media_type`: MIME type (e.g., "video/mp4", "audio/ogg")
    #[inline]
    pub fn create_source(src: AzString, media_type: AzString) -> Self {
        Self::create_node(NodeType::Source)
            .with_attribute(AttributeType::Src(src))
            .with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "type".into(),
                value: media_type,
            }))
    }
    /// Creates a track element for media captions/subtitles.
    ///
    /// **Accessibility**: Essential for deaf/hard-of-hearing users and non-native speakers.
    /// Use `kind` (subtitles/captions/descriptions), `srclang`, and `label` attributes.
    ///
    /// **Parameters:**
    /// - `src`: Track file URL (WebVTT format)
    /// - `kind`: Track kind ("subtitles", "captions", "descriptions", "chapters", "metadata")
    #[inline]
    pub fn create_track(src: AzString, kind: AzString) -> Self {
        Self::create_node(NodeType::Track)
            .with_attribute(AttributeType::Src(src))
            .with_attribute(AttributeType::Custom(AttributeNameValue {
                attr_name: "kind".into(),
                value: kind,
            }))
    }
    /// Creates a map element for image maps.
    ///
    /// **Accessibility**: Provide text alternatives. Ensure all areas have alt text.
    #[inline(always)]
    pub const fn create_map() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Map),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an area element for image map regions without accessibility information.
    ///
    /// Prefer [`Dom::create_area`] so that screen readers can announce the region's purpose.
    #[inline(always)]
    pub const fn create_area_no_a11y() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Area),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an area element for image map regions with accessibility information.
    ///
    /// **Accessibility**: Always provide `alt` text describing the region/link purpose.
    /// Keyboard users should be able to navigate areas.
    ///
    /// Use [`Dom::create_area_no_a11y`] only as a deliberate escape hatch.
    #[inline]
    pub fn create_area(aria: SmallAriaInfo) -> Self {
        Self::create_area_no_a11y().with_accessibility_info(aria.to_full_info())
    }
    // Metadata Elements
    /// Creates an empty title element for document title.
    ///
    /// **Accessibility**: Required for all pages. Screen readers announce this first.
    #[inline(always)]
    pub fn create_title() -> Self {
        Self::create_node(NodeType::Title)
    }
    /// Creates a title element for document title with text.
    ///
    /// **Accessibility**: Required for all pages. Screen readers announce this first.
    /// Should be unique and descriptive. Keep under 60 characters.
    #[inline]
    pub fn create_title_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_title().with_child(Self::create_text(text))
    }
    /// Creates a meta element.
    ///
    /// **Accessibility**: Use for charset, viewport, description. Crucial for proper text display.
    #[inline(always)]
    pub const fn create_meta() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Meta),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a link element for external resources.
    ///
    /// **Accessibility**: Use for stylesheets, icons, alternate versions.
    /// Provide meaningful `title` attribute for alternate stylesheets.
    #[inline(always)]
    pub const fn create_link() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Link),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a script element.
    ///
    /// **Accessibility**: Ensure scripted content is accessible.
    /// Provide noscript fallbacks for critical functionality.
    #[inline(always)]
    pub const fn create_script() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Script),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates an empty style element for embedded CSS.
    ///
    /// **Note**: In Azul, use `.with_component_css()` instead for styling.
    /// This creates a `<style>` HTML element for embedded stylesheets.
    #[inline(always)]
    pub const fn create_style() -> Self {
        Self {
            root: NodeData::create_node(NodeType::Style),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        }
    }
    /// Creates a style element for embedded CSS with the given stylesheet text.
    ///
    /// **Note**: In Azul, use `.with_component_css()` instead for styling.
    /// This creates a `<style>` HTML element for embedded stylesheets.
    #[inline]
    pub fn create_style_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_style().with_child(Self::create_text(text))
    }
    /// Creates a base element for document base URL.
    ///
    /// **Parameters:**
    /// - `href`: Base URL for relative URLs in the document
    #[inline]
    pub fn create_base(href: AzString) -> Self {
        Self::create_node(NodeType::Base).with_attribute(AttributeType::Href(href))
    }
    // Advanced Constructors with Parameters
    /// Creates a table header cell with scope.
    ///
    /// **Parameters:**
    /// - `scope`: "col", "row", "colgroup", or "rowgroup"
    /// - `text`: Header text
    ///
    /// **Accessibility**: The scope attribute is crucial for associating headers with data cells.
    #[inline]
    pub fn create_th_with_scope(scope: AzString, text: AzString) -> Self {
        Self::create_node(NodeType::Th)
            .with_attribute(AttributeType::Scope(scope))
            .with_child(Self::create_text(text))
    }
    /// Creates a table data cell with text.
    ///
    /// **Parameters:**
    /// - `text`: Cell content
    #[inline]
    pub fn create_td_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_td().with_child(Self::create_text(text))
    }
    /// Creates a table header cell with text.
    ///
    /// **Parameters:**
    /// - `text`: Header text
    #[inline]
    pub fn create_th_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_th().with_child(Self::create_text(text))
    }
    /// Creates a list item with text.
    ///
    /// **Parameters:**
    /// - `text`: List item content
    #[inline]
    pub fn create_li_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_li().with_child(Self::create_text(text))
    }
    /// Creates a paragraph with text.
    ///
    /// **Parameters:**
    /// - `text`: Paragraph content
    #[inline]
    pub fn create_p_with_text<S: Into<AzString>>(text: S) -> Self {
        Self::create_p().with_child(Self::create_text(text))
    }
    // Accessibility-Aware Constructors
    // These constructors require explicit accessibility information.
    // Use the `*_no_a11y` variants only as a deliberate escape hatch.
    /// Creates a button with text content and accessibility information.
    ///
    /// Use [`Dom::create_button_no_a11y`] to skip the accessibility information.
    ///
    /// **Parameters:**
    /// - `text`: The visible button text
    /// - `aria`: Accessibility information (role, description, etc.)
    #[inline]
1
    pub fn create_button<S: Into<AzString>>(text: S, aria: SmallAriaInfo) -> Self {
1
        let mut btn = Self::create_button_no_a11y(text.into());
1
        btn.root.set_accessibility_info(aria.to_full_info());
1
        btn
1
    }
    /// Creates a link (anchor) with href, text, and accessibility information.
    ///
    /// Use [`Dom::create_a_no_a11y`] to skip the accessibility information (e.g. for
    /// image-only links whose accessible name comes from an `<img alt>`).
    ///
    /// **Parameters:**
    /// - `href`: The link destination
    /// - `text`: The visible link text
    /// - `aria`: Accessibility information (expanded description, etc.)
    #[inline]
1
    pub fn create_a<S1: Into<AzString>, S2: Into<AzString>>(
1
        href: S1,
1
        text: S2,
1
        aria: SmallAriaInfo,
1
    ) -> Self {
1
        let mut link = Self::create_a_no_a11y(href.into(), OptionString::Some(text.into()));
1
        link.root.set_accessibility_info(aria.to_full_info());
1
        link
1
    }
    /// Creates an input element with type, name, and accessibility information.
    ///
    /// Use [`Dom::create_input_no_a11y`] to skip the accessibility information.
    ///
    /// **Parameters:**
    /// - `input_type`: The input type (text, password, email, etc.)
    /// - `name`: The form field name
    /// - `label`: Base accessibility label
    /// - `aria`: Additional accessibility information (description, etc.)
    #[inline]
1
    pub fn create_input<S1: Into<AzString>, S2: Into<AzString>, S3: Into<AzString>>(
1
        input_type: S1,
1
        name: S2,
1
        label: S3,
1
        aria: SmallAriaInfo,
1
    ) -> Self {
1
        let mut input = Self::create_input_no_a11y(input_type.into(), name.into(), label.into());
1
        input.root.set_accessibility_info(aria.to_full_info());
1
        input
1
    }
    /// Creates a textarea with name and accessibility information.
    ///
    /// Use [`Dom::create_textarea_no_a11y`] to skip the accessibility information.
    ///
    /// **Parameters:**
    /// - `name`: The form field name
    /// - `label`: Base accessibility label
    /// - `aria`: Additional accessibility information (description, etc.)
    #[inline]
1
    pub fn create_textarea<S1: Into<AzString>, S2: Into<AzString>>(
1
        name: S1,
1
        label: S2,
1
        aria: SmallAriaInfo,
1
    ) -> Self {
1
        let mut textarea = Self::create_textarea_no_a11y(name.into(), label.into());
1
        textarea.root.set_accessibility_info(aria.to_full_info());
1
        textarea
1
    }
    /// Creates a select dropdown with name and accessibility information.
    ///
    /// Use [`Dom::create_select_no_a11y`] to skip the accessibility information.
    ///
    /// **Parameters:**
    /// - `name`: The form field name
    /// - `label`: Base accessibility label
    /// - `aria`: Additional accessibility information (description, etc.)
    #[inline]
1
    pub fn create_select<S1: Into<AzString>, S2: Into<AzString>>(
1
        name: S1,
1
        label: S2,
1
        aria: SmallAriaInfo,
1
    ) -> Self {
1
        let mut select = Self::create_select_no_a11y(name.into(), label.into());
1
        select.root.set_accessibility_info(aria.to_full_info());
1
        select
1
    }
    /// Creates a table with caption and accessibility information.
    ///
    /// Use [`Dom::create_table_no_a11y`] to skip the caption and accessibility
    /// information.
    ///
    /// **Parameters:**
    /// - `caption`: Table caption (visible title)
    /// - `aria`: Accessibility information describing table purpose
    #[inline]
1
    pub fn create_table<S: Into<AzString>>(caption: S, aria: SmallAriaInfo) -> Self {
1
        let mut table = Self::create_table_no_a11y()
1
            .with_child(Self::create_caption().with_child(Self::create_text(caption)));
1
        table.root.set_accessibility_info(aria.to_full_info());
1
        table
1
    }
    /// Creates a label for a form control with additional accessibility information.
    ///
    /// Use [`Dom::create_label_no_a11y`] to skip the accessibility information.
    ///
    /// **Parameters:**
    /// - `for_id`: The ID of the associated form control
    /// - `text`: The visible label text
    /// - `aria`: Additional accessibility information (description, etc.)
    #[inline]
1
    pub fn create_label<S1: Into<AzString>, S2: Into<AzString>>(
1
        for_id: S1,
1
        text: S2,
1
        aria: SmallAriaInfo,
1
    ) -> Self {
1
        let mut label = Self::create_label_no_a11y(for_id.into(), text.into());
1
        label.root.set_accessibility_info(aria.to_full_info());
1
        label
1
    }
    /// Parse XML/XHTML string into a DOM
    ///
    /// This is a simple wrapper that parses XML and converts it to a DOM.
    /// For now, it just creates a text node with the content since full XML parsing
    /// requires the xml feature and more complex parsing logic.
    #[cfg(feature = "xml")]
    pub fn from_xml<S: AsRef<str>>(xml_str: S) -> Self {
        // TODO: Implement full XML parsing
        // For now, just create a text node showing that XML was loaded
        Self::create_text(format!(
            "XML content loaded ({} bytes)",
            xml_str.as_ref().len()
        ))
    }
    /// Parse XML/XHTML string into a DOM (fallback without xml feature)
    #[cfg(not(feature = "xml"))]
    pub fn from_xml<S: AsRef<str>>(xml_str: S) -> Self {
        Self::create_text(format!(
            "XML parsing requires 'xml' feature ({} bytes)",
            xml_str.as_ref().len()
        ))
    }
    // Swaps `self` with a default DOM, necessary for builder methods
    #[inline(always)]
    pub fn swap_with_default(&mut self) -> Self {
        let mut s = Self {
            root: NodeData::create_div(),
            children: DomVec::from_const_slice(&[]),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children: 0,
        };
        mem::swap(&mut s, self);
        s
    }
    #[inline]
21738
    pub fn add_child(&mut self, child: Dom) {
21738
        let estimated = child.estimated_total_children;
21738
        let mut v: DomVec = Vec::new().into();
21738
        mem::swap(&mut v, &mut self.children);
21738
        let mut v = v.into_library_owned_vec();
21738
        v.push(child);
21738
        self.children = v.into();
21738
        self.estimated_total_children += estimated + 1;
21738
    }
    #[inline(always)]
233
    pub fn set_children(&mut self, children: DomVec) {
233
        let children_estimated = children
233
            .iter()
335
            .map(|s| s.estimated_total_children + 1)
233
            .sum();
233
        self.children = children;
233
        self.estimated_total_children = children_estimated;
233
    }
    pub fn copy_except_for_root(&mut self) -> Self {
        Self {
            root: self.root.copy_special(),
            children: self.children.clone(),
            css: self.css.clone(),
            estimated_total_children: self.estimated_total_children,
        }
    }
1
    pub fn node_count(&self) -> usize {
1
        self.estimated_total_children + 1
1
    }
    /// Push a component-level stylesheet onto this Dom subtree's
    /// stylesheet list. The cascade pass in `regenerate_layout()` merges
    /// every component-level `Css` together with the inline rules.
    /// Later `with_component_css(...)` calls have higher cascade priority
    /// (override earlier ones at equal specificity).
1
    pub fn with_component_css(mut self, css: azul_css::css::Css) -> Self {
1
        self.add_component_css(css);
1
        self
1
    }
    /// Mutating form of `with_component_css`. Pushes a stylesheet onto
    /// the subtree's component-level CSS list in place.
1
    pub fn add_component_css(&mut self, css: azul_css::css::Css) {
1
        let mut v = Vec::new().into();
1
        core::mem::swap(&mut v, &mut self.css);
1
        let mut v: Vec<azul_css::css::Css> = v.into_library_owned_vec();
1
        v.push(css);
1
        self.css = v.into();
1
    }
    /// Replace the subtree's entire component-level CSS list with the
    /// provided one. Use `add_component_css` / `with_component_css` for
    /// stacking; this is the wholesale-replace form.
    pub fn set_component_css(&mut self, css: azul_css::css::CssVec) {
        self.css = css;
    }
    #[inline(always)]
199
    pub fn with_children(mut self, children: DomVec) -> Self {
199
        self.set_children(children);
199
        self
199
    }
    #[inline(always)]
20820
    pub fn with_child(mut self, child: Self) -> Self {
20820
        self.add_child(child);
20820
        self
20820
    }
    #[inline(always)]
    pub fn with_node_type(mut self, node_type: NodeType) -> Self {
        self.root.set_node_type(node_type);
        self
    }
    #[inline(always)]
    pub fn with_id(mut self, id: AzString) -> Self {
        self.root.add_id(id);
        self
    }
    #[inline(always)]
5
    pub fn with_class(mut self, class: AzString) -> Self {
5
        self.root.add_class(class);
5
        self
5
    }
    #[inline(always)]
    pub fn with_callback<C: Into<CoreCallback>>(
        mut self,
        event: EventFilter,
        data: RefAny,
        callback: C,
    ) -> Self {
        self.root.add_callback(event, data, callback);
        self
    }
    /// Add a CSS property with optional conditions (hover, focus, active, etc.)
    #[inline(always)]
    pub fn with_css_property(mut self, prop: CssPropertyWithConditions) -> Self {
        self.root.add_css_property(prop);
        self
    }
    /// Add a CSS property with optional conditions (hover, focus, active, etc.)
    #[inline(always)]
    pub fn add_css_property(&mut self, prop: CssPropertyWithConditions) {
        self.root.add_css_property(prop);
    }
    #[inline(always)]
    pub fn add_class(&mut self, class: AzString) {
        self.root.add_class(class);
    }
    #[inline(always)]
    pub fn add_callback<C: Into<CoreCallback>>(
        &mut self,
        event: EventFilter,
        data: RefAny,
        callback: C,
    ) {
        self.root.add_callback(event, data, callback);
    }
    #[inline(always)]
8
    pub fn set_tab_index(&mut self, tab_index: TabIndex) {
8
        self.root.set_tab_index(tab_index);
8
    }
    #[inline(always)]
8
    pub fn set_contenteditable(&mut self, contenteditable: bool) {
8
        self.root.set_contenteditable(contenteditable);
8
    }
    #[inline(always)]
    pub fn with_tab_index(mut self, tab_index: TabIndex) -> Self {
        self.root.set_tab_index(tab_index);
        self
    }
    #[inline(always)]
    pub fn with_contenteditable(mut self, contenteditable: bool) -> Self {
        self.root.set_contenteditable(contenteditable);
        self
    }
    #[inline]
    pub fn with_dataset(mut self, data: OptionRefAny) -> Self {
        self.root.set_dataset(data);
        self
    }
    #[inline(always)]
2947
    pub fn with_ids_and_classes(mut self, ids_and_classes: IdOrClassVec) -> Self {
2947
        self.root.set_ids_and_classes(ids_and_classes);
2947
        self
2947
    }
    /// Adds an attribute to this DOM element.
    #[inline(always)]
50
    pub fn with_attribute(mut self, attr: AttributeType) -> Self {
50
        let mut attrs = self.root.attributes().clone();
50
        let mut v = attrs.into_library_owned_vec();
50
        v.push(attr);
50
        self.root.set_attributes(v.into());
50
        self
50
    }
    /// Adds multiple attributes to this DOM element.
    #[inline(always)]
    pub fn with_attributes(mut self, attributes: AttributeTypeVec) -> Self {
        self.root.set_attributes(attributes);
        self
    }
    #[inline(always)]
    pub fn with_callbacks(mut self, callbacks: CoreCallbackDataVec) -> Self {
        self.root.callbacks = callbacks;
        self
    }
    /// Legacy: builder-form for the flat property+conditions list. Each entry
    /// becomes a single-declaration rule at `rule_priority::INLINE`.
    #[inline(always)]
140
    pub fn with_css_props(mut self, css_props: CssPropertyWithConditionsVec) -> Self {
140
        self.root.style = css_props.into();
140
        self
140
    }
    /// Builder-form for setting the inline `Css` directly.
    #[inline(always)]
    pub fn with_style(mut self, style: azul_css::css::Css) -> Self {
        self.root.style = style;
        self
    }
    /// Assigns a stable key to the root node of this DOM for reconciliation.
    ///
    /// This is crucial for performance and correct state preservation when
    /// lists of items change order or items are inserted/removed.
    ///
    /// # Example
    /// ```rust
    /// # use azul_core::dom::Dom;
    /// Dom::create_div()
    ///     .with_key("user-avatar-123");
    /// ```
    #[inline]
    pub fn with_key<K: core::hash::Hash>(mut self, key: K) -> Self {
        self.root.set_key(key);
        self
    }
    /// Registers a callback to merge dataset state from the previous frame.
    ///
    /// This is used for components that maintain heavy internal state (video players,
    /// WebGL contexts, network connections) that should not be destroyed and recreated
    /// on every render frame.
    ///
    /// The callback receives both datasets as `RefAny` (cheap shallow clones) and
    /// returns the `RefAny` that should be used for the new node.
    #[inline]
    pub fn with_merge_callback<C: Into<DatasetMergeCallback>>(mut self, callback: C) -> Self {
        self.root.set_merge_callback(callback);
        self
    }
    /// Parse and set CSS styles with full selector support.
    ///
    /// This is the unified API for setting inline CSS on a DOM node. It supports:
    /// - Simple properties: `color: red; font-size: 14px;`
    /// - Pseudo-selectors: `:hover { background: blue; }`
    /// - @-rules: `@os linux { font-size: 14px; }`
    /// - Nesting: `@os linux { font-size: 14px; :hover { color: red; }}`
    ///
    /// # Examples
    /// ```rust
    /// # use azul_core::dom::Dom;
    /// // Simple inline styles
    /// Dom::create_div().with_css("color: red; font-size: 14px;");
    ///
    /// // With hover and active states
    /// Dom::create_div().with_css("
    ///     color: blue;
    ///     :hover { color: red; }
    ///     :active { color: green; }
    /// ");
    ///
    /// // OS-specific with nested hover
    /// Dom::create_div().with_css("
    ///     font-size: 12px;
    ///     @os linux { font-size: 14px; :hover { color: red; }}
    ///     @os windows { font-size: 13px; }
    /// ");
    /// ```
    pub fn set_css(&mut self, style: &str) {
        let parsed = azul_css::css::Css::parse_inline(style);
        let mut current: azul_css::css::CssRuleBlockVec = Vec::new().into();
        mem::swap(&mut current, &mut self.root.style.rules);
        let mut v = current.into_library_owned_vec();
        v.extend(parsed.rules.into_library_owned_vec());
        self.root.style.rules = v.into();
    }
    /// Builder method for `set_css`
    pub fn with_css(mut self, style: &str) -> Self {
        self.set_css(style);
        self
    }
    /// Sets the context menu for the root node
    #[inline]
    pub fn set_context_menu(&mut self, context_menu: Menu) {
        self.root.set_context_menu(context_menu);
    }
    #[inline]
    pub fn with_context_menu(mut self, context_menu: Menu) -> Self {
        self.set_context_menu(context_menu);
        self
    }
    /// Sets the menu bar for the root node
    #[inline]
    pub fn set_menu_bar(&mut self, menu_bar: Menu) {
        self.root.set_menu_bar(menu_bar);
    }
    #[inline]
    pub fn with_menu_bar(mut self, menu_bar: Menu) -> Self {
        self.set_menu_bar(menu_bar);
        self
    }
    #[inline]
    pub fn with_clip_mask(mut self, clip_mask: ImageMask) -> Self {
        self.root.set_clip_mask(clip_mask);
        self
    }
    #[inline]
10
    pub fn with_svg_clip_path(mut self, clip: crate::svg::SvgMultiPolygon) -> Self {
10
        self.root.set_svg_data(SvgNodeData::Path(clip));
10
        self
10
    }
    #[inline]
    pub fn with_svg_data(mut self, data: SvgNodeData) -> Self {
        self.root.set_svg_data(data);
        self
    }
    #[inline]
    pub fn with_accessibility_info(mut self, accessibility_info: AccessibilityInfo) -> Self {
        self.root.set_accessibility_info(accessibility_info);
        self
    }
25993
    pub fn fixup_children_estimated(&mut self) -> usize {
25993
        if self.children.is_empty() {
9281
            self.estimated_total_children = 0;
9281
        } else {
16712
            self.estimated_total_children = self
16712
                .children
16712
                .iter_mut()
20071
                .map(|s| s.fixup_children_estimated() + 1)
16712
                .sum();
        }
25993
        return self.estimated_total_children;
25993
    }
}
impl core::iter::FromIterator<Dom> for Dom {
    fn from_iter<I: IntoIterator<Item = Dom>>(iter: I) -> Self {
        let mut estimated_total_children = 0;
        let children = iter
            .into_iter()
            .map(|c| {
                estimated_total_children += c.estimated_total_children + 1;
                c
            })
            .collect::<Vec<Dom>>();
        Dom {
            root: NodeData::create_div(),
            children: children.into(),
            css: azul_css::css::CssVec::from_const_slice(&[]),
            estimated_total_children,
        }
    }
}
impl fmt::Debug for Dom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fn print_dom(d: &Dom, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "Dom {{\r\n")?;
            write!(f, "\troot: {:#?}\r\n", d.root)?;
            write!(
                f,
                "\testimated_total_children: {:#?}\r\n",
                d.estimated_total_children
            )?;
            write!(f, "\tchildren: [\r\n")?;
            for c in d.children.iter() {
                print_dom(c, f)?;
            }
            write!(f, "\t]\r\n")?;
            write!(f, "}}\r\n")?;
            Ok(())
        }
        print_dom(self, f)
    }
}