Skip to content

xnano.types

xnano.types

xnano.types


Type aliases and values for layout, input, styling, charts, and components.

The geometry primitives (Area, Size, Padding, align_area, and the alignment aliases) live in xnano.area. They are re-exported here, deprecated, for the previous import path.

Classes:

  • Area

    Rectangular region of a cell grid.

  • Padding

    Padding around a rectangular area.

  • Size

    Resolved width and height in cells.

  • Sizing

    Single-axis layout size.

  • Frame

    Border, title, background, and padding around content.

  • FieldFocus

    Focused grid field.

  • ScrollHandle

    Mutable scroll state for a field.

Functions:

Attributes:

Alignment module-attribute

Alignment: TypeAlias = Literal['left', 'right', 'center']

Horizontal (x-axis) alignment of a grid field or area.

Values

"left": Aligned to the left. "right": Aligned to the right. "center": Centered.

Coordinate module-attribute

Coordinate: TypeAlias = tuple[int, int]

A single (x, y) cell coordinate within the terminal grid.

PaddingLike module-attribute

PaddingLike: TypeAlias = Union[
    int,
    tuple[int, int],
    tuple[int | None, int | None, int | None, int | None],
    "Padding",
]

Padding around a rectangular area, in any accepted input form:

  • A single integer, applied to all four sides.
  • A (vertical, horizontal) tuple of two integers.
  • A (top, right, bottom, left) tuple of four integers.
  • A Padding instance.

VerticalAlignment module-attribute

VerticalAlignment: TypeAlias = Literal[
    "top", "middle", "bottom"
]

Vertical (y-axis) alignment of a grid field or area.

Values

"top": Aligned to the top edge. "middle": Centered vertically. "bottom": Aligned to the bottom edge.

ScrollLike module-attribute

ScrollLike: TypeAlias = (
    "bool | Literal['vertical', 'horizontal', 'auto']"
)

Field(scroll=...) value. True scrolls along the field's direction; "vertical"/"horizontal" force an axis; "auto" scrolls only when content overflows the slot.

Axis module-attribute

Axis: TypeAlias = Literal['x', 'y']

The axis a grid field or area lays out along.

Values

"x": Horizontal layout. "y": Vertical layout.

Border module-attribute

Border: TypeAlias = Literal[
    "plain",
    "rounded",
    "double",
    "thick",
    "quadrant_inside",
    "quadrant_outside",
]

Border style drawn around a rectangular area's outer edges.

Values

"plain": A plain border. (---------) "rounded": Rounded corners. (╭───────╮) "double": Double lines. (╔═══════╗) "thick": Thick/dark lines. (┏━━━━━━━┓) "quadrant_inside": Quadrant-style inner division. (▛▀▀▀▀▀▜) "quadrant_outside": Quadrant-style outer corners. (▗▄▄▄▄▄▖)

Corner module-attribute

Corner: TypeAlias = Literal[
    "top-left", "top-right", "bottom-left", "bottom-right"
]

A single corner of a rectangular grid area.

Values

"top-left", "top-right", "bottom-left", "bottom-right".

Direction module-attribute

Direction: TypeAlias = Literal['horizontal', 'vertical']

The direction content within a grid field or area lays out along.

Values

"horizontal": Laid out horizontally. "vertical": Laid out vertically.

CharacterModifier module-attribute

CharacterModifier: TypeAlias = Literal[
    "bold",
    "dim",
    "italic",
    "underline",
    "slow_blink",
    "rapid_blink",
    "reversed",
]

A modifier applied to the content of a grid field or area.

Values

"bold": Bold text. "dim": Reduced intensity. "italic": Italic text. "underline": Underlined text. "slow_blink": Slow blink. "rapid_blink": Rapid blink. "reversed": Swapped foreground/background colors.

ScrollbarOrientationLike module-attribute

ScrollbarOrientationLike: TypeAlias = Literal[
    "vertical_right",
    "vertical_left",
    "horizontal_bottom",
    "horizontal_top",
]

Placement of a scrollbar widget.

Values

"vertical_right", "vertical_left": Vertical, right/left edge. "horizontal_bottom", "horizontal_top": Horizontal, bottom/top edge.

CanvasMarkerLike module-attribute

CanvasMarkerLike: TypeAlias = Literal[
    "dot", "block", "bar", "braille", "half_block"
]

Marker glyph set used when drawing on a Canvas widget.

Values

"dot": Single-pixel dots. "block": Full-block characters. "bar": Horizontal bar characters. "braille": Braille dot matrix (highest resolution). "half_block": Half-block characters.

GraphTypeLike module-attribute

GraphTypeLike: TypeAlias = Literal["line", "scatter", "bar"]

How a Chart dataset is plotted.

Values

"line": Connected line. "scatter": Unconnected points. "bar": Vertical bars.

LegendPositionLike module-attribute

LegendPositionLike: TypeAlias = Literal[
    "top",
    "top_right",
    "top_left",
    "left",
    "right",
    "bottom",
    "bottom_right",
    "bottom_left",
]

Placement of a Chart's legend within its area.

Side module-attribute

Side: TypeAlias = Literal['top', 'bottom', 'left', 'right']

A single side of a rectangular grid area.

Values

"top", "bottom", "left", "right".

SizePercentage module-attribute

SizePercentage: TypeAlias = tuple[float, float] | float

Percentage of the parent area's width/height a field should occupy — a (width, height) tuple, or one float applied to both axes.

Flex module-attribute

Flex: TypeAlias = (
    int
    | Literal[
        "flex-1",
        "flex-auto",
        "flex-initial",
        "flex-none",
        "grow",
        "grow-0",
        "shrink",
        "shrink-0",
    ]
)

Relative fill weight for proportional layout, or a Tailwind flex utility. Numeric values set the fill weight directly; Tailwind classes map to proportional grow weights — see resolve_flex_weight.

SizingKind module-attribute

SizingKind: TypeAlias = Literal[
    "cells", "percent", "ratio", "fraction", "fit"
]

The kind of sizing intent expressed by a Sizing.

Values

"cells": A fixed cell count. "percent": A percentage of the available axis length. "ratio": A numerator / denominator fraction of the axis length. "fraction": A relative fill weight across leftover space.

"fit": The measured intrinsic size of the content.

SizingKeyword module-attribute

SizingKeyword: TypeAlias = Literal[
    "fit",
    "auto",
    "content",
    "fill",
    "grow",
    "grow-0",
    "shrink",
    "shrink-0",
    "flex-1",
    "flex-auto",
    "flex-initial",
    "flex-none",
    "full",
]

Named sizing keywords accepted by Sizing.parse (plus the tailwind full rewrite). Exposed as a Literal so editors autocomplete the common string forms of width / height.

SizingPercentage module-attribute

SizingPercentage: TypeAlias = Literal[
    "0%",
    "1%",
    "2%",
    "3%",
    "4%",
    "5%",
    "6%",
    "7%",
    "8%",
    "9%",
    "10%",
    "11%",
    "12%",
    "13%",
    "14%",
    "15%",
    "16%",
    "17%",
    "18%",
    "19%",
    "20%",
    "21%",
    "22%",
    "23%",
    "24%",
    "25%",
    "26%",
    "27%",
    "28%",
    "29%",
    "30%",
    "31%",
    "32%",
    "33%",
    "34%",
    "35%",
    "36%",
    "37%",
    "38%",
    "39%",
    "40%",
    "41%",
    "42%",
    "43%",
    "44%",
    "45%",
    "46%",
    "47%",
    "48%",
    "49%",
    "50%",
    "51%",
    "52%",
    "53%",
    "54%",
    "55%",
    "56%",
    "57%",
    "58%",
    "59%",
    "60%",
    "61%",
    "62%",
    "63%",
    "64%",
    "65%",
    "66%",
    "67%",
    "68%",
    "69%",
    "70%",
    "71%",
    "72%",
    "73%",
    "74%",
    "75%",
    "76%",
    "77%",
    "78%",
    "79%",
    "80%",
    "81%",
    "82%",
    "83%",
    "84%",
    "85%",
    "86%",
    "87%",
    "88%",
    "89%",
    "90%",
    "91%",
    "92%",
    "93%",
    "94%",
    "95%",
    "96%",
    "97%",
    "98%",
    "99%",
    "100%",
]

Whole-number percentage sizing strings "0%""100%". Fractions and fr/ratio forms are deliberately left to the open str branch.

SizingLike module-attribute

Any value accepted where a Sizing is expected — see Sizing.parse for the full list of accepted forms.

SizingKeyword and SizingPercentage are folded in ahead of the bare str so editors surface the common values as completions; arbitrary strings ("1fr", "1/3", "37.5%") still typecheck via str.

FrameTitlePosition module-attribute

FrameTitlePosition: TypeAlias = Literal['top', 'bottom']

The side of a frame to display its title on.

Values

"top", "bottom".

KnownKeyboardBinding module-attribute

KnownKeyboardBinding: TypeAlias = Literal[
    "ctrl+c",
    "ctrl+d",
    "ctrl+z",
    "ctrl+x",
    "ctrl+v",
    "ctrl+a",
    "ctrl+s",
    "ctrl+w",
    "ctrl+r",
    "ctrl+f",
    "ctrl+up",
    "ctrl+down",
    "ctrl+left",
    "ctrl+right",
    "shift+tab",
    "shift+up",
    "shift+down",
    "shift+left",
    "shift+right",
    "alt+enter",
    "alt+backspace",
    "alt+up",
    "alt+down",
    "alt+left",
    "alt+right",
]

Commonly used keybindings accepted by @on_keyboard.

KeyboardModifier module-attribute

KeyboardModifier: TypeAlias = Literal[
    "ctrl", "shift", "alt"
]

A modifier key held alongside the primary action key.

KeyboardKey module-attribute

KeyboardKey: TypeAlias = Literal[
    "a",
    "b",
    "c",
    "d",
    "e",
    "f",
    "g",
    "h",
    "i",
    "j",
    "k",
    "l",
    "m",
    "n",
    "o",
    "p",
    "q",
    "r",
    "s",
    "t",
    "u",
    "v",
    "w",
    "x",
    "y",
    "z",
    "0",
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "enter",
    "esc",
    "backspace",
    "tab",
    "backtab",
    "up",
    "down",
    "left",
    "right",
    "home",
    "end",
    "pageup",
    "pagedown",
    "insert",
    "delete",
    "space",
    "null",
    "capslock",
    "scrolllock",
    "numlock",
    "printscreen",
    "pause",
    "menu",
    "keypadbegin",
    "media",
    "f1",
    "f2",
    "f3",
    "f4",
    "f5",
    "f6",
    "f7",
    "f8",
    "f9",
    "f10",
    "f11",
    "f12",
    "other",
]

Standard character/named keys accepted by @on_keyboard.

KeyboardBinding module-attribute

A keyboard binding: a primary key optionally preceded by +-joined modifiers ("ctrl+a", "shift+tab", "alt+enter", "ctrl+shift+z", ...).

MouseButton module-attribute

MouseButton: TypeAlias = Literal[
    "left", "right", "middle", "unknown"
]

The mouse button that triggered a mouse event.

Area dataclass

Area(*, x: int, y: int, width: int, height: int)

Rectangular region of a cell grid.

Attributes:

Methods:

  • contains

    Return whether coordinate lies inside this area.

  • fit_content

    Fit a measured size inside this area on both axes.

x instance-attribute

x: int

Left column.

y instance-attribute

y: int

Top row.

width instance-attribute

width: int

Width in cells.

height instance-attribute

height: int

Height in cells.

size property

size: Size

Width and height of this area.

contains

contains(coordinate: Coordinate) -> bool

Return whether coordinate lies inside this area.

Source code in xnano/area.py
def contains(self, coordinate: Coordinate) -> bool:
    """Return whether ``coordinate`` lies inside this area."""
    column, row = coordinate
    return (
        self.x <= column < self.x + self.width
        and self.y <= row < self.y + self.height
    )

fit_content

fit_content(
    content: Size,
    horizontal: "Alignment | None" = None,
    vertical: "VerticalAlignment | None" = None,
) -> "Area"

Fit a measured size inside this area on both axes.

Parameters:

  • content (Size) –

    Measured content size, clamped to this area.

  • horizontal ('Alignment | None', default: None ) –

    Horizontal placement (default "left").

  • vertical ('VerticalAlignment | None', default: None ) –

    Vertical placement (default "top").

Returns:

  • 'Area'

    The fitted, aligned area.

Source code in xnano/area.py
def fit_content(
    self,
    content: Size,
    horizontal: "Alignment | None" = None,
    vertical: "VerticalAlignment | None" = None,
) -> "Area":
    """Fit a measured size inside this area on both axes.

    Args:
        content: Measured content size, clamped to this area.
        horizontal: Horizontal placement (default ``"left"``).
        vertical: Vertical placement (default ``"top"``).

    Returns:
        The fitted, aligned area.
    """
    return align_area(
        self,
        min(self.width, max(content.width, 1)),
        min(self.height, max(content.height, 1)),
        horizontal=horizontal,
        vertical=vertical,
    )

Padding dataclass

Padding(
    *,
    top: int = 0,
    right: int = 0,
    bottom: int = 0,
    left: int = 0
)

Padding around a rectangular area.

Attributes:

  • top (int) –

    Cells above the content.

  • right (int) –

    Cells to the right of the content.

  • bottom (int) –

    Cells below the content.

  • left (int) –

    Cells to the left of the content.

Examples:

padding = Padding.parse((1, 2))

Methods:

  • parse

    Normalize a padding value.

top class-attribute instance-attribute

top: int = 0

Cells above the content.

right class-attribute instance-attribute

right: int = 0

Cells to the right of the content.

bottom class-attribute instance-attribute

bottom: int = 0

Cells below the content.

left class-attribute instance-attribute

left: int = 0

Cells to the left of the content.

horizontal property

horizontal: int

Total horizontal padding.

vertical property

vertical: int

Total vertical padding.

parse classmethod

parse(padding: PaddingLike | None) -> 'Padding'

Normalize a padding value.

Source code in xnano/area.py
@classmethod
def parse(cls, padding: PaddingLike | None) -> "Padding":
    """Normalize a padding value."""
    if padding is None:
        return cls()
    if isinstance(padding, cls):
        return padding
    if isinstance(padding, int):
        return cls(
            top=padding,
            right=padding,
            bottom=padding,
            left=padding,
        )
    values = cast(
        tuple[int, int]
        | tuple[int | None, int | None, int | None, int | None],
        padding,
    )
    if len(values) == 2:
        vertical, horizontal = values
        return cls(
            top=vertical or 0,
            right=horizontal or 0,
            bottom=vertical or 0,
            left=horizontal or 0,
        )
    top, right, bottom, left = values
    return cls(
        top=top or 0,
        right=right or 0,
        bottom=bottom or 0,
        left=left or 0,
    )

Size dataclass

Size(*, width: int, height: int)

Resolved width and height in cells.

Attributes:

Methods:

width instance-attribute

width: int

Width in cells.

height instance-attribute

height: int

Height in cells.

from_tuple classmethod

from_tuple(size: tuple[int, int]) -> 'Size'

Create a size from (width, height).

Source code in xnano/area.py
@classmethod
def from_tuple(cls, size: tuple[int, int]) -> "Size":
    """Create a size from ``(width, height)``."""
    return cls(width=size[0], height=size[1])

from_int classmethod

from_int(size: int) -> 'Size'

Create a square size.

Source code in xnano/area.py
@classmethod
def from_int(cls, size: int) -> "Size":
    """Create a square size."""
    return cls(width=size, height=size)

Sizing dataclass

Sizing(
    kind: SizingKind,
    value: int = 0,
    denominator: int = 1,
    minimum: int | None = None,
    maximum: int | None = None,
)

Single-axis layout size.

Attributes:

Examples:

sidebar = Sizing.parse("25%")
content = Sizing.parse("1fr")

Methods:

  • cells

    Create a fixed cell size.

  • percent

    Create a percentage of the available length.

  • ratio

    Create a ratio of the available length.

  • fraction

    Create a proportional fill size.

  • fit

    Create a content-measured size.

  • with_bounds

    Return this size with new cell bounds.

  • resolve

    Resolve this size to cells.

  • parse

    Normalize a supported sizing value.

kind instance-attribute

kind: SizingKind

Sizing strategy.

value class-attribute instance-attribute

value: int = 0

Cell count, percentage, numerator, or fill weight.

denominator class-attribute instance-attribute

denominator: int = 1

Denominator for ratio sizing.

minimum class-attribute instance-attribute

minimum: int | None = None

Optional minimum cell count.

maximum class-attribute instance-attribute

maximum: int | None = None

Optional maximum cell count.

is_fill property

is_fill: bool

Whether this size fills remaining space.

is_fit property

is_fit: bool

Whether this size follows measured content.

cells classmethod

cells(count: int) -> 'Sizing'

Create a fixed cell size.

Source code in xnano/types.py
@classmethod
def cells(cls, count: int) -> "Sizing":
    """Create a fixed cell size."""
    return cls(kind="cells", value=max(0, int(count)))

percent classmethod

percent(percentage: float) -> 'Sizing'

Create a percentage of the available length.

Source code in xnano/types.py
@classmethod
def percent(cls, percentage: float) -> "Sizing":
    """Create a percentage of the available length."""
    value = percentage * 100 if 0 <= percentage <= 1 else percentage
    return cls(kind="percent", value=max(0, min(100, round(value))))

ratio classmethod

ratio(numerator: int, denominator: int) -> 'Sizing'

Create a ratio of the available length.

Source code in xnano/types.py
@classmethod
def ratio(cls, numerator: int, denominator: int) -> "Sizing":
    """Create a ratio of the available length."""
    return cls(
        kind="ratio",
        value=max(0, int(numerator)),
        denominator=max(1, int(denominator)),
    )

fraction classmethod

fraction(weight: int = 1) -> 'Sizing'

Create a proportional fill size.

Source code in xnano/types.py
@classmethod
def fraction(cls, weight: int = 1) -> "Sizing":
    """Create a proportional fill size."""
    return cls(kind="fraction", value=max(0, int(weight)))

fit classmethod

fit(
    *,
    minimum: int | None = None,
    maximum: int | None = None
) -> "Sizing"

Create a content-measured size.

Source code in xnano/types.py
@classmethod
def fit(
    cls,
    *,
    minimum: int | None = None,
    maximum: int | None = None,
) -> "Sizing":
    """Create a content-measured size."""
    return cls(kind="fit", minimum=minimum, maximum=maximum)

with_bounds

with_bounds(
    *,
    minimum: int | None = None,
    maximum: int | None = None
) -> "Sizing"

Return this size with new cell bounds.

Source code in xnano/types.py
def with_bounds(
    self,
    *,
    minimum: int | None = None,
    maximum: int | None = None,
) -> "Sizing":
    """Return this size with new cell bounds."""
    return dataclasses.replace(self, minimum=minimum, maximum=maximum)

resolve

resolve(available: int, content: int | None = None) -> int

Resolve this size to cells.

Source code in xnano/types.py
def resolve(self, available: int, content: int | None = None) -> int:
    """Resolve this size to cells."""
    if self.kind == "cells":
        length = self.value
    elif self.kind == "percent":
        length = available * self.value // 100
    elif self.kind == "ratio":
        length = available * self.value // self.denominator
    elif self.kind == "fit":
        length = content or 0
    else:
        length = available
    if self.minimum is not None:
        length = max(length, self.minimum)
    if self.maximum is not None:
        length = min(length, self.maximum)
    return max(0, length)

parse classmethod

parse(value: 'SizingLike | None') -> 'Sizing | None'

Normalize a supported sizing value.

Source code in xnano/types.py
@classmethod
def parse(cls, value: "SizingLike | None") -> "Sizing | None":
    """Normalize a supported sizing value."""
    if value is None:
        return None
    if isinstance(value, cls):
        return value
    if isinstance(value, bool):
        raise TypeError("bool is not a valid sizing value")
    if isinstance(value, int):
        return cls.cells(value)
    if isinstance(value, float):
        return (
            cls.percent(value)
            if 0 <= value <= 1
            else cls.cells(round(value))
        )
    if not isinstance(value, str):
        raise TypeError(
            "sizing must be an int, float, str, or Sizing, "
            f"got {type(value).__name__}"
        )
    token = value.strip().lower()
    if token in ("fit", "auto", "content"):
        return cls.fit()
    if token == "full":
        # Matches the tailwind ``w-full`` / ``h-full`` rewrite: 100% of
        # the available axis length.
        return cls.percent(100)
    if token in ("fill", "grow"):
        return cls.fraction()
    if token in _FLEX_CLASS_WEIGHTS:
        return cls.fraction(_FLEX_CLASS_WEIGHTS[token])
    if token.endswith("%"):
        percentage = float(token[:-1])
        return cls(
            kind="percent",
            value=max(0, min(100, round(percentage))),
        )
    if token.endswith("fr"):
        return cls.fraction(int(token[:-2].strip() or "1"))
    if "/" in token:
        numerator, denominator = token.split("/", 1)
        return cls.ratio(int(numerator), int(denominator))
    try:
        return cls.cells(int(token))
    except ValueError as error:
        raise ValueError(f"invalid sizing string: {value!r}") from error

Frame dataclass

Frame(
    *,
    background: "ColorLike | None" = None,
    border: Border | None = None,
    border_color: "ColorLike | None" = None,
    border_sides: list[Side] | None = None,
    title: str | None = None,
    title_position: FrameTitlePosition | None = None,
    padding: PaddingLike | None = None
)

Border, title, background, and padding around content.

Attributes:

Methods:

  • is_empty

    Return whether this frame has no visible attributes.

background class-attribute instance-attribute

background: 'ColorLike | None' = None

Fill color.

border class-attribute instance-attribute

border: Border | None = None

Border style.

border_color class-attribute instance-attribute

border_color: 'ColorLike | None' = None

Border color.

border_sides class-attribute instance-attribute

border_sides: list[Side] | None = None

Sides to draw.

title class-attribute instance-attribute

title: str | None = None

Border title.

title_position class-attribute instance-attribute

title_position: FrameTitlePosition | None = None

Title edge.

padding class-attribute instance-attribute

padding: PaddingLike | None = None

Inner padding.

is_empty

is_empty() -> bool

Return whether this frame has no visible attributes.

Source code in xnano/types.py
def is_empty(self) -> bool:
    """Return whether this frame has no visible attributes."""
    return not any(
        (
            self.background,
            self.border,
            self.border_color,
            self.border_sides,
            self.title,
            self.title_position,
            self.padding,
        )
    )

FieldFocus dataclass

FieldFocus(
    grid: Any, field_name: str, group: str | None = None
)

Focused grid field.

Attributes:

  • grid (Any) –

    Grid containing the field.

  • field_name (str) –

    Field attribute name.

  • group (str | None) –

    Optional cross-grid focus group.

grid instance-attribute

grid: Any

Grid containing the field.

field_name instance-attribute

field_name: str

Field attribute name.

group class-attribute instance-attribute

group: str | None = None

Optional cross-grid focus group.

ScrollHandle dataclass

ScrollHandle(
    group: str,
    axis: Axis,
    offset: int = 0,
    follow: bool = False,
)

Mutable scroll state for a field.

Attributes:

  • group (str) –

    Field group controlling this scroll region.

  • axis (Axis) –

    Scroll axis.

  • offset (int) –

    Current cell offset.

  • follow (bool) –

    Whether new content keeps the viewport at the end.

Methods:

group instance-attribute

group: str

Field group controlling this scroll region.

axis instance-attribute

axis: Axis

Scroll axis.

offset class-attribute instance-attribute

offset: int = 0

Current cell offset.

follow class-attribute instance-attribute

follow: bool = False

Whether new content keeps the viewport at the end.

scroll

scroll(delta: int) -> int

Move the offset by delta cells.

Source code in xnano/types.py
def scroll(self, delta: int) -> int:
    """Move the offset by ``delta`` cells."""
    self.offset = max(0, self.offset + delta)
    if delta:
        self.follow = False
    return self.offset

scroll_to

scroll_to(offset: int) -> int

Set the offset in cells.

Source code in xnano/types.py
def scroll_to(self, offset: int) -> int:
    """Set the offset in cells."""
    self.offset = max(0, offset)
    self.follow = False
    return self.offset

scroll_to_end

scroll_to_end() -> None

Follow the end of the content.

Source code in xnano/types.py
def scroll_to_end(self) -> None:
    """Follow the end of the content."""
    self.follow = True

align_area

align_area(
    outer: Area,
    width: int,
    height: int,
    *,
    horizontal: "Alignment | None" = None,
    vertical: "VerticalAlignment | None" = None
) -> Area

Place a width x height box inside outer on both axes.

None on an axis anchors to its leading edge.

Parameters:

  • outer (Area) –

    The area to place the box within.

  • width (int) –

    Box width, clamped to outer.

  • height (int) –

    Box height, clamped to outer.

  • horizontal ('Alignment | None', default: None ) –

    Horizontal placement (default "left").

  • vertical ('VerticalAlignment | None', default: None ) –

    Vertical placement (default "top").

Returns:

  • Area

    The placed area, always inside outer.

Source code in xnano/area.py
def align_area(
    outer: Area,
    width: int,
    height: int,
    *,
    horizontal: "Alignment | None" = None,
    vertical: "VerticalAlignment | None" = None,
) -> Area:
    """Place a ``width`` x ``height`` box inside ``outer`` on both axes.

    ``None`` on an axis anchors to its leading edge.

    Args:
        outer: The area to place the box within.
        width: Box width, clamped to ``outer``.
        height: Box height, clamped to ``outer``.
        horizontal: Horizontal placement (default ``"left"``).
        vertical: Vertical placement (default ``"top"``).

    Returns:
        The placed area, always inside ``outer``.
    """
    width = max(0, min(width, outer.width))
    height = max(0, min(height, outer.height))
    if horizontal == "right":
        x = outer.x + outer.width - width
    elif horizontal == "center":
        x = outer.x + (outer.width - width) // 2
    else:
        x = outer.x
    if vertical == "bottom":
        y = outer.y + outer.height - height
    elif vertical == "middle":
        y = outer.y + (outer.height - height) // 2
    else:
        y = outer.y
    return Area(x=x, y=y, width=width, height=height)

resolve_flex_weight

resolve_flex_weight(flex: Flex | None) -> int | None

Return the numeric layout weight represented by flex.

Source code in xnano/types.py
def resolve_flex_weight(flex: Flex | None) -> int | None:
    """Return the numeric layout weight represented by ``flex``."""
    if flex is None:
        return None
    if isinstance(flex, int):
        return max(0, flex)
    return _FLEX_CLASS_WEIGHTS.get(flex)

field_has_frame_chrome

field_has_frame_chrome(field: object) -> bool

Return whether a field defines structural frame styling.

Source code in xnano/types.py
def field_has_frame_chrome(field: object) -> bool:
    """Return whether a field defines structural frame styling."""
    return any(
        getattr(field, name, None) is not None
        for name in ("border", "title", "padding")
    )

field_fills_background

field_fills_background(field: object) -> bool

Return whether a field paints its background across the whole slot.

A fill value takes precedence when set; otherwise a field with a background fills its slot by default (fill=False opts out and reverts to the accent-behind-glyphs behavior).

Source code in xnano/types.py
def field_fills_background(field: object) -> bool:
    """Return whether a field paints its background across the whole slot.

    A ``fill`` value takes precedence when set; otherwise a field with a
    ``background`` fills its slot by default (``fill=False`` opts out and
    reverts to the accent-behind-glyphs behavior).
    """
    fill = getattr(field, "fill", None)
    if fill is not None:
        return bool(fill)
    return getattr(field, "background", None) is not None

frame_from_field

frame_from_field(field: object | None) -> Frame | None

Build frame styling from a field definition.

Source code in xnano/types.py
def frame_from_field(field: object | None) -> Frame | None:
    """Build frame styling from a field definition."""
    if field is None:
        return None
    has_chrome = field_has_frame_chrome(field)
    include_background = getattr(field, "background", None) is not None and (
        has_chrome or field_fills_background(field)
    )
    sides = getattr(field, "border_sides", None)
    frame = Frame(
        background=(
            getattr(field, "background", None) if include_background else None
        ),
        border=getattr(field, "border", None),
        border_color=getattr(field, "border_color", None),
        border_sides=list(sides) if sides is not None else None,
        title=getattr(field, "title", None),
        title_position=getattr(field, "title_position", None),
        padding=getattr(field, "padding", None),
    )
    return None if frame.is_empty() else frame

is_grid

is_grid(value: Any) -> bool

Return whether a value is a grid instance.

Reads the __xnano_grid__ marker rather than importing BaseGrid, so layers below the public DSL can ask this without a circular import.

Source code in xnano/types.py
def is_grid(value: Any) -> bool:
    """Return whether a value is a grid instance.

    Reads the ``__xnano_grid__`` marker rather than importing
    ``BaseGrid``, so layers below the public DSL can ask this without a
    circular import.
    """
    return bool(getattr(type(value), "__xnano_grid__", False))

is_component

is_component(value: Any) -> bool

Return whether a value follows the component contract.

Source code in xnano/types.py
def is_component(value: Any) -> bool:
    """Return whether a value follows the component contract."""
    return bool(getattr(type(value), "_xnano_component_base", False))

uses_default_component_size

uses_default_component_size(value: Any) -> bool

Return whether a component uses the default layout size.

Source code in xnano/types.py
def uses_default_component_size(value: Any) -> bool:
    """Return whether a component uses the default layout size."""
    return is_component(value) and not bool(
        getattr(value, "fit_content", False)
    )

is_focusable_component

is_focusable_component(value: Any) -> bool

Return whether a component accepts field focus.

Source code in xnano/types.py
def is_focusable_component(value: Any) -> bool:
    """Return whether a component accepts field focus."""
    return is_component(value) and bool(getattr(value, "focusable", False))