from dataclasses import dataclass, field from typing import Any # === Condition === @dataclass class Condition: """ Represents a condition for conditional formatting. Attributes: operator: Comparison operator ("==", "!=", "<", "<=", ">", ">=", "contains", "startswith", "endswith", "in", "between", "isempty", "isnotempty") value: Value to compare against (literal, list, or {"col": "..."} for reference) negate: If True, inverts the condition result case_sensitive: If True, string comparisons are case-sensitive (default False) col: Column ID for row-level conditions (evaluate this column instead of current cell) row: Row index for column-level conditions (evaluate this row instead of current cell) """ operator: str value: Any = None negate: bool = False case_sensitive: bool = False col: str = None row: int = None # === Style === @dataclass class Style: """ Represents style properties for cell formatting. Attributes: preset: Name of a style preset ("primary", "success", "error", etc.) background_color: Background color (hex, CSS name, or CSS variable) color: Text color font_weight: "normal" or "bold" font_style: "normal" or "italic" font_size: Font size ("12px", "0.9em") text_decoration: "none", "underline", or "line-through" """ preset: str = None background_color: str = None color: str = None font_weight: str = None font_style: str = None font_size: str = None text_decoration: str = None # === Formatters === @dataclass class Formatter: """Base class for all formatters.""" preset: str = None @dataclass class NumberFormatter(Formatter): """ Formatter for numbers, currencies, and percentages. Attributes: prefix: Text before value (e.g., "$") suffix: Text after value (e.g., " EUR") thousands_sep: Thousands separator (e.g., ",", " ") decimal_sep: Decimal separator (e.g., ".", ",") precision: Number of decimal places multiplier: Multiply value before display (e.g., 100 for percentage) """ prefix: str = "" suffix: str = "" thousands_sep: str = "" decimal_sep: str = "." precision: int = 0 multiplier: float = 1.0 @dataclass class DateFormatter(Formatter): """ Formatter for dates and datetimes. Attributes: format: strftime format pattern (default: "%Y-%m-%d") """ format: str = "%Y-%m-%d" @dataclass class BooleanFormatter(Formatter): """ Formatter for boolean values. Attributes: true_value: Display string for True false_value: Display string for False null_value: Display string for None/null """ true_value: str = "true" false_value: str = "false" null_value: str = "" @dataclass class TextFormatter(Formatter): """ Formatter for text transformations. Attributes: transform: Text transformation ("uppercase", "lowercase", "capitalize") max_length: Maximum length before truncation ellipsis: Suffix when truncated (default: "...") """ transform: str = None max_length: int = None ellipsis: str = "..." @dataclass class ConstantFormatter(Formatter): value: str = None @dataclass class EnumFormatter(Formatter): """ Formatter for mapping values to display labels. Attributes: source: Data source dict with "type" and "value" keys - {"type": "mapping", "value": {"key": "label", ...}} - {"type": "datagrid", "value": "grid_id", "value_column": "id", "display_column": "name"} default: Label for unknown values allow_empty: Show empty option in Select dropdowns empty_label: Label for empty option order_by: Sort order ("source", "display", "value") """ source: dict = field(default_factory=dict) default: str = "" allow_empty: bool = True empty_label: str = "-- Select --" order_by: str = "source" # === Format Rule === @dataclass class FormatRule: """ A formatting rule combining condition, style, and formatter. Rules: - style and formatter can appear alone (unconditional formatting) - condition cannot appear alone - must be paired with style and/or formatter - If condition is present, style/formatter is applied only if condition is met Attributes: condition: Optional condition for conditional formatting style: Optional style to apply formatter: Optional formatter to apply """ condition: Condition = None style: Style = None formatter: Formatter = None