Initial commit: FA Design System source files

Copy of the Funeral Arranger design system components, theme, tokens,
and Storybook config from the original Parsons project. Pre-upgrade
baseline with React 18, MUI v5, Storybook 8.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-22 13:12:45 +10:00
commit 4cafd84142
2555 changed files with 40558 additions and 0 deletions

View File

@@ -0,0 +1,179 @@
import { useState } from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Switch } from './Switch';
import { Typography } from '../Typography';
import { Card } from '../Card';
import Box from '@mui/material/Box';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormGroup from '@mui/material/FormGroup';
const meta: Meta<typeof Switch> = {
title: 'Atoms/Switch',
component: Switch,
tags: ['autodocs'],
parameters: {
layout: 'centered',
design: {
type: 'figma',
url: 'https://www.figma.com/design/XUDUrw4yMkEexBCCYHXUvT/Parsons?node-id=2322-42538',
},
},
argTypes: {
checked: {
control: 'boolean',
description: 'Whether the switch is on',
},
disabled: {
control: 'boolean',
description: 'Disable the switch',
table: { defaultValue: { summary: 'false' } },
},
},
};
export default meta;
type Story = StoryObj<typeof Switch>;
// ─── Default ────────────────────────────────────────────────────────────────
/** Default switch — unchecked */
export const Default: Story = {
args: {},
};
// ─── States ─────────────────────────────────────────────────────────────────
/** All visual states */
export const States: Story = {
render: () => (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
<FormControlLabel control={<Switch />} label="Unchecked" />
<FormControlLabel control={<Switch defaultChecked />} label="Checked" />
<FormControlLabel control={<Switch disabled />} label="Disabled unchecked" />
<FormControlLabel control={<Switch disabled defaultChecked />} label="Disabled checked" />
</Box>
),
};
// ─── Interactive: Service Add-ons ───────────────────────────────────────────
/**
* Realistic arrangement form pattern — toggle add-on services.
*/
export const ServiceAddOns: Story = {
name: 'Interactive — Service Add-ons',
render: () => {
const AddOnDemo = () => {
const [addOns, setAddOns] = useState({
catering: true,
flowers: true,
music: false,
memorial: false,
guestBook: false,
});
const toggle = (key: keyof typeof addOns) => {
setAddOns((prev) => ({ ...prev, [key]: !prev[key] }));
};
const items = [
{
key: 'catering' as const,
label: 'Catering',
desc: 'Light refreshments after the service',
price: '$450',
},
{
key: 'flowers' as const,
label: 'Floral arrangements',
desc: 'Seasonal flowers for the chapel',
price: '$280',
},
{
key: 'music' as const,
label: 'Live music',
desc: 'Organist or solo musician',
price: '$350',
},
{
key: 'memorial' as const,
label: 'Memorial video',
desc: 'Photo slideshow with music',
price: '$200',
},
{
key: 'guestBook' as const,
label: 'Guest book',
desc: 'Leather-bound memorial guest book',
price: '$85',
},
];
const total = items.reduce(
(sum, item) => (addOns[item.key] ? sum + parseInt(item.price.replace('$', ''), 10) : sum),
0,
);
return (
<Box sx={{ maxWidth: 420 }}>
<Typography variant="h4" sx={{ mb: 2 }}>
Service add-ons
</Typography>
<FormGroup>
{items.map((item) => (
<Card key={item.key} variant="outlined" padding="compact" sx={{ mb: 1 }}>
<Box
sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}
>
<Box sx={{ flex: 1 }}>
<Typography variant="label">{item.label}</Typography>
<Typography variant="body2" color="text.secondary">
{item.desc}
</Typography>
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Typography variant="label" color="text.secondary">
{item.price}
</Typography>
<Switch checked={addOns[item.key]} onChange={() => toggle(item.key)} />
</Box>
</Box>
</Card>
))}
</FormGroup>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
mt: 2,
pt: 2,
borderTop: 1,
borderColor: 'divider',
}}
>
<Typography variant="labelLg">Total add-ons</Typography>
<Typography variant="labelLg" color="primary">
${total}
</Typography>
</Box>
</Box>
);
};
return <AddOnDemo />;
},
};
// ─── With Labels ────────────────────────────────────────────────────────────
/** FormControlLabel pairing — the recommended usage pattern */
export const WithLabels: Story = {
name: 'With Labels',
render: () => (
<FormGroup>
<FormControlLabel control={<Switch defaultChecked />} label="Email notifications" />
<FormControlLabel control={<Switch />} label="SMS notifications" />
<FormControlLabel control={<Switch defaultChecked />} label="Save arrangement progress" />
</FormGroup>
),
};