diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000000..082abd608e --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,14 @@ +{ + "hooks": { + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "node -e \"const fs=require('fs'),path=require('path');const base='src/routes/_index/components';if(!fs.existsSync(base))process.exit(0);const comps=fs.readdirSync(base,{withFileTypes:true}).filter(d=>d.isDirectory()).map(d=>d.name);let found=false;comps.forEach(c=>{const p=path.join(base,c,'pipeline-state.json');if(!fs.existsSync(p))return;try{const s=JSON.parse(fs.readFileSync(p,'utf8'));const ip=Object.entries(s.steps||{}).filter(([,v])=>v.status==='in-progress');if(ip.length){found=true;process.stdout.write('\\n⚠️ PIPELINE IN-PROGRESS — do not stop.\\n Component: '+s.component+'\\n Step '+ip.map(([k])=>k).join(', ')+' is still in-progress.\\n Read pipeline-state.json and advance to the next step before stopping.\\n');}}catch(e){}});if(found)process.exit(2);\" 2>/dev/null" + } + ] + } + ] + } +} diff --git a/.claude/skills/evo-a11y/SKILL.md b/.claude/skills/evo-a11y/SKILL.md new file mode 100644 index 0000000000..6c74665591 --- /dev/null +++ b/.claude/skills/evo-a11y/SKILL.md @@ -0,0 +1,283 @@ +--- +name: evo-a11y +description: > + Accessibility validation and incremental docs generation for evo-web components. + Runs in two passes: Pass 1 (Step 7, after static layer) validates HTML and + static storybook, then writes the static sections of accessibility+page.marko. + Pass 2 (Step 12, after all layers) validates Marko and React, then fills in + the interactive sections. The orchestrator explicitly declares which pass and + scope — never inferred from disk. Skipped entirely for style-only revisions. + Use this whenever the user says "run a11y", "validate accessibility", "generate + accessibility docs", "check ARIA", or when the orchestrator invokes Step 7 + (Pass 1) or Step 12 (Pass 2). +--- + +# evo-a11y + +You run in two passes. The orchestrator tells you which pass and scope — do not +infer from disk state (fails on revisions where old files are already present). + +The accessibility docs are built incrementally: Pass 1 writes the static +sections; Pass 2 fills in the interactive sections. For style-only revisions, +this skill is not invoked. + +--- + +## Scope declaration from orchestrator + +You will receive one of: + +- `"Pass 1 — static layer only. Steps 4–6 have run."` +- `"Pass 2 — full scope. Steps 4–11 have run."` +- `"Pass 2 — interactive scope. Steps 8–11 have run."` + +If invoked standalone without declaration, ask which pass and scope. + +--- + +## Pass 1 — Static layer validation + static a11y docs + +**Trigger:** Step 7, after static component + static storybook + css docs (Steps 4–6) + +### Phase 1a: Validate + +**HTML from `/evo-static-component` (in context):** + +- `manifest.a11y.explicitRole: true` → `role="..."` on root element +- `manifest.a11y.labelStrategy === "aria-label-prop"` → `aria-label` present +- `manifest.a11y.labelStrategy === "aria-hidden"` → `aria-hidden="true"` present for null case +- Each entry in `manifest.a11y.ariaAttributes[]` represented in at least one variant +- Root element matches `manifest.rootElement.default` +- No `
This section provides detailed instructions for how different input types + should navigate and operate the pattern.
+ +| Attribute | Description |
|---|