lightningcss/properties/
contain.rs1#![allow(non_upper_case_globals)]
4
5use cssparser::*;
6use smallvec::SmallVec;
7
8#[cfg(feature = "visitor")]
9use crate::visitor::Visit;
10use crate::{
11 context::PropertyHandlerContext,
12 declaration::{DeclarationBlock, DeclarationList},
13 error::{ParserError, PrinterError},
14 macros::{define_shorthand, enum_property, shorthand_handler},
15 printer::Printer,
16 properties::{Property, PropertyId},
17 rules::container::ContainerName as ContainerIdent,
18 targets::Browsers,
19 traits::{IsCompatible, Parse, PropertyHandler, Shorthand, ToCss},
20};
21
22enum_property! {
23 pub enum ContainerType {
26 Normal,
29 InlineSize,
31 Size,
33 ScrollState,
35 }
36}
37
38impl Default for ContainerType {
39 fn default() -> Self {
40 ContainerType::Normal
41 }
42}
43
44impl IsCompatible for ContainerType {
45 fn is_compatible(&self, _browsers: Browsers) -> bool {
46 true
47 }
48}
49
50#[derive(Debug, Clone, PartialEq)]
52#[cfg_attr(feature = "visitor", derive(Visit))]
53#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
54#[cfg_attr(
55 feature = "serde",
56 derive(serde::Serialize, serde::Deserialize),
57 serde(tag = "type", content = "value", rename_all = "kebab-case")
58)]
59#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
60pub enum ContainerNameList<'i> {
61 None,
63 #[cfg_attr(feature = "serde", serde(borrow))]
65 Names(SmallVec<[ContainerIdent<'i>; 1]>),
66}
67
68impl<'i> Default for ContainerNameList<'i> {
69 fn default() -> Self {
70 ContainerNameList::None
71 }
72}
73
74impl<'i> Parse<'i> for ContainerNameList<'i> {
75 fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
76 if input.try_parse(|input| input.expect_ident_matching("none")).is_ok() {
77 return Ok(ContainerNameList::None);
78 }
79
80 let mut names = SmallVec::new();
81 while let Ok(name) = input.try_parse(ContainerIdent::parse) {
82 names.push(name);
83 }
84
85 if names.is_empty() {
86 return Err(input.new_error_for_next_token());
87 } else {
88 return Ok(ContainerNameList::Names(names));
89 }
90 }
91}
92
93impl<'i> ToCss for ContainerNameList<'i> {
94 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
95 where
96 W: std::fmt::Write,
97 {
98 match self {
99 ContainerNameList::None => dest.write_str("none"),
100 ContainerNameList::Names(names) => {
101 let mut first = true;
102 for name in names {
103 if first {
104 first = false;
105 } else {
106 dest.write_char(' ')?;
107 }
108 name.to_css(dest)?;
109 }
110 Ok(())
111 }
112 }
113 }
114}
115
116impl IsCompatible for ContainerNameList<'_> {
117 fn is_compatible(&self, _browsers: Browsers) -> bool {
118 true
119 }
120}
121
122define_shorthand! {
123 pub struct Container<'i> {
125 #[cfg_attr(feature = "serde", serde(borrow))]
127 name: ContainerName(ContainerNameList<'i>),
128 container_type: ContainerType(ContainerType),
130 }
131}
132
133impl<'i> Parse<'i> for Container<'i> {
134 fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
135 let name = ContainerNameList::parse(input)?;
136 let container_type = if input.try_parse(|input| input.expect_delim('/')).is_ok() {
137 ContainerType::parse(input)?
138 } else {
139 ContainerType::default()
140 };
141 Ok(Container { name, container_type })
142 }
143}
144
145impl<'i> ToCss for Container<'i> {
146 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
147 where
148 W: std::fmt::Write,
149 {
150 self.name.to_css(dest)?;
151 if self.container_type != ContainerType::default() {
152 dest.delim('/', true)?;
153 self.container_type.to_css(dest)?;
154 }
155 Ok(())
156 }
157}
158
159shorthand_handler!(ContainerHandler -> Container<'i> {
160 name: ContainerName(ContainerNameList<'i>),
161 container_type: ContainerType(ContainerType),
162});