mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 17:47:24 +01:00
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
163 lines
5.2 KiB
Python
163 lines
5.2 KiB
Python
"""The canonical palette table: one row per colour, named in each stack.
|
|
|
|
Split out of `palette_check.py` to hold both files under the 250-line cap.
|
|
This module is pure data -- the parsing and comparison logic lives in the
|
|
checker. Adding a token to any stack means adding a row here; the checker's
|
|
completeness half fails on a token no row accounts for, which is what stops
|
|
this table from quietly falling behind the sources it describes.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from dataclasses import dataclass
|
|
|
|
STACKS = ("md", "css", "dart", "tk")
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Token:
|
|
"""One canonical colour token and its name in each stack.
|
|
|
|
A `None` name means the token is intentionally absent from that stack;
|
|
`why` records the reason so an absence is a decision on the record rather
|
|
than an oversight.
|
|
"""
|
|
|
|
canonical: str
|
|
md: str | None
|
|
css: str | None
|
|
dart: str | None
|
|
tk: str | None
|
|
why: str = ""
|
|
|
|
|
|
# The canonical palette: one row per colour, named per stack.
|
|
#
|
|
# Deliberate absences (the `None`s) and their reasons:
|
|
# * paper/paper-raised/line-light/text-on-light/muted-on-light -- the light
|
|
# theme. CSS carries it in a `prefers-color-scheme` block (parsed
|
|
# separately below); Dart names them as constants; Tk has no light theme
|
|
# at all, because a locker surface is always dark.
|
|
# * cat-1..6 -- the categorical ramp shipped for web only. Dart and Tk have
|
|
# no chart/tag surfaces yet. Adding one means adding it here too.
|
|
# * on-scrim -- introduced by the web layer for translucent overlays; the
|
|
# other two stacks have no scrim surface.
|
|
PALETTE: tuple[Token, ...] = (
|
|
# --- neutrals, dark (all three code stacks) ---------------------------
|
|
Token("ink", "ink", "--bg", "ink", "bg"),
|
|
Token("ink-raised-1", "ink-raised-1", "--surface-1", "inkRaised1", "field_bg"),
|
|
Token(
|
|
"ink-raised-2",
|
|
"ink-raised-2",
|
|
"--surface-2",
|
|
"inkRaised2",
|
|
None,
|
|
why="Tk gates use a single raised step (field_bg); no second elevation.",
|
|
),
|
|
Token(
|
|
"line-dark",
|
|
"line-dark",
|
|
"--border",
|
|
"lineDark",
|
|
None,
|
|
why="Tk gates draw no borders; elevation is a fill step.",
|
|
),
|
|
Token("text-on-dark", "text-on-dark", "--text", "textOnDark", "fg"),
|
|
Token("muted-on-dark", "muted-on-dark", "--text-muted", "mutedOnDark", "muted"),
|
|
# --- neutrals, light --------------------------------------------------
|
|
Token(
|
|
"paper",
|
|
"paper",
|
|
"--bg@light",
|
|
"paper",
|
|
None,
|
|
why="Tk: locker surfaces are always dark; there is no light theme.",
|
|
),
|
|
Token(
|
|
"paper-raised",
|
|
"paper-raised",
|
|
"--surface-1@light",
|
|
"paperRaised",
|
|
None,
|
|
why="Tk: no light theme.",
|
|
),
|
|
# The light theme collapses both dark elevation steps onto one raised
|
|
# surface: `--surface-2` is redefined to `paper-raised` rather than
|
|
# getting a value of its own. Mapped explicitly (not exempted) so it is
|
|
# still compared -- if either half of the pair moves, this row fails.
|
|
Token(
|
|
"paper-raised-2",
|
|
"paper-raised",
|
|
"--surface-2@light",
|
|
"paperRaised",
|
|
None,
|
|
why="Light theme has one raised step; Tk has no light theme.",
|
|
),
|
|
Token(
|
|
"line-light",
|
|
"line-light",
|
|
"--border@light",
|
|
"lineLight",
|
|
None,
|
|
why="Tk: no light theme, and no borders.",
|
|
),
|
|
Token(
|
|
"text-on-light",
|
|
"text-on-light",
|
|
"--text@light",
|
|
"textOnLight",
|
|
None,
|
|
why="Tk: no light theme.",
|
|
),
|
|
Token(
|
|
"muted-on-light",
|
|
"muted-on-light",
|
|
"--text-muted@light",
|
|
"mutedOnLight",
|
|
None,
|
|
why="Tk: no light theme.",
|
|
),
|
|
# --- accent + semantic roles (all three) -------------------------------
|
|
Token("accent", "accent", "--accent", "accent", "accent"),
|
|
Token(
|
|
"info",
|
|
"info",
|
|
"--info",
|
|
"info",
|
|
None,
|
|
why="Tk: no informational role distinct from accent in the gates.",
|
|
),
|
|
Token("success", "success", "--success", "success", "success"),
|
|
Token("warning", "warning", "--warning", "warning", "warning"),
|
|
Token("danger", "danger", "--danger", "danger", "danger"),
|
|
Token("on-fill", "on-fill", "--on-fill", "onFill", "on_fill"),
|
|
Token("focus-ring", "focus-ring", "--focus-ring", None, "focus_ring"),
|
|
Token(
|
|
"on-scrim",
|
|
None,
|
|
"--on-scrim",
|
|
None,
|
|
None,
|
|
why="Web-only: no scrim/overlay surface in the Flutter or Tk layers.",
|
|
),
|
|
# --- categorical ramp (web only, for now) ------------------------------
|
|
*(
|
|
Token(
|
|
f"cat-{i}",
|
|
f"cat-{i}",
|
|
f"--cat-{i}",
|
|
None,
|
|
None,
|
|
why="Ramp shipped for web only; no chart/tag surface in Dart or Tk yet.",
|
|
)
|
|
for i in range(1, 7)
|
|
),
|
|
)
|
|
|
|
# Tokens a source legitimately defines that are not colours in the palette --
|
|
# structural/typographic values checked by structural_check.py, not the hex check.
|
|
NON_COLOUR_CSS = re.compile(
|
|
r"^--(radius|space|text|tracking|font|measure|shadow)-|^--(font-sans|font-mono|measure)$"
|
|
)
|