- 교각점 고름 = 창 없이 근처(40 px) 아이콘 · 멀면 0.7 s 뒤 숨김 · 누름 = 창 열림(멀어져도 유지) - 창 열린 채 다른 교각점 = 열린 채 새 정보 · 닫힌 채 = 닫힌 채 · [닫기] = 창 닫고 고름 풂 - 부품 상자 아이콘 단추 「유리」 꼴 더함(견본 · 시험 552-2) - 새 지킴 시험 test_445_curve_icon · 398-2 · 408 도우미에 가짜 아이콘 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
106 lines
5.2 KiB
Python
106 lines
5.2 KiB
Python
"""552-2 부품 「단추」 · 「아이콘 단추」 · 「아이콘」 · 크기 여덟 단 지킴 시험 — 화면 확인은 ORCA.
|
|
|
|
· 크기 = data-size 여덟 단(18 ~ 42) · 단마다 높이 · 글자 · 여백 · 아이콘 · 둥글기 · 옛 sm = 18
|
|
· 단추 높이 = 글 한 줄 + 여백 + 테두리 = 단(높이를 박지 않음 — 페이지 여백 덮어쓰기 그대로)
|
|
· 상태 = :hover · :active 를 data-state 로도 받음 · 아이콘 단추 = title + aria-label
|
|
· 색 = 공통 값만(날 색 · --b01-* · --draw-* 없음) · 옛 클래스 이름 그대로 · 부르는 길(ui_template_elements) 그대로
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
UI = ROOT / "ui_template"
|
|
SIZES = [18, 20, 22, 24, 28, 32, 36, 42]
|
|
|
|
|
|
def _text(path: Path) -> str:
|
|
return path.read_text(encoding="utf-8")
|
|
|
|
|
|
def _rungs(css: str) -> dict[int, dict[str, str]]:
|
|
out = {}
|
|
for size, body in re.findall(r':where\(\[data-size="(\d+)"\]\) \{([^}]*)\}', css):
|
|
out[int(size)] = dict(re.findall(r"--ui-size-([\w-]+):\s*([^;]+);", body))
|
|
return out
|
|
|
|
|
|
def test_여덟_단():
|
|
src = _text(UI / "ui_template_button.ts")
|
|
assert "UI_SIZES = [18, 20, 22, 24, 28, 32, 36, 42] as const" in src
|
|
rungs = _rungs(_text(UI / "ui_template_button.css"))
|
|
assert sorted(rungs) == SIZES
|
|
for size, v in rungs.items():
|
|
assert v["h"] == f"{size}px"
|
|
assert set(v) == {"h", "font", "px", "icon", "radius", "gap"}
|
|
# 글자 짝 — 18 ~ 24 = 12 · 28 이상 = 14
|
|
assert v["font"] == ("var(--text-caption)" if size <= 24 else "var(--text-body-sm)")
|
|
# 아이콘 크기 — TS 짝과 같음
|
|
px = dict(re.findall(r"(\d+): (\d+)", re.search(r"ICON_PX[^{]*\{([^}]*)\}", src).group(1)))
|
|
assert {int(k): f"{v}px" for k, v in px.items()} == {s: rungs[s]["icon"] for s in SIZES}
|
|
|
|
|
|
def test_단추_높이_식():
|
|
css = _text(UI / "ui_template_button.css")
|
|
rule = re.search(r"\.ui-btn\[data-size\] \{([^}]*)\}", css).group(1)
|
|
# 552-5 — 여백 = 1em 기준 · 줄 높이 1 (페이지 글 크기 · 줄 높이가 단을 안 바꿈)
|
|
assert "calc((var(--ui-size-h) - 2px - 1em) / 2) var(--ui-size-px)" in rule
|
|
assert "line-height: 1;" in rule
|
|
assert not re.search(r"(^|[^-])height:", rule) # 높이를 박지 않음(line-height 만)
|
|
# 아이콘은 글 높이 안 — 단 높이가 아이콘 때문에 늘지 않음
|
|
assert "margin-block: calc((1em - var(--ui-size-icon)) / 2)" in css
|
|
# 32 단 = 옛 기본(여백 8 · 글 14) · 18 단 = 옛 sm(여백 2 · 글 12)
|
|
rungs = _rungs(css)
|
|
assert (32 - 2 - 14) / 2 == 8 and rungs[32]["px"] == "16px"
|
|
assert (18 - 2 - 12) / 2 == 2 and rungs[18]["px"] == "8px" and rungs[18]["radius"] == "4px"
|
|
|
|
|
|
def test_옛_이름_부르는_길():
|
|
src = _text(UI / "ui_template_button.ts")
|
|
assert 'opts.size === "sm" ? 18' in src
|
|
assert 'opts.size === "sm" ? " ui-btn--sm" : ""' in src # 옛 클래스 그대로
|
|
for cls in ("ui-btn ui-btn--", "ui-btn__icon", "ui-btn__label", "ui-icon-btn ui-icon-btn--"):
|
|
assert cls in src, cls
|
|
elements = _text(UI / "ui_template_elements.ts")
|
|
assert 'export * from "./ui_template_button";' in elements
|
|
assert "export function createButton" not in elements # 한 벌
|
|
|
|
|
|
def test_상태():
|
|
styles = _text(UI / "ui_template_elements_styles.ts")
|
|
for variant in ("filled", "ghost", "pill", "danger", "danger-ghost", "glass"):
|
|
assert f'.ui-btn--{variant}:is(:hover, [data-state="hover"]):not(:disabled)' in styles
|
|
assert '.ui-btn:is(:active, [data-state="active"]):not(:disabled)' in styles
|
|
assert "--color-primary-hover" in styles
|
|
css = _text(UI / "ui_template_button.css")
|
|
assert '.ui-icon-btn:is(:hover, [data-state="hover"]):not(:disabled)' in css
|
|
assert '.ui-icon-btn:is(:active, [data-state="active"]):not(:disabled)' in css
|
|
assert '.ui-icon-btn[aria-pressed="true"]' in css and ".ui-icon-btn:disabled" in css
|
|
assert '.ui-icon-btn--glass:is(:hover, [data-state="hover"]):not(:disabled)' in css # 445-C1
|
|
src = _text(UI / "ui_template_button.ts")
|
|
assert 'title: opts.title, "aria-label": opts.title' in src
|
|
|
|
|
|
def test_날_색_없음():
|
|
for name in ("ui_template_button.css", "ui_template_icons.css"):
|
|
css = _text(UI / name)
|
|
assert not re.search(r"#[0-9a-fA-F]{3,8}\b|rgba?\(", css), name
|
|
assert "--b01-" not in css and "--draw-" not in css and "font-family" not in css
|
|
for name in ("ui_template_button.ts", "ui_template_button.css", "ui_template_icons.ts"):
|
|
assert len(_text(UI / name).splitlines()) <= 700
|
|
|
|
|
|
def test_아이콘():
|
|
src = _text(UI / "ui_template_icons.ts")
|
|
names = re.findall(r"^ (\w+):", src[src.index("const PATHS") : src.index("} as const")], re.M)
|
|
assert len(names) == len(set(names)) >= 60
|
|
for n in ("settings", "x", "menu", "undo", "redo", "mapPin", "dots", "plus", "inbox"):
|
|
assert n in names, n
|
|
assert not re.search(
|
|
r"[\U0001F300-\U0001FAFF☀-➿]", src[src.index("const PATHS") :]
|
|
) # 그림 이모지 없음
|
|
kit = _text(ROOT / "B01_Dashboard" / "B01_Dashboard_UI_PageKit.ts")
|
|
assert "KIT_PATHS" not in kit and "return icon(name, size);" in kit # 한 벌
|