Skip to content

xnano.tailwind

xnano.tailwind

xnano.tailwind


Resolve Tailwind-style utility classes into xnano layout and text styles.

Classes:

  • Style

    Style derived from Tailwind utility classes.

Functions:

Attributes:

TailwindClass module-attribute

TailwindClass: TypeAlias = str

A Tailwind utility class understood by xnano or passed through to web.

TailwindColorClass module-attribute

TailwindColorClass: TypeAlias = str

A foreground, background, or border color class.

TailwindBorderClass module-attribute

TailwindBorderClass: TypeAlias = str

A border style or border-side class.

TailwindFlexClass module-attribute

TailwindFlexClass: TypeAlias = str

A flex growth or shrink class.

TailwindPassthroughClass module-attribute

TailwindPassthroughClass: TypeAlias = str

A class retained for browser output when xnano does not lower it.

TailwindSizingClass module-attribute

TailwindSizingClass: TypeAlias = str

A width or height class.

TailwindSpacingClass module-attribute

TailwindSpacingClass: TypeAlias = str

A padding, margin, or gap class.

TailwindTypographyClass module-attribute

TailwindTypographyClass: TypeAlias = str

A text modifier or alignment class.

KNOWN_TAILWIND_CLASSES module-attribute

KNOWN_TAILWIND_CLASSES: frozenset[str] = frozenset()

Known classes are resolved by grammar, so this set is intentionally lazy.

TailwindStyle module-attribute

TailwindStyle = Style

Resolved Tailwind style.

Style dataclass

Style(
    *,
    foreground: ColorLike | None = None,
    background: ColorLike | None = None,
    border: Border | None = None,
    border_color: ColorLike | None = None,
    border_sides: tuple[Side, ...] | None = None,
    padding: Padding | None = None,
    margin: Padding | None = None,
    gap: int | None = None,
    width: Sizing | None = None,
    height: Sizing | None = None,
    modifiers: tuple[CharacterModifier, ...] = (),
    horizontal_align: Alignment | None = None,
    direction: Direction | None = None,
    title: str | None = None,
    title_position: str | None = None,
    visible: bool | None = None,
    cursor: str | None = None,
    passthrough_classes: tuple[str, ...] = (),
    classes: tuple[str, ...] = ()
)

Style derived from Tailwind utility classes.

Attributes:

Examples:

style = resolve_tailwind_style("text-red-500 bg-black p-2 rounded")

foreground class-attribute instance-attribute

foreground: ColorLike | None = None

Foreground color.

background class-attribute instance-attribute

background: ColorLike | None = None

Background 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: tuple[Side, ...] | None = None

Visible border sides.

padding class-attribute instance-attribute

padding: Padding | None = None

Inner spacing.

margin class-attribute instance-attribute

margin: Padding | None = None

Outer spacing.

gap class-attribute instance-attribute

gap: int | None = None

Cells between children.

width class-attribute instance-attribute

width: Sizing | None = None

Horizontal size.

height class-attribute instance-attribute

height: Sizing | None = None

Vertical size.

modifiers class-attribute instance-attribute

modifiers: tuple[CharacterModifier, ...] = ()

Character modifiers.

horizontal_align class-attribute instance-attribute

horizontal_align: Alignment | None = None

Horizontal alignment.

direction class-attribute instance-attribute

direction: Direction | None = None

Child layout direction.

title class-attribute instance-attribute

title: str | None = None

Optional frame title.

title_position class-attribute instance-attribute

title_position: str | None = None

Frame title alignment.

visible class-attribute instance-attribute

visible: bool | None = None

Visibility override.

cursor class-attribute instance-attribute

cursor: str | None = None

Browser cursor name.

passthrough_classes class-attribute instance-attribute

passthrough_classes: tuple[str, ...] = ()

Classes retained for browser output.

classes class-attribute instance-attribute

classes: tuple[str, ...] = ()

Normalized source classes.

normalize_tailwind_classes

normalize_tailwind_classes(
    class_name: str | Sequence[str],
) -> tuple[str, ...]

Split, trim, and deduplicate utility classes.

Source code in xnano/tailwind.py
def normalize_tailwind_classes(
    class_name: str | Sequence[str],
) -> tuple[str, ...]:
    """Split, trim, and deduplicate utility classes."""
    source = class_name.split() if isinstance(class_name, str) else class_name
    return tuple(
        dict.fromkeys(token for item in source for token in item.split())
    )

resolve_tailwind_classes

resolve_tailwind_classes(
    class_name: str | Sequence[str],
) -> Style

Resolve supported utilities and preserve unknown classes for web.

Source code in xnano/tailwind.py
def resolve_tailwind_classes(class_name: str | Sequence[str]) -> Style:
    """Resolve supported utilities and preserve unknown classes for web."""
    tokens = normalize_tailwind_classes(class_name)
    values: dict[str, object] = {}
    padding: dict[str, int] = {}
    margin: dict[str, int] = {}
    modifiers: list[CharacterModifier] = []
    border_sides: list[Side] = []
    passthrough: list[str] = []

    for token in tokens:
        if token.startswith("text-"):
            suffix = token[5:]
            if suffix in _TEXT_ALIGNMENTS:
                values["horizontal_align"] = suffix
            elif suffix in _TEXT_MODIFIER_SUFFIXES:
                modifiers.append(_TEXT_MODIFIER_SUFFIXES[suffix])
            else:
                values["foreground"] = suffix
        elif token.startswith("bg-"):
            values["background"] = token[3:]
        elif token in _MODIFIER_CLASSES:
            modifiers.append(_MODIFIER_CLASSES[token])
        elif token in _DIRECTION_CLASSES:
            values["direction"] = _DIRECTION_CLASSES[token]
        elif token.startswith("gap-"):
            values["gap"] = _spacing_cells(token[4:], vertical=False)
        elif token.startswith(
            ("p-", "px-", "py-", "pt-", "pr-", "pb-", "pl-")
        ):
            prefix, suffix = token.split("-", 1)
            _update_spacing(padding, prefix[1:], suffix)
        elif token.startswith(
            ("m-", "mx-", "my-", "mt-", "mr-", "mb-", "ml-")
        ):
            prefix, suffix = token.split("-", 1)
            _update_spacing(margin, prefix[1:], suffix)
        elif token.startswith("w-"):
            values["width"] = Sizing.parse(token[2:].replace("full", "100%"))
        elif token.startswith("h-"):
            values["height"] = Sizing.parse(token[2:].replace("full", "100%"))
        elif token in ("border", "rounded", "rounded-md", "rounded-lg"):
            values["border"] = (
                "rounded" if token.startswith("rounded") else "plain"
            )
        elif token in _BORDER_SIDE_CLASSES:
            border_sides.append(_BORDER_SIDE_CLASSES[token])
        elif (color := _color_from_class(token, "border-")) is not None:
            values["border_color"] = color
        elif token.startswith("cursor-"):
            values["cursor"] = token[7:]
        else:
            passthrough.append(token)

    return Style(
        **values,  # ty: ignore[invalid-argument-type]
        padding=Padding(**padding) if padding else None,
        margin=Padding(**margin) if margin else None,
        modifiers=tuple(dict.fromkeys(modifiers)),
        border_sides=tuple(dict.fromkeys(border_sides)) or None,
        passthrough_classes=tuple(passthrough),
        classes=tokens,
    )