cadrumo.entrypoints.tui.components.theme module

The Cadrumo terminal design system: one palette, two appearances.

This module owns the presentation tokens and stylesheet shared by every full-screen surface. It does not read application settings or retain screen state; callers resolve an appearance and pass it to the installation helper. Reusable Textual widgets that consume these tokens live in cadrumo.entrypoints.tui.components.widgets.

class AppearanceHost(*args, **kwargs)[source]

Bases: Protocol

Minimal mutable theme surface needed by the appearance toggle.

theme: str
CADRUMO_CSS_TOKENS: Final[Mapping[str, str]]

The canonical presentation tokens every Cadrumo surface is built from.

Delivered through tokenised() before each Cadrumo stylesheet is handed to Textual. Pre-expansion reaches app-level CSS and each widget’s DEFAULT_CSS alike. Theme variables do not: they are resolved after widget default styles are parsed, so a token spent there raises UnresolvedVariableError in exactly the places a design system most needs to reach.

Spatial tokens are deliberately outside the two Theme objects. Light and dark differ in colour, never in measure; duplicating the scale into both themes would create two places for one fact to drift apart.

exception UnknownDesignTokenError(message=None, *, context=None, translated_message=None)[source]

Bases: CadrumoError

A stylesheet referenced a $cadrumo- token that is not declared.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • translated_message (str | None)

Return type:

None

code
tokenised(css)[source]

Resolve every $cadrumo- token in css to its declared value.

Substitution happens HERE, at import time, rather than through Textual’s get_css_variables hook. The hook works, but it makes a widget’s own DEFAULT_CSS depend on the application that happens to host it: mount a Cadrumo component inside any app that does not implement the hook – a test host, an embedder, a future surface someone forgets to wire – and the widget fails to mount on an undefined variable. A component’s styling should not be a contract with its host.

Resolving into the string keeps one canonical table and one place to edit, and leaves the shipped stylesheets self-contained. Textual’s own $ variables ($primary, $text-muted, the theme colours) are untouched and still resolve at mount, which is right: those DO change at runtime when the operator flips appearance, and these measures never do.

Raises:

UnknownDesignTokenError – When the stylesheet names a token that is not declared. A silent pass-through would reach Textual as an undefined variable and fail far from the typo.

Return type:

str

Parameters:

css (str)

BASE_CSS: Final[str]

Chrome and layout shared by every Cadrumo full-screen surface.

Every measure and every corner resolves from CADRUMO_CSS_TOKENS, so re-tuning the system’s density or shape is an edit to the token table rather than a sweep through this stylesheet and the eighteen others beside it.

resolve_theme_name(appearance, *, host_prefers_dark=True)[source]

Return the registered theme name for an operator appearance choice.

Return type:

str

Parameters:
  • appearance (str)

  • host_prefers_dark (bool)

install_cadrumo_themes(app, *, appearance=None)[source]

Register both themes on app and activate the resolved one.

The component has no settings or application-state authority. A caller that omits an appearance receives the neutral AUTO resolution.

Return type:

None

Parameters:
  • app (App)

  • appearance (str | None)

toggle_appearance(app)[source]

Flip the active surface between the light and dark appearance.

Return type:

str

Parameters:

app (AppearanceHost)