wasm-css 0.2.0

Ergonomic WASM CSS Framework
Documentation
// Authors: Robert Lopez

pub mod components;
pub mod delete;
pub mod error;
pub mod extend_from_css;
pub mod extend_from_style;
pub mod macros;
pub mod remove_keys;

mod generate_random_identity;
mod render;

#[cfg(test)]
mod tests;

use crate::error::WasmCssError;
use components::Components;
use error::format_error;
use generate_random_identity::generate_random_identity;

/// Represents a `<style>` child in the `<head>` element containing CSS.
///
/// `css`: formatted css String.
#[derive(Debug, Clone, PartialEq)]
pub struct Style {
    pub css: String,
    css_name: String,
    components: Components,
}

impl Style {
    /// Create a `Style` from `css`, rendering it to the DOM as a `<style>` in `<head>`.
    /// The `css` is formatted, minfied, and small errors like invalid semi-colons can be
    /// corrected, however invalid CSS itself is not handled by the parser.
    ///
    /// Effects remain there order as defined, but their inner fields, as well as the Style's
    /// fields will be ordered in a deterministic fashion to avoid duplication.
    ///
    /// *Note*: Trailing semi-colons are required.
    ///
    /// Returns error if missing access to: `Head`, `Crypto`(If generating a random ID),
    /// `Window`, `Document`.
    ///
    /// Provide `css_name` to define a class, ID, or to target a global identifier,
    /// E.G.: `div`, `#id`, `.class`.
    ///
    /// ---
    /// Example Usage:
    /// ```
    ///
    /// let style = Style::new(
    ///     "
    ///         display: flex;
    ///
    ///         &:hover {
    ///             background-color: rgba(111, 111, 111, 0.1);
    ///         }
    ///
    ///         @media (max-width: 800px) {
    ///             flex-direction: column;
    ///         }
    ///     ",
    ///     Some(".my_class"),
    /// )?;
    /// ```
    pub fn new(css: &str, css_name: Option<&str>) -> Result<Self, WasmCssError> {
        if css_name.is_some_and(|i| i.is_empty()) {
            return Err(format_error!(
                "A Styles css_name cannot be empty. Use: `body`, `.class`, `#id`, ect."
            ));
        }

        let css_name = css_name
            .map(|id| id.to_string())
            .unwrap_or(format!(".{}", generate_random_identity()?));
        let components = Components::from_css(css);

        let _self = Self {
            css: components.to_css(&css_name),
            css_name,
            components,
        };
        _self.render()?;

        Ok(_self)
    }

    /// Returns the `identity` of the definition inside the `<style>` element.
    ///
    /// Example Usage:
    /// ```
    ///
    /// let style = named_style!(".myStyle", "font-size: 5rem;")?;
    ///
    /// // "myStyle"
    /// let identity = style.identity();
    /// ```
    ///
    /// ```
    ///
    /// let style = named_style!("#myStyle", "font-size: 5rem;")?;
    ///
    /// // "myStyle"
    /// let identity = style.identity();
    /// ```
    ///
    /// ```
    ///
    /// let style = named_style!("body", "font-size: 5rem;")?;
    ///
    /// // "body"
    /// let identity = style.identity();
    pub fn identity(&self) -> &str {
        if self.css_name.starts_with('#') || self.css_name.starts_with('.') {
            self.css_name.split_at(1).1
        } else {
            &self.css_name
        }
    }
}