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