feat(t5): Auswahlgruppe mit Haken, Karten-Variante, Plus/Minus (T5a A6)
- ChoiceGroup nach Spec 10.2: gewählt mit Haken und 2-px-Tintenrahmen, „Nicht geprüft“ gestrichelt; neue Variante appearance="cards" mit Icon und Beschreibung (Winter-Ergebnis, Darstellung, Behördenmeldung). - Eigenbau-Radios in Behördenmeldung, Phänologie-Bericht und Zeilen-Ausrichtung durch ChoiceGroup ersetzt. - Button pressed → aria-pressed (Fett/Kursiv, „Aufbau als Liste“); Druck-Versatz nur mit motion-full. - NumberStepper (ganze Schritte) für Winter-Waben, Milbenzahl (neu und bearbeiten), Weiselzellen, Entnahme/Zählbestand, Startposition; Entnahme nur 1 bis Restmenge, Startposition höchstens 1000. - Baukasten-Wächter: Radios nur in ChoiceGroup, aria-pressed nur in Button und Kalender, auch in Objektform und .ts-Dateien. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
6ac9eef93b
commit
208e9baaf0
30 files changed
+809
-198
No files matched your search
@@ -81,6 +81,38 @@ const RULES: GuardRule[] = [
|
||||
scope: "src/**/*.{ts,tsx}",
|
||||
allow: [],
|
||||
},
|
||||
// Task A6: one radio group for the whole app (spec 10.2, 10.7).
|
||||
{
|
||||
id: "no role radio, radiogroup or type radio outside choice-group.tsx",
|
||||
// JSX (role="radio", type={"radio"}) and object or spread form (role: "radio"); a CSS
|
||||
// attribute selector ([role="radio"]) only finds ChoiceGroup radios and is no own build.
|
||||
pattern: /(?<![\w[-])(?:role|type)\s*[=:]\s*\{?\s*["'`]radio(?:group)?["'`]/,
|
||||
scope: "src/**/*.{ts,tsx}",
|
||||
allow: [
|
||||
{
|
||||
file: "src/components/form/choice-group.tsx",
|
||||
reason: "ChoiceGroup is the radio group of the kit: role radiogroup with one role radio per option.",
|
||||
},
|
||||
],
|
||||
},
|
||||
// Task A6: a toggle button sets aria-pressed through Button `pressed` (spec 10.2, 10.7).
|
||||
{
|
||||
id: "aria-pressed only through Button pressed",
|
||||
// JSX attribute or object/spread key ("aria-pressed": x); not the Tailwind variant aria-pressed:.
|
||||
pattern: /aria-pressed\s*=|["'`]aria-pressed["'`]\s*:/,
|
||||
scope: "src/**/*.{ts,tsx}",
|
||||
allow: [
|
||||
{
|
||||
file: "src/components/ui/button.tsx",
|
||||
reason: "Button turns its `pressed` prop into aria-pressed (toolbar toggles, not a radio group).",
|
||||
},
|
||||
{
|
||||
file: "src/app/(app)/calendar/page.tsx",
|
||||
reason:
|
||||
"The month grid is a grid of day buttons; the chosen day is pressed. It keeps the global focus and the selection ring (spec 10.2).",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const SCOPE_FILE: Record<GuardScope, RegExp> = {
|
||||
@@ -161,6 +193,21 @@ describe("baukasten guard (spec 10.7)", () => {
|
||||
expect(ownOutline.test('"p-3 focus:outline-2 focus:outline-ring"')).toBe(true);
|
||||
expect(ownOutline.test('"focus-visible:outline-2"')).toBe(true);
|
||||
expect(ownOutline.test('"outline-hidden focus:bg-accent"')).toBe(false);
|
||||
const radio = rule("no role radio, radiogroup or type radio outside choice-group.tsx").pattern;
|
||||
expect(radio.test('<input type="radio" name="x" />')).toBe(true);
|
||||
expect(radio.test('<div role="radiogroup">')).toBe(true);
|
||||
expect(radio.test("<button role={'radio'}>")).toBe(true);
|
||||
expect(radio.test('<DropdownMenuRadioItem value="a">')).toBe(false);
|
||||
const pressed = rule("aria-pressed only through Button pressed").pattern;
|
||||
expect(pressed.test("<button aria-pressed={on}>")).toBe(true);
|
||||
expect(pressed.test('"aria-pressed:bg-holo-edge/25"')).toBe(false);
|
||||
expect(pressed.test('{ "aria-pressed": on }')).toBe(true);
|
||||
expect(pressed.test("{ 'aria-pressed': on }")).toBe(true);
|
||||
expect(radio.test('{ role: "radio" }')).toBe(true);
|
||||
expect(radio.test("{ role: 'radiogroup' }")).toBe(true);
|
||||
expect(radio.test('{ type: "radio" }')).toBe(true);
|
||||
expect(radio.test('{ role: "radioactive" }')).toBe(false);
|
||||
expect(radio.test(`querySelector('[role="radio"][tabindex="0"]')`)).toBe(false);
|
||||
expect(rule("no text-white").pattern.test('"text-white/80"')).toBe(true);
|
||||
expect(rule("no gradient prop or gradient token").pattern.test("<PageHeader gradient=\"honey\" />")).toBe(true);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user