Add Button component with NSW DS variants, colours, sizes, and icons

Pill-shaped button with three variants (primary/secondary/tertiary),
four colour schemes (navy/red/light/surface), three sizes, and optional
left/right icon slots. 17 Storybook stories cover all combinations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 11:56:03 +10:00
parent ba796fb247
commit 40d53f86dd
3 changed files with 284 additions and 25 deletions

68
plans/button.md Normal file
View File

@@ -0,0 +1,68 @@
# Button Component Plan
## Source
Example pasted into Figma Examples page (node 10:20). Original has 5 properties × many values = 360+ variants. We're building the light-mode subset.
## Props (React)
```tsx
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'tertiary'
color?: 'navy' | 'red' | 'light' | 'surface'
size?: 'default' | 'comfortable' | 'compact'
leftIcon?: React.ReactNode
rightIcon?: React.ReactNode
}
```
- `children` is the label text
- States (hover, active, focus, disabled) handled via CSS pseudo-classes
- Uses `forwardRef` to wrap `<button>`
## Colour Scheme Mapping
| Prop value | Example name | Primary bg | Primary text | Secondary border | Our tokens |
|---|---|---|---|---|---|
| `navy` | Navy | #002664 | white | #002664 | `blue-01`, `white` |
| `red` | Red | #D7153A | white | #D7153A | `red-02`, `white` |
| `light` | On Primary (Teal) | #CBEDFD | #002664 | #002664 | `blue-04`, `blue-01` |
| `surface` | On Surface | #22272B | white | #22272B | `grey-01`*, `white` |
*Note: source uses #22272B, our grey-01 is #3D3D3D. Close enough for now — revisit if the NSW DS specifies #22272B.
### Variant × Colour behaviour
- **Primary**: filled background, white or dark text
- **Secondary**: transparent bg, 2px border, coloured text
- **Tertiary**: no fill, no border, coloured text (ghost)
## Sizes
| Size | Height | Padding | Typography |
|---|---|---|---|
| Default | 48px | 24px horizontal | Body Strong (16/24 bold) |
| Comfortable | 40px | 20px horizontal | Body Strong (16/24 bold) |
| Compact | 36px | 16px horizontal | Small Strong (14/19 bold) |
## Shared Styling
- Border radius: `rounded-full` (pill shape, 9999px)
- Icon size: 24px (default), 20px (compact)
- Content gap: 8px
- Focus ring: 2px border offset (matches example's "Border" layer)
- Disabled: opacity 50%, cursor not-allowed
## Hover/Active States
- **Primary**: overlay with white at ~10% opacity (hover), ~20% (active)
- **Secondary/Tertiary**: bg fill at ~5% opacity (hover), ~10% (active)
- Implementation: CSS `hover:` and `active:` with bg-opacity modifiers
## Build Order
1. Add tokens (if needed) to tokens.css
2. Build React component + stories
3. Build Figma component on Components page (rebind to our variables)
4. Code Connect link
5. addon-designs embed in story
## Questions resolved
- All four colour schemes included
- Icon slots as ReactNode
- No dark mode