1use crate::{corety::AzString, props::formatter::PrintAsCssValue};
19
20#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
36#[repr(C)]
37pub enum StyleSpatialNavigationAction {
38 #[default]
40 Auto,
41 Focus,
45 Scroll,
49}
50
51impl PrintAsCssValue for StyleSpatialNavigationAction {
52 fn print_as_css_value(&self) -> String {
53 String::from(match self {
54 Self::Auto => "auto",
55 Self::Focus => "focus",
56 Self::Scroll => "scroll",
57 })
58 }
59}
60
61#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
79#[repr(C)]
80pub enum StyleSpatialNavigationContain {
81 #[default]
83 Auto,
84 Contain,
86}
87
88impl PrintAsCssValue for StyleSpatialNavigationContain {
89 fn print_as_css_value(&self) -> String {
90 String::from(match self {
91 Self::Auto => "auto",
92 Self::Contain => "contain",
93 })
94 }
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
99pub enum CssSpatialNavigationActionParseError<'a> {
100 InvalidValue(&'a str),
101}
102
103impl core::fmt::Display for CssSpatialNavigationActionParseError<'_> {
104 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
105 match self {
106 Self::InvalidValue(v) => write!(
107 f,
108 "Invalid spatial-navigation-action value: \"{v}\" (expected auto, focus or scroll)"
109 ),
110 }
111 }
112}
113
114#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
123#[repr(C, u8)]
124pub enum CssSpatialNavigationActionParseErrorOwned {
125 InvalidValue(AzString),
126}
127
128impl<'a> CssSpatialNavigationActionParseError<'a> {
129 #[must_use]
130 pub fn to_contained(&self) -> CssSpatialNavigationActionParseErrorOwned {
131 match self {
132 Self::InvalidValue(v) => {
133 CssSpatialNavigationActionParseErrorOwned::InvalidValue((*v).into())
134 }
135 }
136 }
137}
138
139impl CssSpatialNavigationActionParseErrorOwned {
140 #[must_use]
141 pub fn to_shared(&self) -> CssSpatialNavigationActionParseError<'_> {
142 match self {
143 Self::InvalidValue(v) => CssSpatialNavigationActionParseError::InvalidValue(v.as_str()),
144 }
145 }
146}
147
148#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
150pub enum CssSpatialNavigationContainParseError<'a> {
151 InvalidValue(&'a str),
152}
153
154impl core::fmt::Display for CssSpatialNavigationContainParseError<'_> {
155 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
156 match self {
157 Self::InvalidValue(v) => write!(
158 f,
159 "Invalid spatial-navigation-contain value: \"{v}\" (expected auto or contain)"
160 ),
161 }
162 }
163}
164
165#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
174#[repr(C, u8)]
175pub enum CssSpatialNavigationContainParseErrorOwned {
176 InvalidValue(AzString),
177}
178
179impl<'a> CssSpatialNavigationContainParseError<'a> {
180 #[must_use]
181 pub fn to_contained(&self) -> CssSpatialNavigationContainParseErrorOwned {
182 match self {
183 Self::InvalidValue(v) => {
184 CssSpatialNavigationContainParseErrorOwned::InvalidValue((*v).into())
185 }
186 }
187 }
188}
189
190impl CssSpatialNavigationContainParseErrorOwned {
191 #[must_use]
192 pub fn to_shared(&self) -> CssSpatialNavigationContainParseError<'_> {
193 match self {
194 Self::InvalidValue(v) => {
195 CssSpatialNavigationContainParseError::InvalidValue(v.as_str())
196 }
197 }
198 }
199}
200
201#[cfg(feature = "parser")]
202pub fn parse_style_spatial_navigation_action(
206 input: &str,
207) -> Result<StyleSpatialNavigationAction, CssSpatialNavigationActionParseError<'_>> {
208 match input.trim() {
209 "auto" => Ok(StyleSpatialNavigationAction::Auto),
210 "focus" => Ok(StyleSpatialNavigationAction::Focus),
211 "scroll" => Ok(StyleSpatialNavigationAction::Scroll),
212 _ => Err(CssSpatialNavigationActionParseError::InvalidValue(input)),
213 }
214}
215
216#[cfg(feature = "parser")]
217pub fn parse_style_spatial_navigation_contain(
221 input: &str,
222) -> Result<StyleSpatialNavigationContain, CssSpatialNavigationContainParseError<'_>> {
223 match input.trim() {
224 "auto" => Ok(StyleSpatialNavigationContain::Auto),
225 "contain" => Ok(StyleSpatialNavigationContain::Contain),
226 _ => Err(CssSpatialNavigationContainParseError::InvalidValue(input)),
227 }
228}
229
230#[cfg(all(test, feature = "parser"))]
231mod tests {
232 use super::*;
233
234 #[test]
235 fn the_action_keywords_parse_and_round_trip() {
236 for (text, value) in [
237 ("auto", StyleSpatialNavigationAction::Auto),
238 ("focus", StyleSpatialNavigationAction::Focus),
239 ("scroll", StyleSpatialNavigationAction::Scroll),
240 ] {
241 assert_eq!(parse_style_spatial_navigation_action(text), Ok(value));
242 assert_eq!(value.print_as_css_value(), text);
243 }
244 assert_eq!(
246 parse_style_spatial_navigation_action(" scroll "),
247 Ok(StyleSpatialNavigationAction::Scroll)
248 );
249 }
250
251 #[test]
252 fn the_contain_keywords_parse_and_round_trip() {
253 for (text, value) in [
254 ("auto", StyleSpatialNavigationContain::Auto),
255 ("contain", StyleSpatialNavigationContain::Contain),
256 ] {
257 assert_eq!(parse_style_spatial_navigation_contain(text), Ok(value));
258 assert_eq!(value.print_as_css_value(), text);
259 }
260 }
261
262 #[test]
265 fn a_wrong_keyword_is_an_error_and_not_the_default() {
266 assert!(parse_style_spatial_navigation_action("none").is_err());
267 assert!(parse_style_spatial_navigation_action("contain").is_err());
268 assert!(parse_style_spatial_navigation_contain("none").is_err());
269 assert!(parse_style_spatial_navigation_contain("focus").is_err());
270 }
271
272 #[test]
277 fn both_properties_parse_from_their_css_name() {
278 use crate::props::property::{
279 get_css_key_map, parse_css_property, CssProperty, CssPropertyType,
280 };
281
282 let map = get_css_key_map();
283 let ty = CssPropertyType::from_str("spatial-navigation-action", &map)
284 .expect("`spatial-navigation-action` must be a known property name");
285 assert_eq!(ty, CssPropertyType::SpatialNavigationAction);
286 assert_eq!(
287 parse_css_property(ty, "scroll"),
288 Ok(CssProperty::SpatialNavigationAction(
289 crate::css::CssPropertyValue::Exact(StyleSpatialNavigationAction::Scroll)
290 ))
291 );
292
293 let ty = CssPropertyType::from_str("spatial-navigation-contain", &map)
294 .expect("`spatial-navigation-contain` must be a known property name");
295 assert_eq!(ty, CssPropertyType::SpatialNavigationContain);
296 assert_eq!(
297 parse_css_property(ty, "contain"),
298 Ok(CssProperty::SpatialNavigationContain(
299 crate::css::CssPropertyValue::Exact(StyleSpatialNavigationContain::Contain)
300 ))
301 );
302
303 assert!(!CssPropertyType::SpatialNavigationAction.can_trigger_relayout());
307 assert!(!CssPropertyType::SpatialNavigationContain.can_trigger_relayout());
308 }
309
310 #[test]
313 fn both_properties_default_to_auto() {
314 assert_eq!(
315 StyleSpatialNavigationAction::default(),
316 StyleSpatialNavigationAction::Auto
317 );
318 assert_eq!(
319 StyleSpatialNavigationContain::default(),
320 StyleSpatialNavigationContain::Auto
321 );
322 }
323}