Skip to main content

css_ast/rules/
custom_media.rs

1use super::prelude::*;
2use crate::MediaQueryList;
3
4/// <https://drafts.csswg.org/mediaqueries-5/#at-ruledef-custom-media>
5///
6/// ```text,ignore
7/// @custom-media <extension-name> [ <media-query-list> | true | false ] ;
8/// ```
9#[node]
10#[derive(Peek, Parse, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
12#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
13#[cfg_attr(
14	feature = "css_feature_data",
15	derive(::csskit_derives::ToCSSFeature),
16	css_feature("css.at-rules.custom-media")
17)]
18#[derive(csskit_derives::NodeWithMetadata)]
19#[metadata(node_kinds = AtRule, used_at_rules = CustomMedia)]
20pub struct CustomMediaRule<'a> {
21	#[cfg_attr(feature = "visitable", visit(skip))]
22	#[atom(CssAtomSet::CustomMedia)]
23	pub name: T![AtKeyword],
24	#[cfg_attr(feature = "visitable", visit(skip))]
25	pub extension: T![DashedIdent],
26	pub value: CustomMediaValue<'a>,
27	#[cfg_attr(feature = "visitable", visit(skip))]
28	#[semantic_eq(skip)]
29	pub semicolon: Option<T![;]>,
30}
31
32#[node]
33#[derive(Peek, Parse, ToSpan, ToCursors, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
35#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable))]
36#[derive(csskit_derives::NodeWithMetadata)]
37pub enum CustomMediaValue<'a> {
38	#[atom(CssAtomSet::True)]
39	#[cfg_attr(feature = "visitable", visit(skip))]
40	True(T![Ident]),
41	#[atom(CssAtomSet::False)]
42	#[cfg_attr(feature = "visitable", visit(skip))]
43	False(T![Ident]),
44	MediaQueryList(MediaQueryList<'a>),
45}
46
47#[cfg(test)]
48mod tests {
49	use super::*;
50	use crate::StyleSheet;
51	use css_parse::{assert_parse, assert_parse_error};
52
53	#[test]
54	fn test_writes() {
55		assert_parse!(CssAtomSet::ATOMS, CustomMediaRule, "@custom-media --modern (hover),(pointer:fine);");
56		assert_parse!(CssAtomSet::ATOMS, CustomMediaRule, "@custom-media --narrow screen and (max-width:30em);");
57		assert_parse!(
58			CssAtomSet::ATOMS,
59			StyleSheet,
60			"@custom-media --viewportRange-narrow (max-width: calc(48rem - 0.02px));",
61			|sheet| assert!(matches!(sheet.rules[..], [Rule::CustomMedia(_)]))
62		);
63		assert_parse!(CssAtomSet::ATOMS, CustomMediaRule, "@custom-media --on true;", |rule| {
64			assert!(matches!(rule.value, CustomMediaValue::True(_)))
65		});
66		assert_parse!(CssAtomSet::ATOMS, CustomMediaRule, "@custom-media --off false;", |rule| {
67			assert!(matches!(rule.value, CustomMediaValue::False(_)))
68		});
69		assert_parse!(CssAtomSet::ATOMS, CustomMediaRule, "@custom-media --print print", |rule| {
70			assert!(matches!(rule.value, CustomMediaValue::MediaQueryList(_)))
71		});
72		assert_parse!(
73			CssAtomSet::ATOMS,
74			StyleSheet,
75			"@custom-media --modern (hover);@media(--modern){a{color:red}}",
76			|sheet| assert!(matches!(sheet.rules[..], [Rule::CustomMedia(_), Rule::Media(_)]))
77		);
78	}
79
80	#[test]
81	fn test_errors() {
82		assert_parse_error!(CssAtomSet::ATOMS, CustomMediaRule, "@custom-media modern (color);");
83		assert_parse_error!(CssAtomSet::ATOMS, CustomMediaRule, "@custom-media --modern;");
84	}
85}