@malamute/ai-rules 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -0
- package/bin/cli.js +5 -0
- package/configs/_shared/.claude/commands/fix-issue.md +38 -0
- package/configs/_shared/.claude/commands/generate-tests.md +49 -0
- package/configs/_shared/.claude/commands/review-pr.md +77 -0
- package/configs/_shared/.claude/rules/accessibility.md +270 -0
- package/configs/_shared/.claude/rules/performance.md +226 -0
- package/configs/_shared/.claude/rules/security.md +188 -0
- package/configs/_shared/.claude/skills/debug/SKILL.md +118 -0
- package/configs/_shared/.claude/skills/learning/SKILL.md +224 -0
- package/configs/_shared/.claude/skills/review/SKILL.md +86 -0
- package/configs/_shared/.claude/skills/spec/SKILL.md +112 -0
- package/configs/_shared/CLAUDE.md +174 -0
- package/configs/angular/.claude/rules/components.md +257 -0
- package/configs/angular/.claude/rules/state.md +250 -0
- package/configs/angular/.claude/rules/testing.md +422 -0
- package/configs/angular/.claude/settings.json +31 -0
- package/configs/angular/CLAUDE.md +251 -0
- package/configs/dotnet/.claude/rules/api.md +370 -0
- package/configs/dotnet/.claude/rules/architecture.md +199 -0
- package/configs/dotnet/.claude/rules/database/efcore.md +408 -0
- package/configs/dotnet/.claude/rules/testing.md +389 -0
- package/configs/dotnet/.claude/settings.json +9 -0
- package/configs/dotnet/CLAUDE.md +319 -0
- package/configs/nestjs/.claude/rules/auth.md +321 -0
- package/configs/nestjs/.claude/rules/database/prisma.md +305 -0
- package/configs/nestjs/.claude/rules/database/typeorm.md +379 -0
- package/configs/nestjs/.claude/rules/modules.md +215 -0
- package/configs/nestjs/.claude/rules/testing.md +315 -0
- package/configs/nestjs/.claude/rules/validation.md +279 -0
- package/configs/nestjs/.claude/settings.json +15 -0
- package/configs/nestjs/CLAUDE.md +263 -0
- package/configs/nextjs/.claude/rules/components.md +211 -0
- package/configs/nextjs/.claude/rules/state/redux-toolkit.md +429 -0
- package/configs/nextjs/.claude/rules/state/zustand.md +299 -0
- package/configs/nextjs/.claude/rules/testing.md +315 -0
- package/configs/nextjs/.claude/settings.json +29 -0
- package/configs/nextjs/CLAUDE.md +376 -0
- package/configs/python/.claude/rules/database/sqlalchemy.md +355 -0
- package/configs/python/.claude/rules/fastapi.md +272 -0
- package/configs/python/.claude/rules/flask.md +332 -0
- package/configs/python/.claude/rules/testing.md +374 -0
- package/configs/python/.claude/settings.json +18 -0
- package/configs/python/CLAUDE.md +273 -0
- package/package.json +41 -0
- package/src/install.js +315 -0
package/README.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# AI Rules
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@malamute/ai-rules)
|
|
4
|
+
|
|
5
|
+
CLI to install Claude Code configuration boilerplates for Angular, Next.js, NestJS, .NET, Python and more.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Global install
|
|
11
|
+
npm install -g @malamute/ai-rules
|
|
12
|
+
|
|
13
|
+
# Or use directly with npx
|
|
14
|
+
npx @malamute/ai-rules init angular
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Single technology
|
|
21
|
+
ai-rules init angular
|
|
22
|
+
ai-rules init nestjs
|
|
23
|
+
ai-rules init python
|
|
24
|
+
|
|
25
|
+
# Fullstack (combines multiple configs)
|
|
26
|
+
ai-rules init angular nestjs
|
|
27
|
+
ai-rules init nextjs python
|
|
28
|
+
ai-rules init nextjs dotnet
|
|
29
|
+
|
|
30
|
+
# With extras
|
|
31
|
+
ai-rules init angular --with-skills # /learning, /review, /spec, /debug
|
|
32
|
+
ai-rules init angular nestjs --with-commands # fix-issue, review-pr, generate-tests
|
|
33
|
+
ai-rules init nextjs --with-rules # security, performance, accessibility
|
|
34
|
+
ai-rules init angular nestjs --all # Everything
|
|
35
|
+
|
|
36
|
+
# Custom target directory
|
|
37
|
+
ai-rules init dotnet --target ./my-project
|
|
38
|
+
|
|
39
|
+
# List available technologies
|
|
40
|
+
ai-rules list
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Available Technologies
|
|
44
|
+
|
|
45
|
+
| Technology | Stack |
|
|
46
|
+
| ---------- | ------------------------------------- |
|
|
47
|
+
| `angular` | Angular 21 + Nx + NgRx + Signals |
|
|
48
|
+
| `nextjs` | Next.js 15 + React 19 + App Router |
|
|
49
|
+
| `nestjs` | NestJS 10 + Prisma/TypeORM + Passport |
|
|
50
|
+
| `dotnet` | .NET 8 + ASP.NET Core + EF Core |
|
|
51
|
+
| `python` | FastAPI/Flask + SQLAlchemy 2.0 |
|
|
52
|
+
|
|
53
|
+
## What Gets Installed
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
your-project/
|
|
57
|
+
├── CLAUDE.md # Main instructions for Claude
|
|
58
|
+
└── .claude/
|
|
59
|
+
├── settings.json # Permissions
|
|
60
|
+
├── rules/ # Technology-specific rules
|
|
61
|
+
├── skills/ # Optional: /learning, /review, /spec, /debug
|
|
62
|
+
└── commands/ # Optional: fix-issue, review-pr, generate-tests
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Available Skills
|
|
66
|
+
|
|
67
|
+
| Skill | Usage | Description |
|
|
68
|
+
| ----------- | --------------------- | ----------------------------------------------- |
|
|
69
|
+
| `/learning` | `/learning nextjs` | Pedagogical mode - explains before implementing |
|
|
70
|
+
| `/review` | `/review src/users/` | Code review with structured checklist |
|
|
71
|
+
| `/spec` | `/spec add auth` | Technical specification before implementing |
|
|
72
|
+
| `/debug` | `/debug TypeError...` | Systematic debugging workflow |
|
|
73
|
+
|
|
74
|
+
## Available Commands
|
|
75
|
+
|
|
76
|
+
| Command | Usage | Description |
|
|
77
|
+
| ---------------- | ------------------------------------ | ------------------------------------ |
|
|
78
|
+
| `fix-issue` | `/project:fix-issue 123` | Fetch GitHub issue and implement fix |
|
|
79
|
+
| `review-pr` | `/project:review-pr 456` | Review PR diff with checklist |
|
|
80
|
+
| `generate-tests` | `/project:generate-tests src/users/` | Generate tests for a file |
|
|
81
|
+
|
|
82
|
+
## Shared Rules
|
|
83
|
+
|
|
84
|
+
When using `--with-rules` or `--all`, these transversal rules are included:
|
|
85
|
+
|
|
86
|
+
- **security.md** - OWASP Top 10 (injection, XSS, CSRF, auth, secrets)
|
|
87
|
+
- **performance.md** - N+1 queries, caching, memoization, lazy loading
|
|
88
|
+
- **accessibility.md** - WCAG 2.1 (semantic HTML, ARIA, keyboard nav)
|
|
89
|
+
|
|
90
|
+
## Technology Details
|
|
91
|
+
|
|
92
|
+
### Angular
|
|
93
|
+
|
|
94
|
+
| Aspect | Convention |
|
|
95
|
+
| -------------- | ------------------------------------------- |
|
|
96
|
+
| Components | Standalone by default, OnPush required |
|
|
97
|
+
| Templates | Always in separate `.html` files |
|
|
98
|
+
| Inputs/Outputs | `input()`, `output()`, `model()` functions |
|
|
99
|
+
| State | NgRx + Entity Adapter + Functional Effects |
|
|
100
|
+
| Tests | Vitest + Marble testing (no `.subscribe()`) |
|
|
101
|
+
|
|
102
|
+
### Next.js
|
|
103
|
+
|
|
104
|
+
| Aspect | Convention |
|
|
105
|
+
| ----------------- | ------------------------------------------ |
|
|
106
|
+
| Components | Server Components by default |
|
|
107
|
+
| Client Components | Add `'use client'` directive |
|
|
108
|
+
| Data Fetching | Server Components + `fetch()` |
|
|
109
|
+
| Mutations | Server Actions |
|
|
110
|
+
| State | Zustand (simple) / Redux Toolkit (complex) |
|
|
111
|
+
|
|
112
|
+
### NestJS
|
|
113
|
+
|
|
114
|
+
| Aspect | Convention |
|
|
115
|
+
| ------------ | -------------------------------------- |
|
|
116
|
+
| Architecture | Modular Monolith |
|
|
117
|
+
| Validation | class-validator + class-transformer |
|
|
118
|
+
| Database | Prisma (modern) / TypeORM (decorators) |
|
|
119
|
+
| Auth | Passport + JWT |
|
|
120
|
+
| Tests | Jest + Supertest |
|
|
121
|
+
|
|
122
|
+
### .NET
|
|
123
|
+
|
|
124
|
+
| Aspect | Convention |
|
|
125
|
+
| ------------ | ----------------------------------------- |
|
|
126
|
+
| Architecture | Clean Architecture (Domain → App → Infra) |
|
|
127
|
+
| API Style | Minimal APIs or Controllers |
|
|
128
|
+
| CQRS | MediatR (Commands/Queries) |
|
|
129
|
+
| ORM | Entity Framework Core |
|
|
130
|
+
| Tests | xUnit + NSubstitute + FluentAssertions |
|
|
131
|
+
|
|
132
|
+
### Python
|
|
133
|
+
|
|
134
|
+
| Aspect | Convention |
|
|
135
|
+
| ---------- | ------------------------------------------- |
|
|
136
|
+
| Frameworks | FastAPI (async) / Flask (traditional) |
|
|
137
|
+
| Validation | Pydantic v2 (FastAPI) / Marshmallow (Flask) |
|
|
138
|
+
| ORM | SQLAlchemy 2.0 (async support) |
|
|
139
|
+
| Tests | pytest + httpx |
|
|
140
|
+
| Migrations | Alembic |
|
|
141
|
+
|
|
142
|
+
## Package Structure
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
claude-code-configs/
|
|
146
|
+
├── package.json
|
|
147
|
+
├── bin/
|
|
148
|
+
│ └── cli.js # CLI entry point
|
|
149
|
+
├── src/
|
|
150
|
+
│ └── install.js # Installation logic
|
|
151
|
+
└── configs/
|
|
152
|
+
├── angular/
|
|
153
|
+
├── nextjs/
|
|
154
|
+
├── nestjs/
|
|
155
|
+
├── dotnet/
|
|
156
|
+
├── python/
|
|
157
|
+
└── _shared/
|
|
158
|
+
├── CLAUDE.md
|
|
159
|
+
└── .claude/
|
|
160
|
+
├── skills/
|
|
161
|
+
├── commands/
|
|
162
|
+
└── rules/
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Contributing
|
|
166
|
+
|
|
167
|
+
1. Fork the repository
|
|
168
|
+
2. Create a new technology folder in `configs/`
|
|
169
|
+
3. Add `CLAUDE.md` and `.claude/rules/`
|
|
170
|
+
4. Submit a PR
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Fix GitHub Issue
|
|
2
|
+
|
|
3
|
+
Fix the GitHub issue #$ARGUMENTS
|
|
4
|
+
|
|
5
|
+
## Steps
|
|
6
|
+
|
|
7
|
+
1. **Fetch the issue**
|
|
8
|
+
```bash
|
|
9
|
+
gh issue view $ARGUMENTS
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. **Analyze the issue**
|
|
13
|
+
- Understand what's being reported
|
|
14
|
+
- Identify acceptance criteria
|
|
15
|
+
- Note any labels (bug, feature, etc.)
|
|
16
|
+
|
|
17
|
+
3. **Investigate the codebase**
|
|
18
|
+
- Find relevant files
|
|
19
|
+
- Understand current behavior
|
|
20
|
+
- Identify root cause (if bug)
|
|
21
|
+
|
|
22
|
+
4. **Plan the fix**
|
|
23
|
+
- List files to modify
|
|
24
|
+
- Describe the approach
|
|
25
|
+
- Ask for confirmation before implementing
|
|
26
|
+
|
|
27
|
+
5. **Implement**
|
|
28
|
+
- Make minimal, focused changes
|
|
29
|
+
- Follow project conventions
|
|
30
|
+
- Add/update tests if needed
|
|
31
|
+
|
|
32
|
+
6. **Verify**
|
|
33
|
+
- Run tests
|
|
34
|
+
- Manually verify the fix addresses the issue
|
|
35
|
+
|
|
36
|
+
7. **Prepare for PR**
|
|
37
|
+
- Summarize changes
|
|
38
|
+
- Reference the issue number in commit message: `fix: description (#$ARGUMENTS)`
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Generate Tests
|
|
2
|
+
|
|
3
|
+
Generate tests for: $ARGUMENTS
|
|
4
|
+
|
|
5
|
+
## Steps
|
|
6
|
+
|
|
7
|
+
1. **Analyze the target**
|
|
8
|
+
- Read the file/function to test
|
|
9
|
+
- Understand its purpose and behavior
|
|
10
|
+
- Identify dependencies to mock
|
|
11
|
+
|
|
12
|
+
2. **Identify test cases**
|
|
13
|
+
|
|
14
|
+
### Happy path
|
|
15
|
+
- Normal inputs → expected outputs
|
|
16
|
+
|
|
17
|
+
### Edge cases
|
|
18
|
+
- Empty inputs
|
|
19
|
+
- Null/undefined
|
|
20
|
+
- Boundary values
|
|
21
|
+
- Large inputs
|
|
22
|
+
|
|
23
|
+
### Error cases
|
|
24
|
+
- Invalid inputs
|
|
25
|
+
- Missing dependencies
|
|
26
|
+
- Network/DB failures (if applicable)
|
|
27
|
+
|
|
28
|
+
3. **Check existing patterns**
|
|
29
|
+
- Find similar test files in the project
|
|
30
|
+
- Follow the same structure and conventions
|
|
31
|
+
- Use the same testing utilities
|
|
32
|
+
|
|
33
|
+
4. **Generate tests**
|
|
34
|
+
- Use project's test framework (Jest, Vitest, pytest, xUnit, etc.)
|
|
35
|
+
- Follow AAA pattern: Arrange, Act, Assert
|
|
36
|
+
- One assertion per test when possible
|
|
37
|
+
- Descriptive test names
|
|
38
|
+
|
|
39
|
+
5. **Verify**
|
|
40
|
+
- Run the new tests
|
|
41
|
+
- Ensure they pass
|
|
42
|
+
- Check coverage if available
|
|
43
|
+
|
|
44
|
+
## Output
|
|
45
|
+
|
|
46
|
+
Create the test file following project conventions:
|
|
47
|
+
- `*.spec.ts` or `*.test.ts` (JS/TS)
|
|
48
|
+
- `test_*.py` or `*_test.py` (Python)
|
|
49
|
+
- `*Tests.cs` (C#)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Review Pull Request
|
|
2
|
+
|
|
3
|
+
Review the GitHub PR #$ARGUMENTS
|
|
4
|
+
|
|
5
|
+
## Steps
|
|
6
|
+
|
|
7
|
+
1. **Fetch PR details**
|
|
8
|
+
```bash
|
|
9
|
+
gh pr view $ARGUMENTS
|
|
10
|
+
gh pr diff $ARGUMENTS
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
2. **Understand context**
|
|
14
|
+
- Read PR title and description
|
|
15
|
+
- Check linked issues
|
|
16
|
+
- Note the scope of changes
|
|
17
|
+
|
|
18
|
+
3. **Review the diff**
|
|
19
|
+
Go through each changed file and check:
|
|
20
|
+
|
|
21
|
+
### Correctness
|
|
22
|
+
- Logic errors
|
|
23
|
+
- Edge cases
|
|
24
|
+
- Error handling
|
|
25
|
+
|
|
26
|
+
### Security
|
|
27
|
+
- Input validation
|
|
28
|
+
- Injection risks
|
|
29
|
+
- Auth/authz issues
|
|
30
|
+
|
|
31
|
+
### Performance
|
|
32
|
+
- N+1 queries
|
|
33
|
+
- Unnecessary operations
|
|
34
|
+
- Memory concerns
|
|
35
|
+
|
|
36
|
+
### Code Quality
|
|
37
|
+
- Naming clarity
|
|
38
|
+
- Single responsibility
|
|
39
|
+
- Code duplication
|
|
40
|
+
|
|
41
|
+
### Tests
|
|
42
|
+
- Coverage of new code
|
|
43
|
+
- Edge cases tested
|
|
44
|
+
|
|
45
|
+
### Conventions
|
|
46
|
+
- Project style followed
|
|
47
|
+
- Consistent with codebase
|
|
48
|
+
|
|
49
|
+
4. **Provide feedback**
|
|
50
|
+
|
|
51
|
+
Format your review as:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
## Summary
|
|
55
|
+
[Overall assessment: approve/request changes/comment]
|
|
56
|
+
|
|
57
|
+
## Critical (must fix)
|
|
58
|
+
- [ ] Issue 1 (file:line)
|
|
59
|
+
- [ ] Issue 2 (file:line)
|
|
60
|
+
|
|
61
|
+
## Suggestions (nice to have)
|
|
62
|
+
- [ ] Suggestion 1
|
|
63
|
+
- [ ] Suggestion 2
|
|
64
|
+
|
|
65
|
+
## Questions
|
|
66
|
+
- Question about design choice?
|
|
67
|
+
|
|
68
|
+
## Positive
|
|
69
|
+
- What's done well
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
5. **Optional: Submit review via CLI**
|
|
73
|
+
```bash
|
|
74
|
+
gh pr review $ARGUMENTS --approve
|
|
75
|
+
gh pr review $ARGUMENTS --request-changes --body "..."
|
|
76
|
+
gh pr review $ARGUMENTS --comment --body "..."
|
|
77
|
+
```
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.tsx"
|
|
4
|
+
- "**/*.jsx"
|
|
5
|
+
- "**/*.html"
|
|
6
|
+
- "**/*.vue"
|
|
7
|
+
- "**/*.svelte"
|
|
8
|
+
- "**/components/**/*.ts"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Accessibility Rules (WCAG 2.1)
|
|
12
|
+
|
|
13
|
+
## Semantic HTML
|
|
14
|
+
|
|
15
|
+
### Use Correct Elements
|
|
16
|
+
```html
|
|
17
|
+
<!-- Bad -->
|
|
18
|
+
<div onclick="submit()">Submit</div>
|
|
19
|
+
<div class="heading">Title</div>
|
|
20
|
+
|
|
21
|
+
<!-- Good -->
|
|
22
|
+
<button type="submit">Submit</button>
|
|
23
|
+
<h1>Title</h1>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Heading Hierarchy
|
|
27
|
+
```html
|
|
28
|
+
<!-- Bad - skipping levels -->
|
|
29
|
+
<h1>Page Title</h1>
|
|
30
|
+
<h3>Section</h3>
|
|
31
|
+
|
|
32
|
+
<!-- Good - sequential -->
|
|
33
|
+
<h1>Page Title</h1>
|
|
34
|
+
<h2>Section</h2>
|
|
35
|
+
<h3>Subsection</h3>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Landmarks
|
|
39
|
+
```html
|
|
40
|
+
<header role="banner">...</header>
|
|
41
|
+
<nav role="navigation">...</nav>
|
|
42
|
+
<main role="main">...</main>
|
|
43
|
+
<aside role="complementary">...</aside>
|
|
44
|
+
<footer role="contentinfo">...</footer>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Images
|
|
48
|
+
|
|
49
|
+
### Alt Text
|
|
50
|
+
```html
|
|
51
|
+
<!-- Informative image -->
|
|
52
|
+
<img src="chart.png" alt="Sales increased 25% in Q4 2024" />
|
|
53
|
+
|
|
54
|
+
<!-- Decorative image -->
|
|
55
|
+
<img src="decoration.png" alt="" role="presentation" />
|
|
56
|
+
|
|
57
|
+
<!-- Complex image -->
|
|
58
|
+
<figure>
|
|
59
|
+
<img src="diagram.png" alt="System architecture diagram" />
|
|
60
|
+
<figcaption>Detailed description of the system architecture...</figcaption>
|
|
61
|
+
</figure>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Forms
|
|
65
|
+
|
|
66
|
+
### Labels
|
|
67
|
+
```html
|
|
68
|
+
<!-- Bad -->
|
|
69
|
+
<input type="email" placeholder="Email" />
|
|
70
|
+
|
|
71
|
+
<!-- Good -->
|
|
72
|
+
<label for="email">Email</label>
|
|
73
|
+
<input type="email" id="email" name="email" />
|
|
74
|
+
|
|
75
|
+
<!-- Or with aria-label -->
|
|
76
|
+
<input type="search" aria-label="Search products" />
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Error Messages
|
|
80
|
+
```html
|
|
81
|
+
<label for="email">Email</label>
|
|
82
|
+
<input
|
|
83
|
+
type="email"
|
|
84
|
+
id="email"
|
|
85
|
+
aria-describedby="email-error"
|
|
86
|
+
aria-invalid="true"
|
|
87
|
+
/>
|
|
88
|
+
<span id="email-error" role="alert">
|
|
89
|
+
Please enter a valid email address
|
|
90
|
+
</span>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Required Fields
|
|
94
|
+
```html
|
|
95
|
+
<label for="name">
|
|
96
|
+
Name <span aria-hidden="true">*</span>
|
|
97
|
+
</label>
|
|
98
|
+
<input type="text" id="name" required aria-required="true" />
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Keyboard Navigation
|
|
102
|
+
|
|
103
|
+
### Focus Management
|
|
104
|
+
```typescript
|
|
105
|
+
// Trap focus in modals
|
|
106
|
+
function trapFocus(element: HTMLElement) {
|
|
107
|
+
const focusableElements = element.querySelectorAll(
|
|
108
|
+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
|
109
|
+
);
|
|
110
|
+
const firstElement = focusableElements[0] as HTMLElement;
|
|
111
|
+
const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;
|
|
112
|
+
|
|
113
|
+
element.addEventListener('keydown', (e) => {
|
|
114
|
+
if (e.key === 'Tab') {
|
|
115
|
+
if (e.shiftKey && document.activeElement === firstElement) {
|
|
116
|
+
lastElement.focus();
|
|
117
|
+
e.preventDefault();
|
|
118
|
+
} else if (!e.shiftKey && document.activeElement === lastElement) {
|
|
119
|
+
firstElement.focus();
|
|
120
|
+
e.preventDefault();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Visible Focus
|
|
128
|
+
```css
|
|
129
|
+
/* Never remove focus outline without replacement */
|
|
130
|
+
/* Bad */
|
|
131
|
+
*:focus { outline: none; }
|
|
132
|
+
|
|
133
|
+
/* Good */
|
|
134
|
+
*:focus {
|
|
135
|
+
outline: 2px solid #0066cc;
|
|
136
|
+
outline-offset: 2px;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* Or custom focus styles */
|
|
140
|
+
*:focus-visible {
|
|
141
|
+
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.5);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Skip Links
|
|
146
|
+
```html
|
|
147
|
+
<a href="#main-content" class="skip-link">
|
|
148
|
+
Skip to main content
|
|
149
|
+
</a>
|
|
150
|
+
|
|
151
|
+
<style>
|
|
152
|
+
.skip-link {
|
|
153
|
+
position: absolute;
|
|
154
|
+
left: -9999px;
|
|
155
|
+
}
|
|
156
|
+
.skip-link:focus {
|
|
157
|
+
left: 0;
|
|
158
|
+
top: 0;
|
|
159
|
+
z-index: 9999;
|
|
160
|
+
}
|
|
161
|
+
</style>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## ARIA
|
|
165
|
+
|
|
166
|
+
### When to Use
|
|
167
|
+
```html
|
|
168
|
+
<!-- Use ARIA only when HTML semantics aren't enough -->
|
|
169
|
+
|
|
170
|
+
<!-- Custom components need ARIA -->
|
|
171
|
+
<div
|
|
172
|
+
role="button"
|
|
173
|
+
tabindex="0"
|
|
174
|
+
aria-pressed="false"
|
|
175
|
+
onkeydown="handleKeyDown(event)"
|
|
176
|
+
>
|
|
177
|
+
Toggle
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<!-- Prefer native elements when possible -->
|
|
181
|
+
<button type="button">Toggle</button>
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Live Regions
|
|
185
|
+
```html
|
|
186
|
+
<!-- Announce dynamic content changes -->
|
|
187
|
+
<div aria-live="polite" aria-atomic="true">
|
|
188
|
+
{{ statusMessage }}
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
<!-- Urgent announcements -->
|
|
192
|
+
<div role="alert">
|
|
193
|
+
Error: Form submission failed
|
|
194
|
+
</div>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### State Management
|
|
198
|
+
```html
|
|
199
|
+
<!-- Expanded/collapsed -->
|
|
200
|
+
<button aria-expanded="false" aria-controls="menu">
|
|
201
|
+
Menu
|
|
202
|
+
</button>
|
|
203
|
+
<ul id="menu" hidden>...</ul>
|
|
204
|
+
|
|
205
|
+
<!-- Selected -->
|
|
206
|
+
<li role="option" aria-selected="true">Option 1</li>
|
|
207
|
+
|
|
208
|
+
<!-- Loading -->
|
|
209
|
+
<button aria-busy="true" aria-disabled="true">
|
|
210
|
+
<span class="spinner" aria-hidden="true"></span>
|
|
211
|
+
Loading...
|
|
212
|
+
</button>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Color & Contrast
|
|
216
|
+
|
|
217
|
+
### Minimum Contrast
|
|
218
|
+
- Normal text: 4.5:1 ratio
|
|
219
|
+
- Large text (18px+ or 14px+ bold): 3:1 ratio
|
|
220
|
+
- UI components: 3:1 ratio
|
|
221
|
+
|
|
222
|
+
### Don't Rely on Color Alone
|
|
223
|
+
```html
|
|
224
|
+
<!-- Bad -->
|
|
225
|
+
<span class="error" style="color: red;">Invalid</span>
|
|
226
|
+
|
|
227
|
+
<!-- Good -->
|
|
228
|
+
<span class="error" style="color: red;">
|
|
229
|
+
⚠️ Invalid - please check this field
|
|
230
|
+
</span>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Motion
|
|
234
|
+
|
|
235
|
+
### Respect User Preferences
|
|
236
|
+
```css
|
|
237
|
+
@media (prefers-reduced-motion: reduce) {
|
|
238
|
+
*,
|
|
239
|
+
*::before,
|
|
240
|
+
*::after {
|
|
241
|
+
animation-duration: 0.01ms !important;
|
|
242
|
+
transition-duration: 0.01ms !important;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Testing
|
|
248
|
+
|
|
249
|
+
### Automated Tools
|
|
250
|
+
- axe-core (browser extension)
|
|
251
|
+
- eslint-plugin-jsx-a11y (React)
|
|
252
|
+
- @angular-eslint (Angular)
|
|
253
|
+
|
|
254
|
+
### Manual Testing
|
|
255
|
+
1. Navigate with keyboard only (Tab, Enter, Escape, Arrow keys)
|
|
256
|
+
2. Test with screen reader (VoiceOver, NVDA)
|
|
257
|
+
3. Zoom to 200% - check content reflows
|
|
258
|
+
4. Test with high contrast mode
|
|
259
|
+
|
|
260
|
+
## Quick Checklist
|
|
261
|
+
|
|
262
|
+
- [ ] All images have appropriate alt text
|
|
263
|
+
- [ ] Form inputs have associated labels
|
|
264
|
+
- [ ] Heading hierarchy is logical (h1 → h2 → h3)
|
|
265
|
+
- [ ] Interactive elements are keyboard accessible
|
|
266
|
+
- [ ] Focus is visible and managed correctly
|
|
267
|
+
- [ ] Color contrast meets WCAG requirements
|
|
268
|
+
- [ ] ARIA is used correctly (roles, states, properties)
|
|
269
|
+
- [ ] Dynamic content changes are announced
|
|
270
|
+
- [ ] Motion respects prefers-reduced-motion
|