Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
5 changes: 5 additions & 0 deletions .changeset/quiet-forms-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@skillsoft/gamut': patch
---

Migrate Form stories into packages/gamut and fix the SelectDropdown "Remove all" button, which was focusable but `aria-hidden`. Screen readers now announce it by its label.
6 changes: 3 additions & 3 deletions packages/gamut-agent-tools/skills/gamut-forms/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,21 @@ For typical product forms, prefer `GridForm` (declarative `fields`, `LayoutGrid`

## `Radio` and `RadioGroup`

`packages/gamut/src/Form/inputs/Radio.tsx` · `packages/gamut/src/Form/inputs/RadioGroup.tsx` · reference: `packages/styleguide/src/lib/Atoms/FormInputs/Radio/Radio.mdx`
`packages/gamut/src/Form/inputs/Radio/Radio.tsx` · `packages/gamut/src/Form/inputs/Radio/RadioGroup.tsx` · reference: `packages/gamut/src/Form/inputs/Radio/Radio.stories.tsx`

### No `variant`/`size` props — state is derived, not chosen

`Radio` does not take a consumer-facing `variant` or `size` prop. Its visual state is derived internally from the booleans you already pass:

- `error?: boolean` and `disabled?: boolean` (from `BaseInputProps`) feed a `conditionalStyleState(error, disabled)` helper that resolves to `'error' | 'disabled' | undefined`, which is then applied via `variant()` (from `@skillsoft/gamut-styles`) on both the input and its label (`conditionalRadioInputStyles` / `conditionalRadioLabelStyles` in `Form/styles/Radio-styles.ts`).
- `error?: boolean` and `disabled?: boolean` (from `BaseInputProps`) feed a `conditionalStyleState(error, disabled)` helper that resolves to `'error' | 'disabled' | undefined`, which is then applied via `variant()` (from `@skillsoft/gamut-styles`) on both the input and its label (`conditionalRadioInputStyles` / `conditionalRadioLabelStyles` in `Form/inputs/Radio/styles.ts`).
- `error` wins over `disabled` when both are true — do not pass both expecting a combined visual; pick the one that matches the actual field state.
- There is no size scale — all Radio inputs render at a fixed 20×20 indicator. If a design calls for a different size, that's a design deviation to flag, not a prop to reach for.

### Visually-hidden-input pattern

The real `<input type="radio">` (`RadioInput`) is styled with `screenReaderOnly` from `@skillsoft/gamut-styles` — it stays in the accessibility tree and keeps native keyboard/focus/change behavior, but is visually hidden. The circle indicator the user sees is rendered on the sibling `RadioLabel`'s `::before` (outer ring) and `::after` (fill dot) pseudo-elements, driven by CSS sibling selectors keyed to the hidden input's `:checked`, `:hover`, and `:focus` state (`InputSelectors.CHECKED_AFTER`, `HOVER_FOCUS_BEFORE`, etc.).

Do not rebuild this with a `className`/inline-`style` override or a separate decorative `<span>` — that duplicates state the hidden input already owns and drifts out of sync on focus/hover/checked. If a design needs a different indicator look, change `Radio-styles.ts`, not the call site.
Do not rebuild this with a `className`/inline-`style` override or a separate decorative `<span>` — that duplicates state the hidden input already owns and drifts out of sync on focus/hover/checked. If a design needs a different indicator look, change `Form/inputs/Radio/styles.ts`, not the call site.

### Group and label wiring

Expand Down
130 changes: 0 additions & 130 deletions packages/gamut/src/Form/__fixtures__/utils.tsx

This file was deleted.

142 changes: 0 additions & 142 deletions packages/gamut/src/Form/__tests__/Checkbox.test.tsx

This file was deleted.

Loading
Loading