Skip to content

xnano.components.table

xnano.components.table

xnano.components.table


Render mappings, dataclasses, or objects as a sortable data table.

Classes:

  • Column

    Describe one table column.

  • Table

    Declarative data table.

Attributes:

ColumnsArg module-attribute

ColumnsArg: TypeAlias = (
    "dict[str, Column | str | Callable[[Any], Any]] | list[str] | None"
)

Optional column overrides for the data-driven Table path.

SortDirection module-attribute

SortDirection: TypeAlias = Literal[
    "ascending", "descending"
]

Sort order applied to a derived row index without mutating data.

Column dataclass

Column(
    header: str | None = None,
    accessor: Callable[[Any], Any] | None = None,
    format: FormatResolver = None,
    foreground: ColorResolver = None,
    background: ColorResolver = None,
    horizontal_align: "Alignment | None" = None,
    width: int | float | None = None,
)

Bases: ComponentDescriptor

Describe one table column.

Attributes:

  • header (str | None) –

    Header displayed for the column.

  • accessor (Callable[[Any], Any] | None) –

    Row attribute, mapping key, or value callback.

  • format (FormatResolver) –

    Optional format string or value callback.

  • foreground (ColorResolver) –

    Cell foreground color.

  • background (ColorResolver) –

    Cell background color.

  • horizontal_align ('Alignment | None') –

    Cell alignment.

  • width (int | float | None) –

    Fixed or proportional column width.

Methods:

name class-attribute instance-attribute

name: str = dataclasses.field(default='', init=False)

Attribute name assigned by the component class.

header class-attribute instance-attribute

header: str | None = None

Displayed column header.

accessor class-attribute instance-attribute

accessor: Callable[[Any], Any] | None = None

Custom row value accessor.

format class-attribute instance-attribute

format: FormatResolver = None

Value formatter.

foreground class-attribute instance-attribute

foreground: ColorResolver = None

Foreground color or resolver.

background class-attribute instance-attribute

background: ColorResolver = None

Background color or resolver.

horizontal_align class-attribute instance-attribute

horizontal_align: 'Alignment | None' = None

Cell text alignment.

width class-attribute instance-attribute

width: int | float | None = None

Fixed width or fractional width.

resolve_header

resolve_header() -> str

Return the displayed header.

Source code in xnano/components/schema.py
def resolve_header(self) -> str:
    """Return the displayed header."""
    return self.header or self.name.replace("_", " ").title()

resolve_value

resolve_value(row: Any) -> Any

Read this column's value from a row.

Source code in xnano/components/schema.py
def resolve_value(self, row: Any) -> Any:
    """Read this column's value from a row."""
    if self.accessor is not None:
        return self.accessor(row)
    if isinstance(row, dict):
        return row.get(self.name)
    return getattr(row, self.name, None)

resolve_text

resolve_text(value: Any) -> str

Format a value for display.

Source code in xnano/components/schema.py
def resolve_text(self, value: Any) -> str:
    """Format a value for display."""
    if value is None:
        return ""
    if self.format is None:
        return str(value)
    if isinstance(self.format, str):
        return self.format.format(value)
    return self.format(value)

resolve_color

resolve_color(value: Any) -> Any

Resolve the foreground color for a value.

Source code in xnano/components/schema.py
def resolve_color(self, value: Any) -> Any:
    """Resolve the foreground color for a value."""
    resolver = self.foreground
    return resolver(value) if callable(resolver) else resolver

resolve_background

resolve_background(value: Any) -> Any

Resolve the background color for a value.

Source code in xnano/components/schema.py
def resolve_background(self, value: Any) -> Any:
    """Resolve the background color for a value."""
    return (
        self.background(value)
        if callable(self.background)
        else self.background
    )

Table dataclass

Table(
    data: list[Any] = list(),
    columns: ColumnsArg = None,
    selected: int | None = None,
    show_header: bool = True,
    column_spacing: int = 1,
    highlight_color: "ColorLike | None" = None,
    highlight_background: "ColorLike | None" = None,
    highlight_symbol: str | None = None,
    focusable: bool = False,
    passthrough: Sequence[str] = (),
    sort: str | None = None,
    sort_direction: SortDirection = "ascending",
    *,
    visible: bool = True,
    z: int = 0,
    fit_content: bool = True
)

Bases: Component

Declarative data table.

Feed it a list of rows — dicts, dataclasses, or arbitrary objects — and the columns are derived for you. Selection is a single attribute. For full control, subclass and declare Column descriptors.

Example

Table(data=({"name": "Ada", "role": "Engineer"},))

Attributes:

Methods:

  • move

    Move the selection by delta rows in display order.

  • handle_keyboard

    Navigate selection when focusable is enabled.

  • compose

    Compose TableGrid content with a native TableNode paint fallback.

  • component_post_init

    Initialize subclass state after dataclass fields are assigned.

  • get_frame

    Optional frame/panel chrome around composed content.

  • get_size

    Return the preferred cell size of this component.

  • before_render

    Called before rendering; returns the effective render area.

  • after_render

    Called after rendering for optional post-paint work.

  • compose_extra_small

    Compose content when the viewport is extra small (< 40 cols).

  • compose_small

    Compose content when the viewport is small (40–79 cols).

  • compose_medium

    Compose content when the viewport is medium (80–119 cols).

  • compose_large

    Compose content when the viewport is large (120–159 cols).

  • compose_extra_large

    Compose content when the viewport is extra large (>= 160 cols).

  • handle_paste

    Optional paste handler while focused.

data class-attribute instance-attribute

data: list[Any] = dataclasses.field(default_factory=list)

The rows — dicts, dataclasses, or objects with attributes.

columns class-attribute instance-attribute

columns: ColumnsArg = None

Optional column overrides for the data-driven path.

selected class-attribute instance-attribute

selected: int | None = None

Highlighted row index in display order.

show_header class-attribute instance-attribute

show_header: bool = True

Whether to render the derived header row.

column_spacing class-attribute instance-attribute

column_spacing: int = 1

Space between columns in terminal columns.

highlight_color class-attribute instance-attribute

highlight_color: 'ColorLike | None' = None

Selection foreground color.

highlight_background class-attribute instance-attribute

highlight_background: 'ColorLike | None' = None

Selection background color.

highlight_symbol class-attribute instance-attribute

highlight_symbol: str | None = None

Glyph prepended to the selected row.

focusable class-attribute instance-attribute

focusable: bool = False

Whether keyboard navigation is enabled.

passthrough class-attribute instance-attribute

passthrough: Sequence[str] = ()

Key bindings that bubble without being consumed.

sort class-attribute instance-attribute

sort: str | None = None

Optional column name used for a derived sort index.

sort_direction class-attribute instance-attribute

sort_direction: SortDirection = 'ascending'

Ascending or descending sort order.

selected_row property

selected_row: Any | None

Return the source row currently selected, if any.

value property

value: Any | None

Alias for selected_row.

visible class-attribute instance-attribute

visible: bool = dataclasses.field(
    default=True, kw_only=True
)

Whether this component paints at all.

z class-attribute instance-attribute

z: int = dataclasses.field(default=0, kw_only=True)

Stacking order among sibling content.

fit_content class-attribute instance-attribute

fit_content: bool = dataclasses.field(
    default=True, kw_only=True
)

When True, paint at natural size inside a larger slot.

focused property

focused: bool

Whether this component currently holds field focus.

move

move(delta: int) -> int | None

Move the selection by delta rows in display order.

Parameters:

  • delta (int) –

    Positive moves down; negative moves up.

Returns:

  • int | None

    The new selected index, or None when there is no data.

Source code in xnano/components/table.py
def move(self, delta: int) -> int | None:
    """Move the selection by ``delta`` rows in display order.

    Args:
        delta: Positive moves down; negative moves up.

    Returns:
        The new selected index, or ``None`` when there is no data.
    """
    count = len(self.data)
    if count == 0:
        self.selected = None
        return None
    current = 0 if self.selected is None else self.selected
    self.selected = max(0, min(count - 1, current + delta))
    return self.selected

handle_keyboard

handle_keyboard(keyboard: 'KeyboardEventData') -> bool

Navigate selection when focusable is enabled.

Returns:

  • bool

    True when the event was consumed.

Source code in xnano/components/table.py
def handle_keyboard(self, keyboard: "KeyboardEventData") -> bool:
    """Navigate selection when ``focusable`` is enabled.

    Returns:
        ``True`` when the event was consumed.
    """
    if not self.focusable:
        return False
    for binding in self.passthrough:
        if keyboard.matches(binding):
            return False
    if keyboard.matches("up", "k"):
        self.move(-1)
        return True
    if keyboard.matches("down", "j"):
        self.move(1)
        return True
    if keyboard.matches("home"):
        if self.data:
            self.selected = 0
        return True
    if keyboard.matches("end"):
        if self.data:
            self.selected = len(self.data) - 1
        return True
    if keyboard.matches("pageup"):
        self.move(-10)
        return True
    if keyboard.matches("pagedown"):
        self.move(10)
        return True
    return False

compose

compose(ctx: 'ComponentRenderContext')

Compose TableGrid content with a native TableNode paint fallback.

Returns:

  • Interface-neutral content for this table.

Source code in xnano/components/table.py
def compose(self, ctx: "ComponentRenderContext"):
    """Compose TableGrid content with a native TableNode paint fallback.

    Returns:
        Interface-neutral content for this table.
    """
    return self._compose_table_grid()

component_post_init

component_post_init() -> None

Initialize subclass state after dataclass fields are assigned.

Override this method instead of __post_init__.

Source code in xnano/components/component.py
def component_post_init(self) -> None:
    """Initialize subclass state after dataclass fields are assigned.

    Override this method instead of ``__post_init__``.
    """
    return None

get_frame

get_frame() -> Any | None

Optional frame/panel chrome around composed content.

Source code in xnano/components/component.py
def get_frame(self) -> Any | None:
    """Optional frame/panel chrome around composed content."""
    return None

get_size

get_size(ctx: ComponentRenderContext[StateT]) -> Size

Return the preferred cell size of this component.

Source code in xnano/components/component.py
def get_size(self, ctx: ComponentRenderContext[StateT]) -> Size:
    """Return the preferred cell size of this component."""
    return Size(width=0, height=0)

before_render

before_render(
    ctx: ComponentRenderContext[StateT], area: "Area"
) -> "Area"

Called before rendering; returns the effective render area.

Source code in xnano/components/component.py
def before_render(
    self,
    ctx: ComponentRenderContext[StateT],
    area: "Area",
) -> "Area":
    """Called before rendering; returns the effective render area."""
    return area

after_render

after_render(
    ctx: ComponentRenderContext[StateT], area: "Area"
) -> None

Called after rendering for optional post-paint work.

Source code in xnano/components/component.py
def after_render(
    self,
    ctx: ComponentRenderContext[StateT],
    area: "Area",
) -> None:
    """Called after rendering for optional post-paint work."""
    return None

compose_extra_small

compose_extra_small(
    ctx: ComponentRenderContext[StateT],
) -> Content | None

Compose content when the viewport is extra small (< 40 cols).

Optional responsive counterpart to :meth:compose. When overridden, it is used instead of compose while the window is in this size tier. Overriding any compose_* variant opts the component into breakpoint dispatch; a component that overrides none pays no per-frame cost.

Source code in xnano/components/component.py
@responsive_noop
def compose_extra_small(
    self, ctx: ComponentRenderContext[StateT]
) -> Content | None:
    """Compose content when the viewport is extra small (< 40 cols).

    Optional responsive counterpart to :meth:`compose`. When
    overridden, it is used *instead of* ``compose`` while the window
    is in this size tier. Overriding any ``compose_*`` variant opts the
    component into breakpoint dispatch; a component that overrides none
    pays no per-frame cost.
    """
    return None

compose_small

compose_small(
    ctx: ComponentRenderContext[StateT],
) -> Content | None

Compose content when the viewport is small (40–79 cols).

See :meth:compose_extra_small.

Source code in xnano/components/component.py
@responsive_noop
def compose_small(
    self, ctx: ComponentRenderContext[StateT]
) -> Content | None:
    """Compose content when the viewport is small (40–79 cols).

    See :meth:`compose_extra_small`.
    """
    return None

compose_medium

compose_medium(
    ctx: ComponentRenderContext[StateT],
) -> Content | None

Compose content when the viewport is medium (80–119 cols).

See :meth:compose_extra_small.

Source code in xnano/components/component.py
@responsive_noop
def compose_medium(
    self, ctx: ComponentRenderContext[StateT]
) -> Content | None:
    """Compose content when the viewport is medium (80–119 cols).

    See :meth:`compose_extra_small`.
    """
    return None

compose_large

compose_large(
    ctx: ComponentRenderContext[StateT],
) -> Content | None

Compose content when the viewport is large (120–159 cols).

See :meth:compose_extra_small.

Source code in xnano/components/component.py
@responsive_noop
def compose_large(
    self, ctx: ComponentRenderContext[StateT]
) -> Content | None:
    """Compose content when the viewport is large (120–159 cols).

    See :meth:`compose_extra_small`.
    """
    return None

compose_extra_large

compose_extra_large(
    ctx: ComponentRenderContext[StateT],
) -> Content | None

Compose content when the viewport is extra large (>= 160 cols).

See :meth:compose_extra_small.

Source code in xnano/components/component.py
@responsive_noop
def compose_extra_large(
    self, ctx: ComponentRenderContext[StateT]
) -> Content | None:
    """Compose content when the viewport is extra large (>= 160 cols).

    See :meth:`compose_extra_small`.
    """
    return None

handle_paste

handle_paste(text: str) -> bool

Optional paste handler while focused.

Returns:

  • bool

    True when the paste was consumed.

Source code in xnano/components/component.py
def handle_paste(self, text: str) -> bool:
    """Optional paste handler while focused.

    Returns:
        ``True`` when the paste was consumed.
    """
    return False