wasm_css/lib.rs
1// Authors: Robert Lopez
2
3pub mod components;
4pub mod delete;
5pub mod error;
6pub mod extend_from_css;
7pub mod extend_from_style;
8pub mod macros;
9pub mod remove_keys;
10
11mod generate_random_identity;
12mod render;
13
14#[cfg(test)]
15mod tests;
16
17use crate::error::WasmCssError;
18use components::Components;
19use error::format_error;
20use generate_random_identity::generate_random_identity;
21
22/// Represents a `<style>` child in the `<head>` element containing CSS.
23///
24/// `css`: formatted css String.
25#[derive(Debug, Clone, PartialEq)]
26pub struct Style {
27 pub css: String,
28 css_name: String,
29 components: Components,
30}
31
32impl Style {
33 /// Create a `Style` from `css`, rendering it to the DOM as a `<style>` in `<head>`.
34 /// The `css` is formatted, minfied, and small errors like invalid semi-colons can be
35 /// corrected, however invalid CSS itself is not handled by the parser.
36 ///
37 /// Effects remain there order as defined, but their inner fields, as well as the Style's
38 /// fields will be ordered in a deterministic fashion to avoid duplication.
39 ///
40 /// *Note*: Trailing semi-colons are required.
41 ///
42 /// Returns error if missing access to: `Head`, `Crypto`(If generating a random ID),
43 /// `Window`, `Document`.
44 ///
45 /// Provide `css_name` to define a class, ID, or to target a global identifier,
46 /// E.G.: `div`, `#id`, `.class`.
47 ///
48 /// ---
49 /// Example Usage:
50 /// ```
51 ///
52 /// let style = Style::new(
53 /// "
54 /// display: flex;
55 ///
56 /// &:hover {
57 /// background-color: rgba(111, 111, 111, 0.1);
58 /// }
59 ///
60 /// @media (max-width: 800px) {
61 /// flex-direction: column;
62 /// }
63 /// ",
64 /// Some(".my_class"),
65 /// )?;
66 /// ```
67 pub fn new(css: &str, css_name: Option<&str>) -> Result<Self, WasmCssError> {
68 if css_name.is_some_and(|i| i.is_empty()) {
69 return Err(format_error!(
70 "A Styles css_name cannot be empty. Use: `body`, `.class`, `#id`, ect."
71 ));
72 }
73
74 let css_name = css_name
75 .map(|id| id.to_string())
76 .unwrap_or(format!(".{}", generate_random_identity()?));
77 let components = Components::from_css(css);
78
79 let _self = Self {
80 css: components.to_css(&css_name),
81 css_name,
82 components,
83 };
84 _self.render()?;
85
86 Ok(_self)
87 }
88
89 /// Returns the `identity` of the definition inside the `<style>` element.
90 ///
91 /// Example Usage:
92 /// ```
93 ///
94 /// let style = named_style!(".myStyle", "font-size: 5rem;")?;
95 ///
96 /// // "myStyle"
97 /// let identity = style.identity();
98 /// ```
99 ///
100 /// ```
101 ///
102 /// let style = named_style!("#myStyle", "font-size: 5rem;")?;
103 ///
104 /// // "myStyle"
105 /// let identity = style.identity();
106 /// ```
107 ///
108 /// ```
109 ///
110 /// let style = named_style!("body", "font-size: 5rem;")?;
111 ///
112 /// // "body"
113 /// let identity = style.identity();
114 pub fn identity(&self) -> &str {
115 if self.css_name.starts_with('#') || self.css_name.starts_with('.') {
116 self.css_name.split_at(1).1
117 } else {
118 &self.css_name
119 }
120 }
121}