Source code for animaid.containers.divider

"""HTMLDivider - Visual separator for content."""

from __future__ import annotations

import html
import uuid

from animaid.css_types import Color, CSSValue, DividerStyle, Size
from animaid.html_object import HTMLObject


def _to_css(value: object) -> str:
    """Convert a value to its CSS string representation."""
    if hasattr(value, "to_css"):
        return str(value.to_css())
    return str(value)


[docs] class HTMLDivider(HTMLObject): """A visual separator (horizontal or vertical line). HTMLDivider creates a line to visually separate content sections. It can be horizontal (default) or vertical (for use in rows). Examples: >>> from animaid import HTMLDivider >>> divider = HTMLDivider() # Simple horizontal line >>> # With label >>> divider = HTMLDivider("OR") >>> # Vertical divider for rows >>> divider = HTMLDivider().vertical() >>> # Styled divider >>> divider = HTMLDivider().dashed().color("gray") """ _styles: dict[str, str] _css_classes: list[str] _label: str | None _is_vertical: bool _obs_id: str def __init__( self, label: str | None = None, **styles: str | CSSValue, ) -> None: """Create a new divider. Args: label: Optional text label to display in the middle of the divider. **styles: Initial CSS styles. """ self._label = label self._is_vertical = False self._styles = {} self._css_classes = [] self._obs_id = str(uuid.uuid4()) # Default styles self._styles["border-color"] = "#e5e7eb" self._styles["border-style"] = DividerStyle.SOLID.to_css() for key, value in styles.items(): css_key = key.replace("_", "-") self._styles[css_key] = _to_css(value) def _notify(self) -> None: """Publish change notification via pypubsub.""" try: from pubsub import pub pub.sendMessage("animaid.changed", obs_id=self._obs_id) except ImportError: pass
[docs] def render(self) -> str: """Render the divider. Returns: HTML string for the divider. """ if self._is_vertical: return self._render_vertical() return self._render_horizontal()
def _render_horizontal(self) -> str: """Render a horizontal divider.""" border_color = self._styles.get("border-color", "#e5e7eb") border_style = self._styles.get("border-style", "solid") border_width = self._styles.get("border-width", "1px") margin = self._styles.get("margin", "16px 0") if self._label: # Divider with label: two lines with text in between escaped_label = html.escape(self._label) line_style = ( f"flex: 1; border-bottom: {border_width} {border_style} {border_color};" ) label_style = "padding: 0 12px; color: #6b7280; font-size: 0.875em;" return ( f'<div style="display: flex; align-items: center; margin: {margin};">' f'<div style="{line_style}"></div>' f'<span style="{label_style}">{escaped_label}</span>' f'<div style="{line_style}"></div>' f"</div>" ) else: # Simple horizontal rule style = f"border: none; border-top: {border_width} {border_style} {border_color}; margin: {margin};" return f'<hr style="{style}">' def _render_vertical(self) -> str: """Render a vertical divider.""" border_color = self._styles.get("border-color", "#e5e7eb") border_style = self._styles.get("border-style", "solid") border_width = self._styles.get("border-width", "1px") margin = self._styles.get("margin", "0 16px") height = self._styles.get("height", "auto") align_self = self._styles.get("align-self", "stretch") style = ( f"border-left: {border_width} {border_style} {border_color}; " f"margin: {margin}; height: {height}; align-self: {align_self};" ) return f'<div style="{style}"></div>' def __html__(self) -> str: """Jinja2 auto-escaping protocol.""" return self.render() # ========================================================================= # Orientation Methods # =========================================================================
[docs] def vertical(self) -> "HTMLDivider": """Make the divider vertical (for use in flex rows). Returns: Self for method chaining. """ self._is_vertical = True self._notify() return self
[docs] def horizontal(self) -> "HTMLDivider": """Make the divider horizontal (default). Returns: Self for method chaining. """ self._is_vertical = False self._notify() return self
# ========================================================================= # Style Methods # =========================================================================
[docs] def style(self, value: DividerStyle | str) -> "HTMLDivider": """Set the line style. Args: value: DividerStyle enum or CSS border-style string. Returns: Self for method chaining. """ if isinstance(value, DividerStyle): self._styles["border-style"] = value.to_css() else: self._styles["border-style"] = value self._notify() return self
[docs] def solid(self) -> "HTMLDivider": """Set solid line style. Returns: Self for method chaining. """ self._styles["border-style"] = DividerStyle.SOLID.to_css() self._notify() return self
[docs] def dashed(self) -> "HTMLDivider": """Set dashed line style. Returns: Self for method chaining. """ self._styles["border-style"] = DividerStyle.DASHED.to_css() self._notify() return self
[docs] def dotted(self) -> "HTMLDivider": """Set dotted line style. Returns: Self for method chaining. """ self._styles["border-style"] = DividerStyle.DOTTED.to_css() self._notify() return self
# ========================================================================= # Color and Size Methods # =========================================================================
[docs] def color(self, value: Color | str) -> "HTMLDivider": """Set the divider color. Args: value: Color enum or CSS color string. Returns: Self for method chaining. """ self._styles["border-color"] = _to_css(value) self._notify() return self
[docs] def thickness(self, size: Size | str | int) -> "HTMLDivider": """Set the divider thickness. Args: size: Thickness (Size, CSS string, or int pixels). Returns: Self for method chaining. """ if isinstance(size, int): size = Size.px(size) self._styles["border-width"] = _to_css(size) self._notify() return self
[docs] def margin(self, size: Size | str) -> "HTMLDivider": """Set the margin around the divider. Args: size: Margin size. Returns: Self for method chaining. """ self._styles["margin"] = _to_css(size) self._notify() return self
# ========================================================================= # Label Methods # =========================================================================
[docs] def set_label(self, text: str | None) -> "HTMLDivider": """Set or remove the divider label. Args: text: Label text, or None to remove. Returns: Self for method chaining. """ self._label = text self._notify() return self
# ========================================================================= # Presets # =========================================================================
[docs] def subtle(self) -> "HTMLDivider": """Apply subtle divider styling (lighter color). Returns: Self for method chaining. """ self._styles["border-color"] = "#f3f4f6" self._notify() return self
[docs] def bold(self) -> "HTMLDivider": """Apply bold divider styling (thicker, darker). Returns: Self for method chaining. """ self._styles["border-color"] = "#374151" self._styles["border-width"] = "2px" self._notify() return self
# ========================================================================= # HTMLObject required methods # =========================================================================
[docs] def styled(self, **styles: str | CSSValue) -> "HTMLDivider": """Apply additional inline styles. Args: **styles: CSS property-value pairs. Returns: Self for method chaining. """ for key, value in styles.items(): css_key = key.replace("_", "-") self._styles[css_key] = _to_css(value) self._notify() return self
[docs] def add_class(self, *class_names: str) -> "HTMLDivider": """Add CSS classes. Args: *class_names: CSS class names to add. Returns: Self for method chaining. """ for name in class_names: if name not in self._css_classes: self._css_classes.append(name) self._notify() return self