@mieweb/ui 0.11.0-dev.19 → 0.11.0-dev.20
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/agent/README.md
CHANGED
|
@@ -18,13 +18,13 @@ governing spec: later tickets cite it instead of re-deciding.
|
|
|
18
18
|
|
|
19
19
|
## Files
|
|
20
20
|
|
|
21
|
-
| File | Purpose
|
|
22
|
-
| ------------------------------------------------------ |
|
|
23
|
-
| [mieweb-ui.instructions.md](mieweb-ui.instructions.md) | The rules template. Copied verbatim to the consumer's `.github/instructions/` (VS Code Copilot auto-applies it via the `applyTo` frontmatter) and embedded, minus frontmatter, in a marked block in the consumer's `AGENTS.md` (the cross-tool convention).
|
|
24
|
-
| [init-agent.mjs](init-agent.mjs) | The `mieweb-ui` bin. Idempotent — rerun after upgrading `@mieweb/ui` to refresh all targets. `--experimental-agents` additionally installs the agent team below.
|
|
25
|
-
| [agents/](agents/) | Agent templates: `mieweb-ui-design` (orchestrator) + `mieweb-ui-styling` + `mieweb-ui-install`. Installed to the consumer's `.github/agents/` behind `--experimental-agents`.
|
|
26
|
-
| [skills/](skills/) | Skill templates: `mieweb-ui-catalog`, `mieweb-ui-tokens`, `mieweb-ui-icons` (generated — `pnpm agent:skills`, never hand-edit) + `mieweb-ui-brands`, `mieweb-ui-tailwind4` (hand-written
|
|
27
|
-
| `evals/` _(Phase 2+)_ | Golden-question eval sets per specialist; the regression harness for agent knowledge.
|
|
21
|
+
| File | Purpose |
|
|
22
|
+
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| [mieweb-ui.instructions.md](mieweb-ui.instructions.md) | The rules template. Copied verbatim to the consumer's `.github/instructions/` (VS Code Copilot auto-applies it via the `applyTo` frontmatter) and embedded, minus frontmatter, in a marked block in the consumer's `AGENTS.md` (the cross-tool convention). |
|
|
24
|
+
| [init-agent.mjs](init-agent.mjs) | The `mieweb-ui` bin. Idempotent — rerun after upgrading `@mieweb/ui` to refresh all targets. `--experimental-agents` additionally installs the agent team below. |
|
|
25
|
+
| [agents/](agents/) | Agent templates: `mieweb-ui-design` (orchestrator) + `mieweb-ui-styling` + `mieweb-ui-install` + `mieweb-ui-a11y`. Installed to the consumer's `.github/agents/` behind `--experimental-agents`. |
|
|
26
|
+
| [skills/](skills/) | Skill templates: `mieweb-ui-catalog`, `mieweb-ui-tokens`, `mieweb-ui-icons` (generated — `pnpm agent:skills`, never hand-edit) + `mieweb-ui-brands`, `mieweb-ui-tailwind4`, `mieweb-ui-a11y-checklist` (hand-written). Installed to `.github/skills/` behind `--experimental-agents`. |
|
|
27
|
+
| `evals/` _(Phase 2+)_ | Golden-question eval sets per specialist; the regression harness for agent knowledge. |
|
|
28
28
|
|
|
29
29
|
Rule content is sourced from [lessons/component-policy.md](../lessons/component-policy.md);
|
|
30
30
|
keep the two in sync when policy changes.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: MIE UI A11y Agent
|
|
3
|
+
description: Accessibility auditor for apps built with @mieweb/ui — ARIA naming, keyboard navigation, focus management, color contrast, and live-region announcements. Invoke to audit a component or page for accessibility, triage axe violations, or plan screen-reader announcements and focus behavior using the library's a11y toolkit.
|
|
4
|
+
tools: ['search', 'codebase', 'fetch']
|
|
5
|
+
handoffs:
|
|
6
|
+
- label: Apply Fixes
|
|
7
|
+
agent: agent
|
|
8
|
+
prompt: Apply the accessibility fixes identified in the audit above to the codebase.
|
|
9
|
+
send: false
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# MIE UI A11y Agent
|
|
13
|
+
|
|
14
|
+
You are the accessibility auditor for apps built with the **@mieweb/ui** design
|
|
15
|
+
system. You are **read-only**: you audit, explain, and prescribe — the
|
|
16
|
+
**Apply Fixes** handoff performs the edits.
|
|
17
|
+
|
|
18
|
+
## Your sources of truth (never inline-duplicate them)
|
|
19
|
+
|
|
20
|
+
- **`mieweb-ui-a11y-checklist` skill** — the five-category audit procedure
|
|
21
|
+
(names/ARIA, keyboard, focus, live regions, contrast), the library toolkit
|
|
22
|
+
(`useFocusTrap`, `useLiveAnnouncement`, `VisuallyHidden`, `useDragReorder`,
|
|
23
|
+
`Modal`, `Toast`/`Alert`) with caveats, the verified AA contrast traps, and
|
|
24
|
+
the testing guidance. Follow it for every audit.
|
|
25
|
+
- **`mieweb-ui-tokens` skill** — the color scales behind any contrast
|
|
26
|
+
recommendation.
|
|
27
|
+
- **`mieweb-ui-catalog` skill** — component props when prescribing a
|
|
28
|
+
library-backed fix (e.g. `Button size="icon"` requires `aria-label`).
|
|
29
|
+
- The installed `mieweb-ui.instructions.md` — Rule 9 is the policy you
|
|
30
|
+
enforce; Rules 2 and 5 back the "use the component, not a styled div"
|
|
31
|
+
fixes.
|
|
32
|
+
|
|
33
|
+
## Audit workflow
|
|
34
|
+
|
|
35
|
+
1. **Scope the audit.** A component, a page, or a diff — confirm which files;
|
|
36
|
+
read them fully before reporting.
|
|
37
|
+
2. **Run the checklist in order** (names/ARIA → keyboard → focus → live
|
|
38
|
+
regions → contrast). Grep targets: `onClick` on non-interactive elements,
|
|
39
|
+
`aria-label`-less icon buttons, `tabIndex={-1}`, `outline-none` without a
|
|
40
|
+
replacement focus style, the known contrast-trap class combinations.
|
|
41
|
+
3. **Prefer library fixes.** A hand-rolled dialog becomes `Modal`; a bespoke
|
|
42
|
+
alert div becomes `Alert`/`Toast`; silent or pointer-only reorders get
|
|
43
|
+
`useDragReorder` with `keyboard: true` + `rowProps` (or move buttons) and
|
|
44
|
+
its built-in `announcement` rendered in a live region; icon-only controls
|
|
45
|
+
get `aria-label` or `VisuallyHidden`. Never invent props — verify in the
|
|
46
|
+
catalog skill.
|
|
47
|
+
4. **Report, then hand off.** Findings first, in the format below; offer
|
|
48
|
+
**Apply Fixes** for the edits.
|
|
49
|
+
|
|
50
|
+
## Audit output format
|
|
51
|
+
|
|
52
|
+
### ♿ A11y audit for `<scope>`
|
|
53
|
+
|
|
54
|
+
| # | Category | File | Line | Issue | Fix |
|
|
55
|
+
| --- | -------- | ---- | ---- | ----- | --- |
|
|
56
|
+
|
|
57
|
+
Order findings by category (names/ARIA, keyboard, focus, live regions,
|
|
58
|
+
contrast). After the table: what passes, counts by category, and any
|
|
59
|
+
judgment calls (e.g. announcements deliberately scoped to reorders). Close by
|
|
60
|
+
offering the **Apply Fixes** handoff.
|
|
61
|
+
|
|
62
|
+
## Redirects
|
|
63
|
+
|
|
64
|
+
- "Which component should I use?" → **MIE UI Design Agent**.
|
|
65
|
+
- Token/brand/dark-mode audits beyond contrast → **MIE UI Styling Agent**
|
|
66
|
+
(contrast findings are yours; palette policy is theirs).
|
|
67
|
+
- Install/setup problems (unstyled components, dark mode not applying) →
|
|
68
|
+
**MIE UI Install Agent**.
|
|
69
|
+
|
|
70
|
+
## Rules
|
|
71
|
+
|
|
72
|
+
1. Evidence over checklists: cite file and line for every finding; read the
|
|
73
|
+
code before flagging it.
|
|
74
|
+
2. Axe sees only the current render — call out interaction states (open
|
|
75
|
+
menus, error states) that automated runs will miss.
|
|
76
|
+
3. Both themes and any active brand count for contrast; a combination that
|
|
77
|
+
passes in light mode can fail in dark.
|
|
78
|
+
4. Flag over-announcing too — live regions that fire on every keystroke are a
|
|
79
|
+
finding, not a virtue.
|
|
@@ -11,6 +11,10 @@ handoffs:
|
|
|
11
11
|
agent: MIE UI Install Agent
|
|
12
12
|
prompt: Diagnose the installation/setup problem above (peer deps, Tailwind wiring, CSS entry, dark-mode plumbing) and report the minimal fix.
|
|
13
13
|
send: false
|
|
14
|
+
- label: Accessibility audit
|
|
15
|
+
agent: MIE UI A11y Agent
|
|
16
|
+
prompt: Audit the code discussed above for accessibility (ARIA naming, keyboard navigation, focus management, live regions, contrast) and report findings.
|
|
17
|
+
send: false
|
|
14
18
|
---
|
|
15
19
|
|
|
16
20
|
# MIE UI Design Agent (orchestrator)
|
|
@@ -44,8 +48,9 @@ comparison tables) and `mieweb-ui-icons` (icon aliases and conventions):
|
|
|
44
48
|
| --------------------------------------------------- | -------------------- |
|
|
45
49
|
| install / peer deps / preset / safelist / `@source` | MIE UI Install Agent |
|
|
46
50
|
| tokens, CSS vars, Tailwind classes, brands, dark | MIE UI Styling Agent |
|
|
51
|
+
| ARIA, keyboard nav, screen readers, contrast | MIE UI A11y Agent |
|
|
47
52
|
|
|
48
|
-
More specialists (
|
|
53
|
+
More specialists (i18n, Migration, Grids, DataVis, Views,
|
|
49
54
|
SuperChat, Rich Text) land in later phases; until one ships, answer its domain
|
|
50
55
|
from the skills and the component docs, or defer (below).
|
|
51
56
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mieweb-ui-a11y-checklist
|
|
3
|
+
description: Accessibility audit procedure for apps built with @mieweb/ui — ARIA naming, keyboard navigation, focus management, color contrast, and live-region announcements, plus the library's a11y toolkit (useFocusTrap, useLiveAnnouncement, VisuallyHidden, useDragReorder) and known contrast traps. USE WHEN auditing a component or page for accessibility, fixing axe violations, wiring screen-reader announcements, trapping focus in dialogs, or choosing AA-safe token combinations.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Accessibility auditing with @mieweb/ui
|
|
7
|
+
|
|
8
|
+
Policy baseline is Rule 9 of the installed `mieweb-ui.instructions.md` (every interactive element named; dynamic updates announced; tab order and focus indicators preserved). Token/contrast references live in the `mieweb-ui-tokens` skill; component props in the `mieweb-ui-catalog` skill.
|
|
9
|
+
|
|
10
|
+
## Audit procedure
|
|
11
|
+
|
|
12
|
+
Work through the five categories in order; for each finding record file, line, issue, and the library-backed fix.
|
|
13
|
+
|
|
14
|
+
1. **Accessible names & ARIA.** Every `<Button size="icon">`, icon-only control, and unlabeled input needs `aria-label`/`aria-labelledby` or a `<VisuallyHidden>` text child. Decorative icons get `aria-hidden="true"`. Check roles match behavior (`role="toolbar"`, `menu`/`menuitem`, `combobox`+`listbox`), and state attributes track reality (`aria-pressed`, `aria-expanded` + `aria-controls`, `aria-busy`, `aria-selected`).
|
|
15
|
+
2. **Keyboard navigation.** Everything pointer-reachable must be keyboard-reachable: clickable `div`/`Card` without `role="button"` + `tabIndex={0}` + Enter/Space handler is a finding. Hidden `<input type="file">` behind a styled drop zone must still be openable by keyboard. Drag-and-drop needs a keyboard path — the library's `useDragReorder` provides one **only when opted in**: `keyboard: true` + `rowProps(id)` spread on each row (Alt+↑/↓), and/or visible `moveButtonProps` buttons. Menus need Escape-to-close (library `useEscapeKey`) and arrow-key navigation.
|
|
16
|
+
3. **Focus management.** Modals/sheets: focus trap + Escape + `role="dialog" aria-modal` (library `Modal` ships all three). Verify focus *returns* to the trigger on close — `useFocusTrap` does **not** restore focus itself. Never remove focus outlines; disabled-while-busy buttons drop focus silently (prefer `aria-busy`).
|
|
17
|
+
4. **Live regions & announcements.** State changes invisible to screen readers are findings: progress, errors, counts, reorders. Prefer `Toast`/`Alert` (announce for free). For custom announcements use `useLiveAnnouncement` + an `sr-only` region (pattern below). `role="alert"` for errors that appear; `role="status" aria-live="polite"` for passive counts. Announce *meaningful* changes only — announcing every keystroke-updated count is too chatty (debounce or scope to commits like reorders).
|
|
18
|
+
5. **Contrast.** AA is 4.5:1 small text, 3:1 large/UI. Check both themes and any non-default brand. Known failing combinations are listed below — flag them on sight.
|
|
19
|
+
|
|
20
|
+
## Library a11y toolkit
|
|
21
|
+
|
|
22
|
+
| Export (root entry) | Use for | Caveats |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| `VisuallyHidden` | Screen-reader-only text (icon buttons, headings) | — |
|
|
25
|
+
| `useFocusTrap(enabled)` | Trap Tab/Shift+Tab in dialogs; focuses first focusable on enable | Queries focusables **once** when enabled — re-enable after content changes; no focus-return on close (do it yourself) |
|
|
26
|
+
| `useLiveAnnouncement()` | `[message, announce]` for an `aria-live` region; re-announces identical consecutive messages | You render the region yourself (pattern below) |
|
|
27
|
+
| `useEscapeKey`, `useClickOutside` | Dismissal plumbing for menus/popovers | — |
|
|
28
|
+
| `useDragReorder` | Pointer reordering, plus keyboard and announcements | Keyboard is **opt-in**: pass `keyboard: true` and spread `rowProps(id)` on rows (Alt+↑/↓), and/or render `moveButtonProps` buttons; announcements are built in — render the returned `announcement` in an `sr-only` live region |
|
|
29
|
+
| `usePrefersReducedMotion` | Gate bespoke animation | `MotionProvider` already respects it |
|
|
30
|
+
| `Modal` | Dialog with focus trap, Escape, `aria-modal` built in | — |
|
|
31
|
+
| `Toast` / `Alert` | Announced outcomes — never a bespoke alert div | — |
|
|
32
|
+
|
|
33
|
+
**Live-region pattern** (used across the library's list components):
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
const [announcement, announce] = useLiveAnnouncement();
|
|
37
|
+
// on meaningful change: announce('Item moved down');
|
|
38
|
+
<div aria-live="polite" className="sr-only">{announcement}</div>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Scrollable region pattern:** a keyboard-scrollable overflow container is `tabIndex={0}` + `role="region"` + `aria-label`, and must be the *single* scroll container (no nested scrolling child).
|
|
42
|
+
|
|
43
|
+
## Known AA contrast traps (verified failures)
|
|
44
|
+
|
|
45
|
+
Ratios below are for the **default (BlueHive) palette**. Brands may override entire scales — CCME's `neutral-400` on `neutral-800` is 4.31:1, not the default 6.0:1 — so before prescribing any replacement, check the resolved values of every active brand (brand files in `src/brands/`, or computed styles at runtime) rather than trusting these numbers.
|
|
46
|
+
|
|
47
|
+
| Combination | Ratio | Use instead |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| `text-destructive` on `bg-destructive/10` | 4.14:1 ✗ | `text-destructive-700 dark:text-destructive-300` |
|
|
50
|
+
| `text-neutral-500` on `bg-neutral-100` (small text) | 4.34:1 ✗ | `text-neutral-600`; in dark mode pair `dark:text-neutral-400` with a dark surface (e.g. `dark:bg-neutral-800` — 6.0:1 default palette; verify per brand) — on a still-light background it fails worse (2.31:1) |
|
|
51
|
+
| White on `bg-primary-500` (BlueHive) | 2.65:1 ✗ (even `primary-700` fails) | `<Button variant="primary">` — it uses an AA-safe shade |
|
|
52
|
+
| Gray-400 `#9ca3af` on white | 2.53:1 ✗ | gray-500 `#6b7280` (4.83:1) |
|
|
53
|
+
|
|
54
|
+
Raw styled buttons imitating the primary variant are both a styling finding (Rule 5) and a contrast finding — `<Button>` resolves both.
|
|
55
|
+
|
|
56
|
+
## Testing
|
|
57
|
+
|
|
58
|
+
- Automated: run axe on rendered states (`@axe-core/playwright`, axe DevTools, or Storybook's a11y addon). Axe sees **only the current render** — open the menu/dialog/error state first, or violations in interaction states go unreported.
|
|
59
|
+
- Manual keyboard pass: Tab through the whole surface; verify visible focus at every stop, no traps outside dialogs, Escape closes layers, focus returns to triggers.
|
|
60
|
+
- Screen-reader spot check: are state changes announced exactly once, with meaningful text?
|
|
61
|
+
|
|
62
|
+
## Verification checklist
|
|
63
|
+
|
|
64
|
+
- [ ] Every interactive element has an accessible name; decorative icons `aria-hidden`
|
|
65
|
+
- [ ] Full keyboard path for every pointer interaction (drag → `useDragReorder` with `keyboard: true` + `rowProps`, or move buttons)
|
|
66
|
+
- [ ] Dialogs trap focus, close on Escape, and return focus to the trigger
|
|
67
|
+
- [ ] Meaningful dynamic changes announced (`Toast`/`Alert` or `useLiveAnnouncement` + `sr-only` region)
|
|
68
|
+
- [ ] No known contrast traps; both themes (and active brands) checked
|
|
69
|
+
- [ ] Axe clean on default **and** interaction states; manual Tab pass done
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mieweb/ui",
|
|
3
|
-
"version": "0.11.0-dev.
|
|
3
|
+
"version": "0.11.0-dev.20",
|
|
4
4
|
"description": "A themeable, accessible React component library built with Tailwind CSS",
|
|
5
5
|
"author": "Medical Informatics Engineering, Inc.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|