Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions skills/wix-app/references/EDITOR_REACT_COMPONENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,11 @@ File where you can override the generated manifest from `<componentName>.generat
`[[ -d "node_modules/@wix/react-component-schema" && -d "node_modules/@wix/react-component-utils" && -d "node_modules/@wix/editor-react-types" ]] || ([ -f yarn.lock ] && yarn add @wix/react-component-schema @wix/react-component-utils @wix/editor-react-types || npm install @wix/react-component-schema @wix/react-component-utils @wix/editor-react-types)`
3. Edit the generated react and CSS files in
`src/site/components/ComponentName/`.
4. Run `npx wix build && npx wix generate manifest` so the editor picks up
4. Run the A11y Review on the edited component per [`editor-react-component/A11Y-REVIEW.md`](editor-react-component/A11Y-REVIEW.md). It runs two scanners over the component's `.tsx`/`.jsx` files, triages findings, and applies fixes before the manifest is regenerated.
5. Run `npx wix build && npx wix generate manifest` so the editor picks up
the new/updated prop schema. This command regenerates manifest
parts for all components.
5. Update `Component.extensions.ts` file according to [`editor-react-component/COMPONENT-CONFIGURATION.md`](editor-react-component/COMPONENT-CONFIGURATION.md)
6. Update `Component.extensions.ts` file according to [`editor-react-component/COMPONENT-CONFIGURATION.md`](editor-react-component/COMPONENT-CONFIGURATION.md)

Reference: when modifying an _existing_ component, follow
[`editor-react-component/EDIT-FLOW.md`](editor-react-component/EDIT-FLOW.md).
Expand All @@ -69,6 +70,7 @@ Core rules and workflow: [`editor-react-component/REACT-GUIDELINES.md`](editor-r
Topic-focused references (rules + patterns + common mistakes in one place):

- [`editor-react-component/ACCESSIBILITY.md`](editor-react-component/ACCESSIBILITY.md) — ARIA/a11y rules and patterns
- [`editor-react-component/A11Y-REVIEW.md`](editor-react-component/A11Y-REVIEW.md) — Automated a11y scan + triage workflow to run after editing
- [`editor-react-component/DIRECTIONALITY.md`](editor-react-component/DIRECTIONALITY.md) — RTL/LTR rules and patterns
- [`editor-react-component/PROPS-VS-CSS.md`](editor-react-component/PROPS-VS-CSS.md) — What should be a React prop vs CSS
- [`editor-react-component/COMPONENT-API.md`](editor-react-component/COMPONENT-API.md) — Props structure, elementProps, data types, file splitting, containers, array props
Expand Down
183 changes: 183 additions & 0 deletions skills/wix-app/references/editor-react-component/A11Y-REVIEW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Editor React Component A11y Review

Use this reference to audit and fix accessibility issues in an Editor React Component before reporting completion. This complements [`ACCESSIBILITY.md`](ACCESSIBILITY.md) (which covers ARIA prop conventions and patterns) by adding an automated scan + triage workflow over the component's runtime, manifest extension, and shared code.

This is not a separate skill — it runs as part of the Editor React Component workflow described in [`../EDITOR_REACT_COMPONENT.md`](../EDITOR_REACT_COMPONENT.md). Run it after editing the React/CSS sources and before `npx wix build && npx wix generate manifest`.

## Scanner Invocation

Two scanners live at the wix-app skill root:

```bash
node skills/wix-app/scripts/scan-a11y-eslint.js <file1> [file2] ...
node skills/wix-app/scripts/scan-a11y-code.js <file1> [file2] ...
```

Run them from the consumer project root (the Wix CLI app's working directory) so dependencies resolve from the project's `package.json`. Pass paths relative to that cwd.

The ESLint scanner uses `eslint-plugin-jsx-a11y` (usually transitively available); the custom scanner performs cross-file semantic resolution (follows imports up to 4 levels deep) with confidence scoring.

## When To Run

Run the review when:

- You finished editing an Editor React Component's `.tsx` / `.module.css` files.
- The user asks for an a11y audit, accessibility review, or a11y fix on an Editor React Component.
- The user mentions missing alt text, invalid ARIA, broken semantics, direction issues, icon-only controls, or wrappers that hide accessibility issues.

Do not run on generated files (`*.generated.ts`) — they're regenerated from JSX and CSS Modules.

## Target Resolution

Resolve scope before scanning:

| User says | Required scope |
|-----------|----------------|
| Specific file | That file plus any imported wrappers / shared components it renders |
| "this component" | `<componentName>.tsx`, `component.tsx`, `<componentName>.extension.ts`, plus shared imports |
| A component name | All in-component files (excluding `*.generated.ts`) |
| "full audit" | Every Editor React Component folder under `src/site/components/`, excluding `*.generated.ts` |

## Workflow

Execute phases in order; do not pause for approval between phases.

### Phase 1: Resolve Topology

1. Enumerate in-scope files under `src/site/components/<componentName>/`.
2. Include any imported shared components or utilities that affect rendered semantics.
3. Exclude `*.generated.ts`.
4. Note the topology (wrapper → shared primitive → leaf element) before scanning.

### Phase 2a: ESLint JSX A11y Scan (Tier 0)

```bash
node skills/wix-app/scripts/scan-a11y-eslint.js <file1> [file2] ...
```

Single-file lint-level detections covering 31 `jsx-a11y` rules (interaction, focus, labeling, structural). High-signal for native elements; treat as leads for custom components. Full rule list: [`a11y-review/RULES.md`](a11y-review/RULES.md).

### Phase 2b: Custom Semantic Scan (Tier 1)

```bash
node skills/wix-app/scripts/scan-a11y-code.js <file1> [file2] ...
```

Cross-file semantic resolution with confidence scoring. Covers five rule families:

- `alt-text`
- `anchor-is-valid`
- `aria-props`
- `aria-role`
- `aria-unsupported-elements`

Neither scanner validates manifest contracts or all project-specific patterns — see Phase 3.

### Deduplication and Triage

After both scans, evaluate every Tier 0 finding before fixing.

**Deduplicate.** When both scanners flag the same location for the same issue, keep the richer one — prefer the custom scanner when it has semantic evidence; prefer ESLint when it covers a rule the custom scanner does not.

**Verdicts:**

| Verdict | Meaning | Action |
|---------|---------|--------|
| `confirmed` | The violation is real | Proceed to fix |
| `false-positive` | Lint rule fires but code is correct | Discard with one-sentence reason |
| `not-relevant` | Rule does not apply in this architecture | Discard with one-sentence reason |

**How to evaluate:**

1. **Native vs custom.** Native element findings are usually real. Custom component findings need verification — does the component render the element the rule assumes?
2. **Delegated semantics.** Editor React Components route ARIA through the typed `a11y` prop and `convertA11yKeysToHtmlFormat(a11y)` (see [`ACCESSIBILITY.md`](ACCESSIBILITY.md)). If a11y attributes reach the element via a runtime path the linter can't see, the finding is a false positive.
3. **Conditional interactivity.** When `onClick` is spread conditionally with `role`, `tabIndex`, and `onKeyDown`, the finding is a false positive. If only `onClick` is conditional, the finding is confirmed.
4. **Repo-specific exemptions** — see the originals in [`a11y-review/MANUAL-REVIEW-CHECKLIST.md`](a11y-review/MANUAL-REVIEW-CHECKLIST.md).
5. **When uncertain, default to `confirmed`.**

Only confirmed findings proceed to fix. Report discards in Phase 6 with reasons.

### Phase 3: Editor React Component Semantic Review

Perform a manual semantic review even when scanners return zero findings.

Editor React Component–specific checks:

- All ARIA attributes come through the typed `a11y?: A11y` prop — never individual `ariaLabel?: string`, `role?: string`, etc. (See [`ACCESSIBILITY.md`](ACCESSIBILITY.md).)
- `a11y` is forwarded to the root via `{...(a11y && convertA11yKeysToHtmlFormat(a11y))}`, or to an inner element via `elementProps.<name>.a11y` when requirements specify.
- Icon-only interactive elements (icon/emoji/image/svg with no text node) have an accessible name from `constants.ts` or from user-configurable `a11y` — never a hardcoded string literal.
- If the component supports text direction, the root applies `dir` (see [`DIRECTIONALITY.md`](DIRECTIONALITY.md)).
- `<componentName>.extension.ts` overrides do not strip a11y-relevant manifest fields generated from the JSX.
- Decorative-only output is hidden with `aria-hidden` when appropriate.
- Heading/tag selection (when configurable) reaches the rendered semantic element.
- Interactive-looking non-interactive elements expose keyboard behavior and roles.

Use the Tier 2 checklist in [`a11y-review/MANUAL-REVIEW-CHECKLIST.md`](a11y-review/MANUAL-REVIEW-CHECKLIST.md) alongside these checks.

### Phase 4: Fix

Apply fixes only to findings that survived triage. Confidence drives action:

- `high`: fix immediately
- `medium`: read surrounding code, confirm, then fix
- `low`: attempt to resolve semantics; fix only if confirmed

Confirmed safe/local fixes must be applied; only ambiguous or risky non-local changes may remain unresolved. See [`a11y-review/CONFIDENCE-MODEL.md`](a11y-review/CONFIDENCE-MODEL.md).

**Fix principles:**

- Preserve intended visual and runtime behavior.
- Fix the real semantic owner: component root, inner element via `elementProps`, or shared base.
- Prefer Editor React Component–native patterns: route ARIA through `a11y`, use `constants.ts` for required labels, never hardcode string literals.
- Before adding `role`, `tabIndex`, or keyboard handlers to a non-interactive element, run the pre-fix checks in [`a11y-review/FIX-STRATEGIES.md`](a11y-review/FIX-STRATEGIES.md#pre-fix-checks-for-adding-button-semantics-to-a-non-interactive-element).

### Phase 5: Verify

If any `.tsx` / `.jsx` file was edited:

1. Re-run both scanners on the modified files.
2. Run `npx wix build && npx wix generate manifest` so the manifest reflects any JSX changes (this is also required by the Editor React Component workflow).
3. Run the project's TypeScript check (`npx tsc --noEmit`) — already part of the wix-app validation flow.

Verification is mandatory after edits. Do not consider the review complete until it has run or you've explicitly reported why it could not.

### Phase 6: Report

Summarize:

1. **Topology and scope** — files reviewed, layers covered.
2. **Tier 0 ESLint findings** — grouped by rule with dispositions.
3. **Tier 1 custom scanner findings** — grouped by rule with dispositions.
4. **Tier 2 semantic findings** — including manifest/shared-layer items neither scanner catches.
5. **Verification** — scanner re-runs, `npx wix build && npx wix generate manifest`, `npx tsc --noEmit`.
6. **Unresolved items** — with exact blockers.

Every finding ends in one of:

- `fixed`
- `skipped-ambiguous`
- `skipped-risky`
- `false-positive` (one-sentence reason)
- `not-relevant` (one-sentence reason)

Any disposition other than `fixed` requires a one-sentence concrete blocker or reason.

## Confidence Handling

- `high`: fix immediately
- `medium`: confirm by reading code, then fix
- `low`: attempt to resolve semantics; fix only if confirmed; otherwise report as advisory

Severity affects reporting priority, not whether a confirmed safe/local fix should be applied.

See [`a11y-review/CONFIDENCE-MODEL.md`](a11y-review/CONFIDENCE-MODEL.md).

## References

- Rule criteria: [`a11y-review/RULES.md`](a11y-review/RULES.md)
- Fix strategies: [`a11y-review/FIX-STRATEGIES.md`](a11y-review/FIX-STRATEGIES.md)
- Tier 2 semantic checklist: [`a11y-review/MANUAL-REVIEW-CHECKLIST.md`](a11y-review/MANUAL-REVIEW-CHECKLIST.md)
- Semantic inference model: [`a11y-review/SEMANTIC-RESOLUTION.md`](a11y-review/SEMANTIC-RESOLUTION.md)
- Confidence handling: [`a11y-review/CONFIDENCE-MODEL.md`](a11y-review/CONFIDENCE-MODEL.md)
- Pattern examples: [`a11y-review/EXAMPLES.md`](a11y-review/EXAMPLES.md)
- ARIA conventions for Editor React Components: [`ACCESSIBILITY.md`](ACCESSIBILITY.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Confidence Model

## Tier 0 (ESLint) Findings

ESLint findings do not carry a confidence level from the scanner. During the triage step, assign confidence based on the flagged element:

- **Native element** (`div`, `img`, `a`, `button`, etc.): treat as `high` confidence. The rule sees the actual semantic element.
- **Custom component that resolves to a known native element** (confirmed via Tier 1 scan or by reading the source): treat as `medium` confidence.
- **Custom component that cannot be resolved** or whose semantics are delegated through runtime props/spread: evaluate for `false-positive` or `not-relevant`. If neither applies, treat as `low` confidence.

After assigning confidence, apply the same fix eligibility rules as Tier 1 findings below.

---

## Tier 1 (Custom Scanner) and Tier 2 (Manual) Findings

## High

Use high confidence when:

- the element is a native tag
- a local or package component clearly resolves to a native semantic element
- a polymorphic prop explicitly sets a native semantic element

High-confidence findings can be presented as definite issues.

**Fix eligibility**: Fix immediately. No confirmation needed.

## Medium

Use medium confidence when:

- props strongly imply semantics
- a wrapper only partially resolves but still preserves likely semantics
- the component name and surrounding evidence strongly agree

Medium-confidence findings can be presented as likely issues, but the code should still be read before applying a fix.

**Fix eligibility**: Fix after reading the surrounding code to confirm the semantic inference is correct. If confirmed, fix without asking. If the code contradicts the inference, skip the fix and report the finding as unresolved.

## Low

Use low confidence when:

- only weak heuristics support the semantic guess
- the implementation cannot be resolved
- the component might be semantic but the evidence is thin

Low-confidence matches are not definite violations. Treat them as leads for manual review.

**Fix eligibility**: Read the code and attempt to resolve the semantics. If the code confirms the issue, upgrade to medium or high and fix. If the semantics remain unclear, skip the fix and report the finding as advisory only.

## Confidence vs. Actionability

Confidence answers "is this issue real?" It does not answer "is this issue important enough to fix?"

Use this decision rule after reading the code:

- Confirmed + safe/local fix => fix now.
- Confirmed + risky behavior change or non-local refactor => report as unresolved with the exact blocker.
- Unconfirmed or ambiguous => advisory only.

If you can see the violation in the code and describe a localized, behavior-preserving fix, treat it as confirmed and fix it.

## Valid Reasons to Skip a Fix

Only skip a fix when one of these is true:

- the semantics remain ambiguous after reading the code
- product intent cannot be derived from the code
- the fix would require a risky behavior change or a non-local refactor

## Invalid Reasons to Skip a Fix

Never skip a confirmed finding for any of these reasons:

- it seems low severity
- it is a secondary or convenience interaction
- it lives in a shared layer, wrapper, or component-library file
- it is outside the main component file or package the user first mentioned
- it is probably intentional without code evidence proving that intent
Loading
Loading