Skip to main content

euv_core/vdom/attribute/
struct.rs

1use crate::*;
2
3/// Represents a single attribute on a virtual DOM node.
4///
5/// Combines an attribute name with its corresponding value.
6#[derive(Clone, CustomDebug, Data, New)]
7pub struct AttributeEntry {
8    /// The name of the attribute.
9    #[get_mut(pub(crate))]
10    #[set(pub(crate))]
11    pub(crate) name: String,
12    /// The value of the attribute.
13    #[debug(skip)]
14    #[get(pub(crate))]
15    #[get_mut(pub(crate))]
16    #[set(pub(crate))]
17    pub(crate) value: AttributeValue,
18}
19
20/// Represents a CSS pseudo-class or pseudo-element rule attached to a class.
21///
22/// Each rule has a selector suffix (e.g., ":hover", "::before", ":focus")
23/// and a style declaration string. When injected into the DOM, it produces
24/// a rule like `.class-name:hover { background: red; }`.
25#[derive(Clone, Data, Debug, Default, Eq, Hash, New, PartialEq)]
26pub struct PseudoRule {
27    /// The CSS pseudo selector suffix appended to the class name
28    /// (e.g., ":hover", ":focus", ":active", ":disabled", "::before", "::after",
29    /// ":first-child", ":last-child", ":nth-child(2n)", etc.).
30    #[get(pub(crate))]
31    #[get_mut(pub(crate))]
32    #[set(pub(crate))]
33    selector: String,
34    /// The CSS style declarations for this pseudo rule
35    /// (e.g., "background: rgba(79, 70, 229, 0.04); color: #4f46e5;").
36    #[get(pub(crate))]
37    #[get_mut(pub(crate))]
38    #[set(pub(crate))]
39    style: String,
40}
41
42/// Represents a CSS class with a name, its style declarations, and optional pseudo rules.
43///
44/// Created by the `class!` macro and used in `html!` via the `class:` attribute.
45/// When the renderer encounters a `Css`, it injects the styles into the
46/// DOM's `<style>` element on first use and applies the class name to the element.
47#[derive(Clone, Data, Debug, Default, New)]
48pub struct Css {
49    /// The CSS class name used in the DOM.
50    #[get_mut(pub(crate))]
51    #[set(pub(crate))]
52    name: String,
53    /// The CSS style declarations (e.g., "max-width: 800px; margin: 0 auto;").
54    #[get_mut(pub(crate))]
55    #[set(pub(crate))]
56    style: String,
57    /// The pseudo-class and pseudo-element rules for this class
58    /// (e.g., ":hover", ":focus", ":active", "::before", etc.).
59    #[get_mut(pub(crate))]
60    #[set(pub(crate))]
61    pseudo_rules: Vec<PseudoRule>,
62    /// The media query rules for this class.
63    #[get_mut(pub(crate))]
64    #[set(pub(crate))]
65    media_rules: Vec<MediaRule>,
66}
67
68/// Represents a CSS @media rule attached to a class.
69///
70/// Each media rule has a query string (e.g., "(max-width: 767px)"),
71/// a style declaration string, and optional nested pseudo-element rules.
72/// When injected into the DOM, it produces a rule like:
73/// `@media (max-width: 767px) { .class-name { font-size: 14px; } .class-name::-webkit-scrollbar { width: 0px; } }`.
74#[derive(Clone, Data, Debug, Default, Eq, Hash, New, PartialEq)]
75pub struct MediaRule {
76    /// The media query condition string (e.g., "(max-width: 767px)").
77    #[get(pub(crate))]
78    #[get_mut(pub(crate))]
79    #[set(pub(crate))]
80    query: String,
81    /// The CSS style declarations inside this media rule
82    /// (e.g., "font-size: 14px; padding: 8px;").
83    #[get(pub(crate))]
84    #[get_mut(pub(crate))]
85    #[set(pub(crate))]
86    style: String,
87    /// The pseudo-element rules nested inside this media rule
88    /// (e.g., `::-webkit-scrollbar { width: "0px"; }`).
89    #[get(pub(crate))]
90    #[get_mut(pub(crate))]
91    #[set(pub(crate))]
92    pseudo_rules: Vec<PseudoRule>,
93}
94
95/// Adapts various event value types into an `AttributeValue` for event attributes.
96///
97/// The `html!` macro generates `EventAdapter::new(expr).into_attribute(event_name)`
98/// instead of inline trait dispatch boilerplate. This eliminates the per-attribute-site
99/// generation of `__EventWrapper`, `__IsClosure`, `__ClosurePicker`, `__ValuePicker`,
100/// `__FallbackHelper`, and `__dispatch` types, significantly reducing macro output size.
101///
102/// The adapter pattern handles three cases:
103/// - `FnMut(NativeEvent)` closure → `AttributeValue::Event` via `NativeEventHandler`
104/// - `NativeEventHandler` directly → `AttributeValue::Event` as-is
105/// - `Option<NativeEventHandler>` → `AttributeValue::Event` or `AttributeValue::Text`
106#[derive(Data, Debug, New)]
107pub struct EventAdapter<T> {
108    /// The wrapped value to be adapted into an attribute.
109    #[get(pub(crate))]
110    #[get_mut(pub(crate))]
111    #[set(pub(crate))]
112    pub(crate) inner: T,
113}
114
115/// Adapts an event with a specific event name into an `AttributeValue`.
116///
117/// This type wraps an event value and its event name, enabling
118/// `Into<AttributeValue>` trait implementation for events.
119/// Used by the `html!` macro for event attributes like `onclick`.
120#[derive(Data, Debug, New)]
121pub struct EventNamedAdapter<T> {
122    /// The wrapped event value to be adapted.
123    #[get(pub(crate))]
124    #[get_mut(pub(crate))]
125    #[set(pub(crate))]
126    pub(crate) inner: T,
127    /// The event name (e.g., "click", "mouseover").
128    #[get(pub(crate), type(copy))]
129    #[get_mut(pub(crate))]
130    #[set(pub(crate))]
131    pub(crate) event_name: &'static str,
132}
133
134/// Adapts an arbitrary attribute value expression into an `AttributeValue`.
135///
136/// Handles the dispatch between event closures and reactive values without
137/// requiring the macro to generate inline trait hierarchies. The macro emits
138/// `AttrValueAdapter::new(expr).into_attribute_value()` instead of the
139/// `__IsClosure` / `__ClosurePicker` / `__ValuePicker` / `__FallbackHelper`
140/// / `__dispatch` boilerplate.
141///
142/// For event attributes (key starts with "on"), event closures are wrapped
143/// into `AttributeValue::Event`. For non-event attributes, values are
144/// converted via `IntoReactiveValue`.
145#[derive(Data, Debug, New)]
146pub struct AttrValueAdapter<T> {
147    /// The wrapped value to be adapted into an attribute.
148    #[get(pub(crate))]
149    #[get_mut(pub(crate))]
150    #[set(pub(crate))]
151    pub(crate) inner: T,
152}
153
154/// Adapts a callback with a custom name into an `AttributeValue`.
155///
156/// This type wraps a callback and its custom attribute name, enabling
157/// `Into<AttributeValue>` trait implementation for named callbacks.
158/// Used by the `html!` macro for component callback props.
159#[derive(Data, Debug, New)]
160pub struct CallbackNamedAdapter<T> {
161    /// The wrapped callback to be adapted.
162    #[get(pub(crate))]
163    #[get_mut(pub(crate))]
164    #[set(pub(crate))]
165    pub(crate) inner: T,
166    /// The custom attribute name (e.g., "on-increment", "on-change").
167    #[get(pub(crate), type(copy))]
168    #[get_mut(pub(crate))]
169    #[set(pub(crate))]
170    pub(crate) name: &'static str,
171}
172
173/// A `Sync` wrapper for single-threaded global `HashSet` access.
174///
175/// SAFETY: This type is only safe to use in single-threaded contexts
176/// (e.g., WASM). It implements `Sync` to allow usage as a `static mut`
177/// variable, but concurrent access from multiple threads would be
178/// undefined behavior.
179#[derive(Data, Debug, New)]
180pub(crate) struct InjectedClassesCell(
181    /// Interior-mutable storage for the injected classes set.
182    #[get(pub(crate))]
183    #[get_mut(pub(crate))]
184    #[set(pub(crate))]
185    pub(crate) UnsafeCell<Option<HashSet<String>>>,
186);