iris-cssom 1.1.4

Iris CSS Object Model (CSSOM) implementation: CSS parsing, style computation, CSS Modules, and Web API
Documentation
//! Iris CSSOM — CSS Object Model implementation.
//!
//! Parse CSS strings, compute resolved styles for elements,
//! support CSS Modules (scoped class names), and provide
//! CSSOM Web API surfaces (CSSStyleSheet, CSSRule, etc.).

mod parser;
pub mod computed;
pub mod css_modules;
pub mod web_api;

pub use parser::*;
pub use computed::*;
pub use css_modules::*;
pub use web_api::*;

use std::collections::HashMap;

/// A single CSS declaration (property: value).
#[derive(Debug, Clone, PartialEq)]
pub struct Declaration {
    pub property: String,
    pub value: String,
}

/// A CSS rule: selector + declarations.
#[derive(Debug, Clone)]
pub struct CssRule {
    pub selectors: Vec<String>,
    pub declarations: Vec<Declaration>,
}

/// A parsed stylesheet (list of rules).
#[derive(Debug, Clone, Default)]
pub struct StyleSheet {
    pub rules: Vec<CssRule>,
}

impl StyleSheet {
    /// Parse a CSS string into a StyleSheet.
    pub fn parse(css: &str) -> Result<Self, String> {
        parser::parse_css(css)
    }

    /// Query all declarations matching a given class name.
    pub fn declarations_for_class(&self, class: &str) -> Vec<Declaration> {
        let mut result = Vec::new();
        let class_selector = format!(".{}", class);
        for rule in &self.rules {
            if rule.selectors.iter().any(|s| s == &class_selector || s.contains(&class_selector)) {
                result.extend(rule.declarations.clone());
            }
        }
        result
    }

    /// Query all declarations matching a given tag name.
    pub fn declarations_for_tag(&self, tag: &str) -> Vec<Declaration> {
        let mut result = Vec::new();
        for rule in &self.rules {
            if rule.selectors.iter().any(|s| s == tag) {
                result.extend(rule.declarations.clone());
            }
        }
        result
    }

    /// Compute the full set of resolved declarations for a set of class names and tag.
    pub fn compute(&self, classes: &[String], tag: &str) -> HashMap<String, String> {
        let mut map = HashMap::new();
        for class in classes {
            for decl in self.declarations_for_class(class) {
                map.insert(decl.property, decl.value);
            }
        }
        for decl in self.declarations_for_tag(tag) {
            map.entry(decl.property).or_insert(decl.value);
        }
        map
    }
}