Source code for rational.events
"""Event payloads and declarative browser-local operations.
Python never runs in the browser. ``js.*`` builds a small, closed set of
operations that the runtime executes locally, with no server round trip.
Targets are CSS selectors; ``None`` means the element itself and
``"closest:<selector>"`` searches its ancestors.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any
from .styling.theme import ThemeMode
[docs]
@dataclass(frozen=True, slots=True)
class Event:
"""Generic payload for handlers annotated with ``event: Event``."""
name: str
value: Any = None
key: str | None = None
form: dict[str, Any] = field(default_factory=dict)
[docs]
@dataclass(frozen=True, slots=True)
class ClientOp:
op: str
args: tuple[str | None, ...]
def to_json(self) -> list[str | None]:
return [self.op, *self.args]
class js: # noqa: N801 - used as a namespace: js.toggle_class(...)
@staticmethod
def toggle_class(cls: str, target: str | None = None) -> ClientOp:
return ClientOp("toggle_class", (target, cls))
@staticmethod
def add_class(cls: str, target: str | None = None) -> ClientOp:
return ClientOp("add_class", (target, cls))
@staticmethod
def remove_class(cls: str, target: str | None = None) -> ClientOp:
return ClientOp("remove_class", (target, cls))
@staticmethod
def set_attr(name: str, value: str, target: str | None = None) -> ClientOp:
return ClientOp("set_attr", (target, name, value))
@staticmethod
def toggle_attr(name: str, on: str = "true", off: str = "false", target: str | None = None) -> ClientOp:
"""Flip ``name`` between two values, e.g. ``aria-expanded``."""
return ClientOp("toggle_attr", (target, name, on, off))
@staticmethod
def confirm(message: str) -> ClientOp:
"""Ask the user first; if they decline, the rest of the operations and the server event are skipped."""
return ClientOp("confirm", (None, message))
@staticmethod
def focus(target: str) -> ClientOp:
return ClientOp("focus", (target,))
@staticmethod
def set_theme(mode: ThemeMode) -> ClientOp:
return ClientOp("set_theme", (None, mode))
@staticmethod
def toggle_theme() -> ClientOp:
return ClientOp("toggle_theme", (None,))