1use super::prelude::*;
2use crate::{CalcableValue, ColorInterpolationMethod, PaletteIdentifier, Percentage, Ranged, Value};
3
4#[node]
10#[derive(Parse, Peek, ToCursors, ToSpan, 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(all))]
13#[derive(csskit_derives::NodeWithMetadata)]
14pub struct PaletteMixFunction<'a> {
15 #[atom(CssAtomSet::PaletteMix)]
16 #[cfg_attr(feature = "visitable", visit(skip))]
17 pub name: T![Function],
18 pub interpolation: ColorInterpolationMethod,
19 #[cfg_attr(feature = "visitable", visit(skip))]
20 #[semantic_eq(skip)]
21 pub interpolation_comma: Option<T![,]>,
22 pub first: PaletteMixFunctionParams<'a>,
23 #[cfg_attr(feature = "visitable", visit(skip))]
24 #[semantic_eq(skip)]
25 pub comma: Option<T![,]>,
26 pub second: PaletteMixFunctionParams<'a>,
27 #[cfg_attr(feature = "visitable", visit(skip))]
28 #[semantic_eq(skip)]
29 pub close: T![')'],
30}
31
32#[node]
40#[derive(ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
41#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
42#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(children))]
43#[derive(csskit_derives::NodeWithMetadata)]
44pub struct PaletteMixFunctionParams<'a> {
45 pub palette: PaletteMixPalette<'a>,
46 pub percentage: Option<CalcableValue<'a, Ranged<Percentage, 0, 100>>>,
47}
48
49impl<'a> Peek<'a> for PaletteMixFunctionParams<'a> {
50 const PEEK_KINDSET: KindSet =
51 PaletteMixPalette::PEEK_KINDSET.combine(CalcableValue::<Ranged<Percentage, 0, 100>>::PEEK_KINDSET);
52
53 #[inline(always)]
54 fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
55 where
56 I: Iterator<Item = Cursor> + Clone,
57 {
58 PaletteMixPalette::peek(p, c) || CalcableValue::<Ranged<Percentage, 0, 100>>::peek(p, c)
59 }
60}
61
62impl<'a> Parse<'a> for PaletteMixFunctionParams<'a> {
63 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
64 where
65 I: Iterator<Item = Cursor> + Clone,
66 {
67 let mut palette = p.parse_if_peek::<PaletteMixPalette>()?;
68 let percentage = p.parse_if_peek::<CalcableValue<Ranged<Percentage, 0, 100>>>()?;
69 if palette.is_none() {
70 palette = Some(p.parse::<PaletteMixPalette>()?);
71 }
72 Ok(Self { palette: palette.unwrap(), percentage })
73 }
74}
75
76#[node]
82#[derive(Parse, Peek, ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
83#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
84#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit(self))]
85#[derive(csskit_derives::NodeWithMetadata)]
86pub enum PaletteMixPalette<'a> {
87 #[atom(CssAtomSet::Normal)]
88 Normal(T![Ident]),
89 #[atom(CssAtomSet::Light)]
90 Light(T![Ident]),
91 #[atom(CssAtomSet::Dark)]
92 Dark(T![Ident]),
93 Identifier(Value<'a, PaletteIdentifier>),
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use crate::CssAtomSet;
100 use css_parse::{assert_parse, assert_parse_error};
101
102 #[test]
103 fn test_writes() {
104 assert_parse!(CssAtomSet::ATOMS, PaletteMixFunction, "palette-mix(in lch,normal,dark)");
105 assert_parse!(CssAtomSet::ATOMS, PaletteMixFunction, "palette-mix(in oklab,light 40%,dark 60%)");
106 assert_parse!(CssAtomSet::ATOMS, PaletteMixFunction, "palette-mix(in lch,40% light,60% dark)");
107 assert_parse!(CssAtomSet::ATOMS, PaletteMixFunction, "palette-mix(in lch longer hue,--blues 30%,--reds)");
108 assert_parse!(CssAtomSet::ATOMS, PaletteMixFunction, "palette-mix(in lch,--blues var(--pct),--reds)");
109 }
110
111 #[test]
112 fn test_errors() {
113 assert_parse_error!(CssAtomSet::ATOMS, PaletteMixFunction, "palette-mix(normal,dark)");
114 assert_parse_error!(CssAtomSet::ATOMS, PaletteMixFunction, "palette-mix(in lch,normal)");
115 assert_parse_error!(CssAtomSet::ATOMS, PaletteMixFunction, "palette-mix(in lch,normal,dark,light)");
116 assert_parse_error!(CssAtomSet::ATOMS, PaletteMixFunction, "palette-mix(in lch,normal 120%,dark)");
117 assert_parse_error!(CssAtomSet::ATOMS, PaletteMixFunction, "palette-mix(in lch,30%,dark)");
118 }
119
120 #[test]
121 #[cfg(feature = "visitable")]
122 fn test_visits() {
123 use crate::assert_visits;
124 assert_visits!(
125 "palette-mix(in lch,--blues 30%,--reds)",
126 PaletteMixFunction,
127 ColorInterpolationMethod,
128 PaletteMixPalette,
129 Percentage,
130 PaletteMixPalette,
131 );
132 }
133}