Skip to content
Draft
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
27 changes: 27 additions & 0 deletions .github/agents/primer-component-reviewer.agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
name: primer-component-reviewer
description: Reviews Primer React component changes against accepted architectural decisions and maintained repository guidance.
tools:
- read
- search
- execute
skills:
- primer-component-review
---

You are a read-only reviewer for Primer React component changes. Never modify
files.

Use the `primer-component-review` skill and its generated policy reference.
Review component APIs, implementation structure, accessibility, behavior,
stories, tests, CSS, deprecations, documentation metadata, exports, versioning,
and changesets when relevant to the diff.

Report only concrete, actionable mismatches introduced or expanded by the
change. Cite the changed file and line and the governing policy rule ID. Explain
the impact and recommend the smallest design-level correction.

Do not expose or speculate about private architectural sources. Rules labeled
`Primer architecture policy` are complete outcome-only guidance.

If the change follows the applicable policy, say so directly.
26 changes: 26 additions & 0 deletions .github/instructions/adr-review-guidance.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
applyTo: 'contributor-docs/adrs/**/*.md,contributor-docs/CONTRIBUTING.md,contributor-docs/style.md,contributor-docs/testing.md,contributor-docs/authoring-css.md,contributor-docs/behaviors.md,contributor-docs/component-contents-api-patterns.md,contributor-docs/deprecating-components.md,contributor-docs/versioning.md'
---

# Maintaining component review guidance

When an ADR or maintained contributor guide changes an actionable decision about
component APIs, implementation, accessibility, stories, testing, CSS,
deprecations, documentation, or versioning:

1. Update, add, supersede, or remove the corresponding rule in
`contributor-docs/review-guidance/policy.json`.
2. Keep each rule outcome-focused and suitable for public review comments. Do not
copy private rationale or implementation history into a rule.
3. Use `enforce` only for accepted, current expectations. Use `advisory` for
guidance that should apply only while a related contract is being designed or
expanded.
4. Ensure each affected rule cites the exact changed source in its `source`
field.
5. Run `npm run accept:review-guidance-sources` only after reviewing all rules
mapped to the changed source.
6. Run `npm run build:review-guidance`.
7. Run `npm run check:review-guidance` and
`npm run test:review-guidance`.

If the source change has no component-review impact, do not add a rule.
43 changes: 0 additions & 43 deletions .github/instructions/component-review.instructions.md

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
applyTo: 'packages/react/src/**/*.ts,packages/react/src/**/*.tsx,packages/react/src/**/*.docs.json,packages/react/src/**/*.hookDocs.json'
---

<!-- Generated by script/review-guidance.mjs. Do not edit directly. -->

# Component API language

Policy set: `architecture-api-language`. Source digest: `sanitized-import`.

Review changed code against these rules. Report only concrete, actionable mismatches introduced or expanded by the change. Cite the rule ID in each finding. Do not report pre-existing migration debt unless the change makes it worse.

### `architecture-api-language.semantic-size-names` (advisory)

- **Check:** New public size, density, thickness, and viewport-range APIs use the established semantic vocabulary instead of abbreviations, CSS literals, or default as a size name.
- **Prefer:** Use descriptive full names and semantic values that remain meaningful across platforms.
- **Authority:** Primer architecture policy: `architecture-api-language.semantic-size-names`

### `architecture-api-language.component-references` (advisory)

- **Check:** Documentation and stories use the exported code name when referring to a specific React component and sentence case when discussing a generic interface pattern.
- **Prefer:** Keep API references unambiguous without presenting every generic pattern name as a code identifier.
- **Authority:** Primer architecture policy: `architecture-api-language.component-references`

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
applyTo: 'packages/react/src/**/*Button*.tsx,packages/react/src/**/*Button*.css,packages/react/src/SelectPanel/**/*.tsx,packages/react/src/experimental/SelectPanel2/**/*.tsx'
---

<!-- Generated by script/review-guidance.mjs. Do not edit directly. -->

# Button layout semantics

Policy set: `architecture-button-layout`. Source digest: `sanitized-import`.

Review changed code against these rules. Report only concrete, actionable mismatches introduced or expanded by the change. Cite the rule ID in each finding. Do not report pre-existing migration debt unless the change makes it worse.

### `architecture-button-layout.full-width-alignment` (advisory)

- **Check:** A full-width call-to-action centers its content, while a full-width selection trigger aligns its primary content to the start and keeps any trailing affordance at the end.
- **Prefer:** Use alignment to communicate whether the control performs an action or exposes a selection.
- **Authority:** Primer architecture policy: `architecture-button-layout.full-width-alignment`

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
applyTo: 'packages/react/src/**/*.module.css'
---

<!-- Generated by script/review-guidance.mjs. Do not edit directly. -->

# Semantic color and contrast

Policy set: `architecture-color`. Source digest: `sanitized-import`.

Review changed code against these rules. Report only concrete, actionable mismatches introduced or expanded by the change. Cite the rule ID in each finding. Do not report pre-existing migration debt unless the change makes it worse.

### `architecture-color.state-roles` (advisory)

- **Check:** Open and closed states use their corresponding semantic functional color roles instead of success and danger roles.
- **Prefer:** Preserve the distinction between lifecycle state and validation or outcome semantics.
- **Authority:** Primer architecture policy: `architecture-color.state-roles`

### `architecture-color.canonical-variants`

- **Check:** The change does not introduce deprecated subtle functional color variants.
- **Prefer:** Use muted for secondary or less-prominent treatment and emphasis for stronger treatment.
- **Authority:** Primer architecture policy: `architecture-color.canonical-variants`

### `architecture-color.text-and-links` (advisory)

- **Check:** Non-decorative text and placeholders maintain at least 4.5:1 contrast against every supported background, and links remain distinguishable from surrounding text without relying only on color.
- **Prefer:** Use supported token pairs and retain a visible non-color link affordance.
- **Authority:** Primer architecture policy: `architecture-color.text-and-links`

### `architecture-color.focus-and-state` (advisory)

- **Check:** Focus indicators and simultaneously visible interactive states maintain at least 3:1 contrast against adjacent colors.
- **Prefer:** Verify contrast across supported themes without imposing a contrast requirement on purely decorative or inactive control borders.
- **Authority:** Primer architecture policy: `architecture-color.focus-and-state`

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
applyTo: 'packages/react/src/**/*.ts,packages/react/src/**/*.tsx,packages/react/src/**/*.docs.json'
---

<!-- Generated by script/review-guidance.mjs. Do not edit directly. -->

# Notification patterns

Policy set: `architecture-notifications`. Source digest: `sanitized-import`.

Review changed code against these rules. Report only concrete, actionable mismatches introduced or expanded by the change. Cite the rule ID in each finding. Do not report pre-existing migration debt unless the change makes it worse.

### `architecture-notifications.no-toast-pattern`

- **Check:** The change does not add, restore, or recommend a toast component or toast recipe.
- **Prefer:** Use a supported feedback pattern appropriate to the interaction, such as a banner, inline validation, inline message, or dialog.
- **Authority:** Primer architecture policy: `architecture-notifications.no-toast-pattern`

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
applyTo: 'packages/react/src/SelectPanel/**/*'
---

<!-- Generated by script/review-guidance.mjs. Do not edit directly. -->

# SelectPanel interaction contract

Policy set: `architecture-select-panel`. Source digest: `sanitized-import`.

Review changed code against these rules. Report only concrete, actionable mismatches introduced or expanded by the change. Cite the rule ID in each finding. Do not report pre-existing migration debt unless the change makes it worse.

### `architecture-select-panel.focus-restoration`

- **Check:** Opening moves focus to the configured initial target and closing restores focus to the trigger.
- **Prefer:** Focus the filter input by default while preserving explicit deferred-focus behavior and the component's established secondary-focus semantics.
- **Authority:** Primer architecture policy: `architecture-select-panel.focus-restoration`

### `architecture-select-panel.commit-behavior`

- **Check:** Anchored dismissal preserves the latest selection, while modal Save finalizes changes and modal cancellation or dismissal invokes the cancellation contract.
- **Prefer:** Preserve distinct anchored and modal commit semantics across every close path so consumers can restore the prior committed modal selection.
- **Authority:** Primer architecture policy: `architecture-select-panel.commit-behavior`

### `architecture-select-panel.filter-focus`

- **Check:** Input focus and filtering preserve a valid active option whenever option activation is enabled.
- **Prefer:** Keep the input and list behavior connected and normally activate the first available option after filtering.
- **Exceptions:** An explicit deferred-initial-focus configuration may wait for user interaction before assigning the active option.
- **Authority:** Primer architecture policy: `architecture-select-panel.filter-focus`

### `architecture-select-panel.keyboard-navigation`

- **Check:** Keyboard behavior supports toggling the active option, sequential tab navigation, directional option navigation, first and last option shortcuts, and Escape dismissal.
- **Prefer:** Maintain the complete interaction contract instead of adding isolated key handlers.
- **Authority:** Primer architecture policy: `architecture-select-panel.keyboard-navigation`

### `architecture-select-panel.announcements`

- **Check:** Screen-reader announcements communicate the active option, its position, and selection state without announcing on every filtering keystroke.
- **Prefer:** Use polite, delayed announcements and debounce filtering updates.
- **Authority:** Primer architecture policy: `architecture-select-panel.announcements`

90 changes: 90 additions & 0 deletions .github/instructions/generated/component-api.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
applyTo: 'packages/react/src/**/*.ts,packages/react/src/**/*.tsx'
---

<!-- Generated by script/review-guidance.mjs. Do not edit directly. -->

# Component API and implementation

Policy set: `component-api`. Source digest: `e2ac6c7a9525`.

Review changed code against these rules. Report only concrete, actionable mismatches introduced or expanded by the change. Cite the rule ID in each finding. Do not report pre-existing migration debt unless the change makes it worse.

### `component-api.spectrum-of-abstraction`

- **Check:** New component APIs begin with flexible presentational components and behavior hooks unless the product pattern and its defaults are already stable.
- **Prefer:** Build config components by composing established presentational parts and hooks instead of duplicating their behavior or markup.
- **Authority:** `contributor-docs/style.md`

### `component-api.children-for-content`

- **Check:** Content uses React children when consumers own the rendered elements or need free-form composition.
- **Prefer:** Use data props when the component must own, transform, order, or constrain the rendered elements. Do not support equivalent children and data APIs simultaneously without a concrete need.
- **Authority:** `contributor-docs/component-contents-api-patterns.md`

### `component-api.no-speculative-parts`

- **Check:** Compound parts, render props, child-prop pass-through APIs, and escape hatches address demonstrated use cases rather than speculative flexibility.
- **Prefer:** Start with the smallest API that supports known scenarios and open it up when a concrete need appears.
- **Authority:** `contributor-docs/adrs/adr-004-children-as-api.md`

### `component-api.avoid-slots-by-default`

- **Check:** Slots, useSlots, and __SLOT__ markers are only introduced when a parent must identify a specific child or the requested API requires child extraction.
- **Prefer:** Use normal React composition and preserve consumer-authored child order.
- **Authority:** `contributor-docs/style.md`

### `component-api.reuse-base-primitives`

- **Check:** Components reuse existing base components, accessibility primitives, hooks, and utilities before introducing parallel implementations.
- **Prefer:** Use primitives such as ButtonBase for Primer-owned native semantics, interactions, and reset styling.
- **Authority:** `contributor-docs/style.md`

### `component-api.controlled-state`

- **Check:** Components supporting controlled and uncontrolled state use the shared useControllableState pattern.
- **Prefer:** Keep controlled value, default value, and change callback behavior aligned with the repository helper.
- **Authority:** `contributor-docs/style.md`

### `component-api.root-rest-props`

- **Check:** Forwarded rest props and className are applied to the component root unless the public contract explicitly identifies another element.
- **Prefer:** Test that forwarded props reach the documented element.
- **Authority:** `contributor-docs/style.md`

### `component-api.extensible-callbacks`

- **Check:** New public callback props use a single object argument when the callback payload may grow.
- **Prefer:** Use a named object payload instead of positional arguments.
- **Authority:** `contributor-docs/style.md`

### `component-api.ssr`

- **Check:** Render paths avoid browser-only APIs and hydration-dependent layout changes.
- **Prefer:** Progressively enhance after hydration and move browser access into appropriate effects or event handlers.
- **Authority:** `contributor-docs/style.md`

### `component-api.focus-from-events`

- **Check:** Focus moves as a direct result of user events rather than unrelated effect dependency changes.
- **Prefer:** Manage focus in the event handler that caused the transition.
- **Authority:** `contributor-docs/style.md`

### `component-api.hook-ref-input`

- **Check:** Hooks that operate on a caller-owned DOM node accept a ref instead of creating and returning an incompatible ref.
- **Prefer:** Let callers compose multiple behaviors around the same ref.
- **Authority:** `contributor-docs/style.md`

### `component-api.stable-hook-callbacks`

- **Check:** Hook effects do not repeatedly resubscribe solely because a callback argument changed identity.
- **Prefer:** Use the repository stable-callback pattern so subscriptions always call the latest callback.
- **Authority:** `contributor-docs/style.md`

### `component-api.public-hooks-need-consumers`

- **Check:** New public hooks represent a clear consumer capability rather than exposing subcomponent implementation details.
- **Prefer:** Keep behavior hooks internal until a supported external use case and complete public contract exist.
- **Authority:** `contributor-docs/style.md`

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
applyTo: 'packages/react/src/**/*'
---

<!-- Generated by script/review-guidance.mjs. Do not edit directly. -->

# Component files and public surface

Policy set: `component-structure`. Source digest: `21badb7273eb`.

Review changed code against these rules. Report only concrete, actionable mismatches introduced or expanded by the change. Cite the rule ID in each finding. Do not report pre-existing migration debt unless the change makes it worse.

### `component-structure.colocate-files`

- **Check:** New components use a PascalCase directory and colocate implementation, CSS, tests, stories, docs metadata, and exports according to repository conventions.
- **Prefer:** Name subcomponent files with the parent component prefix for discoverability.
- **Authority:** `contributor-docs/adrs/adr-013-file-structure.md`

### `component-structure.internal-modules`

- **Check:** New shared modules that are not public API live under packages/react/src/internal and are not exported from public entrypoints.
- **Prefer:** Keep implementation details internal until a supported public API is intentionally designed.
- **Authority:** `contributor-docs/adrs/adr-015-internal-modules.md`

### `component-structure.stable-identifiers` (advisory)

- **Check:** New or changed component roots, public subcomponents, and meaningful structural parts follow the established data-component naming contract.
- **Prefer:** Use PascalCase component API names, keep state in separate data attributes, and test stable identifier values.
- **Authority:** `contributor-docs/adrs/adr-023-stable-selectors-api.md`

### `component-structure.complete-public-surface`

- **Check:** Public API changes update exports, export snapshots, docs metadata, tests, stories, and changesets as applicable.
- **Prefer:** Treat all public surfaces as one component contract.
- **Authority:** `contributor-docs/CONTRIBUTING.md`

Loading
Loading