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
219 changes: 140 additions & 79 deletions packages/gamut/agent-tools/commands/gamut-review.md

Large diffs are not rendered by default.

93 changes: 70 additions & 23 deletions packages/gamut/agent-tools/guidelines/components/buttons.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,91 @@
# Buttons

## Variants
Agent reference: which **button component** and which **`variant`** to use. Colors are wired inside each atom — consumers do **not** pass `color`, `bg`, hex, or semantic token names on stock buttons.

| Component | Use for | Background | Text |
|---|---|---|---|
| `FillButton` | Primary CTA, high-emphasis actions | `primary` | `white` |
| `StrokeButton` | Secondary actions, outlined style | transparent | `secondary` |
| `CTAButton` | High-visibility marketing promotions | `primary` | `white` |
| `CTAButton` (inverse) | CTA on a colored surface | `primary-inverse` | `secondary` |
| `TextButton` | Low-emphasis, inline text actions | transparent | `primary` |
| `IconButton` | Compact icon-only actions | — | — |
**Related docs:** [overview.md](../overview.md) (reading order) · [foundations/color.md](../foundations/color.md) and `gamut-color-mode` skill — semantic tokens for **custom** styled controls only, not stock button atoms · [foundations/modes.md](../foundations/modes.md) — ColorMode / `<Background>` when placing buttons on colored surfaces

**Storybook (UX source of truth):**

- [Atoms / Buttons / Button](https://gamut.codecademy.com/?path=/docs-atoms-buttons-button--docs) — variants, light/dark examples
- [FillButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-fillbutton--docs) · [StrokeButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-strokebutton--docs) · [TextButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-textbutton--docs) · [IconButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-iconbutton--docs) · [CTAButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-ctabutton--docs)
- [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) — semantic tokens for custom `css` / `variant` / `states`, not prebuilt atoms
- [UX Writing / Component guidelines / Buttons](https://gamut.codecademy.com/?path=/docs-ux-writing-component-guidelines-buttons--docs) — label copy

## Component selection

| Component | Use for | Default `variant` |
| -------------- | --------------------------------------------- | ------------------------------------------------ |
| `FillButton` | Primary / high-emphasis actions | `primary` |
| `StrokeButton` | Secondary / outlined actions | `primary` (often pass `secondary` per Storybook) |
| `TextButton` | Low-emphasis, inline actions | `primary` |
| `IconButton` | Icon-only; requires `tip` and accessible name | `secondary` |
| `CTAButton` | Marketing / high-visibility CTA only | `primary` (only option) |

## `variant` prop

Shared by `FillButton`, `StrokeButton`, `TextButton`, and `IconButton`. `CTAButton` only supports `primary`.

| `variant` | Typical use |
| ----------- | ------------------------------ |
| `primary` | Submit, main CTA |
| `secondary` | Close, cancel, low priority |
| `danger` | Destructive actions |
| `interface` | Controls styled like UI chrome |

```tsx
<FillButton variant="primary">Submit</FillButton>
<StrokeButton variant="secondary">Cancel</StrokeButton>
<IconButton icon={SearchIcon} tip="Search" variant="secondary" />
<CTAButton>Try Pro for free</CTAButton>
```

## Sizes

`small` | `normal` (default) | `large`

## Key props

| Prop | Type | Effect |
|---|---|---|
| `size` | `"small" \| "normal" \| "large"` | Controls padding and font size |
| `icon` | Icon component | Leading or trailing icon |
| `iconPosition` | `"left" \| "right"` | Defaults to left |
| `disabled` | boolean | Disabled state styling |
| `href` | string | Renders as `<a>` tag |
| Prop | Type | Effect |
| -------------- | ----------------------------------------------------- | ------------------------------------------------ |
| `variant` | `"primary" \| "secondary" \| "danger" \| "interface"` | Color emphasis (see table above) |
| `size` | `"small" \| "normal" \| "large"` | Padding and font size |
| `icon` | Icon component | Leading or trailing icon (Fill, Stroke, Text) |
| `iconPosition` | `"left" \| "right"` | Defaults to left |
| `disabled` | boolean | Disabled state styling |
| `href` | string | Renders as `<a>` tag |
| `tip` | string | Required on `IconButton` (tooltip + hover label) |

## States

`default` → `hover` (`primary-hover` / `secondary-hover`) → `active` → `disabled` (`text-disabled` + `background-disabled`)
Hover, active, and disabled colors are handled by the component. Do not override state colors with `color` / `bg` props.

## Token cheatsheet
## Accessibility — `disabled` vs `aria-disabled`

| Situation | Use | Why |
| ------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Button should not be activatable (default) | `disabled` prop | Renders native `disabled` on `<button>`; removed from tab order; correct for most forms and actions |
| Disabled button **with a tooltip** that must stay readable on focus | `aria-disabled` only — **do not** also pass `disabled` | Native `disabled` blocks keyboard focus, so the tooltip cannot be reached. Gamut disabled **styles** also match `[aria-disabled='true']`. See [ToolTip — With a disabled Button](https://gamut.codecademy.com/?path=/docs-molecules-tips-tooltip--docs) |

```tsx
// Default — not interactive
<FillButton disabled>Submit</FillButton>

// Disabled but focusable (e.g. wrapped in ToolTip explaining why)
<ToolTip id="why-disabled" info="Complete the lesson first">
<FillButton aria-describedby="why-disabled" aria-disabled>
Submit
</FillButton>
</ToolTip>
```
FillButton → bg: primary (#3A10E5 light / #FFD300 dark), color: white, hover: primary-hover
StrokeButton → bg: transparent, border: secondary (#10162F / #fff), hover: secondary-hover
TextButton → bg: transparent, color: primary, hover: primary-hover
```

- **`href` + `disabled`:** `ButtonBase` (internal) drops `href` and renders a `<button disabled>` — link-style buttons cannot stay anchors while disabled.
- **`IconButton`:** provide an accessible name via `tip` (used as `aria-label` when `aria-label` is omitted). See ToolTip / IconButton Storybook pages.
- **`ButtonBase` is not exported** from `@codecademy/gamut` (only the `ButtonBaseElements` type is). Prefer stock atoms; custom button styling belongs in Gamut itself or via `css` / `variant` from `gamut-styles`, not by importing `ButtonBase`.

## Rules

- Use `FillButton` for primary actions and `StrokeButton` for secondary — do not use both at equal weight.
- Use `FillButton` for primary actions and `StrokeButton` for secondary — do not use both at equal weight on the same screen.
- Reserve `CTAButton` for marketing / high-visibility promotions; do not use it for standard UI actions.
- Avoid placing buttons in the wrong color-mode context (e.g. light-mode buttons on a navy band without `<Background>`). See [modes.md](../foundations/modes.md).
- Every interactive `Card` wrapped in `<Anchor>` should have `isInteractive` — not a button inside.
- Do not set `color`, `bg`, or hex on stock button components. For custom styled controls, follow [color.md](../foundations/color.md) and `gamut-styles` utilities — do not import internal `ButtonBase`.
22 changes: 15 additions & 7 deletions packages/gamut/agent-tools/guidelines/components/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,36 @@ ContentContainer, GridContainer, Layout, LayoutGrid
## Key patterns

### Buttons

See [buttons.md](buttons.md) for full reference. Use `FillButton` for primary actions, `StrokeButton` for secondary.

### Forms and accessibility

**`FormGroup`**, **`GridForm`**, **`ConnectedForm`**, tips, dialogs, composite widgets: **[`skills/gamut-forms/SKILL.md`](../../skills/gamut-forms/SKILL.md)** (forms) · **[`skills/gamut-accessibility/SKILL.md`](../../skills/gamut-accessibility/SKILL.md)** (overlays, composites, checklists) · Storybook [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page).

### Cards

- **Background variants**: `default` (ColorMode-responsive), `white`, `yellow`, `beige`, `navy`, `hyper`
- **Shadow variants**: `none` (default), `outline`, `patternLeft`, `patternRight`
- Add `isInteractive` when wrapping in `<Anchor>` — enables hover shadow + `borderRadius: md`
- Default `borderRadius` is `none`; override with `borderRadius` prop

### Color-aware components

- `<ColorMode mode="light|dark|system">` — scopes a subtree to an explicit color mode
- `<Background bg="<color>">` — applies background color + auto-switches inner color mode for contrast

### Alerts
| Variant | Tokens |
|---|---|
| Error | `feedback-error` + `background-error` |

| Variant | Tokens |
| ------- | ----------------------------------------- |
| Error | `feedback-error` + `background-error` |
| Success | `feedback-success` + `background-success` |
| Warning | `feedback-warning` + `background-warning` |

## Global tokens

| Token | Value | Use |
|---|---|---|
| `headerHeight` | 64px (base), 80px (md+) | Global page header height |
| `headerZ` | 15 | Z-index for global page header |
| Token | Value | Use |
| -------------- | ----------------------- | ------------------------------ |
| `headerHeight` | 64px (base), 80px (md+) | Global page header height |
| `headerZ` | 15 | Z-index for global page header |
Loading
Loading