Add IconButton, Divider, and Link atom components

IconButton:
- Wraps MUI IconButton with FA theme (focus ring, brand hover colours)
- 3 sizes reusing Button height tokens: small 32px, medium 40px, large 48px
- 5 stories: Default, Sizes, Colours, States, CommonUseCases

Divider:
- Wraps MUI Divider with FA border token
- Horizontal/vertical, fullWidth/inset/middle variants, text support
- 6 stories: Default, Variants, Vertical, WithText, InContent, NavigationList

Link:
- Wraps MUI Link with FA brand colour (copper brand.600, 4.8:1 contrast)
- Underline on hover by default, focus-visible ring, fontWeight 500
- 7 stories: Default, UnderlineVariants, ColourVariants, Inline, Navigation,
  FooterLinks, OnDifferentBackgrounds

Theme: Added MuiIconButton, MuiDivider, MuiLink overrides

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 20:16:23 +11:00
parent 7c9d71cc84
commit 933dca3f09
10 changed files with 593 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Divider } from './Divider';
import Box from '@mui/material/Box';
const meta: Meta<typeof Divider> = {
title: 'Atoms/Divider',
component: Divider,
tags: ['autodocs'],
argTypes: {
orientation: { control: 'select', options: ['horizontal', 'vertical'] },
variant: { control: 'select', options: ['fullWidth', 'inset', 'middle'] },
light: { control: 'boolean' },
},
};
export default meta;
type Story = StoryObj<typeof Divider>;
// ─── Default ────────────────────────────────────────────────────────────────
export const Default: Story = {
decorators: [(Story) => <Box sx={{ width: 400 }}><Story /></Box>],
};
// ─── Variants ───────────────────────────────────────────────────────────────
/** fullWidth, inset, and middle variants */
export const Variants: Story = {
render: () => (
<Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 2 }}>
<Box>
<Box sx={{ fontSize: 12, color: 'text.secondary', mb: 1 }}>fullWidth (default)</Box>
<Divider />
</Box>
<Box>
<Box sx={{ fontSize: 12, color: 'text.secondary', mb: 1 }}>inset</Box>
<Divider variant="inset" />
</Box>
<Box>
<Box sx={{ fontSize: 12, color: 'text.secondary', mb: 1 }}>middle</Box>
<Divider variant="middle" />
</Box>
</Box>
),
};
// ─── Vertical ───────────────────────────────────────────────────────────────
/** Vertical divider inside a flex container */
export const Vertical: Story = {
render: () => (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, height: 40 }}>
<Box>Left</Box>
<Divider orientation="vertical" flexItem />
<Box>Right</Box>
</Box>
),
};
// ─── With Text ──────────────────────────────────────────────────────────────
/** Divider with centered text (MUI "textAlign" support) */
export const WithText: Story = {
name: 'With Text',
render: () => (
<Box sx={{ width: 400, display: 'flex', flexDirection: 'column', gap: 3 }}>
<Divider>OR</Divider>
<Divider textAlign="left">Section</Divider>
<Divider textAlign="right">End</Divider>
</Box>
),
};
// ─── In Content ─────────────────────────────────────────────────────────────
/** Dividers separating content sections */
export const InContent: Story = {
name: 'In Content',
render: () => (
<Box sx={{ width: 400, p: 3, border: '1px solid', borderColor: 'divider', borderRadius: 1 }}>
<Box sx={{ fontWeight: 600, mb: 1 }}>Service Details</Box>
<Box sx={{ fontSize: 14, color: 'text.secondary', mb: 2 }}>
Chapel service with traditional ceremony
</Box>
<Divider />
<Box sx={{ fontWeight: 600, mt: 2, mb: 1 }}>Venue</Box>
<Box sx={{ fontSize: 14, color: 'text.secondary', mb: 2 }}>
West Chapel, Strathfield
</Box>
<Divider />
<Box sx={{ fontWeight: 600, mt: 2, mb: 1 }}>Total</Box>
<Box sx={{ fontSize: 14, color: 'text.primary' }}>$2,400</Box>
</Box>
),
};
// ─── Navigation List ────────────────────────────────────────────────────────
/** Dividers between navigation items (footer pattern) */
export const NavigationList: Story = {
name: 'Navigation List',
render: () => (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5, height: 20 }}>
<Box sx={{ fontSize: 14, color: 'text.secondary' }}>FAQ</Box>
<Divider orientation="vertical" flexItem />
<Box sx={{ fontSize: 14, color: 'text.secondary' }}>Contact Us</Box>
<Divider orientation="vertical" flexItem />
<Box sx={{ fontSize: 14, color: 'text.secondary' }}>Privacy</Box>
<Divider orientation="vertical" flexItem />
<Box sx={{ fontSize: 14, color: 'text.secondary' }}>Terms</Box>
</Box>
),
};

View File

@@ -0,0 +1,41 @@
import React from 'react';
import MuiDivider from '@mui/material/Divider';
import type { DividerProps as MuiDividerProps } from '@mui/material/Divider';
// ─── Types ───────────────────────────────────────────────────────────────────
/** Props for the FA Divider component */
export interface DividerProps extends MuiDividerProps {}
// ─── Component ───────────────────────────────────────────────────────────────
/**
* Visual separator for the FA design system.
*
* Thin line for separating content sections, navigation groups, or
* list items. Wraps MUI Divider with FA border tokens.
*
* Orientations:
* - `horizontal` (default) — full-width horizontal line
* - `vertical` — full-height vertical line (use inside flex containers)
*
* Variants:
* - `fullWidth` (default) — spans the full container
* - `inset` — indented from the left (for list item separators)
* - `middle` — indented from both sides
*
* Usage:
* ```tsx
* <Divider />
* <Divider orientation="vertical" flexItem />
* <Divider variant="inset" />
* ```
*/
export const Divider = React.forwardRef<HTMLHRElement, DividerProps>(
(props, ref) => {
return <MuiDivider ref={ref} {...props} />;
},
);
Divider.displayName = 'Divider';
export default Divider;

View File

@@ -0,0 +1,2 @@
export { Divider, default } from './Divider';
export type { DividerProps } from './Divider';