Fix P2 accessibility issues across atom components

- Input: Record<string, any> → Theme type for boxShadow theme accessor
- Button: Document aria-label requirement for icon-only usage
- Badge: Document aria-label requirement for icon-only badges
- Switch: Strengthen a11y docs — always wrap in FormControlLabel with example
- Radio: Strengthen a11y docs — always use RadioGroup + FormControlLabel with example
- Chip: Document aria-label requirement for icon-only deletable chips

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 19:55:12 +11:00
parent 9323b52376
commit b0ea3144e1
6 changed files with 31 additions and 4 deletions

View File

@@ -77,6 +77,9 @@ const softColors: Record<BadgeColor, (t: Theme) => { bg: string; text: string }>
* Variant options:
* - `soft` (default) — tonal background, coloured text. Calmer, preferred for FA.
* - `filled` — solid background, white text. For high-priority emphasis.
*
* **Accessibility**: If a Badge contains only an icon (no text children),
* provide an `aria-label` prop so screen readers can announce the status.
*/
export const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
(

View File

@@ -29,6 +29,10 @@ export interface ButtonProps extends MuiButtonProps {
* - `outlined` + `secondary` — Outlined grey (neutral border)
* - `text` + `primary` — Ghost / text button (copper text)
* - `text` + `secondary` — Ghost secondary (grey text)
*
* **Accessibility**: Icon-only buttons (no visible text) require an
* `aria-label` prop. Without it, screen readers announce nothing.
* Example: `<Button startIcon={<DeleteIcon />} aria-label="Delete item" />`
*/
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(

View File

@@ -38,6 +38,10 @@ export interface ChipProps extends MuiChipProps {
*
* Selected state:
* - `selected` prop applies brand styling (filled primary bg or outlined primary border)
*
* **Accessibility**: If a Chip has no visible label text (icon-only) and is
* deletable, provide an `aria-label` so screen readers can announce what
* is being removed.
*/
export const Chip = React.forwardRef<HTMLDivElement, ChipProps>(
(

View File

@@ -5,6 +5,7 @@ import OutlinedInput from '@mui/material/OutlinedInput';
import type { OutlinedInputProps } from '@mui/material/OutlinedInput';
import FormHelperText from '@mui/material/FormHelperText';
import InputAdornment from '@mui/material/InputAdornment';
import type { Theme } from '@mui/material/styles';
// ─── Types ───────────────────────────────────────────────────────────────────
@@ -140,7 +141,7 @@ export const Input = React.forwardRef<HTMLDivElement, InputProps>(
borderColor: 'success.main',
},
'&.Mui-focused': {
boxShadow: (theme: Record<string, any>) =>
boxShadow: (theme: Theme) =>
`0 0 0 3px ${theme.palette.common.white}, 0 0 0 5px ${theme.palette.success.main}`,
},
},

View File

@@ -18,10 +18,19 @@ export interface RadioProps extends MuiRadioProps {}
* From Parsons 1.0 Figma radio component — 16px circle with brand dot.
*
* Usage:
* - Always use inside a RadioGroup for proper keyboard navigation
* - Pair with FormControlLabel for accessible labels
* - For binary on/off, use Switch instead
* - For multi-select, use Checkbox (planned) or Chip
*
* **Accessibility**: Always use inside a `RadioGroup` and wrap each Radio
* in `FormControlLabel`. A standalone Radio without a label or group is
* inaccessible — screen readers cannot announce the option or allow
* keyboard arrow-key navigation between options.
* ```tsx
* <RadioGroup value={value} onChange={handleChange}>
* <FormControlLabel value="burial" control={<Radio />} label="Burial" />
* <FormControlLabel value="cremation" control={<Radio />} label="Cremation" />
* </RadioGroup>
* ```
*/
export const Radio = React.forwardRef<HTMLButtonElement, RadioProps>(
(props, ref) => {

View File

@@ -20,8 +20,14 @@ export interface SwitchProps extends MuiSwitchProps {}
*
* Usage:
* - Use for boolean settings ("Include catering", "Add memorial video")
* - Pair with a label via FormControlLabel for accessibility
* - For mutually exclusive options, use Radio instead
*
* **Accessibility**: Always wrap in `FormControlLabel` with a `label` prop.
* A standalone Switch without a visible label is inaccessible — screen
* readers cannot announce what the toggle controls.
* ```tsx
* <FormControlLabel control={<Switch />} label="Include catering" />
* ```
*/
export const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
(props, ref) => {