1use std::borrow::Cow;
7use std::fmt;
8use std::fmt::Write;
9
10pub struct Val<'a>(Cow<'a, str>);
12
13#[allow(rustdoc::broken_intra_doc_links)]
15#[derive(Debug, Clone)]
47pub struct Prop {
48 sep: &'static str,
50 val: String,
52}
53
54#[derive(Clone, Debug, PartialEq, Eq)]
56pub struct Sel {
57 val: String,
59}
60
61#[derive(Clone, Debug)]
63pub struct Rule {
64 sel: Sel,
66 prop: Prop,
68}
69
70impl Val<'_> {
71 pub(crate) fn chars(&'_ self) -> impl Iterator<Item = char> {
73 match &self.0 {
74 Cow::Borrowed(s) => s.chars(),
75 Cow::Owned(s) => s.chars(),
76 }
77 }
78
79 fn string_dbl(&self) -> Option<&str> {
81 match &self.0 {
82 Cow::Borrowed(s) => {
83 if let Some(("", s)) = s.split_once('"')
84 && let Some((s, "")) = s.rsplit_once('"')
85 {
86 return Some(s);
87 }
88 }
89 Cow::Owned(s) => {
90 if let Some(("", s)) = s.split_once('"')
91 && let Some((s, "")) = s.rsplit_once('"')
92 {
93 return Some(s);
94 }
95 }
96 }
97 None
98 }
99
100 fn string_sng(&self) -> Option<&str> {
102 match &self.0 {
103 Cow::Borrowed(s) => {
104 if let Some(("", s)) = s.split_once('\'')
105 && let Some((s, "")) = s.rsplit_once('\'')
106 {
107 return Some(s);
108 }
109 }
110 Cow::Owned(s) => {
111 if let Some(("", s)) = s.split_once('\'')
112 && let Some((s, "")) = s.rsplit_once('\'')
113 {
114 return Some(s);
115 }
116 }
117 }
118 None
119 }
120
121 fn fmt_string_dbl(&self, f: &mut fmt::Formatter, s: &str) -> fmt::Result {
123 write!(f, "\"")?;
124 for c in s.chars() {
125 match c {
126 '\0' => write!(f, "\u{FFFD}")?,
128 '\u{0001}'..='\u{001f}' | '\u{007f}' => {
129 if let Ok(v) = u16::try_from(c) {
130 write!(f, "\\{v:X} ")?;
131 }
132 }
133 '"' => write!(f, r#"\""#)?,
134 '\\' => write!(f, r"\\")?,
135 _ => write!(f, "{c}")?,
136 }
137 }
138 write!(f, "\"")
139 }
140
141 fn fmt_string_sng(&self, f: &mut fmt::Formatter, s: &str) -> fmt::Result {
143 write!(f, "'")?;
144 for c in s.chars() {
145 match c {
146 '\0' => write!(f, "\u{FFFD}")?,
148 '\u{0001}'..='\u{001f}' | '\u{007f}' => {
149 if let Ok(v) = u16::try_from(c) {
150 write!(f, "\\{v:X} ")?;
151 }
152 }
153 '\'' => write!(f, r"\'")?,
154 '\\' => write!(f, r"\\")?,
155 _ => write!(f, "{c}")?,
156 }
157 }
158 write!(f, "'")
159 }
160
161 fn fmt_other(&self, f: &mut fmt::Formatter) -> fmt::Result {
163 for c in self.chars() {
164 match c {
165 '\0' => write!(f, "\u{FFFD}")?,
167 '\u{0001}'..='\u{001f}' | '\u{007f}' => {
168 if let Ok(v) = u16::try_from(c) {
169 write!(f, "\\{v:X} ")?;
170 }
171 }
172 '\\' => write!(f, r"\\")?,
173 _ => write!(f, "{c}")?,
174 }
175 }
176 Ok(())
177 }
178
179 fn ident_character(val: &mut String, c: char) {
181 match c {
182 '\0' => val.push('\u{FFFD}'),
184 '\u{0001}'..='\u{001f}' | '\u{007f}' => {
185 if let Ok(v) = u16::try_from(c) {
186 val.push_str(&format!("\\{v:X} "));
187 }
188 }
189 '-' | '_' | '0'..='9' | 'A'..='Z' | 'a'..='z' | '\u{0080}'.. => {
190 val.push(c)
191 }
192 _ => {
193 val.push('\\');
194 val.push(c);
195 }
196 }
197 }
198
199 fn to_ident(&self) -> String {
201 let mut val = String::new();
202 let mut chars = self.chars();
203 if let Some(c) = chars.next() {
204 match c {
205 '0'..='9' => {
207 if let Ok(v) = u16::try_from(c) {
208 val.push_str(&format!("\\{v:X} "));
209 }
210 }
211 '-' => {
212 if let Some(c) = chars.next() {
214 match c {
215 '0'..='9' => {
216 if let Ok(v) = u16::try_from(c) {
217 val.push_str(&format!("\\{v:X} "));
218 }
219 }
220 _ => Self::ident_character(&mut val, c),
221 }
222 } else {
223 val.push_str(r"\-");
225 }
226 }
227 _ => Self::ident_character(&mut val, c),
228 }
229 }
230 for c in chars {
231 Self::ident_character(&mut val, c);
232 }
233 val
234 }
235}
236
237impl<'a> fmt::Display for Val<'a> {
238 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
239 if let Some(s) = self.string_dbl() {
240 return self.fmt_string_dbl(f, s);
241 }
242 if let Some(s) = self.string_sng() {
243 return self.fmt_string_sng(f, s);
244 }
245 self.fmt_other(f)
246 }
247}
248
249impl<'c> From<&'c str> for Val<'c> {
250 fn from(v: &'c str) -> Self {
251 Val(Cow::Borrowed(v))
252 }
253}
254
255impl From<String> for Val<'_> {
256 fn from(v: String) -> Self {
257 Val(Cow::Owned(v))
258 }
259}
260
261impl<'c> From<&'c String> for Val<'c> {
262 fn from(v: &'c String) -> Self {
263 Val(Cow::Borrowed(v))
264 }
265}
266
267impl<'c> From<Cow<'c, str>> for Val<'c> {
268 fn from(v: Cow<'c, str>) -> Self {
269 Val(v)
270 }
271}
272
273impl From<char> for Val<'_> {
274 fn from(v: char) -> Self {
275 Val(Cow::Owned(v.to_string()))
276 }
277}
278
279impl From<bool> for Val<'_> {
280 fn from(v: bool) -> Self {
281 Val(Cow::Owned(v.to_string()))
282 }
283}
284
285impl From<i8> for Val<'_> {
286 fn from(v: i8) -> Self {
287 Val(Cow::Owned(v.to_string()))
288 }
289}
290
291impl From<u8> for Val<'_> {
292 fn from(v: u8) -> Self {
293 Val(Cow::Owned(v.to_string()))
294 }
295}
296
297impl From<i16> for Val<'_> {
298 fn from(v: i16) -> Self {
299 Val(Cow::Owned(v.to_string()))
300 }
301}
302
303impl From<u16> for Val<'_> {
304 fn from(v: u16) -> Self {
305 Val(Cow::Owned(v.to_string()))
306 }
307}
308
309impl From<i32> for Val<'_> {
310 fn from(v: i32) -> Self {
311 Val(Cow::Owned(v.to_string()))
312 }
313}
314
315impl From<u32> for Val<'_> {
316 fn from(v: u32) -> Self {
317 Val(Cow::Owned(v.to_string()))
318 }
319}
320
321impl From<i64> for Val<'_> {
322 fn from(v: i64) -> Self {
323 Val(Cow::Owned(v.to_string()))
324 }
325}
326
327impl From<u64> for Val<'_> {
328 fn from(v: u64) -> Self {
329 Val(Cow::Owned(v.to_string()))
330 }
331}
332
333impl From<i128> for Val<'_> {
334 fn from(v: i128) -> Self {
335 Val(Cow::Owned(v.to_string()))
336 }
337}
338
339impl From<u128> for Val<'_> {
340 fn from(v: u128) -> Self {
341 Val(Cow::Owned(v.to_string()))
342 }
343}
344
345impl From<isize> for Val<'_> {
346 fn from(v: isize) -> Self {
347 Val(Cow::Owned(v.to_string()))
348 }
349}
350
351impl From<usize> for Val<'_> {
352 fn from(v: usize) -> Self {
353 Val(Cow::Owned(v.to_string()))
354 }
355}
356
357impl From<f32> for Val<'_> {
358 fn from(v: f32) -> Self {
359 Val(Cow::Owned(v.to_string()))
360 }
361}
362
363impl From<f64> for Val<'_> {
364 fn from(v: f64) -> Self {
365 Val(Cow::Owned(v.to_string()))
366 }
367}
368
369impl fmt::Display for Prop {
370 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
371 if self.val.is_empty() {
372 Ok(())
373 } else {
374 write!(f, "{};", self.val)
375 }
376 }
377}
378
379impl From<Prop> for String {
380 fn from(mut prop: Prop) -> Self {
381 if !prop.val.is_empty() {
383 prop.val.push(';');
384 }
385 prop.val
386 }
387}
388
389impl Default for Prop {
390 fn default() -> Self {
391 Self::new()
392 }
393}
394
395impl Prop {
396 pub fn new() -> Self {
398 Prop {
399 sep: " ",
400 val: String::with_capacity(16),
401 }
402 }
403
404 fn push_sep(&mut self) {
406 if !self.val.is_empty() {
407 self.val.push(';');
408 self.val.push_str(self.sep);
409 }
410 }
411
412 pub fn custom<'a, V>(mut self, name: &str, v: V) -> Self
422 where
423 V: Into<Val<'a>>,
424 {
425 self.push_sep();
426 self.val.push_str("--");
427 self.val.push_str(name);
429 self.val.push_str(": ");
430 let _ = write!(self.val, "{}", v.into());
431 self
432 }
433
434 pub fn important(mut self) -> Self {
444 if !self.val.is_empty() && !self.val.ends_with("!important") {
445 self.val.push_str(" !important");
446 }
447 self
448 }
449}
450
451impl Prop {
455 css_prop!(all, "all");
456 #[cfg(feature = "limited-availability")]
457 css_prop!(accent_color, "accent-color");
458 css_prop!(anchor_name, "anchor-name");
459 css_prop!(anchor_scope, "anchor-scope");
460 css_prop!(appearance, "appearance");
461 css_prop!(aspect_ratio, "aspect-ratio");
462 css_prop!(backdrop_filter, "backdrop-filter");
463 css_prop!(backface_visibility, "backface-visibility");
464 css_prop!(block_size, "block-size");
465 #[cfg(feature = "limited-availability")]
466 css_prop!(box_decoration_break, "box-decoration-break");
467 css_prop!(box_shadow, "box-shadow");
468 css_prop!(box_sizing, "box-sizing");
469 css_prop!(break_after, "break-after");
470 css_prop!(break_before, "break-before");
471 css_prop!(break_inside, "break-inside");
472 css_prop!(caption_side, "caption-side");
473 #[cfg(feature = "experimental")]
474 css_prop!(caret, "caret");
475 #[cfg(feature = "experimental")]
476 css_prop!(caret_animation, "caret-animation");
477 css_prop!(caret_color, "caret-color");
478 #[cfg(feature = "experimental")]
479 css_prop!(caret_shape, "caret-shape");
480 css_prop!(clear, "clear");
481 css_prop!(clip_path, "clip-path");
482 css_prop!(color, "color");
483 css_prop!(color_scheme, "color-scheme");
484 css_prop!(content, "content");
485 css_prop!(counter_increment, "counter-increment");
486 css_prop!(counter_reset, "counter-reset");
487 css_prop!(counter_set, "counter-set");
488 css_prop!(cursor, "cursor");
489 css_prop!(direction, "direction");
490 css_prop!(display, "display");
491 #[cfg(feature = "limited-availability")]
492 css_prop!(dynamic_range_limit, "dynamic-range-limit");
493 css_prop!(empty_cells, "empty-cells");
494 #[cfg(feature = "limited-availability")]
495 css_prop!(field_sizing, "field-sizing");
496 css_prop!(filter, "filter");
497 css_prop!(float, "float");
498 #[cfg(feature = "limited-availability")]
499 css_prop!(forced_color_adjust, "forced-color-adjust");
500 css_prop!(gap, "gap");
501 #[cfg(feature = "limited-availability")]
502 css_prop!(hanging_punctuation, "hanging-punctuation");
503 css_prop!(hyphenate_character, "hyphenate-character");
504 #[cfg(feature = "limited-availability")]
505 css_prop!(hyphenate_limit_chars, "hyphenate-limit-chars");
506 css_prop!(hyphens, "hyphens");
507 css_prop!(image_orientation, "image-orientation");
508 css_prop!(image_rendering, "image-rendering");
509 #[cfg(feature = "experimental")]
510 css_prop!(image_resolution, "image-resolution");
511 #[cfg(feature = "limited-availability")]
512 css_prop!(initial_letter, "initial-letter");
513 css_prop!(inline_size, "inline-size");
514 #[cfg(feature = "experimental")]
515 css_prop!(interactivity, "interactivity");
516 #[cfg(feature = "experimental")]
517 css_prop!(interest_delay, "interest-delay");
518 #[cfg(feature = "experimental")]
519 css_prop!(interest_delay_start, "interest-delay-start");
520 #[cfg(feature = "experimental")]
521 css_prop!(interest_delay_end, "interest-delay-end");
522 #[cfg(feature = "experimental")]
523 css_prop!(interpolate_size, "interpolate-size");
524 css_prop!(isolation, "isolation");
525 css_prop!(letter_spacing, "letter-spacing");
526 css_prop!(line_break, "line-break");
527 #[cfg(feature = "limited-availability")]
528 css_prop!(line_clamp, "line-clamp");
529 css_prop!(line_height, "line-height");
530 #[cfg(feature = "experimental")]
531 css_prop!(line_height_step, "line-height-step");
532 css_prop!(list_style, "list-style");
533 css_prop!(list_style_image, "list-style-image");
534 css_prop!(list_style_position, "list-style-position");
535 css_prop!(list_style_type, "list-style-type");
536 css_prop!(max_block_size, "max-block-size");
537 css_prop!(max_inline_size, "max-inline-size");
538 css_prop!(min_block_size, "min-block-size");
539 css_prop!(min_inline_size, "min-inline-size");
540 css_prop!(mix_blend_mode, "mix-blend-mode");
541 css_prop!(object_fit, "object-fit");
542 css_prop!(object_position, "object-position");
543 #[cfg(feature = "experimental")]
544 css_prop!(object_view_box, "object-view-box");
545 css_prop!(opacity, "opacity");
546 css_prop!(order, "order");
547 #[cfg(feature = "limited-availability")]
548 css_prop!(orphans, "orphans");
549 css_prop!(overflow, "overflow");
550 #[cfg(feature = "limited-availability")]
551 css_prop!(overflow_anchor, "overflow-anchor");
552 css_prop!(overflow_block, "overflow-block");
553 #[cfg(feature = "limited-availability")]
554 css_prop!(overflow_clip_margin, "overflow-clip-margin");
555 css_prop!(overflow_inline, "overflow-inline");
556 css_prop!(overflow_wrap, "overflow-wrap");
557 css_prop!(overflow_x, "overflow-x");
558 css_prop!(overflow_y, "overflow-y");
559 #[cfg(feature = "experimental")]
560 css_prop!(overlay, "overlay");
561 css_prop!(page, "page");
562 css_prop!(paint_order, "paint-order");
563 css_prop!(perspective, "perspective");
564 css_prop!(perspective_origin, "perspective-origin");
565 css_prop!(pointer_events, "pointer-events");
566 css_prop!(position, "position");
567 #[cfg(feature = "limited-availability")]
568 css_prop!(position_anchor, "position-anchor");
569 css_prop!(position_area, "position-area");
570 css_prop!(position_try, "position-try");
571 css_prop!(position_try_fallbacks, "position-try-fallbacks");
572 css_prop!(position_try_order, "position-try-order");
573 css_prop!(position_visibility, "position-visibility");
574 css_prop!(print_color_adjust, "print-color-adjust");
575 css_prop!(quotes, "quotes");
576 #[cfg(feature = "experimental")]
577 css_prop!(reading_flow, "reading-flow");
578 #[cfg(feature = "experimental")]
579 css_prop!(reading_order, "reading-order");
580 #[cfg(feature = "limited-availability")]
581 css_prop!(resize, "resize");
582 css_prop!(rotate, "rotate");
583 css_prop!(row_gap, "row-gap");
584 css_prop!(ruby_align, "ruby-align");
585 #[cfg(feature = "limited-availability")]
586 css_prop!(ruby_overhang, "ruby-overhang");
587 css_prop!(ruby_position, "ruby-position");
588 css_prop!(scale, "scale");
589 css_prop!(scrollbar_color, "scrollbar-color");
590 css_prop!(scrollbar_gutter, "scrollbar-gutter");
591 css_prop!(scrollbar_width, "scrollbar-width");
592 css_prop!(shape_image_threshold, "shape-image-threshold");
593 css_prop!(shape_margin, "shape-margin");
594 css_prop!(shape_outside, "shape-outside");
595 #[cfg(feature = "experimental")]
596 css_prop!(speak_as, "speak-as");
597 css_prop!(tab_size, "tab-size");
598 css_prop!(table_layout, "table-layout");
599 css_prop!(touch_action, "touch-action");
600 css_prop!(transform, "transform");
601 css_prop!(transform_box, "transform-box");
602 css_prop!(transform_origin, "transform-origin");
603 css_prop!(transform_style, "transform-style");
604 css_prop!(translate, "translate");
605 css_prop!(unicode_bidi, "unicode-bidi");
606 #[cfg(feature = "limited-availability")]
607 css_prop!(user_select, "user-select");
608 css_prop!(visibility, "visibility");
609 css_prop!(white_space, "white-space");
610 css_prop!(white_space_collapse, "white-space-collapse");
611 #[cfg(feature = "limited-availability")]
612 css_prop!(widows, "widows");
613 css_prop!(will_change, "will-change");
614 css_prop!(word_break, "word-break");
615 css_prop!(word_spacing, "word-spacing");
616 css_prop!(writing_mode, "writing-mode");
617 css_prop!(z_index, "z-index");
618 css_prop!(zoom, "zoom");
619}
620
621impl Prop {
625 css_prop!(align_content, "align-content");
626 css_prop!(align_items, "align-items");
627 css_prop!(align_self, "align-self");
628 css_prop!(justify_content, "justify-content");
629 css_prop!(justify_items, "justify-items");
630 css_prop!(justify_self, "justify-self");
631 css_prop!(place_content, "place-content");
632 css_prop!(place_items, "place-items");
633 css_prop!(place_self, "place-self");
634 css_prop!(text_align, "text-align");
635 css_prop!(text_align_last, "text-align-last");
636 #[cfg(feature = "limited-availability")]
637 css_prop!(text_justify, "text-justify");
638 css_prop!(vertical_align, "vertical-align");
639 css_prop!(alignment_baseline, "alignment-baseline");
640 css_prop!(baseline_shift, "baseline-shift");
641 #[cfg(feature = "limited-availability")]
642 css_prop!(baseline_source, "baseline-source");
643 css_prop!(dominant_baseline, "dominant-baseline");
644}
645
646impl Prop {
650 css_prop!(animation, "animation");
651 css_prop!(animation_composition, "animation-composition");
652 css_prop!(animation_delay, "animation-delay");
653 css_prop!(animation_direction, "animation-direction");
654 css_prop!(animation_duration, "animation-duration");
655 css_prop!(animation_fill_mode, "animation-fill-mode");
656 css_prop!(animation_iteration_count, "animation-iteration-count");
657 css_prop!(animation_name, "animation-name");
658 css_prop!(animation_play_state, "animation-play-state");
659 #[cfg(feature = "limited-availability")]
660 css_prop!(animation_range_start, "animation-range-start");
661 #[cfg(feature = "limited-availability")]
662 css_prop!(animation_range_end, "animation-range-end");
663 #[cfg(feature = "limited-availability")]
664 css_prop!(animation_range, "animation-range");
665 #[cfg(feature = "limited-availability")]
666 css_prop!(animation_timeline, "animation-timeline");
667 css_prop!(animation_timing_function, "animation-timing-function");
668 css_prop!(offset, "offset");
669 css_prop!(offset_anchor, "offset-anchor");
670 css_prop!(offset_distance, "offset-distance");
671 css_prop!(offset_path, "offset-path");
672 css_prop!(offset_position, "offset-position");
673 css_prop!(offset_rotate, "offset-rotate");
674 #[cfg(feature = "limited-availability")]
675 css_prop!(timeline_scope, "timeline-scope");
676 css_prop!(transition, "transition");
677 css_prop!(transition_behavior, "transition-behavior");
678 css_prop!(transition_delay, "transition-delay");
679 css_prop!(transition_duration, "transition-duration");
680 css_prop!(transition_property, "transition-property");
681 css_prop!(transition_timing_function, "transition-timing-function");
682 #[cfg(feature = "limited-availability")]
683 css_prop!(view_timeline, "view-timeline");
684 #[cfg(feature = "limited-availability")]
685 css_prop!(view_timeline_axis, "view-timeline-axis");
686 #[cfg(feature = "limited-availability")]
687 css_prop!(view_timeline_inset, "view-timeline-inset");
688 #[cfg(feature = "limited-availability")]
689 css_prop!(view_timeline_name, "view-timeline-name");
690 css_prop!(view_transition_class, "view-transition-class");
691 css_prop!(view_transition_name, "view-transition-name");
692}
693
694impl Prop {
698 css_prop!(background, "background");
699 css_prop!(background_attachment, "background-attachment");
700 css_prop!(background_blend_mode, "background-blend-mode");
701 css_prop!(background_clip, "background-clip");
702 css_prop!(background_color, "background-color");
703 css_prop!(background_image, "background-image");
704 css_prop!(background_origin, "background-origin");
705 css_prop!(background_position, "background-position");
706 css_prop!(background_position_x, "background-position-x");
707 css_prop!(background_position_y, "background-position-y");
708 css_prop!(background_repeat, "background-repeat");
709 #[cfg(feature = "experimental")]
710 css_prop!(background_repeat_x, "background-repeat-x");
711 #[cfg(feature = "experimental")]
712 css_prop!(background_repeat_y, "background-repeat-y");
713 css_prop!(background_size, "background-size");
714}
715
716impl Prop {
720 css_prop!(border, "border");
721 css_prop!(border_collapse, "border-collapse");
722 css_prop!(border_color, "border-color");
723 css_prop!(border_style, "border-style");
724 css_prop!(border_spacing, "border-spacing");
725 css_prop!(border_width, "border-width");
726 css_prop!(border_bottom, "border-bottom");
727 css_prop!(border_bottom_color, "border-bottom-color");
728 css_prop!(border_bottom_style, "border-bottom-style");
729 css_prop!(border_bottom_width, "border-bottom-width");
730 css_prop!(border_left, "border-left");
731 css_prop!(border_left_color, "border-left-color");
732 css_prop!(border_left_style, "border-left-style");
733 css_prop!(border_left_width, "border-left-width");
734 css_prop!(border_right, "border-right");
735 css_prop!(border_right_color, "border-right-color");
736 css_prop!(border_right_style, "border-right-style");
737 css_prop!(border_right_width, "border-right-width");
738 css_prop!(border_top, "border-top");
739 css_prop!(border_top_color, "border-top-color");
740 css_prop!(border_top_style, "border-top-style");
741 css_prop!(border_top_width, "border-top-width");
742 css_prop!(border_radius, "border-radius");
743 css_prop!(border_bottom_left_radius, "border-bottom-left-radius");
744 css_prop!(border_bottom_right_radius, "border-bottom-right-radius");
745 css_prop!(border_top_left_radius, "border-top-left-radius");
746 css_prop!(border_top_right_radius, "border-top-right-radius");
747 css_prop!(border_start_start_radius, "border-start-start-radius");
748 css_prop!(border_start_end_radius, "border-start-end-radius");
749 css_prop!(border_end_start_radius, "border-end-start-radius");
750 css_prop!(border_end_end_radius, "border-end-end-radius");
751 css_prop!(border_block, "border-block");
752 css_prop!(border_block_color, "border-block-color");
753 css_prop!(border_block_style, "border-block-style");
754 css_prop!(border_block_width, "border-block-width");
755 css_prop!(border_block_start, "border-block-start");
756 css_prop!(border_block_start_color, "border-block-start-color");
757 css_prop!(border_block_start_style, "border-block-start-style");
758 css_prop!(border_block_start_width, "border-block-start-width");
759 css_prop!(border_block_end, "border-block-end");
760 css_prop!(border_block_end_color, "border-block-end-color");
761 css_prop!(border_block_end_style, "border-block-end-style");
762 css_prop!(border_block_end_width, "border-block-end-width");
763 css_prop!(border_image, "border-image");
764 css_prop!(border_image_outset, "border-image-outset");
765 css_prop!(border_image_repeat, "border-image-repeat");
766 css_prop!(border_image_slice, "border-image-slice");
767 css_prop!(border_image_source, "border-image-source");
768 css_prop!(border_image_width, "border-image-width");
769 css_prop!(border_inline, "border-inline");
770 css_prop!(border_inline_color, "border-inline-color");
771 css_prop!(border_inline_style, "border-inline-style");
772 css_prop!(border_inline_width, "border-inline-width");
773 css_prop!(border_inline_start, "border-inline-start");
774 css_prop!(border_inline_start_color, "border-inline-start-color");
775 css_prop!(border_inline_start_style, "border-inline-start-style");
776 css_prop!(border_inline_start_width, "border-inline-start-width");
777 css_prop!(border_inline_end, "border-inline-end");
778 css_prop!(border_inline_end_color, "border-inline-end-color");
779 css_prop!(border_inline_end_style, "border-inline-end-style");
780 css_prop!(border_inline_end_width, "border-inline-end-width");
781 css_prop!(outline, "outline");
782 css_prop!(outline_color, "outline-color");
783 css_prop!(outline_offset, "outline-offset");
784 css_prop!(outline_style, "outline-style");
785 css_prop!(outline_width, "outline-width");
786}
787
788impl Prop {
792 css_prop!(columns, "columns");
793 css_prop!(column_count, "column-count");
794 css_prop!(column_fill, "column-fill");
795 css_prop!(column_gap, "column-gap");
796 #[cfg(feature = "experimental")]
797 css_prop!(column_height, "column-height");
798 css_prop!(column_rule, "column-rule");
799 css_prop!(column_rule_color, "column-rule-color");
800 css_prop!(column_rule_style, "column-rule-style");
801 css_prop!(column_rule_width, "column-rule-width");
802 css_prop!(column_span, "column-span");
803 css_prop!(column_width, "column-width");
804 #[cfg(feature = "experimental")]
805 css_prop!(column_wrap, "column-wrap");
806}
807
808impl Prop {
812 css_prop!(height, "height");
813 css_prop!(min_height, "min-height");
814 css_prop!(max_height, "max-height");
815 css_prop!(width, "width");
816 css_prop!(max_width, "max-width");
817 css_prop!(min_width, "min-width");
818}
819
820impl Prop {
824 css_prop!(contain, "contain");
825 css_prop!(contain_intrinsic_block_size, "contain-intrinsic-block-size");
826 css_prop!(contain_intrinsic_height, "contain-intrinsic-height");
827 css_prop!(
828 contain_intrinsic_inline_size,
829 "contain-intrinsic-inline-size"
830 );
831 css_prop!(contain_intrinsic_size, "contain-intrinsic-size");
832 css_prop!(contain_intrinsic_width, "contain-intrinsic-width");
833 css_prop!(container, "container");
834 css_prop!(container_name, "container-name");
835 css_prop!(container_type, "container-type");
836 css_prop!(content_visibility, "content-visibility");
837}
838
839#[cfg(feature = "experimental")]
840impl Prop {
844 css_prop!(corner_shape, "corner-shape");
845 css_prop!(corner_bottom_shape, "corner-bottom-shape");
846 css_prop!(corner_left_shape, "corner-left-shape");
847 css_prop!(corner_right_shape, "corner-right-shape");
848 css_prop!(corner_top_shape, "corner-top-shape");
849 css_prop!(corner_bottom_left_shape, "corner-bottom-left-shape");
850 css_prop!(corner_bottom_right_shape, "corner-bottom-right-shape");
851 css_prop!(corner_top_left_shape, "corner-top-left-shape");
852 css_prop!(corner_top_right_shape, "corner-top-right-shape");
853 css_prop!(corner_block_start_shape, "corner-block-start-shape");
854 css_prop!(corner_block_end_shape, "corner-block-end-shape");
855 css_prop!(corner_inline_end_shape, "corner-inline-end-shape");
856 css_prop!(corner_inline_start_shape, "corner-inline-start-shape");
857 css_prop!(corner_start_start_shape, "corner-start-start-shape");
858 css_prop!(corner_start_end_shape, "corner-start-end-shape");
859 css_prop!(corner_end_start_shape, "corner-end-start-shape");
860 css_prop!(corner_end_end_shape, "corner-end-end-shape");
861}
862
863impl Prop {
867 css_prop!(flex, "flex");
868 css_prop!(flex_basis, "flex-basis");
869 css_prop!(flex_direction, "flex-direction");
870 css_prop!(flex_flow, "flex-flow");
871 css_prop!(flex_grow, "flex-grow");
872 css_prop!(flex_shrink, "flex-shrink");
873 css_prop!(flex_wrap, "flex-wrap");
874}
875
876impl Prop {
880 css_prop!(font, "font");
881 css_prop!(font_family, "font-family");
882 css_prop!(font_feature_settings, "font-feature-settings");
883 css_prop!(font_kerning, "font-kerning");
884 #[cfg(feature = "limited-availability")]
885 css_prop!(font_language_override, "font-language-override");
886 css_prop!(font_optical_sizing, "font-optical-sizing");
887 css_prop!(font_palette, "font-palette");
888 css_prop!(font_size, "font-size");
889 css_prop!(font_size_adjust, "font-size-adjust");
890 css_prop!(font_stretch, "font-stretch");
891 css_prop!(font_style, "font-style");
892 css_prop!(font_synthesis, "font-synthesis");
893 #[cfg(feature = "experimental")]
894 css_prop!(font_synthesis_position, "font-synthesis-position");
895 css_prop!(font_synthesis_small_caps, "font-synthesis-small-caps");
896 css_prop!(font_synthesis_style, "font-synthesis-style");
897 css_prop!(font_synthesis_weight, "font-synthesis-weight");
898 css_prop!(font_variant, "font-variant");
899 css_prop!(font_variant_alternates, "font-variant-alternates");
900 css_prop!(font_variant_caps, "font-variant-caps");
901 css_prop!(font_variant_east_asian, "font-variant-east-asian");
902 #[cfg(feature = "limited-availability")]
903 css_prop!(font_variant_emoji, "font-variant-emoji");
904 css_prop!(font_variant_ligatures, "font-variant-ligatures");
905 css_prop!(font_variant_numeric, "font-variant-numeric");
906 css_prop!(font_variant_position, "font-variant-position");
907 css_prop!(font_variation_settings, "font-variation-settings");
908 css_prop!(font_weight, "font-weight");
909 #[cfg(feature = "experimental")]
910 css_prop!(font_width, "font-width");
911}
912
913impl Prop {
917 css_prop!(grid, "grid");
918 css_prop!(grid_area, "grid-area");
919 css_prop!(grid_auto_columns, "grid-auto-columns");
920 css_prop!(grid_auto_flow, "grid-auto-flow");
921 css_prop!(grid_auto_rows, "grid-auto-rows");
922 css_prop!(grid_column, "grid-column");
923 css_prop!(grid_column_start, "grid-column-start");
924 css_prop!(grid_column_end, "grid-column-end");
925 css_prop!(grid_row, "grid-row");
926 css_prop!(grid_row_start, "grid-row-start");
927 css_prop!(grid_row_end, "grid-row-end");
928 css_prop!(grid_template, "grid-template");
929 css_prop!(grid_template_areas, "grid-template-areas");
930 css_prop!(grid_template_columns, "grid-template-columns");
931 css_prop!(grid_template_rows, "grid-template-rows");
932}
933
934impl Prop {
938 css_prop!(inset, "inset");
939 css_prop!(bottom, "bottom");
940 css_prop!(left, "left");
941 css_prop!(right, "right");
942 css_prop!(top, "top");
943 css_prop!(inset_block, "inset-block");
944 css_prop!(inset_block_start, "inset-block-start");
945 css_prop!(inset_block_end, "inset-block-end");
946 css_prop!(inset_inline, "inset-inline");
947 css_prop!(inset_inline_start, "inset-inline-start");
948 css_prop!(inset_inline_end, "inset-inline-end");
949}
950
951impl Prop {
955 css_prop!(margin, "margin");
956 css_prop!(margin_bottom, "margin-bottom");
957 css_prop!(margin_left, "margin-left");
958 css_prop!(margin_right, "margin-right");
959 css_prop!(margin_top, "margin-top");
960 css_prop!(margin_block, "margin-block");
961 css_prop!(margin_block_start, "margin-block-start");
962 css_prop!(margin_block_end, "margin-block-end");
963 css_prop!(margin_inline, "margin-inline");
964 css_prop!(margin_inline_start, "margin-inline-start");
965 css_prop!(margin_inline_end, "margin-inline-end");
966 #[cfg(feature = "experimental")]
967 css_prop!(margin_trim, "margin-trim");
968}
969
970impl Prop {
974 css_prop!(mask, "mask");
975 #[cfg(feature = "limited-availability")]
976 css_prop!(mask_border, "mask-border");
977 #[cfg(feature = "limited-availability")]
978 css_prop!(mask_border_mode, "mask-border-mode");
979 #[cfg(feature = "limited-availability")]
980 css_prop!(mask_border_outset, "mask-border-outset");
981 #[cfg(feature = "limited-availability")]
982 css_prop!(mask_border_repeat, "mask-border-repeat");
983 #[cfg(feature = "limited-availability")]
984 css_prop!(mask_border_slice, "mask-border-slice");
985 #[cfg(feature = "limited-availability")]
986 css_prop!(mask_border_source, "mask-border-source");
987 #[cfg(feature = "limited-availability")]
988 css_prop!(mask_border_width, "mask-border-width");
989 css_prop!(mask_clip, "mask-clip");
990 css_prop!(mask_composite, "mask-composite");
991 css_prop!(mask_image, "mask-image");
992 css_prop!(mask_mode, "mask-mode");
993 css_prop!(mask_origin, "mask-origin");
994 css_prop!(mask_position, "mask-position");
995 css_prop!(mask_repeat, "mask-repeat");
996 css_prop!(mask_size, "mask-size");
997}
998
999impl Prop {
1003 css_prop!(math_depth, "math-depth");
1004 css_prop!(math_shift, "math-shift");
1005 css_prop!(math_style, "math-style");
1006}
1007
1008impl Prop {
1012 css_prop!(padding, "padding");
1013 css_prop!(padding_bottom, "padding-bottom");
1014 css_prop!(padding_left, "padding-left");
1015 css_prop!(padding_right, "padding-right");
1016 css_prop!(padding_top, "padding-top");
1017 css_prop!(padding_block, "padding-block");
1018 css_prop!(padding_block_start, "padding-block-start");
1019 css_prop!(padding_block_end, "padding-block-end");
1020 css_prop!(padding_inline, "padding-inline");
1021 css_prop!(padding_inline_start, "padding-inline-start");
1022 css_prop!(padding_inline_end, "padding-inline-end");
1023}
1024
1025impl Prop {
1029 css_prop!(scroll_behavior, "scroll-behavior");
1030 #[cfg(feature = "experimental")]
1031 css_prop!(scroll_initial_target, "scroll-initial-target");
1032 #[cfg(feature = "experimental")]
1033 css_prop!(scroll_marker_group, "scroll-marker-group");
1034 css_prop!(scroll_margin, "scroll-margin");
1035 css_prop!(scroll_margin_bottom, "scroll-margin-bottom");
1036 css_prop!(scroll_margin_left, "scroll-margin-left");
1037 css_prop!(scroll_margin_right, "scroll-margin-right");
1038 css_prop!(scroll_margin_top, "scroll-margin-top");
1039 css_prop!(scroll_margin_block, "scroll-margin-block");
1040 css_prop!(scroll_margin_block_start, "scroll-margin-block-start");
1041 css_prop!(scroll_margin_block_end, "scroll-margin-block-end");
1042 css_prop!(scroll_margin_inline, "scroll-margin-inline");
1043 css_prop!(scroll_margin_inline_start, "scroll-margin-inline-start");
1044 css_prop!(scroll_margin_inline_end, "scroll-margin-inline-end");
1045 css_prop!(scroll_padding, "scroll-padding");
1046 css_prop!(scroll_padding_bottom, "scroll-padding-bottom");
1047 css_prop!(scroll_padding_left, "scroll-padding-left");
1048 css_prop!(scroll_padding_right, "scroll-padding-right");
1049 css_prop!(scroll_padding_top, "scroll-padding-top");
1050 css_prop!(scroll_padding_block, "scroll-padding-block");
1051 css_prop!(scroll_padding_block_start, "scroll-padding-block-start");
1052 css_prop!(scroll_padding_block_end, "scroll-padding-block-end");
1053 css_prop!(scroll_padding_inline, "scroll-padding-inline");
1054 css_prop!(scroll_padding_inline_start, "scroll-padding-inline-start");
1055 css_prop!(scroll_padding_inline_end, "scroll-padding-inline-end");
1056 css_prop!(scroll_snap_align, "scroll-snap-align");
1057 css_prop!(scroll_snap_stop, "scroll-snap-stop");
1058 css_prop!(scroll_snap_type, "scroll-snap-type");
1059 #[cfg(feature = "experimental")]
1060 css_prop!(scroll_target_group, "scroll-target-group");
1061 #[cfg(feature = "limited-availability")]
1062 css_prop!(scroll_timeline, "scroll-timeline");
1063 #[cfg(feature = "limited-availability")]
1064 css_prop!(scroll_timeline_axis, "scroll-timeline-axis");
1065 #[cfg(feature = "limited-availability")]
1066 css_prop!(scroll_timeline_name, "scroll-timeline-name");
1067 #[cfg(feature = "limited-availability")]
1068 css_prop!(overscroll_behavior, "overscroll-behavior");
1069 #[cfg(feature = "limited-availability")]
1070 css_prop!(overscroll_behavior_block, "overscroll-behavior-block");
1071 #[cfg(feature = "limited-availability")]
1072 css_prop!(overscroll_behavior_inline, "overscroll-behavior-inline");
1073 #[cfg(feature = "limited-availability")]
1074 css_prop!(overscroll_behavior_x, "overscroll-behavior-x");
1075 #[cfg(feature = "limited-availability")]
1076 css_prop!(overscroll_behavior_y, "overscroll-behavior-y");
1077}
1078
1079impl Prop {
1083 css_prop!(clip_rule, "clip-rule");
1084 css_prop!(color_interpolation, "color-interpolation");
1085 css_prop!(color_interpolation_filters, "color-interpolation-filters");
1086 css_prop!(cx, "cx");
1087 css_prop!(cy, "cy");
1088 #[cfg(feature = "limited-availability")]
1089 css_prop!(d, "d");
1090 css_prop!(fill, "fill");
1091 css_prop!(fill_opacity, "fill-opacity");
1092 css_prop!(fill_rule, "fill-rule");
1093 css_prop!(flood_color, "flood-color");
1094 css_prop!(flood_opacity, "flood-opacity");
1095 css_prop!(lighting_color, "lighting-color");
1096 css_prop!(marker, "marker");
1097 css_prop!(marker_start, "marker-start");
1098 css_prop!(marker_mid, "marker-mid");
1099 css_prop!(marker_end, "marker-end");
1100 css_prop!(mask_type, "mask-type");
1101 css_prop!(r, "r");
1102 css_prop!(rx, "rx");
1103 css_prop!(ry, "ry");
1104 css_prop!(shape_rendering, "shape-rendering");
1105 css_prop!(stop_color, "stop-color");
1106 css_prop!(stop_opacity, "stop-opacity");
1107 css_prop!(stroke, "stroke");
1108 css_prop!(stroke_dasharray, "stroke-dasharray");
1109 css_prop!(stroke_dashoffset, "stroke-dashoffset");
1110 css_prop!(stroke_linecap, "stroke-linecap");
1111 css_prop!(stroke_linejoin, "stroke-linejoin");
1112 css_prop!(stroke_miterlimit, "stroke-miterlimit");
1113 css_prop!(stroke_opacity, "stroke-opacity");
1114 css_prop!(stroke_width, "stroke-width");
1115 css_prop!(text_anchor, "text-anchor");
1116 css_prop!(vector_effect, "vector-effect");
1117 css_prop!(x, "x");
1118 css_prop!(y, "y");
1119}
1120
1121impl Prop {
1125 css_prop!(text_autospace, "text-autospace");
1126 #[cfg(feature = "limited-availability")]
1127 css_prop!(text_box, "text-box");
1128 #[cfg(feature = "limited-availability")]
1129 css_prop!(text_box_edge, "text-box-edge");
1130 #[cfg(feature = "limited-availability")]
1131 css_prop!(text_box_trim, "text-box-trim");
1132 css_prop!(text_combine_upright, "text-combine-upright");
1133 css_prop!(text_decoration, "text-decoration");
1134 css_prop!(text_decoration_color, "text-decoration-color");
1135 #[cfg(feature = "experimental")]
1136 css_prop!(text_decoration_inset, "text-decoration-inset");
1137 css_prop!(text_decoration_line, "text-decoration-line");
1138 css_prop!(text_decoration_skip_ink, "text-decoration-skip-ink");
1139 css_prop!(text_decoration_style, "text-decoration-style");
1140 css_prop!(text_decoration_thickness, "text-decoration-thickness");
1141 css_prop!(text_emphasis, "text-emphasis");
1142 css_prop!(text_emphasis_color, "text-emphasis-color");
1143 css_prop!(text_emphasis_position, "text-emphasis-position");
1144 css_prop!(text_emphasis_style, "text-emphasis-style");
1145 css_prop!(text_indent, "text-indent");
1146 css_prop!(text_orientation, "text-orientation");
1147 css_prop!(text_overflow, "text-overflow");
1148 css_prop!(text_rendering, "text-rendering");
1149 css_prop!(text_shadow, "text-shadow");
1150 #[cfg(feature = "experimental")]
1151 css_prop!(text_size_adjust, "text-size-adjust");
1152 #[cfg(feature = "experimental")]
1153 css_prop!(text_spacing_trim, "text-spacing-trim");
1154 css_prop!(text_transform, "text-transform");
1155 css_prop!(text_underline_offset, "text-underline-offset");
1156 css_prop!(text_underline_position, "text-underline-position");
1157 css_prop!(text_wrap, "text-wrap");
1158 css_prop!(text_wrap_mode, "text-wrap-mode");
1159 css_prop!(text_wrap_style, "text-wrap-style");
1160}
1161
1162impl fmt::Display for Sel {
1163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1164 write!(f, "{}", self.val)
1165 }
1166}
1167
1168impl Sel {
1169 pub fn any() -> Self {
1171 Sel {
1172 val: "*".to_string(),
1173 }
1174 }
1175
1176 pub fn tp<'a, V>(tp: V) -> Self
1180 where
1181 V: Into<Val<'a>>,
1182 {
1183 let val = tp.into().to_ident();
1184 Sel { val }
1185 }
1186
1187 pub fn cls<'a, V>(cls: V) -> Self
1191 where
1192 V: Into<Val<'a>>,
1193 {
1194 let mut val = cls.into().to_ident();
1195 val.insert(0, '.');
1196 Sel { val }
1197 }
1198
1199 pub fn ident<'a, V>(ident: V) -> Self
1203 where
1204 V: Into<Val<'a>>,
1205 {
1206 let mut val = ident.into().to_ident();
1207 val.insert(0, '#');
1208 Sel { val }
1209 }
1210
1211 pub fn with(mut self, other: Self) -> Self {
1213 self.val.push_str(&other.val);
1214 self
1215 }
1216
1217 pub fn list(mut self, other: Self) -> Self {
1219 self.val.push_str(", ");
1220 self.val.push_str(&other.val);
1221 self
1222 }
1223
1224 pub fn descendant(mut self, other: Self) -> Self {
1226 self.val.push(' ');
1227 self.val.push_str(&other.val);
1228 self
1229 }
1230
1231 pub fn child(mut self, other: Self) -> Self {
1233 self.val.push_str(" > ");
1234 self.val.push_str(&other.val);
1235 self
1236 }
1237
1238 pub fn next_sibling(mut self, other: Self) -> Self {
1240 self.val.push_str(" + ");
1241 self.val.push_str(&other.val);
1242 self
1243 }
1244
1245 pub fn subsequent_sibling(mut self, other: Self) -> Self {
1247 self.val.push_str(" ~ ");
1248 self.val.push_str(&other.val);
1249 self
1250 }
1251}
1252
1253impl fmt::Display for Rule {
1254 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1255 writeln!(f, "{} {{\n{}\n}}", self.sel, self.prop)
1256 }
1257}
1258
1259impl Rule {
1260 pub fn new(sel: Sel, mut prop: Prop) -> Self {
1262 prop.sep = "\n";
1263 Rule { sel, prop }
1264 }
1265
1266 pub fn selector(&self) -> &Sel {
1268 &self.sel
1269 }
1270
1271 pub fn prop(&self) -> &Prop {
1273 &self.prop
1274 }
1275}
1276
1277#[cfg(test)]
1278mod test {
1279 use super::*;
1280
1281 #[test]
1282 fn sel() {
1283 let sel = Sel::tp("td").list(Sel::tp("th"));
1284 assert_eq!(sel.to_string(), "td, th");
1285 }
1286
1287 #[test]
1288 fn rule() {
1289 let prop = Prop::new().color("rebeccapurple");
1290 let rule = Rule::new(Sel::any(), prop);
1291 assert_eq!(rule.to_string(), "* {\ncolor: rebeccapurple;\n}\n");
1292 }
1293}