"""HTMLRow - Horizontal flex container."""
from __future__ import annotations
from typing import Any
from animaid.containers.base import HTMLContainer, _to_css
from animaid.css_types import (
AlignItems,
CSSValue,
FlexWrap,
JustifyContent,
Size,
Spacing,
)
[docs]
class HTMLRow(HTMLContainer):
"""A horizontal flex container for arranging items in a row.
HTMLRow uses CSS flexbox with `flex-direction: row` to arrange
children horizontally. It provides methods for controlling
alignment, justification, wrapping, and spacing.
Examples:
>>> from animaid import HTMLRow, HTMLButton
>>> row = HTMLRow([
... HTMLButton("Save").primary(),
... HTMLButton("Cancel"),
... ])
>>> # With alignment and gap
>>> row = HTMLRow([item1, item2, item3]).gap(10).align(AlignItems.CENTER)
>>> # Button row preset
>>> row = HTMLRow(buttons).buttons()
"""
def __init__(
self,
children: list[Any] | None = None,
**styles: str | CSSValue,
) -> None:
"""Create a new horizontal row container.
Args:
children: List of child elements.
**styles: Initial CSS styles.
"""
super().__init__(children, **styles)
# Set default flex styles
self._styles["display"] = "flex"
self._styles["flex-direction"] = "row"
# =========================================================================
# Alignment Methods
# =========================================================================
[docs]
def align(self, value: AlignItems | str) -> "HTMLRow":
"""Set vertical alignment of items within the row.
Args:
value: AlignItems enum or CSS string (start, center, end, stretch, baseline).
Returns:
Self for method chaining.
Example:
>>> row.align(AlignItems.CENTER)
>>> row.align("center") # Also works
"""
if isinstance(value, str):
value = AlignItems(value)
self._styles["align-items"] = value.to_css()
self._notify()
return self
[docs]
def justify(self, value: JustifyContent | str) -> "HTMLRow":
"""Set horizontal distribution of items within the row.
Args:
value: JustifyContent enum or CSS string
(start, center, end, space-between, space-around, space-evenly).
Returns:
Self for method chaining.
Example:
>>> row.justify(JustifyContent.SPACE_BETWEEN)
>>> row.justify("space-between") # Also works
"""
if isinstance(value, str):
value = JustifyContent(value)
self._styles["justify-content"] = value.to_css()
self._notify()
return self
# =========================================================================
# Wrapping Methods
# =========================================================================
[docs]
def wrap(self, value: FlexWrap | str = FlexWrap.WRAP) -> "HTMLRow":
"""Allow items to wrap to the next line.
Args:
value: FlexWrap enum or CSS string (wrap, nowrap, wrap-reverse).
Default is WRAP.
Returns:
Self for method chaining.
Example:
>>> row.wrap() # Enable wrapping
>>> row.wrap(FlexWrap.WRAP_REVERSE) # Wrap in reverse order
"""
if isinstance(value, str):
value = FlexWrap(value)
self._styles["flex-wrap"] = value.to_css()
self._notify()
return self
[docs]
def nowrap(self) -> "HTMLRow":
"""Prevent items from wrapping (default behavior).
Returns:
Self for method chaining.
"""
self._styles["flex-wrap"] = FlexWrap.NOWRAP.to_css()
self._notify()
return self
# =========================================================================
# Direction Methods
# =========================================================================
[docs]
def reverse(self) -> "HTMLRow":
"""Reverse the order of items.
Returns:
Self for method chaining.
"""
self._styles["flex-direction"] = "row-reverse"
self._notify()
return self
# =========================================================================
# Item Sizing
# =========================================================================
[docs]
def min_item_width(self, size: Size | str | int) -> "HTMLRow":
"""Set minimum width for child items (via CSS custom property).
This works best with `.wrap()` to prevent items from becoming
too small before wrapping.
Args:
size: Minimum item width.
Returns:
Self for method chaining.
"""
if isinstance(size, int):
size = Size.px(size)
# Use a CSS custom property that children can reference
self._styles["--min-item-width"] = _to_css(size)
self._notify()
return self
# =========================================================================
# Presets
# =========================================================================
[docs]
def centered(self) -> "HTMLRow":
"""Center all items both horizontally and vertically.
Returns:
Self for method chaining.
"""
self._styles["justify-content"] = "center"
self._styles["align-items"] = "center"
self._notify()
return self
[docs]
def spaced(self) -> "HTMLRow":
"""Distribute items with space between them.
Returns:
Self for method chaining.
"""
self._styles["justify-content"] = "space-between"
self._styles["align-items"] = "center"
self._notify()
return self
[docs]
def start(self) -> "HTMLRow":
"""Align items to the start (left).
Returns:
Self for method chaining.
"""
self._styles["justify-content"] = "flex-start"
self._notify()
return self
[docs]
def end(self) -> "HTMLRow":
"""Align items to the end (right).
Returns:
Self for method chaining.
"""
self._styles["justify-content"] = "flex-end"
self._notify()
return self
# =========================================================================
# Override styled and add_class for correct return type
# =========================================================================
[docs]
def styled(self, **styles: str | CSSValue) -> "HTMLRow":
"""Apply additional inline styles.
Args:
**styles: CSS property-value pairs.
Returns:
Self for method chaining.
"""
super().styled(**styles)
return self
[docs]
def add_class(self, *class_names: str) -> "HTMLRow":
"""Add CSS classes.
Args:
*class_names: CSS class names to add.
Returns:
Self for method chaining.
"""
super().add_class(*class_names)
return self
[docs]
def gap(self, size: Size | str | int) -> "HTMLRow":
"""Set the gap between child elements.
Args:
size: Gap size.
Returns:
Self for method chaining.
"""
super().gap(size)
return self
[docs]
def padding(self, size: "Spacing | Size | str | int") -> "HTMLRow":
"""Set internal padding.
Args:
size: Padding size.
Returns:
Self for method chaining.
"""
super().padding(size)
return self
[docs]
def margin(self, size: "Spacing | Size | str | int") -> "HTMLRow":
"""Set external margin.
Args:
size: Margin size.
Returns:
Self for method chaining.
"""
super().margin(size)
return self
[docs]
def width(self, size: Size | str | int) -> "HTMLRow":
"""Set container width.
Args:
size: Width.
Returns:
Self for method chaining.
"""
super().width(size)
return self
[docs]
def height(self, size: Size | str | int) -> "HTMLRow":
"""Set container height.
Args:
size: Height.
Returns:
Self for method chaining.
"""
super().height(size)
return self