euv_core/reactive/cast/impl.rs
1use super::*;
2
3/// Converts a static `String` into a text attribute value.
4impl From<String> for AttributeValue {
5 /// Converts this string into an `AttributeValue::Text`.
6 ///
7 /// # Returns
8 ///
9 /// - `AttributeValue` - A text attribute value containing this string.
10 ///
11 /// # Arguments
12 ///
13 /// - `String` - Input value to convert from.
14 fn from(value: String) -> Self {
15 AttributeValue::Text(value)
16 }
17}
18
19/// Converts a string slice into a text attribute value.
20impl From<&str> for AttributeValue {
21 /// Converts this string slice into an `AttributeValue::Text`.
22 ///
23 /// # Returns
24 ///
25 /// - `AttributeValue` - A text attribute value containing the owned string.
26 ///
27 /// # Arguments
28 ///
29 /// - `&str` - Input value to convert from.
30 fn from(value: &str) -> Self {
31 AttributeValue::Text(value.to_string())
32 }
33}
34
35/// Converts a string signal into a reactive attribute value.
36impl From<Signal<String>> for AttributeValue {
37 /// Converts this string signal into an `AttributeValue::Signal`.
38 ///
39 /// # Returns
40 ///
41 /// - `AttributeValue` - A signal-backed attribute value.
42 ///
43 /// # Arguments
44 ///
45 /// - `Signal<String>` - Input value to convert from.
46 fn from(signal: Signal<String>) -> Self {
47 AttributeValue::Signal(signal)
48 }
49}
50
51/// Converts a mutable bool signal into a reactive attribute value.
52///
53/// The signal is mapped to a `Signal<String>` that yields `"true"` or `"false"`,
54/// enabling boolean attributes like `checked` to reactively update the DOM.
55impl From<Signal<bool>> for AttributeValue {
56 /// Converts this bool signal into an `AttributeValue` via string mapping.
57 ///
58 /// # Returns
59 ///
60 /// - `AttributeValue` - A signal-backed attribute value yielding `"true"` or `"false"`.
61 ///
62 /// # Arguments
63 ///
64 /// - `Signal<bool>` - Input value to convert from.
65 fn from(signal: Signal<bool>) -> Self {
66 AttributeValue::bool_to_attr(signal)
67 }
68}
69
70/// Converts a `bool` into a dynamic attribute value.
71///
72/// Stored as `AttributeValue::Dynamic("true"/"false")` so components can
73/// extract the original boolean via `try_get_typed_prop`.
74impl From<bool> for AttributeValue {
75 /// Converts this boolean into an `AttributeValue::Dynamic`.
76 ///
77 /// # Returns
78 ///
79 /// - `AttributeValue` - A dynamic attribute value containing the boolean string.
80 ///
81 /// # Arguments
82 ///
83 /// - `bool` - Input value to convert from.
84 fn from(value: bool) -> Self {
85 AttributeValue::Dynamic(value.to_string())
86 }
87}
88
89/// Converts an `i32` into a dynamic attribute value.
90///
91/// Stored as `AttributeValue::Dynamic` so components can extract the
92/// original integer via `try_get_typed_prop`.
93impl From<i32> for AttributeValue {
94 /// Converts this integer into an `AttributeValue::Dynamic`.
95 ///
96 /// # Returns
97 ///
98 /// - `AttributeValue` - A dynamic attribute value containing the integer string.
99 ///
100 /// # Arguments
101 ///
102 /// - `i32` - Input value to convert from.
103 fn from(value: i32) -> Self {
104 AttributeValue::Dynamic(value.to_string())
105 }
106}
107
108/// Converts an `f64` into a dynamic attribute value.
109///
110/// Stored as `AttributeValue::Dynamic` so components can extract the
111/// original float via `try_get_typed_prop`.
112impl From<f64> for AttributeValue {
113 /// Converts this float into an `AttributeValue::Dynamic`.
114 ///
115 /// # Returns
116 ///
117 /// - `AttributeValue` - A dynamic attribute value containing the float string.
118 ///
119 /// # Arguments
120 ///
121 /// - `f64` - Input value to convert from.
122 fn from(value: f64) -> Self {
123 AttributeValue::Dynamic(value.to_string())
124 }
125}
126
127/// Converts a CSS class reference into an attribute value.
128impl From<Css> for AttributeValue {
129 /// Converts this CSS class into an `AttributeValue::Css`.
130 ///
131 /// # Returns
132 ///
133 /// - `AttributeValue` - A CSS class attribute value.
134 ///
135 /// # Arguments
136 ///
137 /// - `Css` - Input value to convert from.
138 fn from(css: Css) -> Self {
139 AttributeValue::Css(css)
140 }
141}
142
143/// Converts a reference to a CSS class into an attribute value without cloning.
144///
145/// OPT 11: previously this impl deep-cloned the `Css` struct (name, style,
146/// pseudo_rules, media_rules) every time a static class was referenced from
147/// `html!`. The `class!` macro produces `&'static Css` references backed
148/// by `OnceLock`, so storing the reference directly is sound and removes
149/// the per-element allocation.
150impl From<&'static Css> for AttributeValue {
151 /// Converts this CSS class reference into an `AttributeValue::CssRef`
152 /// without cloning.
153 ///
154 /// # Returns
155 ///
156 /// - `AttributeValue` - A CSS class attribute value borrowing the
157 /// `class!` macro's static storage.
158 ///
159 /// # Arguments
160 ///
161 /// - `&'static Css` - Input value to convert from.
162 fn from(css: &'static Css) -> Self {
163 AttributeValue::CssRef(css)
164 }
165}
166
167/// Converts a closure into a callback attribute value.
168impl<F> From<F> for AttributeValue
169where
170 F: FnMut(Event) + 'static,
171{
172 /// Wraps this closure into an `AttributeValue::Event` with a generic "callback" event name.
173 ///
174 /// # Returns
175 ///
176 /// - `AttributeValue` - An event attribute value wrapping this closure.
177 ///
178 /// # Arguments
179 ///
180 /// - `F` - Input value to convert from.
181 fn from(closure: F) -> Self {
182 AttributeValue::Event(NativeEventHandler::create(CALLBACK_EVENT_NAME, closure))
183 }
184}
185
186/// Converts an owned event handler into a callback attribute value.
187///
188/// Re-wraps the handler with a generic "callback" event name so that
189/// subsequent `EventAdapter::into_attribute` calls can override it with
190/// the correct DOM event type.
191impl From<NativeEventHandler> for AttributeValue {
192 /// Converts this event handler into an `AttributeValue::Event`.
193 ///
194 /// # Returns
195 ///
196 /// - `AttributeValue` - An event attribute value with a generic callback event name.
197 ///
198 /// # Arguments
199 ///
200 /// - `NativeEventHandler` - Input value to convert from.
201 fn from(handler: NativeEventHandler) -> Self {
202 AttrValueAdapter::new(handler).into()
203 }
204}
205
206/// Converts an optional event handler into a callback attribute value.
207///
208/// Re-wraps a `Some` handler with a generic "callback" event name so that
209/// subsequent `EventAdapter::into_attribute` calls can override it with
210/// the correct DOM event type.
211impl From<Option<NativeEventHandler>> for AttributeValue {
212 /// Converts this optional handler into an `AttributeValue::Event` or `AttributeValue::Text` if `None`.
213 ///
214 /// # Returns
215 ///
216 /// - `AttributeValue` - An event attribute value if `Some`, otherwise an empty text attribute.
217 ///
218 /// # Arguments
219 ///
220 /// - `Option<NativeEventHandler>` - Input value to convert from.
221 fn from(handler: Option<NativeEventHandler>) -> Self {
222 match handler {
223 Some(event_handler) => AttrValueAdapter::new(event_handler).into(),
224 None => AttributeValue::Text(String::new()),
225 }
226 }
227}
228
229/// Converts an optional string signal into a reactive or empty attribute value.
230///
231/// `Some(signal)` becomes `AttributeValue::Signal`, `None` becomes
232/// `AttributeValue::Text(String::new())`. This supports component props
233/// that use `Option<Signal<String>>` for optional reactive attributes.
234impl From<Option<Signal<String>>> for AttributeValue {
235 /// Converts this optional signal into an `AttributeValue::Signal` or `AttributeValue::Text` if `None`.
236 ///
237 /// # Returns
238 ///
239 /// - `AttributeValue` - A signal-backed attribute value if `Some`, otherwise an empty text attribute.
240 ///
241 /// # Arguments
242 ///
243 /// - `Option<Signal<String>>` - Input value to convert from.
244 fn from(signal: Option<Signal<String>>) -> Self {
245 match signal {
246 Some(string_signal) => AttributeValue::Signal(string_signal),
247 None => AttributeValue::Text(String::new()),
248 }
249 }
250}