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 }
34}
35
36impl Default for ContainerType {
37 fn default() -> Self {
38 ContainerType::Normal
39 }
40}
41
42impl IsCompatible for ContainerType {
43 fn is_compatible(&self, _browsers: Browsers) -> bool {
44 true
45 }
46}
47
48#[derive(Debug, Clone, PartialEq)]
50#[cfg_attr(feature = "visitor", derive(Visit))]
51#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
52#[cfg_attr(
53 feature = "serde",
54 derive(serde::Serialize, serde::Deserialize),
55 serde(tag = "type", content = "value", rename_all = "kebab-case")
56)]
57#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
58pub enum ContainerNameList<'i> {
59 None,
61 #[cfg_attr(feature = "serde", serde(borrow))]
63 Names(SmallVec<[ContainerIdent<'i>; 1]>),
64}
65
66impl<'i> Default for ContainerNameList<'i> {
67 fn default() -> Self {
68 ContainerNameList::None
69 }
70}
71
72impl<'i> Parse<'i> for ContainerNameList<'i> {
73 fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
74 if input.try_parse(|input| input.expect_ident_matching("none")).is_ok() {
75 return Ok(ContainerNameList::None);
76 }
77
78 let mut names = SmallVec::new();
79 while let Ok(name) = input.try_parse(ContainerIdent::parse) {
80 names.push(name);
81 }
82
83 if names.is_empty() {
84 return Err(input.new_error_for_next_token());
85 } else {
86 return Ok(ContainerNameList::Names(names));
87 }
88 }
89}
90
91impl<'i> ToCss for ContainerNameList<'i> {
92 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
93 where
94 W: std::fmt::Write,
95 {
96 match self {
97 ContainerNameList::None => dest.write_str("none"),
98 ContainerNameList::Names(names) => {
99 let mut first = true;
100 for name in names {
101 if first {
102 first = false;
103 } else {
104 dest.write_char(' ')?;
105 }
106 name.to_css(dest)?;
107 }
108 Ok(())
109 }
110 }
111 }
112}
113
114impl IsCompatible for ContainerNameList<'_> {
115 fn is_compatible(&self, _browsers: Browsers) -> bool {
116 true
117 }
118}
119
120define_shorthand! {
121 pub struct Container<'i> {
123 #[cfg_attr(feature = "serde", serde(borrow))]
125 name: ContainerName(ContainerNameList<'i>),
126 container_type: ContainerType(ContainerType),
128 }
129}
130
131impl<'i> Parse<'i> for Container<'i> {
132 fn parse<'t>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
133 let name = ContainerNameList::parse(input)?;
134 let container_type = if input.try_parse(|input| input.expect_delim('/')).is_ok() {
135 ContainerType::parse(input)?
136 } else {
137 ContainerType::default()
138 };
139 Ok(Container { name, container_type })
140 }
141}
142
143impl<'i> ToCss for Container<'i> {
144 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
145 where
146 W: std::fmt::Write,
147 {
148 self.name.to_css(dest)?;
149 if self.container_type != ContainerType::default() {
150 dest.delim('/', true)?;
151 self.container_type.to_css(dest)?;
152 }
153 Ok(())
154 }
155}
156
157shorthand_handler!(ContainerHandler -> Container<'i> {
158 name: ContainerName(ContainerNameList<'i>),
159 container_type: ContainerType(ContainerType),
160});