Skip to main content

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}