mod animation;
mod computed;
pub mod error;
mod parser;
mod properties;
mod theme;
mod theme_signal;
pub mod themes;
mod transition;
pub use animation::{
easing,
widget_animations,
Animation,
AnimationDirection,
AnimationFillMode,
AnimationGroup,
AnimationState,
Animations,
Choreographer,
CssKeyframe,
GroupMode,
KeyframeAnimation,
Stagger,
Tween,
};
pub use computed::ComputedStyle;
pub use error::{
suggest_property, ErrorCode, ParseErrors, RichParseError, Severity, SourceLocation, Suggestion,
KNOWN_PROPERTIES,
};
pub use parser::{
apply_declaration, Declaration, KeyframeBlock, KeyframesDefinition, Rule, StyleSheet,
};
pub use properties::*;
pub use theme::{
shared_theme, theme_manager, Palette, SharedTheme, Theme, ThemeBuilder, ThemeChangeListener,
ThemeColors, ThemeManager, ThemeVariant, Themes,
};
pub use theme_signal::{
cycle_theme, get_theme, register_theme, set_theme, set_theme_by_id, theme_ids,
theme_to_css_variables, toggle_theme, use_theme,
};
pub use themes::BuiltinTheme;
pub use transition::{
effective_duration,
lerp_f32,
lerp_u8,
should_skip_animation,
ActiveTransition,
Easing,
Transition,
TransitionManager,
Transitions,
};
pub fn parse_css(css: &str) -> Result<StyleSheet, ParseError> {
parser::parse(css)
}
#[derive(Debug, Clone)]
pub struct ParseError {
pub line: usize,
pub column: usize,
pub message: String,
pub code: ErrorCode,
pub offset: usize,
pub length: usize,
pub suggestions: Vec<String>,
}
impl ParseError {
pub fn new(message: impl Into<String>, line: usize, column: usize) -> Self {
Self {
line,
column,
message: message.into(),
code: ErrorCode::InvalidSyntax,
offset: 0,
length: 1,
suggestions: Vec::new(),
}
}
pub fn at_offset(message: impl Into<String>, source: &str, offset: usize) -> Self {
let loc = SourceLocation::from_offset(source, offset);
Self {
line: loc.line,
column: loc.column,
message: message.into(),
code: ErrorCode::InvalidSyntax,
offset,
length: 1,
suggestions: Vec::new(),
}
}
pub fn with_code(mut self, code: ErrorCode) -> Self {
self.code = code;
self
}
pub fn with_length(mut self, length: usize) -> Self {
self.length = length;
self
}
pub fn suggest(mut self, suggestion: impl Into<String>) -> Self {
self.suggestions.push(suggestion.into());
self
}
pub fn pretty_print(&self, source: &str) -> String {
let rich = self.to_rich();
rich.pretty_print(source)
}
pub fn to_rich(&self) -> RichParseError {
let mut error = RichParseError::new(
self.code,
&self.message,
SourceLocation::new(self.line, self.column, self.offset, self.length),
);
for s in &self.suggestions {
error.suggestions.push(Suggestion::new(s.clone()));
}
error
}
}
impl std::error::Error for ParseError {}
impl std::fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"[{}] CSS error at line {}, column {}: {}",
self.code, self.line, self.column, self.message
)
}
}