# SPDX-License-Identifier: AGPL-3.0-only # Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0 """UI font size scaling contracts (Settings > Appearance). The preference must scale typography through the --ui-font-scale tokens, never by mutating the root font size, so rem-based layout stays put. These contracts also act as the guard against reintroducing raw pixel typography that would silently ignore the preference. """ import re from pathlib import Path REPO = Path(__file__).resolve().parents[2] SRC = REPO / "studio/frontend/src" INDEX_CSS = (SRC / "index.css").read_text(encoding = "utf-8") STORE = (SRC / "features/settings/stores/appearance-custom-store.ts").read_text(encoding = "utf-8") SELECT = (SRC / "components/ui/select.tsx").read_text(encoding = "utf-8") # Raw numeric fontSize props are only allowed where a scaled stylesheet rule # (.recharts-text) overrides the presentation attribute at render time. FONTSIZE_PROP_ALLOWED_DIRS = ( "features/studio/sections/charts", "features/studio/sections/training-section.tsx", ) # Non-visible typography that intentionally stays fixed. FONTSIZE_STYLE_ALLOWLIST = { # Offscreen textarea; 12pt+ suppresses the iOS focus zoom. Never rendered. "lib/copy-to-clipboard.ts", } def _frontend_sources(): for path in sorted(SRC.rglob("*")): if path.suffix in {".ts", ".tsx", ".css"}: yield path def test_preference_writes_a_scale_not_the_root_font_size(): assert 'setVar("--ui-font-scale"' in STORE assert 'el.setAttribute("data-ui-font-size"' in STORE # Older builds set an inline root font-size; the applier must clear it. assert 'style.removeProperty("font-size")' in STORE assert "style.fontSize" not in STORE def test_named_text_tokens_scale(): for token, rem in ( ("--text-xs", "0.75rem"), ("--text-sm", "0.875rem"), ("--text-base", "1rem"), ("--text-lg", "1.125rem"), ): assert f"{token}: calc({rem} * var(--ui-font-scale, 1));" in INDEX_CSS def test_numeric_leading_scales_with_the_preference(): for n, rem in ((3, "0.75rem"), (5, "1.25rem"), (6, "1.5rem")): assert f"--leading-{n}: calc({rem} * var(--ui-font-scale, 1));" in INDEX_CSS def test_ui_token_families_exist(): assert "--text-ui-11: calc(0.6875rem * var(--ui-font-scale, 1));" in INDEX_CSS assert "--text-ui-10p5: calc(0.65625rem * var(--ui-font-scale, 1));" in INDEX_CSS assert "--leading-ui-17: calc(1.0625rem * var(--ui-font-scale, 1));" in INDEX_CSS def test_explicit_code_font_size_is_never_multiplied(): match = re.search(r"html\[data-code-font-size\][^{]*\{([^}]*)\}", INDEX_CSS) assert match is not None body = match.group(1) assert "var(--custom-code-font-size)" in body assert "--ui-font-scale" not in body def test_radix_select_viewport_owns_the_scroll_state(): viewport = SELECT[SELECT.index("SelectPrimitive.Viewport") :] assert "overflow-y-auto" in viewport.split("")[0] # The rounded surface itself must not scroll (WebKit squares its corners). content_cls = re.search( r"SelectPrimitive\.Content[\s\S]*?className=\{cn\(\s*\"([^\"]+)\"", SELECT ) assert content_cls is not None assert "overflow-hidden" in content_cls.group(1) assert "overflow-y-auto" not in content_cls.group(1) def test_no_raw_pixel_text_utilities(): offenders = [] for path in _frontend_sources(): text = path.read_text(encoding = "utf-8") for m in re.finditer(r"(?