rtml/
css.rs

1use crate::*;
2
3pub trait CssSelector {
4    fn is_selector(&self) {}
5}
6pub trait CssClass: CssSelector {
7    fn is_class(&self) {}
8}
9pub trait CssId: CssSelector {
10    fn is_id(&self) {}
11}
12pub trait CssElement: CssSelector {}
13pub trait CssAttribute: CssSelector {}
14pub trait CssPseudoClass: CssSelector {
15    fn is_pseudo_class(&self) {}
16}
17
18pub trait CssPseudoElement: CssSelector {
19    fn is_pseudo_element(&self) {}
20}
21pub trait CssIsParenable {
22    fn is_parenable(&self) {}
23}
24pub trait CssGlobal: CssSelector {}
25
26/// # Example
27/// ```
28/// # #[macro_use] extern crate rtml;
29/// # fn main() {
30/// use rtml::*;
31///
32/// // create your own custom class.
33/// make_class!(my_class);
34/// let css = css!(
35///     .my_class {
36///         color: "red"
37///     }).render();
38/// // this css renders to
39/// // .my_class {
40/// //   color: "red";
41/// //  }
42/// assert_eq!(css, ".my_class {\n  color: red;\n  }\n");
43///
44/// // it can be used in conjunction with html macros
45///
46/// let block = p! { .class = my_class, "red text!" }.render();
47/// // this html renders to
48/// // <p class="my_class">red text!</p>
49/// assert_eq!(block, "<p class=\"my_class\">red text!</p>");
50///
51/// # }
52/// ```
53
54#[macro_export]
55macro_rules! make_class {
56    ($ident:ident) => {
57        #[allow(non_camel_case_types)]
58        #[derive(Clone)]
59        pub struct $ident;
60        impl CssClass for $ident {}
61        impl CssSelector for $ident {}
62
63        impl std::fmt::Display for $ident {
64            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
65                return write!(f, "{}", stringify!($ident));
66            }
67        }
68    };
69}
70
71/// # Example
72/// ```
73/// # #[macro_use] extern crate rtml;
74/// # fn main() {
75/// use rtml::*;
76///
77/// // create your own custom id.
78/// make_id!(my_id);
79/// let css = css!(
80///     #my_id {
81///         color: "red"
82///     }).render();
83/// // this css renders to
84/// // #my_id {
85/// //   color: "red";
86/// //  }
87/// assert_eq!(css, "#my_id {\n  color: red;\n  }\n");
88///
89/// // it can be used in conjunction with html macros
90///
91/// let block = p! { .id = my_id, "red text!" }.render();
92/// // this html renders to
93/// // <p id="my_id">red text!</p>
94/// assert_eq!(block, "<p id=\"my_id\">red text!</p>");
95///
96/// # }
97/// ```
98#[macro_export]
99macro_rules! make_id {
100    ($ident:ident) => {
101        #[allow(non_camel_case_types)]
102        #[derive(Clone)]
103        pub struct $ident;
104        impl CssId for $ident {}
105        impl CssSelector for $ident {}
106
107        impl std::fmt::Display for $ident {
108            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
109                return write!(f, "{}", stringify!($ident));
110            }
111        }
112    };
113}
114
115macro_rules! selectorit {
116    ($ident:ident) => {
117        impl CssElement for $ident {}
118        impl CssSelector for $ident {}
119    };
120}
121
122selectorit!(a);
123selectorit!(abbr);
124selectorit!(address);
125selectorit!(area);
126selectorit!(article);
127selectorit!(aside);
128selectorit!(audio);
129selectorit!(b);
130selectorit!(base);
131selectorit!(bdi);
132selectorit!(bdo);
133selectorit!(blockquote);
134selectorit!(body);
135selectorit!(br);
136selectorit!(button);
137selectorit!(canvas);
138selectorit!(caption);
139selectorit!(cite);
140selectorit!(code);
141selectorit!(col);
142selectorit!(colgroup);
143selectorit!(data);
144selectorit!(datalist);
145selectorit!(dd);
146selectorit!(del);
147selectorit!(details);
148selectorit!(dfn);
149selectorit!(dialog);
150selectorit!(div);
151selectorit!(dl);
152selectorit!(dt);
153selectorit!(em);
154selectorit!(embed);
155selectorit!(fieldset);
156selectorit!(figcaption);
157selectorit!(figure);
158selectorit!(footer);
159selectorit!(form);
160selectorit!(h1);
161selectorit!(h2);
162selectorit!(h3);
163selectorit!(h4);
164selectorit!(h5);
165selectorit!(h6);
166selectorit!(head);
167selectorit!(header);
168selectorit!(hr);
169selectorit!(html);
170selectorit!(i);
171selectorit!(iframe);
172selectorit!(img);
173selectorit!(input);
174selectorit!(ins);
175selectorit!(kbd);
176selectorit!(label);
177selectorit!(legend);
178selectorit!(li);
179selectorit!(link);
180selectorit!(main);
181selectorit!(map);
182selectorit!(mark);
183selectorit!(menu);
184selectorit!(meta);
185selectorit!(meter);
186selectorit!(nav);
187selectorit!(noscript);
188selectorit!(object);
189selectorit!(ol);
190selectorit!(optgroup);
191selectorit!(option);
192selectorit!(output);
193selectorit!(p);
194selectorit!(picture);
195selectorit!(pre);
196selectorit!(progress);
197selectorit!(q);
198selectorit!(rp);
199selectorit!(rt);
200selectorit!(ruby);
201selectorit!(s);
202selectorit!(samp);
203selectorit!(script);
204selectorit!(section);
205selectorit!(select);
206selectorit!(small);
207selectorit!(source);
208selectorit!(span);
209selectorit!(strong);
210selectorit!(style);
211selectorit!(sub);
212selectorit!(summary);
213selectorit!(sup);
214selectorit!(table);
215selectorit!(tbody);
216selectorit!(td);
217selectorit!(template);
218selectorit!(textarea);
219selectorit!(tfoot);
220selectorit!(th);
221selectorit!(thead);
222selectorit!(time);
223selectorit!(title);
224selectorit!(tr);
225selectorit!(track);
226selectorit!(u);
227selectorit!(ul);
228selectorit!(var);
229selectorit!(video);
230selectorit!(wbr);
231
232pub trait CssProperty {
233    fn is_prop(&self) {}
234}
235
236macro_rules! propit {
237    ($ident:ident) => {
238        impl CssProperty for $ident {}
239    };
240}
241
242propit!(_webkit_line_clamp);
243propit!(_webkit_text_fill_color);
244propit!(_webkit_text_stroke);
245propit!(_webkit_text_stroke_color);
246propit!(_webkit_text_stroke_width);
247propit!(accent_color);
248propit!(align_content);
249propit!(align_items);
250propit!(align_self);
251propit!(all);
252propit!(animation);
253propit!(animation_delay);
254propit!(animation_direction);
255propit!(animation_duration);
256propit!(animation_fill_mode);
257propit!(animation_iteration_count);
258propit!(animation_name);
259propit!(animation_play_state);
260propit!(animation_timing_function);
261propit!(appearance);
262propit!(aspect_ration);
263propit!(backdrop_filter);
264propit!(backface_visibility);
265propit!(background);
266propit!(background_attachment);
267propit!(background_blend_mode);
268propit!(background_clip);
269propit!(background_color);
270propit!(background_image);
271propit!(background_origin);
272propit!(background_position);
273propit!(background_position_x);
274propit!(background_position_y);
275propit!(background_repeat);
276propit!(background_size);
277propit!(block_size);
278propit!(border);
279propit!(border_block);
280propit!(border_block_color);
281propit!(border_block_end);
282propit!(border_block_end_color);
283propit!(border_block_end_style);
284propit!(border_block_end_width);
285propit!(border_block_start);
286propit!(border_block_start_color);
287propit!(border_block_start_style);
288propit!(border_block_start_width);
289propit!(border_block_style);
290propit!(border_block_width);
291propit!(border_bottom);
292propit!(border_bottom_color);
293propit!(border_bottom_left_radius);
294propit!(border_bottom_right_radius);
295propit!(border_bottom_style);
296propit!(border_bottom_width);
297propit!(border_collapse);
298propit!(border_color);
299propit!(border_end_end_radius);
300propit!(border_end_start_radius);
301propit!(border_image);
302propit!(border_image_outset);
303propit!(border_image_repeat);
304propit!(border_image_slice);
305propit!(border_image_source);
306propit!(border_image_width);
307propit!(border_inline);
308propit!(border_inline_color);
309propit!(border_inline_end);
310propit!(border_inline_end_color);
311propit!(border_inline_end_style);
312propit!(border_inline_end_width);
313propit!(border_inline_start);
314propit!(border_inline_start_color);
315propit!(border_inline_start_style);
316propit!(border_inline_start_width);
317propit!(border_inline_style);
318propit!(border_inline_width);
319propit!(border_left);
320propit!(border_left_color);
321propit!(border_left_style);
322propit!(border_left_width);
323propit!(border_radius);
324propit!(border_right);
325propit!(border_right_color);
326propit!(border_right_style);
327propit!(border_right_wdith);
328propit!(border_spacing);
329propit!(border_start_end_radius);
330propit!(border_start_start_radius);
331propit!(border_style);
332propit!(border_top);
333propit!(border_top_color);
334propit!(border_top_left_radius);
335propit!(border_top_right_radius);
336propit!(border_top_style);
337propit!(border_top_width);
338propit!(border_width);
339propit!(bottom);
340propit!(break_after);
341propit!(break_before);
342propit!(break_inside);
343propit!(caption_side);
344propit!(caret_color);
345propit!(clear);
346propit!(clip_path);
347propit!(color);
348propit!(color_scheme);
349propit!(column_count);
350propit!(column_fill);
351propit!(column_gap);
352propit!(column_rule);
353propit!(column_rule_color);
354propit!(column_rule_style);
355propit!(column_rule_width);
356propit!(column_span);
357propit!(column_width);
358propit!(columns);
359propit!(container);
360propit!(container_name);
361propit!(container_type);
362propit!(counter_increment);
363propit!(counter_reset);
364propit!(counter_set);
365propit!(content);
366propit!(content_visibility);
367propit!(cursor);
368propit!(direction);
369propit!(display);
370propit!(empty_cells);
371propit!(filter);
372propit!(flex);
373propit!(flex_basis);
374propit!(flex_direction);
375propit!(flex_flow);
376propit!(flex_grow);
377propit!(flex_shrink);
378propit!(flex_wrap);
379propit!(float);
380propit!(font);
381propit!(font_family);
382propit!(font_feature_setting);
383propit!(font_kerning);
384propit!(font_language_override);
385propit!(font_optical_sizing);
386propit!(font_palette);
387propit!(font_size);
388propit!(font_size_adjust);
389propit!(font_stretch);
390propit!(font_style);
391propit!(font_synthesis);
392propit!(font_variant);
393propit!(font_variant_alternatives);
394propit!(font_variant_caps);
395propit!(font_variant_east_asian);
396propit!(font_variant_emoji);
397propit!(font_variant_ligatures);
398propit!(font_variant_numeric);
399propit!(font_variant_position);
400propit!(font_variant_settings);
401propit!(font_weight);
402propit!(forced_color_adjust);
403propit!(gap);
404propit!(grid);
405propit!(grid_area);
406propit!(grid_auto_columns);
407propit!(grid_auto_flow);
408propit!(grid_auto_rows);
409propit!(grid_column);
410propit!(grid_column_end);
411propit!(grid_column_start);
412propit!(grid_row);
413propit!(grid_row_end);
414propit!(grid_row_start);
415propit!(grid_template);
416propit!(grid_template_areas);
417propit!(grid_template_columns);
418propit!(grid_template_rows);
419propit!(hanging_punctuation);
420propit!(hyphenate_character);
421propit!(hyphenate_limit_chars);
422propit!(hyphens);
423propit!(inline_size);
424propit!(image_orientation);
425propit!(image_rendering);
426propit!(isolation);
427propit!(inset);
428propit!(inset_block);
429propit!(inset_block_end);
430propit!(inset_block_start);
431propit!(inset_inline);
432propit!(inset_inline_end);
433propit!(inset_inline_start);
434propit!(justify_content);
435propit!(justify_items);
436propit!(justify_self);
437propit!(left);
438propit!(letter_spacing);
439propit!(line_break);
440propit!(line_height);
441propit!(list_style);
442propit!(list_style_image);
443propit!(list_style_position);
444propit!(list_style_type);
445propit!(margin);
446propit!(margin_block);
447propit!(margin_block_end);
448propit!(margin_block_start);
449propit!(margin_bottom);
450propit!(margin_inline);
451propit!(margin_inline_end);
452propit!(margin_inline_start);
453propit!(margin_left);
454propit!(margin_right);
455propit!(margin_top);
456propit!(mask);
457propit!(mask_border);
458propit!(mask_border_mode);
459propit!(mask_border_outset);
460propit!(mask_border_repeat);
461propit!(mask_border_slice);
462propit!(mask_border_source);
463propit!(mask_border_width);
464propit!(mask_clip);
465propit!(mask_composite);
466propit!(mask_image);
467propit!(mask_mode);
468propit!(mask_origin);
469propit!(mask_position);
470propit!(mask_repeat);
471propit!(mask_size);
472propit!(mask_type);
473propit!(math_style);
474propit!(max_block_size);
475propit!(max_height);
476propit!(max_inline_size);
477propit!(max_width);
478propit!(min_block_size);
479propit!(min_height);
480propit!(min_inline_size);
481propit!(min_width);
482propit!(offset);
483propit!(offset_anchar);
484propit!(offset_distance);
485propit!(offset_path);
486propit!(offset_rotate);
487propit!(mix_blend_mode);
488propit!(object_fit);
489propit!(object_position);
490propit!(opacity);
491propit!(order);
492propit!(orphans);
493propit!(outline);
494propit!(outline_color);
495propit!(outline_offset);
496propit!(outline_style);
497propit!(outline_width);
498propit!(overflow);
499propit!(overflow_anchor);
500propit!(overflow_block);
501propit!(overflow_clip_margin);
502propit!(overflow_inline);
503propit!(overflow_wrap);
504propit!(overflow_x);
505propit!(overflow_y);
506propit!(overscoll_behavior);
507propit!(overscoll_behavior_block);
508propit!(overscoll_behavior_inline);
509propit!(overscoll_behavior_x);
510propit!(overscoll_behavior_y);
511propit!(padding);
512propit!(padding_block);
513propit!(padding_block_end);
514propit!(padding_block_start);
515propit!(padding_bottom);
516propit!(padding_inline);
517propit!(padding_inline_end);
518propit!(padding_inline_start);
519propit!(padding_left);
520propit!(padding_right);
521propit!(padding_top);
522propit!(page_break_after);
523propit!(page_break_before);
524propit!(page_break_inside);
525propit!(paint_order);
526propit!(perspective);
527propit!(perspective_origin);
528propit!(place_content);
529propit!(place_items);
530propit!(place_self);
531propit!(pointer_events);
532propit!(position);
533propit!(print_color_adjust);
534propit!(quotes);
535propit!(resize);
536propit!(right);
537propit!(rotate);
538propit!(row_gap);
539propit!(ruby_position);
540propit!(scale);
541propit!(scroll_behavior);
542propit!(scroll_margin);
543propit!(scroll_margin_block);
544propit!(scroll_margin_block_end);
545propit!(scroll_margin_block_start);
546propit!(scroll_margin_bottom);
547propit!(scroll_margin_inline);
548propit!(scroll_margin_inline_end);
549propit!(scroll_margin_inline_start);
550propit!(scroll_margin_left);
551propit!(scroll_margin_right);
552propit!(scroll_margin_top);
553propit!(scroll_padding);
554propit!(scroll_padding_block);
555propit!(scroll_padding_block_end);
556propit!(scroll_padding_block_start);
557propit!(scroll_padding_bottom);
558propit!(scroll_padding_inline);
559propit!(scroll_padding_inline_end);
560propit!(scroll_padding_inline_start);
561propit!(scroll_padding_left);
562propit!(scroll_padding_right);
563propit!(scroll_padding_top);
564propit!(scroll_snap_align);
565propit!(scroll_snap_stop);
566propit!(scroll_snap_type);
567propit!(scrollbar_color);
568propit!(scrollbar_gutter);
569propit!(scrollbar_width);
570propit!(shape_image_threshold);
571propit!(shape_margin);
572propit!(shape_outside);
573propit!(tab_size);
574propit!(table_layout);
575propit!(text_align);
576propit!(text_align_last);
577propit!(text_combine_upright);
578propit!(text_decoration);
579propit!(text_decoration_color);
580propit!(text_decoration_line);
581propit!(text_decoration_skip_ink);
582propit!(text_decoration_style);
583propit!(text_decoration_thickness);
584propit!(text_emphasis);
585propit!(text_emphasis_color);
586propit!(text_emphasis_position);
587propit!(text_emphasis_style);
588propit!(text_indent);
589propit!(text_justify);
590propit!(text_orientation);
591propit!(text_overflow);
592propit!(text_rendering);
593propit!(text_shadow);
594propit!(text_transform);
595propit!(text_underline_offset);
596propit!(text_underline_position);
597propit!(top);
598propit!(touch_action);
599propit!(transform);
600propit!(transform_box);
601propit!(transform_origin);
602propit!(transform_style);
603propit!(transition);
604propit!(transition_delay);
605propit!(transition_duration);
606propit!(transition_property);
607propit!(transition_timing_function);
608propit!(translate);
609propit!(unicode_bidi);
610propit!(user_select);
611propit!(vertical_align);
612propit!(visibility);
613propit!(white_space);
614propit!(widows);
615propit!(width);
616propit!(will_change);
617propit!(word_break);
618propit!(word_spacing);
619propit!(writing_mode);
620propit!(z_index);
621
622macro_rules! pseudoclassit {
623    ($ident:ident) => {
624        impl CssPseudoClass for $ident {}
625        impl CssSelector for $ident {}
626    };
627}
628
629macro_rules! parenable {
630    ($ident:ident) => {
631        impl CssIsParenable for $ident {}
632    };
633}
634
635pseudoclassit!(active);
636pseudoclassit!(any_link);
637pseudoclassit!(autofill);
638pseudoclassit!(checked);
639pseudoclassit!(current);
640pseudoclassit!(default);
641pseudoclassit!(defined);
642pseudoclassit!(dir);
643parenable!(dir);
644pseudoclassit!(disabled);
645pseudoclassit!(empty);
646pseudoclassit!(enabled);
647pseudoclassit!(first);
648pseudoclassit!(first_child);
649pseudoclassit!(first_of_type);
650pseudoclassit!(focus);
651pseudoclassit!(focus_visible);
652pseudoclassit!(focus_within);
653pseudoclassit!(fullscreen);
654pseudoclassit!(future);
655pseudoclassit!(has);
656parenable!(has);
657pseudoclassit!(hover);
658pseudoclassit!(in_range);
659pseudoclassit!(indeterminate);
660pseudoclassit!(invalid);
661pseudoclassit!(is);
662parenable!(is);
663pseudoclassit!(lang);
664parenable!(lang);
665pseudoclassit!(last_child);
666parenable!(last_child);
667pseudoclassit!(last_of_type);
668pseudoclassit!(left);
669// DUPLICATE selector
670// pseudoclassit!(link);
671pseudoclassit!(local_link);
672pseudoclassit!(modal);
673pseudoclassit!(not);
674parenable!(not);
675pseudoclassit!(nth_child);
676parenable!(nth_child);
677pseudoclassit!(nth_col);
678parenable!(nth_col);
679pseudoclassit!(nth_last_child);
680parenable!(nth_last_child);
681pseudoclassit!(nth_last_col);
682parenable!(nth_last_col);
683pseudoclassit!(nth_last_of_type);
684parenable!(nth_last_of_type);
685pseudoclassit!(nth_of_type);
686parenable!(nth_of_type);
687pseudoclassit!(only_child);
688pseudoclassit!(only_of_type);
689pseudoclassit!(optional);
690pseudoclassit!(out_of_range);
691pseudoclassit!(past);
692pseudoclassit!(paused);
693pseudoclassit!(picture_in_picture);
694pseudoclassit!(placeholder_shown);
695pseudoclassit!(playing);
696pseudoclassit!(read_only);
697pseudoclassit!(read_write);
698pseudoclassit!(required);
699pseudoclassit!(right);
700pseudoclassit!(root);
701pseudoclassit!(scope);
702pseudoclassit!(target);
703pseudoclassit!(target_within);
704pseudoclassit!(valid);
705pseudoclassit!(visited);
706pseudoclassit!(_where);
707parenable!(_where);
708
709macro_rules! pseudoelementit {
710    ($ident:ident) => {
711        impl CssPseudoElement for $ident {}
712        impl CssSelector for $ident {}
713    };
714}
715
716pseudoelementit!(after);
717pseudoelementit!(backdrop);
718pseudoelementit!(before);
719pseudoelementit!(cue);
720pseudoelementit!(cue_region);
721pseudoelementit!(file_selector_button);
722pseudoelementit!(first_letter);
723pseudoelementit!(first_line);
724pseudoelementit!(marker);
725pseudoelementit!(part);
726parenable!(part);
727pseudoelementit!(placeholder);
728pseudoelementit!(selection);
729pseudoelementit!(slotted);
730parenable!(slotted);
731
732/// # Example
733/// ```
734/// # #[macro_use] extern crate rtml;
735/// # fn main() {
736/// use rtml::*;
737///
738/// let css = css!(
739///     p > div {
740///         background_color: "green",
741///     }
742///     p div {
743///         float: "left"
744///     }
745///    )
746///    .render(); assert_eq!( css,
747///     "p > div {\n  background-color: green;\n  }\np div {\n  float: left;\n  }\n"
748/// );
749///
750/// # }
751/// ```
752#[macro_export]
753macro_rules! css {
754    ($($next:tt)*) => {
755        selector!($($next)*)
756    };
757}
758
759#[macro_export]
760macro_rules! selector {
761    (.$class:ident $($inner:tt)*) => {{
762        CssClass::is_class(&$class);
763        render_fn!(".{}{}", $class, combinator!($($inner)*))
764    }};
765    (#$id:ident $($inner:tt)*) => {{
766        CssId::is_id(&$id);
767        render_fn!("#{}{}", $id, combinator!($($inner)*))
768    }};
769    ($tag:ident $($inner:tt)*) => {{
770        let ident = $tag;
771        CssSelector::is_selector(&ident);
772        render_fn!("{}{}", ident, combinator!($($inner)*))
773    }};
774    (:$($inner:tt)*) => {
775        pseudo_class!($($inner)*)
776    };
777    (::$($inner:tt)*) => {
778        pseudo_element!($($inner)*)
779    };
780    (* $($inner:tt)*) => {
781        render_fn!("*{}", combinator!($($inner)*))
782    };
783    ({ $($inner:tt)* }) => {
784        css_body!($($inner)*)
785    };
786    ({ $($inner:tt)* } $($next:tt)+) => {
787        render_fn!("{}{}", css_body!($($inner)*), selector!($($next)*))
788    };
789}
790
791#[macro_export]
792macro_rules! pseudo_class {
793    ($head:ident ($lit:expr) $($rest:tt)+) => {
794        {
795            let ident = $head;
796            CssPseudoClass::is_pseudo_class(&ident);
797            render_fn!(":{}({}){}", ident, $lit, combinator!($($rest)*))
798        }
799    };
800    ($head:ident $($rest:tt)+) => {
801        {
802            let ident = $head ;
803            CssPseudoClass::is_pseudo_class(&ident);
804            render_fn!(":{}{}", ident, combinator!($($rest)*))
805        }
806    };
807}
808
809#[macro_export]
810macro_rules! pseudo_element {
811    ($head:ident $($rest:tt)+) => {
812        {
813            let ident = $head;
814            CssPseudoElement::is_pseudo_element(&ident);
815            render_fn!("::{}{}", ident, combinator!($($rest)*))
816        }
817
818    };
819    ($head:ident ($lit:expr) $($rest:tt)+) => {
820        {
821            let ident = $head;
822            CssPseudoElement::is_pseudo_element(&ident);
823            render_fn!("::{}({}){}", ident, $lit, combinator!($($rest)*))
824        }
825    };
826}
827
828#[macro_export]
829macro_rules! combinator {
830    (~ $($selector:tt)+) => {
831        render_fn!(" ~ {}", selector!($($selector)*))
832    };
833    (+ $($selector:tt)+) => {
834        render_fn!(" + {}", selector!($($selector)*))
835    };
836    (, $($selector:tt)+) => {
837        render_fn!(",\n{}", selector!($($selector)*))
838    };
839    (> $($selector:tt)+) => {
840        render_fn!(" > {}", selector!($($selector)*))
841    };
842    ($head:ident $($selector:tt)+) => {{
843        let ident = $head;
844        CssSelector::is_selector(&ident);
845        render_fn!(" {}{}", ident, selector!($($selector)*))
846    }};
847    (_ $($selector:tt)+) => {
848        render_fn!(" {}", selector!($($selector)*))
849    };
850    ({$($selector:tt)*}) => {
851        css_body!($($selector)*)
852    };
853    ({$($selector:tt)*} $($next:tt)+) => {
854        render_fn!("{}{}", css_body!($($selector)*), selector!($($next)*))
855    };
856    ([$($inner:tt)*] $($next:tt)+) => {
857        render_fn!("{}{}", attr_selector!([$($inner)*]), selector!($($next)*))
858    };
859    ($($rest:tt)*) => {
860        selector!($($rest)*)
861    };
862}
863
864#[macro_export]
865macro_rules! attr_selector {
866    () => {
867        ""
868    };
869    (,.$attr:ident = $val:expr $(,.$attrs:ident$(-$nexts:ident)* = $vals:expr)*) => {{
870        let ident = $attr;
871
872        render_fn!(" {}=\"{}\"{}", ident, $val, attr_selector!($(,.$attrs = $vals)*))
873    }
874    };
875    ([.$attr:ident = $val:expr $(,.$attrs:ident = $vals:expr)*]) => {{
876        let ident = $attr;
877        render_fn!("[{}=\"{}\"{}]", ident,$val, attr_selector!($(,.$attrs = $vals)*))
878    }};
879}
880
881#[macro_export]
882macro_rules! css_body {
883    ($($inner:tt)*) => {
884        render_fn!(" {{\n  {}}}\n", property!($($inner)*))
885    };
886}
887
888#[macro_export]
889macro_rules! property_value {
890    ($val:literal) => {
891        $val
892    };
893}
894
895#[macro_export]
896macro_rules! property {
897    () => { "" };
898    ($head:ident : $val:literal) => {{
899        let ident = $head;
900        CssProperty::is_prop(&ident);
901        render_fn!("{}: {};\n  ", ident, property_value!($val))
902    }};
903    (: $val:literal) => {
904        render_fn!(": {};\n  ", property_value!($val))
905    };
906    (: $val:literal, $($next:tt)*) => {
907        render_fn!(": {};\n  {}", property_value!($val), property!($($next)*))
908    };
909    ($head:ident : $val:literal, $($next:tt)*) => {{
910            let ident = $head;
911            CssProperty::is_prop(&ident);
912
913        render_fn!("{}: {};\n  {}", ident, property_value!($val), property!($($next)*))
914    }
915    };
916    ($head:ident : $($rest:tt)*) => {
917        {
918            let ident = $head;
919            CssProperty::is_prop(&ident);
920            render_fn!("{}{}", ident, property!(: $($rest)*))
921        }
922    };
923}