Skip to main content

euv_core/vdom/attribute/
struct.rs

1use crate::*;
2
3/// Represents a CSS style property.
4///
5/// A single key-value pair representing a CSS declaration.
6#[derive(Data, Default, New)]
7pub struct StyleProperty {
8    /// The CSS property name (e.g., "margin", "padding").
9    #[get(pub)]
10    #[set(pub)]
11    name: String,
12    /// The CSS property value.
13    #[get(pub)]
14    #[set(pub)]
15    value: String,
16}
17
18/// A collection of CSS style properties that can be converted to a style string.
19#[derive(Data, New)]
20pub struct Style {
21    /// The list of style properties.
22    #[get(pub)]
23    #[set(pub)]
24    properties: Vec<StyleProperty>,
25}
26
27/// Represents a single attribute on a virtual DOM node.
28///
29/// Combines an attribute name with its corresponding value.
30#[derive(Clone, Data, Debug, New)]
31pub struct AttributeEntry {
32    /// The name of the attribute.
33    #[get(pub(crate))]
34    #[set(pub(crate))]
35    pub(crate) name: String,
36    /// The value of the attribute.
37    #[get(pub(crate))]
38    #[set(pub(crate))]
39    pub(crate) value: AttributeValue,
40}
41
42/// Represents a CSS pseudo-class or pseudo-element rule attached to a class.
43///
44/// Each rule has a selector suffix (e.g., ":hover", "::before", ":focus")
45/// and a style declaration string. When injected into the DOM, it produces
46/// a rule like `.class-name:hover { background: red; }`.
47#[derive(Clone, Data, Debug, Default, New)]
48pub struct PseudoRule {
49    /// The CSS pseudo selector suffix appended to the class name
50    /// (e.g., ":hover", ":focus", ":active", ":disabled", "::before", "::after",
51    /// ":first-child", ":last-child", ":nth-child(2n)", etc.).
52    #[get(pub)]
53    #[set(pub)]
54    selector: String,
55    /// The CSS style declarations for this pseudo rule
56    /// (e.g., "background: rgba(79, 70, 229, 0.04); color: #4f46e5;").
57    #[get(pub)]
58    #[set(pub)]
59    style: String,
60}
61
62/// Represents a CSS class with a name, its style declarations, and optional pseudo rules.
63///
64/// Created by the `class!` macro and used in `html!` via the `class:` attribute.
65/// When the renderer encounters a `CssClass`, it injects the styles into the
66/// DOM's `<style>` element on first use and applies the class name to the element.
67#[derive(Clone, Data, Debug, Default)]
68pub struct CssClass {
69    /// The CSS class name used in the DOM.
70    #[get(pub)]
71    #[set(pub)]
72    name: String,
73    /// The CSS style declarations (e.g., "max-width: 800px; margin: 0 auto;").
74    #[get(pub)]
75    #[set(pub)]
76    style: String,
77    /// The pseudo-class and pseudo-element rules for this class
78    /// (e.g., ":hover", ":focus", ":active", "::before", etc.).
79    #[get(pub)]
80    #[set(pub)]
81    pseudo_rules: Vec<PseudoRule>,
82    /// The media query rules for this class.
83    #[get(pub)]
84    #[set(pub)]
85    media_rules: Vec<MediaRule>,
86}
87
88/// Represents a CSS @media rule attached to a class.
89///
90/// Each media rule has a query string (e.g., "(max-width: 767px)")
91/// and a style declaration string. When injected into the DOM, it produces
92/// a rule like `@media (max-width: 767px) { .class-name { font-size: 14px; } }`.
93#[derive(Clone, Data, Debug, Default, New)]
94pub struct MediaRule {
95    /// The media query condition string (e.g., "(max-width: 767px)").
96    #[get(pub)]
97    #[set(pub)]
98    query: String,
99    /// The CSS style declarations inside this media rule
100    /// (e.g., "font-size: 14px; padding: 8px;").
101    #[get(pub)]
102    #[set(pub)]
103    style: String,
104}
105
106/// Adapts various event value types into an `AttributeValue` for event attributes.
107///
108/// The `html!` macro generates `EventAdapter::new(expr).into_attribute(event_name)`
109/// instead of inline trait dispatch boilerplate. This eliminates the per-attribute-site
110/// generation of `__EventWrapper`, `__IsClosure`, `__ClosurePicker`, `__ValuePicker`,
111/// `__FallbackHelper`, and `__dispatch` types, significantly reducing macro output size.
112///
113/// The adapter pattern handles three cases:
114/// - `FnMut(NativeEvent)` closure → `AttributeValue::Event` via `NativeEventHandler`
115/// - `NativeEventHandler` directly → `AttributeValue::Event` as-is
116/// - `Option<NativeEventHandler>` → `AttributeValue::Event` or `AttributeValue::Text`
117pub struct EventAdapter<T> {
118    /// The wrapped value to be adapted into an attribute.
119    pub(crate) inner: T,
120}
121
122/// Adapts an arbitrary attribute value expression into an `AttributeValue`.
123///
124/// Handles the dispatch between event closures and reactive values without
125/// requiring the macro to generate inline trait hierarchies. The macro emits
126/// `AttrValueAdapter::new(expr).into_attribute_value()` instead of the
127/// `__IsClosure` / `__ClosurePicker` / `__ValuePicker` / `__FallbackHelper`
128/// / `__dispatch` boilerplate.
129///
130/// For event attributes (key starts with "on"), event closures are wrapped
131/// into `AttributeValue::Event`. For non-event attributes, values are
132/// converted via `IntoReactiveValue`.
133pub struct AttrValueAdapter<T> {
134    /// The wrapped value to be adapted into an attribute.
135    pub(crate) inner: T,
136}